You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
2. Set `existingKeyGeneration = OzoneConsts.EXPECTED_DATA_GENERATION_CREATE_IF_NOT_EXISTS`.
82
111
3. Call `RpcClient.rewriteKey()`.
83
112
84
113
##### OM Create Phase
85
114
86
-
1.Validate `expectedDataGeneration == -1`.
87
-
2. If key exists → throw `KEY_ALREADY_EXISTS`.
88
-
3.Store `-1` in open key metadata.
115
+
1.OM receives request with `expectedDataGeneration == OzoneConsts.EXPECTED_DATA_GENERATION_CREATE_IF_NOT_EXISTS`.
116
+
2.**Pre-check**: If key is already in the OpenKeyTable or KeyTable, throw `KEY_ALREADY_EXISTS`.
117
+
3.If not exists, proceed to create the open key entry.
89
118
90
-
##### OM Commit Phase
119
+
##### OM Commit Phase (Atomicity)
91
120
92
-
1. Check `expectedDataGeneration == -1` from open key.
93
-
2. If key now exists (race condition) → throw `KEY_ALREADY_EXISTS`.
94
-
3. Commit key.
121
+
1. During the commit phase (or strict atomic create), the OM validates that the key still does not exist.
122
+
2. If a concurrent client created the key between the Create and Commit phases, the transaction fails with `KEY_ALREADY_EXISTS`.
95
123
96
124
##### Race Condition Handling
97
125
98
-
Using `-1` ensures atomicity. If a concurrent write (Client B) commits between Client A's Create and Commit, Client A's commit fails the `-1` validation check (key now exists), preserving strict create-if-not-exists semantics.
126
+
Using `OzoneConsts.EXPECTED_DATA_GENERATION_CREATE_IF_NOT_EXISTS = -1` ensures atomicity. If a concurrent write (Client B) commits between Client A's Create and Commit,
127
+
Client A's commit fails the `CREATE IF NOT EXISTS` validation check, preserving strict create-if-not-exists semantics.
99
128
100
129
#### If-Match Implementation
101
130
102
-
Leverages existing `expectedDataGeneration` from HDDS-10656:
131
+
To optimize performance and reduce latency, we avoid a pre-flight check (GetS3KeyDetails) and instead validate the ETag during the OM Write operation.
132
+
This requires adding an optional `expectedETag` field to `KeyArgs`. This approach optimizes the "happy path" (successful match) by removing an extra network round trip.
133
+
For failing requests, they still incur the cost of a write RPC and Raft log entry, but this is acceptable under optimistic concurrency control assumptions.
3. Populate `KeyArgs` with the parsed `expectedETag`.
139
+
4. Send the write request (CreateKey/OpenKey) to OM.
111
140
112
-
##### OM Create Phase
141
+
##### OM Layer (Validation Logic)
142
+
143
+
Validation is performed within the `validateAndUpdateCache` method to ensure atomicity within the Ratis state machine application.
113
144
114
-
1. Receive `expectedDataGeneration` parameter
115
-
2. Look up current key and validate exists
116
-
3. Extract current key's `updateID` value
117
-
4. Create open key with `expectedDataGeneration = updateID`
118
-
5. Return stream to S3 gateway
145
+
1.**Locking**: The OM acquires the write lock for the bucket/key.
146
+
2.**Key Lookup**: Retrieve the existing key from `KeyTable`.
147
+
3.**Validation**:
119
148
120
-
##### OM Commit Phase
149
+
-**Key Not Found**: If the key does not exist, throw `KEY_NOT_FOUND` (maps to S3 412).
150
+
-**No ETag Metadata**: If the existing key (e.g., uploaded via OFS) does not have an ETag property, validation fails. We do **not** calculate ETag on the spot to avoid performance overhead on the applier thread. Throws `PRECONDITION_FAILED`.
151
+
-**ETag Mismatch**: Compare `existingKey.ETag` with `expectedETag`. If they do not match, throw `PRECONDITION_FAILED` (maps to S3 412).
121
152
122
-
1. Read open key (contains `expectedDataGeneration`)
0 commit comments