@@ -132,33 +132,23 @@ class TraditionalKeyGenerator : public KeyGenerator {
132
132
public:
133
133
// / @brief create the generator
134
134
explicit TraditionalKeyGenerator (bool allowUserKeys)
135
- : KeyGenerator(allowUserKeys),
136
- _lastValue(0 ) {}
135
+ : KeyGenerator(allowUserKeys) {}
137
136
138
137
bool hasDynamicState () const override { return true ; }
139
-
138
+
140
139
// / @brief generate a key
141
140
std::string generate () override final {
142
141
uint64_t tick = generateValue ();
143
142
144
- {
145
- MUTEX_LOCKER (mutexLocker, _lock);
146
-
147
- if (tick == UINT64_MAX || _lastValue >= UINT64_MAX - 1ULL ) {
148
- // oops, out of keys!
149
- return std::string ();
150
- }
151
-
152
- if (tick <= _lastValue) {
153
- tick = ++_lastValue;
154
- } else {
155
- _lastValue = tick;
156
- }
143
+ if (ADB_UNLIKELY (tick == 0 )) {
144
+ // unlikely case we have run out of keys
145
+ // returning an empty string will trigger an error on the call site
146
+ return std::string ();
157
147
}
158
148
159
149
return arangodb::basics::StringUtils::itoa (tick);
160
150
}
161
-
151
+
162
152
// / @brief validate a key
163
153
int validate (char const * p, size_t length, bool isRestore) override {
164
154
int res = KeyGenerator::validate (p, length, isRestore);
@@ -180,12 +170,7 @@ class TraditionalKeyGenerator : public KeyGenerator {
180
170
uint64_t value = NumberUtils::atoi_zero<uint64_t >(p, p + length);
181
171
182
172
if (value > 0 ) {
183
- MUTEX_LOCKER (mutexLocker, _lock);
184
-
185
- if (value > _lastValue) {
186
- // and update our last value
187
- _lastValue = value;
188
- }
173
+ track (value);
189
174
}
190
175
}
191
176
}
@@ -194,76 +179,123 @@ class TraditionalKeyGenerator : public KeyGenerator {
194
179
void toVelocyPack (arangodb::velocypack::Builder& builder) const override {
195
180
KeyGenerator::toVelocyPack (builder);
196
181
builder.add (" type" , VPackValue (" traditional" ));
197
-
198
- MUTEX_LOCKER (mutexLocker, _lock);
199
- builder.add (StaticStrings::LastValue, VPackValue (_lastValue));
200
182
}
201
183
202
184
protected:
185
+ // / @brief generate a new key value (internal)
203
186
virtual uint64_t generateValue () = 0;
204
187
205
- private:
206
- mutable arangodb::Mutex _lock;
207
-
208
- uint64_t _lastValue;
188
+ // / @brief track a value (internal)
189
+ virtual void track (uint64_t value) = 0;
209
190
};
210
191
211
192
// / @brief traditional key generator for a single server
212
193
class TraditionalKeyGeneratorSingle final : public TraditionalKeyGenerator {
213
194
public:
214
195
// / @brief create the generator
215
196
explicit TraditionalKeyGeneratorSingle (bool allowUserKeys)
216
- : TraditionalKeyGenerator(allowUserKeys) {}
197
+ : TraditionalKeyGenerator(allowUserKeys), _lastValue(0 ) {
198
+ TRI_ASSERT (!ServerState::instance ()->isCoordinator ());
199
+ }
200
+
201
+ // / @brief build a VelocyPack representation of the generator in the builder
202
+ void toVelocyPack (arangodb::velocypack::Builder& builder) const override {
203
+ TraditionalKeyGenerator::toVelocyPack (builder);
204
+
205
+ // add our specific stuff
206
+ MUTEX_LOCKER (mutexLocker, _lock);
207
+ builder.add (StaticStrings::LastValue, VPackValue (_lastValue));
208
+ }
217
209
218
210
private:
219
- // / @brief generate a key
211
+ // / @brief generate a key value (internal)
220
212
uint64_t generateValue () override {
221
- return TRI_NewTickServer ();
213
+ uint64_t tick = TRI_NewTickServer ();
214
+
215
+ if (ADB_UNLIKELY (tick == UINT64_MAX)) {
216
+ // out of keys
217
+ return 0 ;
218
+ }
219
+
220
+ // keep track of last assigned value, and make sure the value
221
+ // we hand out is always higher than it
222
+ {
223
+ MUTEX_LOCKER (mutexLocker, _lock);
224
+
225
+ if (ADB_UNLIKELY (_lastValue >= UINT64_MAX - 1ULL )) {
226
+ // oops, out of keys!
227
+ return 0 ;
228
+ }
229
+
230
+ if (tick <= _lastValue) {
231
+ tick = ++_lastValue;
232
+ } else {
233
+ _lastValue = tick;
234
+ }
235
+ }
236
+
237
+ return tick;
238
+ }
239
+
240
+ // / @brief track a key value (internal)
241
+ void track (uint64_t value) override {
242
+ MUTEX_LOCKER (mutexLocker, _lock);
243
+
244
+ if (value > _lastValue) {
245
+ // and update our last value
246
+ _lastValue = value;
247
+ }
222
248
}
249
+
250
+ private:
251
+ mutable arangodb::Mutex _lock;
252
+
253
+ uint64_t _lastValue;
223
254
};
224
255
225
256
// / @brief traditional key generator for a coordinator
257
+ // / please note that coordinator-based key generators are frequently
258
+ // / created and discarded, so ctor & dtor need to be very efficient.
259
+ // / additionally, do not put any state into this object, as for the
260
+ // / same logical collection the ClusterInfo may create many different
261
+ // / temporary LogicalCollection objects one after the other, which
262
+ // / will also discard the collection's particular KeyGenerator object!
226
263
class TraditionalKeyGeneratorCluster final : public TraditionalKeyGenerator {
227
264
public:
228
265
// / @brief create the generator
229
266
explicit TraditionalKeyGeneratorCluster (bool allowUserKeys)
230
- : TraditionalKeyGenerator(allowUserKeys) {}
231
-
267
+ : TraditionalKeyGenerator(allowUserKeys) {
268
+ TRI_ASSERT (ServerState::instance ()->isCoordinator ());
269
+ }
270
+
232
271
private:
233
- // / @brief generate a key
272
+ // / @brief generate a key value (internal)
234
273
uint64_t generateValue () override {
235
274
ClusterInfo* ci = ClusterInfo::instance ();
236
275
return ci->uniqid ();
237
276
}
277
+
278
+ // / @brief track a key value (internal)
279
+ void track (uint64_t /* value */ ) override {}
238
280
};
239
281
240
282
// / @brief base class for padded key generators
241
283
class PaddedKeyGenerator : public KeyGenerator {
242
284
public:
243
285
// / @brief create the generator
244
286
explicit PaddedKeyGenerator (bool allowUserKeys)
245
- : KeyGenerator(allowUserKeys),
246
- _lastValue(0 ) {}
287
+ : KeyGenerator(allowUserKeys) {}
247
288
248
289
bool hasDynamicState () const override { return true ; }
249
290
250
291
// / @brief generate a key
251
292
std::string generate () override {
252
293
uint64_t tick = generateValue ();
253
-
254
- {
255
- MUTEX_LOCKER (mutexLocker, _lock);
256
-
257
- if (tick == UINT64_MAX || _lastValue >= UINT64_MAX - 1ULL ) {
258
- // oops, out of keys!
259
- return std::string ();
260
- }
261
294
262
- if (tick <= _lastValue) {
263
- tick = ++_lastValue;
264
- } else {
265
- _lastValue = tick;
266
- }
295
+ if (ADB_UNLIKELY (tick == 0 )) {
296
+ // unlikely case we have run out of keys
297
+ // returning an empty string will trigger an error on the call site
298
+ return std::string ();
267
299
}
268
300
269
301
return encode (tick);
@@ -287,26 +319,22 @@ class PaddedKeyGenerator : public KeyGenerator {
287
319
// check the numeric key part
288
320
uint64_t value = decode (p, length);
289
321
if (value > 0 ) {
290
- MUTEX_LOCKER (mutexLocker, _lock);
291
-
292
- if (value > _lastValue) {
293
- // and update our last value
294
- _lastValue = value;
295
- }
322
+ track (value);
296
323
}
297
324
}
298
325
299
326
// / @brief build a VelocyPack representation of the generator in the builder
300
327
void toVelocyPack (arangodb::velocypack::Builder& builder) const override {
301
328
KeyGenerator::toVelocyPack (builder);
302
329
builder.add (" type" , VPackValue (" padded" ));
303
-
304
- MUTEX_LOCKER (mutexLocker, _lock);
305
- builder.add (StaticStrings::LastValue, VPackValue (_lastValue));
306
330
}
307
331
308
332
protected:
333
+ // / @brief generate a key value (internal)
309
334
virtual uint64_t generateValue () = 0;
335
+
336
+ // / @brief track a value (internal)
337
+ virtual void track (uint64_t value) = 0;
310
338
311
339
private:
312
340
uint64_t decode (char const * p, size_t length) {
@@ -360,40 +388,94 @@ class PaddedKeyGenerator : public KeyGenerator {
360
388
361
389
return std::string (&buffer[0 ], sizeof (uint64_t ) * 2 );
362
390
}
363
-
364
- private:
365
- mutable arangodb::Mutex _lock;
366
-
367
- uint64_t _lastValue;
368
391
};
369
392
370
393
// / @brief padded key generator for a single server
371
394
class PaddedKeyGeneratorSingle final : public PaddedKeyGenerator {
372
F438
395
public:
373
396
// / @brief create the generator
374
397
explicit PaddedKeyGeneratorSingle (bool allowUserKeys)
375
- : PaddedKeyGenerator(allowUserKeys) {}
398
+ : PaddedKeyGenerator(allowUserKeys), _lastValue(0 ) {
399
+ TRI_ASSERT (!ServerState::instance ()->isCoordinator ());
400
+ }
401
+
402
+ // / @brief build a VelocyPack representation of the generator in the builder
403
+ void toVelocyPack (arangodb::velocypack::Builder& builder) const override {
404
+ PaddedKeyGenerator::toVelocyPack (builder);
405
+
406
+ // add our own specific values
407
+ MUTEX_LOCKER (mutexLocker, _lock);
408
+ builder.add (StaticStrings::LastValue, VPackValue (_lastValue));
409
+ }
376
410
377
411
private:
378
412
// / @brief generate a key
379
413
uint64_t generateValue () override {
380
- return TRI_NewTickServer ();
414
+ uint64_t tick = TRI_NewTickServer ();
415
+
416
+ if (ADB_UNLIKELY (tick == UINT64_MAX)) {
417
+ // oops, out of keys!
418
+ return 0 ;
419
+ }
420
+
421
+ {
422
+ MUTEX_LOCKER (mutexLocker, _lock);
423
+
424
+ if (ADB_UNLIKELY (_lastValue >= UINT64_MAX - 1ULL )) {
425
+ // oops, out of keys!
426
+ return 0 ;
427
+ }
428
+
429
+ if (tick <= _lastValue) {
430
+ tick = ++_lastValue;
431
+ } else {
432
+ _lastValue = tick;
433
+ }
434
+ }
435
+
436
+ return tick;
437
+ }
438
+
439
+ // / @brief generate a key value (internal)
440
+ void track (uint64_t value) override {
441
+ MUTEX_LOCKER (mutexLocker, _lock);
442
+
443
+ if (value > _lastValue) {
444
+ // and update our last value
445
+ _lastValue = value;
446
+ }
381
447
}
448
+
449
+ private:
450
+ mutable arangodb::Mutex _lock;
451
+
452
+ uint64_t _lastValue;
382
453
};
383
454
384
455
// / @brief padded key generator for a coordinator
456
+ // / please note that coordinator-based key generators are frequently
457
+ // / created and discarded, so ctor & dtor need to be very efficient.
458
+ // / additionally, do not put any state into this object, as for the
459
+ // / same logical collection the ClusterInfo may create many different
460
+ // / temporary LogicalCollection objects one after the other, which
461
+ // / will also discard the collection's particular KeyGenerator object!
385
462
class PaddedKeyGeneratorCluster final : public PaddedKeyGenerator {
386
463
public:
387
464
// / @brief create the generator
388
465
explicit PaddedKeyGeneratorCluster (bool allowUserKeys)
389
- : PaddedKeyGenerator(allowUserKeys) {}
466
+ : PaddedKeyGenerator(allowUserKeys) {
467
+ TRI_ASSERT (ServerState::instance ()->isCoordinator ());
468
+ }
390
469
391
470
private:
392
- // / @brief generate a key
471
+ // / @brief generate a key value (internal)
393
472
uint64_t generateValue () override {
394
473
ClusterInfo* ci = ClusterInfo::instance ();
395
474
return ci->uniqid ();
396
475
}
476
+
477
+ // / @brief generate a key value (internal)
478
+ void track (uint64_t /* value */ ) override {}
397
479
};
398
480
399
481
// / @brief auto-increment key generator - not usable in cluster
0 commit comments