Skip to content

GetBlobChunk fails with "found multiple chunks with number" after concurrent upload #490

Description

@vasconcelosvcd

What happened:

GetBlobChunk returns FailedPrecondition with the error:

number (1): rpc error: code = FailedPrecondition desc = found multiple chunks with number (1)
found for record (...)

Two ChunkRef entities with the same Number exist in Datastore for the same BlobRef. FindChunkRefByNumber finds more than one and rejects the request.

What you expected to happen:

At most one ChunkRef per (BlobRef, Number) tuple exists. Re-uploading a chunk (e.g. after a network error) replaces the previous one. GetBlobChunk succeeds.

How to reproduce it (as minimally and precisely as possible):

  1. Create a chunked blob upload session.
  2. Send two concurrent UploadChunk RPCs for the same session ID and the same chunk Number (e.g. Number = 1). A client retry under load reproduces this naturally.
  3. Both complete without error.
  4. Call GetBlobChunk for that chunk number.

Root cause:

UploadChunk ran deduplication and insert as two separate, non-atomic steps:
deleteSameNumberChunks(ctx, chunk) // query + delete in separate TX
InsertChunkRef(ctx, blob, chunk) // insert in separate TX

Two concurrent uploads both execute deleteSameNumberChunks before either calls InsertChunkRef. Both queries return empty, both deletes are no-ops, both inserts succeed — leaving two ChunkRef rows with the same Number.

The comment in InsertChunkRef promised atomic deduplication ("If the current session has another chunk with the same Number, it will be marked for deletion") but the implementation did not do it.

Fix:

Move the dedup query and delete inside InsertChunkRef's own Datastore transaction, making the find-old → delete-old → insert-new sequence atomic. Return the superseded chunks to the caller for GCS object cleanup.

Environment:

  • Open Saves version: v1.2.0
  • Kubernetes version (use kubectl version): 1.33.9-gke.1060000
  • Cloud provider or hardware configuration: GKE
  • Install method (yaml/helm): yaml
  • Troubleshooting guide log(s):
  • Others:

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions