1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
11 #include "db_stress_tool/db_stress_common.h"
12 #include "rocksdb/utilities/transaction_db.h"
13 #include "utilities/fault_injection_fs.h"
15 namespace ROCKSDB_NAMESPACE
{
16 class NonBatchedOpsStressTest
: public StressTest
{
18 NonBatchedOpsStressTest() {}
20 virtual ~NonBatchedOpsStressTest() {}
22 void VerifyDb(ThreadState
* thread
) const override
{
23 // This `ReadOptions` is for validation purposes. Ignore
24 // `FLAGS_rate_limit_user_ops` to avoid slowing any validation.
25 ReadOptions
options(FLAGS_verify_checksum
, true);
28 if (FLAGS_user_timestamp_size
> 0) {
29 ts_str
= GetNowNanos();
31 options
.timestamp
= &ts
;
34 auto shared
= thread
->shared
;
35 const int64_t max_key
= shared
->GetMaxKey();
36 const int64_t keys_per_thread
= max_key
/ shared
->GetNumThreads();
37 int64_t start
= keys_per_thread
* thread
->tid
;
38 int64_t end
= start
+ keys_per_thread
;
39 uint64_t prefix_to_use
=
40 (FLAGS_prefix_size
< 0) ? 1 : static_cast<size_t>(FLAGS_prefix_size
);
42 if (thread
->tid
== shared
->GetNumThreads() - 1) {
46 for (size_t cf
= 0; cf
< column_families_
.size(); ++cf
) {
47 if (thread
->shared
->HasVerificationFailedYet()) {
51 enum class VerificationMethod
{
56 // Add any new items above kNumberOfMethods
60 constexpr int num_methods
=
61 static_cast<int>(VerificationMethod::kNumberOfMethods
);
63 const VerificationMethod method
=
64 static_cast<VerificationMethod
>(thread
->rand
.Uniform(
65 (FLAGS_user_timestamp_size
> 0) ? num_methods
- 1 : num_methods
));
67 if (method
== VerificationMethod::kIterator
) {
68 std::unique_ptr
<Iterator
> iter(
69 db_
->NewIterator(options
, column_families_
[cf
]));
71 std::string seek_key
= Key(start
);
74 Slice
prefix(seek_key
.data(), prefix_to_use
);
76 for (int64_t i
= start
; i
< end
; ++i
) {
77 if (thread
->shared
->HasVerificationFailedYet()) {
81 const std::string key
= Key(i
);
83 const Slice
pfx(key
.data(), prefix_to_use
);
85 // Reseek when the prefix changes
86 if (prefix_to_use
> 0 && prefix
.compare(pfx
) != 0) {
89 prefix
= Slice(seek_key
.data(), prefix_to_use
);
92 Status s
= iter
->status();
97 const int diff
= iter
->key().compare(k
);
100 s
= Status::NotFound();
101 } else if (diff
== 0) {
102 const WideColumns expected_columns
= GenerateExpectedWideColumns(
103 GetValueBase(iter
->value()), iter
->value());
104 if (iter
->columns() != expected_columns
) {
105 VerificationAbort(shared
, static_cast<int>(cf
), i
,
106 iter
->value(), iter
->columns(),
111 from_db
= iter
->value().ToString();
116 VerificationAbort(shared
, "An out of range key was found",
117 static_cast<int>(cf
), i
);
120 // The iterator found no value for the key in question, so do not
121 // move to the next item in the iterator
122 s
= Status::NotFound();
125 VerifyOrSyncValue(static_cast<int>(cf
), i
, options
, shared
, from_db
,
126 s
, /* strict */ true);
128 if (!from_db
.empty()) {
129 PrintKeyValue(static_cast<int>(cf
), static_cast<uint32_t>(i
),
130 from_db
.data(), from_db
.size());
133 } else if (method
== VerificationMethod::kGet
) {
134 for (int64_t i
= start
; i
< end
; ++i
) {
135 if (thread
->shared
->HasVerificationFailedYet()) {
139 const std::string key
= Key(i
);
142 Status s
= db_
->Get(options
, column_families_
[cf
], key
, &from_db
);
144 VerifyOrSyncValue(static_cast<int>(cf
), i
, options
, shared
, from_db
,
145 s
, /* strict */ true);
147 if (!from_db
.empty()) {
148 PrintKeyValue(static_cast<int>(cf
), static_cast<uint32_t>(i
),
149 from_db
.data(), from_db
.size());
152 } else if (method
== VerificationMethod::kMultiGet
) {
153 for (int64_t i
= start
; i
< end
;) {
154 if (thread
->shared
->HasVerificationFailedYet()) {
158 // Keep the batch size to some reasonable value
159 size_t batch_size
= thread
->rand
.Uniform(128) + 1;
160 batch_size
= std::min
<size_t>(batch_size
, end
- i
);
162 std::vector
<std::string
> keystrs(batch_size
);
163 std::vector
<Slice
> keys(batch_size
);
164 std::vector
<PinnableSlice
> values(batch_size
);
165 std::vector
<Status
> statuses(batch_size
);
167 for (size_t j
= 0; j
< batch_size
; ++j
) {
168 keystrs
[j
] = Key(i
+ j
);
169 keys
[j
] = Slice(keystrs
[j
].data(), keystrs
[j
].size());
172 db_
->MultiGet(options
, column_families_
[cf
], batch_size
, keys
.data(),
173 values
.data(), statuses
.data());
175 for (size_t j
= 0; j
< batch_size
; ++j
) {
176 const std::string from_db
= values
[j
].ToString();
178 VerifyOrSyncValue(static_cast<int>(cf
), i
+ j
, options
, shared
,
179 from_db
, statuses
[j
], /* strict */ true);
181 if (!from_db
.empty()) {
182 PrintKeyValue(static_cast<int>(cf
), static_cast<uint32_t>(i
+ j
),
183 from_db
.data(), from_db
.size());
190 assert(method
== VerificationMethod::kGetMergeOperands
);
192 // Start off with small size that will be increased later if necessary
193 std::vector
<PinnableSlice
> values(4);
195 GetMergeOperandsOptions merge_operands_info
;
196 merge_operands_info
.expected_max_number_of_operands
=
197 static_cast<int>(values
.size());
199 for (int64_t i
= start
; i
< end
; ++i
) {
200 if (thread
->shared
->HasVerificationFailedYet()) {
204 const std::string key
= Key(i
);
207 int number_of_operands
= 0;
209 Status s
= db_
->GetMergeOperands(options
, column_families_
[cf
], k
,
210 values
.data(), &merge_operands_info
,
211 &number_of_operands
);
213 if (s
.IsIncomplete()) {
214 // Need to resize values as there are more than values.size() merge
215 // operands on this key. Should only happen a few times when we
216 // encounter a key that had more merge operands than any key seen so
218 values
.resize(number_of_operands
);
219 merge_operands_info
.expected_max_number_of_operands
=
220 static_cast<int>(number_of_operands
);
221 s
= db_
->GetMergeOperands(options
, column_families_
[cf
], k
,
222 values
.data(), &merge_operands_info
,
223 &number_of_operands
);
225 // Assumed here that GetMergeOperands always sets number_of_operand
226 if (number_of_operands
) {
227 from_db
= values
[number_of_operands
- 1].ToString();
230 VerifyOrSyncValue(static_cast<int>(cf
), i
, options
, shared
, from_db
,
231 s
, /* strict */ true);
233 if (!from_db
.empty()) {
234 PrintKeyValue(static_cast<int>(cf
), static_cast<uint32_t>(i
),
235 from_db
.data(), from_db
.size());
243 void ContinuouslyVerifyDb(ThreadState
* thread
) const override
{
248 assert(!cmp_cfhs_
.empty());
249 Status s
= cmp_db_
->TryCatchUpWithPrimary();
255 const auto checksum_column_family
= [](Iterator
* iter
,
256 uint32_t* checksum
) -> Status
{
257 assert(nullptr != checksum
);
259 for (iter
->SeekToFirst(); iter
->Valid(); iter
->Next()) {
260 ret
= crc32c::Extend(ret
, iter
->key().data(), iter
->key().size());
261 ret
= crc32c::Extend(ret
, iter
->value().data(), iter
->value().size());
264 return iter
->status();
267 auto* shared
= thread
->shared
;
269 const int64_t max_key
= shared
->GetMaxKey();
270 ReadOptions
read_opts(FLAGS_verify_checksum
, true);
273 if (FLAGS_user_timestamp_size
> 0) {
274 ts_str
= GetNowNanos();
276 read_opts
.timestamp
= &ts
;
279 static Random64
rand64(shared
->GetSeed());
283 std::unique_ptr
<Iterator
> it(cmp_db_
->NewIterator(read_opts
));
284 s
= checksum_column_family(it
.get(), &crc
);
286 fprintf(stderr
, "Computing checksum of default cf: %s\n",
287 s
.ToString().c_str());
292 for (auto* handle
: cmp_cfhs_
) {
293 if (thread
->rand
.OneInOpt(3)) {
295 uint64_t key
= rand64
.Uniform(static_cast<uint64_t>(max_key
));
296 std::string key_str
= Key(key
);
299 s
= cmp_db_
->Get(read_opts
, handle
, key_str
, &value
,
300 FLAGS_user_timestamp_size
> 0 ? &key_ts
: nullptr);
301 s
.PermitUncheckedError();
304 std::unique_ptr
<Iterator
> iter(cmp_db_
->NewIterator(read_opts
, handle
));
305 uint32_t rnd
= (thread
->rand
.Next()) % 4;
307 // SeekToFirst() + Next()*5
308 read_opts
.total_order_seek
= true;
310 for (int i
= 0; i
< 5 && iter
->Valid(); ++i
, iter
->Next()) {
312 } else if (1 == rnd
) {
313 // SeekToLast() + Prev()*5
314 read_opts
.total_order_seek
= true;
316 for (int i
= 0; i
< 5 && iter
->Valid(); ++i
, iter
->Prev()) {
318 } else if (2 == rnd
) {
320 uint64_t key
= rand64
.Uniform(static_cast<uint64_t>(max_key
));
321 std::string key_str
= Key(key
);
323 for (int i
= 0; i
< 5 && iter
->Valid(); ++i
, iter
->Next()) {
326 // SeekForPrev() + Prev()*5
327 uint64_t key
= rand64
.Uniform(static_cast<uint64_t>(max_key
));
328 std::string key_str
= Key(key
);
329 iter
->SeekForPrev(key_str
);
330 for (int i
= 0; i
< 5 && iter
->Valid(); ++i
, iter
->Prev()) {
337 void ContinuouslyVerifyDb(ThreadState
* /*thread*/) const override
{}
338 #endif // ROCKSDB_LITE
340 void MaybeClearOneColumnFamily(ThreadState
* thread
) override
{
341 if (FLAGS_column_families
> 1) {
342 if (thread
->rand
.OneInOpt(FLAGS_clear_column_family_one_in
)) {
343 // drop column family and then create it again (can't drop default)
344 int cf
= thread
->rand
.Next() % (FLAGS_column_families
- 1) + 1;
345 std::string new_name
=
346 std::to_string(new_column_family_name_
.fetch_add(1));
348 MutexLock
l(thread
->shared
->GetMutex());
351 "[CF %d] Dropping and recreating column family. new name: %s\n",
352 cf
, new_name
.c_str());
354 thread
->shared
->LockColumnFamily(cf
);
355 Status s
= db_
->DropColumnFamily(column_families_
[cf
]);
356 delete column_families_
[cf
];
358 fprintf(stderr
, "dropping column family error: %s\n",
359 s
.ToString().c_str());
362 s
= db_
->CreateColumnFamily(ColumnFamilyOptions(options_
), new_name
,
363 &column_families_
[cf
]);
364 column_family_names_
[cf
] = new_name
;
365 thread
->shared
->ClearColumnFamily(cf
);
367 fprintf(stderr
, "creating column family error: %s\n",
368 s
.ToString().c_str());
371 thread
->shared
->UnlockColumnFamily(cf
);
376 bool ShouldAcquireMutexOnKey() const override
{ return true; }
378 bool IsStateTracked() const override
{ return true; }
380 Status
TestGet(ThreadState
* thread
, const ReadOptions
& read_opts
,
381 const std::vector
<int>& rand_column_families
,
382 const std::vector
<int64_t>& rand_keys
) override
{
383 auto cfh
= column_families_
[rand_column_families
[0]];
384 std::string key_str
= Key(rand_keys
[0]);
389 if (fault_fs_guard
) {
390 fault_fs_guard
->EnableErrorInjection();
391 SharedState::ignore_read_error
= false;
394 std::unique_ptr
<MutexLock
> lock(new MutexLock(
395 thread
->shared
->GetMutexForKey(rand_column_families
[0], rand_keys
[0])));
397 ReadOptions read_opts_copy
= read_opts
;
398 std::string read_ts_str
;
400 bool read_older_ts
= MaybeUseOlderTimestampForPointLookup(
401 thread
, read_ts_str
, read_ts_slice
, read_opts_copy
);
403 Status s
= db_
->Get(read_opts_copy
, cfh
, key
, &from_db
);
404 if (fault_fs_guard
) {
405 error_count
= fault_fs_guard
->GetAndResetErrorCount();
408 if (fault_fs_guard
) {
409 if (error_count
&& !SharedState::ignore_read_error
) {
410 // Grab mutex so multiple thread don't try to print the
411 // stack trace at the same time
412 MutexLock
l(thread
->shared
->GetMutex());
413 fprintf(stderr
, "Didn't get expected error from Get\n");
414 fprintf(stderr
, "Callstack that injected the fault\n");
415 fault_fs_guard
->PrintFaultBacktrace();
420 thread
->stats
.AddGets(1, 1);
421 // we only have the latest expected state
422 if (!FLAGS_skip_verifydb
&& !read_opts_copy
.timestamp
&&
423 thread
->shared
->Get(rand_column_families
[0], rand_keys
[0]) ==
424 SharedState::DELETION_SENTINEL
) {
425 thread
->shared
->SetVerificationFailure();
427 "error : inconsistent values for key %s: Get returns %s, "
428 "expected state does not have the key.\n",
429 key
.ToString(true).c_str(), StringToHex(from_db
).c_str());
431 } else if (s
.IsNotFound()) {
433 thread
->stats
.AddGets(1, 0);
434 if (!FLAGS_skip_verifydb
&& !read_older_ts
) {
436 thread
->shared
->Get(rand_column_families
[0], rand_keys
[0]);
437 if (expected
!= SharedState::DELETION_SENTINEL
&&
438 expected
!= SharedState::UNKNOWN_SENTINEL
) {
439 thread
->shared
->SetVerificationFailure();
441 "error : inconsistent values for key %s: expected state has "
442 "the key, Get() returns NotFound.\n",
443 key
.ToString(true).c_str());
447 if (error_count
== 0) {
449 thread
->stats
.AddErrors(1);
451 thread
->stats
.AddVerifiedErrors(1);
454 if (fault_fs_guard
) {
455 fault_fs_guard
->DisableErrorInjection();
460 std::vector
<Status
> TestMultiGet(
461 ThreadState
* thread
, const ReadOptions
& read_opts
,
462 const std::vector
<int>& rand_column_families
,
463 const std::vector
<int64_t>& rand_keys
) override
{
464 size_t num_keys
= rand_keys
.size();
465 std::vector
<std::string
> key_str
;
466 std::vector
<Slice
> keys
;
467 key_str
.reserve(num_keys
);
468 keys
.reserve(num_keys
);
469 std::vector
<PinnableSlice
> values(num_keys
);
470 std::vector
<Status
> statuses(num_keys
);
471 ColumnFamilyHandle
* cfh
= column_families_
[rand_column_families
[0]];
473 // Do a consistency check between Get and MultiGet. Don't do it too
474 // often as it will slow db_stress down
475 bool do_consistency_check
= thread
->rand
.OneIn(4);
477 ReadOptions readoptionscopy
= read_opts
;
478 if (do_consistency_check
) {
479 readoptionscopy
.snapshot
= db_
->GetSnapshot();
482 std::string read_ts_str
;
484 MaybeUseOlderTimestampForPointLookup(thread
, read_ts_str
, read_ts_slice
,
487 readoptionscopy
.rate_limiter_priority
=
488 FLAGS_rate_limit_user_ops
? Env::IO_USER
: Env::IO_TOTAL
;
490 // To appease clang analyzer
491 const bool use_txn
= FLAGS_use_txn
;
493 // Create a transaction in order to write some data. The purpose is to
494 // exercise WriteBatchWithIndex::MultiGetFromBatchAndDB. The transaction
495 // will be rolled back once MultiGet returns.
497 Transaction
* txn
= nullptr;
500 if (FLAGS_rate_limit_auto_wal_flush
) {
501 wo
.rate_limiter_priority
= Env::IO_USER
;
503 Status s
= NewTxn(wo
, &txn
);
505 fprintf(stderr
, "NewTxn: %s\n", s
.ToString().c_str());
510 for (size_t i
= 0; i
< num_keys
; ++i
) {
511 key_str
.emplace_back(Key(rand_keys
[i
]));
512 keys
.emplace_back(key_str
.back());
515 // With a 1 in 10 probability, insert the just added key in the batch
516 // into the transaction. This will create an overlap with the MultiGet
517 // keys and exercise some corner cases in the code
518 if (thread
->rand
.OneIn(10)) {
519 int op
= thread
->rand
.Uniform(2);
524 uint32_t value_base
=
525 thread
->rand
.Next() % thread
->shared
->UNKNOWN_SENTINEL
;
527 size_t sz
= GenerateValue(value_base
, value
, sizeof(value
));
530 s
= txn
->Put(cfh
, keys
.back(), v
);
532 s
= txn
->Merge(cfh
, keys
.back(), v
);
537 s
= txn
->Delete(cfh
, keys
.back());
543 fprintf(stderr
, "Transaction put: %s\n", s
.ToString().c_str());
552 if (fault_fs_guard
) {
553 fault_fs_guard
->EnableErrorInjection();
554 SharedState::ignore_read_error
= false;
556 db_
->MultiGet(readoptionscopy
, cfh
, num_keys
, keys
.data(), values
.data(),
558 if (fault_fs_guard
) {
559 error_count
= fault_fs_guard
->GetAndResetErrorCount();
563 txn
->MultiGet(readoptionscopy
, cfh
, num_keys
, keys
.data(), values
.data(),
568 if (fault_fs_guard
&& error_count
&& !SharedState::ignore_read_error
) {
570 for (const auto& s
: statuses
) {
571 if (!s
.ok() && !s
.IsNotFound()) {
576 if (stat_nok
< error_count
) {
577 // Grab mutex so multiple thread don't try to print the
578 // stack trace at the same time
579 MutexLock
l(thread
->shared
->GetMutex());
580 fprintf(stderr
, "Didn't get expected error from MultiGet. \n");
581 fprintf(stderr
, "num_keys %zu Expected %d errors, seen %d\n", num_keys
,
582 error_count
, stat_nok
);
583 fprintf(stderr
, "Callstack that injected the fault\n");
584 fault_fs_guard
->PrintFaultBacktrace();
588 if (fault_fs_guard
) {
589 fault_fs_guard
->DisableErrorInjection();
592 for (size_t i
= 0; i
< statuses
.size(); ++i
) {
593 Status s
= statuses
[i
];
594 bool is_consistent
= true;
595 // Only do the consistency check if no error was injected and MultiGet
596 // didn't return an unexpected error
597 if (do_consistency_check
&& !error_count
&& (s
.ok() || s
.IsNotFound())) {
603 tmp_s
= txn
->Get(readoptionscopy
, cfh
, keys
[i
], &value
);
604 #endif // ROCKSDB_LITE
606 tmp_s
= db_
->Get(readoptionscopy
, cfh
, keys
[i
], &value
);
608 if (!tmp_s
.ok() && !tmp_s
.IsNotFound()) {
609 fprintf(stderr
, "Get error: %s\n", s
.ToString().c_str());
610 is_consistent
= false;
611 } else if (!s
.ok() && tmp_s
.ok()) {
612 fprintf(stderr
, "MultiGet returned different results with key %s\n",
613 keys
[i
].ToString(true).c_str());
614 fprintf(stderr
, "Get returned ok, MultiGet returned not found\n");
615 is_consistent
= false;
616 } else if (s
.ok() && tmp_s
.IsNotFound()) {
617 fprintf(stderr
, "MultiGet returned different results with key %s\n",
618 keys
[i
].ToString(true).c_str());
619 fprintf(stderr
, "MultiGet returned ok, Get returned not found\n");
620 is_consistent
= false;
621 } else if (s
.ok() && value
!= values
[i
].ToString()) {
622 fprintf(stderr
, "MultiGet returned different results with key %s\n",
623 keys
[i
].ToString(true).c_str());
624 fprintf(stderr
, "MultiGet returned value %s\n",
625 values
[i
].ToString(true).c_str());
626 fprintf(stderr
, "Get returned value %s\n",
627 Slice(value
).ToString(true /* hex */).c_str());
628 is_consistent
= false;
632 if (!is_consistent
) {
633 fprintf(stderr
, "TestMultiGet error: is_consistent is false\n");
634 thread
->stats
.AddErrors(1);
635 // Fail fast to preserve the DB state
636 thread
->shared
->SetVerificationFailure();
640 thread
->stats
.AddGets(1, 1);
641 } else if (s
.IsNotFound()) {
643 thread
->stats
.AddGets(1, 0);
644 } else if (s
.IsMergeInProgress() && use_txn
) {
645 // With txn this is sometimes expected.
646 thread
->stats
.AddGets(1, 1);
648 if (error_count
== 0) {
650 fprintf(stderr
, "MultiGet error: %s\n", s
.ToString().c_str());
651 thread
->stats
.AddErrors(1);
653 thread
->stats
.AddVerifiedErrors(1);
658 if (readoptionscopy
.snapshot
) {
659 db_
->ReleaseSnapshot(readoptionscopy
.snapshot
);
669 Status
TestPrefixScan(ThreadState
* thread
, const ReadOptions
& read_opts
,
670 const std::vector
<int>& rand_column_families
,
671 const std::vector
<int64_t>& rand_keys
) override
{
672 assert(!rand_column_families
.empty());
673 assert(!rand_keys
.empty());
675 ColumnFamilyHandle
* const cfh
= column_families_
[rand_column_families
[0]];
678 const std::string key
= Key(rand_keys
[0]);
679 const Slice
prefix(key
.data(), FLAGS_prefix_size
);
681 std::string upper_bound
;
683 ReadOptions ro_copy
= read_opts
;
685 // Get the next prefix first and then see if we want to set upper bound.
686 // We'll use the next prefix in an assertion later on
687 if (GetNextPrefix(prefix
, &upper_bound
) && thread
->rand
.OneIn(2)) {
688 // For half of the time, set the upper bound to the next prefix
689 ub_slice
= Slice(upper_bound
);
690 ro_copy
.iterate_upper_bound
= &ub_slice
;
693 std::string read_ts_str
;
695 MaybeUseOlderTimestampForRangeScan(thread
, read_ts_str
, read_ts_slice
,
698 std::unique_ptr
<Iterator
> iter(db_
->NewIterator(ro_copy
, cfh
));
703 for (iter
->Seek(prefix
); iter
->Valid() && iter
->key().starts_with(prefix
);
707 // When iter_start_ts is set, iterator exposes internal keys, including
708 // tombstones; however, we want to perform column validation only for
710 if (ro_copy
.iter_start_ts
) {
711 const ValueType value_type
= ExtractValueType(iter
->key());
712 if (value_type
!= kTypeValue
&& value_type
!= kTypeBlobIndex
&&
713 value_type
!= kTypeWideColumnEntity
) {
718 const WideColumns expected_columns
= GenerateExpectedWideColumns(
719 GetValueBase(iter
->value()), iter
->value());
720 if (iter
->columns() != expected_columns
) {
721 s
= Status::Corruption(
722 "Value and columns inconsistent",
723 DebugString(iter
->value(), iter
->columns(), expected_columns
));
728 if (ro_copy
.iter_start_ts
== nullptr) {
729 assert(count
<= GetPrefixKeyCount(prefix
.ToString(), upper_bound
));
737 fprintf(stderr
, "TestPrefixScan error: %s\n", s
.ToString().c_str());
738 thread
->stats
.AddErrors(1);
743 thread
->stats
.AddPrefixes(1, count
);
748 Status
TestPut(ThreadState
* thread
, WriteOptions
& write_opts
,
749 const ReadOptions
& read_opts
,
750 const std::vector
<int>& rand_column_families
,
751 const std::vector
<int64_t>& rand_keys
,
752 char (&value
)[100]) override
{
753 assert(!rand_column_families
.empty());
754 assert(!rand_keys
.empty());
756 auto shared
= thread
->shared
;
759 const int64_t max_key
= shared
->GetMaxKey();
761 int64_t rand_key
= rand_keys
[0];
762 int rand_column_family
= rand_column_families
[0];
763 std::string write_ts
;
765 std::unique_ptr
<MutexLock
> lock(
766 new MutexLock(shared
->GetMutexForKey(rand_column_family
, rand_key
)));
767 while (!shared
->AllowsOverwrite(rand_key
) &&
768 (FLAGS_use_merge
|| shared
->Exists(rand_column_family
, rand_key
))) {
771 rand_key
= thread
->rand
.Next() % max_key
;
772 rand_column_family
= thread
->rand
.Next() % FLAGS_column_families
;
775 new MutexLock(shared
->GetMutexForKey(rand_column_family
, rand_key
)));
776 if (FLAGS_user_timestamp_size
> 0) {
777 write_ts
= GetNowNanos();
781 if (write_ts
.empty() && FLAGS_user_timestamp_size
) {
782 write_ts
= GetNowNanos();
785 const std::string k
= Key(rand_key
);
787 ColumnFamilyHandle
* const cfh
= column_families_
[rand_column_family
];
790 if (FLAGS_verify_before_write
) {
792 Status s
= db_
->Get(read_opts
, cfh
, k
, &from_db
);
793 if (!VerifyOrSyncValue(rand_column_family
, rand_key
, read_opts
, shared
,
794 from_db
, s
, /* strict */ true)) {
799 const uint32_t value_base
= thread
->rand
.Next() % shared
->UNKNOWN_SENTINEL
;
800 const size_t sz
= GenerateValue(value_base
, value
, sizeof(value
));
801 const Slice
v(value
, sz
);
803 shared
->Put(rand_column_family
, rand_key
, value_base
, true /* pending */);
807 if (FLAGS_use_merge
) {
808 if (!FLAGS_use_txn
) {
809 if (FLAGS_user_timestamp_size
== 0) {
810 s
= db_
->Merge(write_opts
, cfh
, k
, v
);
812 s
= db_
->Merge(write_opts
, cfh
, k
, write_ts
, v
);
817 s
= NewTxn(write_opts
, &txn
);
819 s
= txn
->Merge(cfh
, k
, v
);
821 s
= CommitTxn(txn
, thread
);
826 } else if (FLAGS_use_put_entity_one_in
> 0 &&
827 (value_base
% FLAGS_use_put_entity_one_in
) == 0) {
828 s
= db_
->PutEntity(write_opts
, cfh
, k
,
829 GenerateWideColumns(value_base
, v
));
831 if (!FLAGS_use_txn
) {
832 if (FLAGS_user_timestamp_size
== 0) {
833 s
= db_
->Put(write_opts
, cfh
, k
, v
);
835 s
= db_
->Put(write_opts
, cfh
, k
, write_ts
, v
);
840 s
= NewTxn(write_opts
, &txn
);
842 s
= txn
->Put(cfh
, k
, v
);
844 s
= CommitTxn(txn
, thread
);
851 shared
->Put(rand_column_family
, rand_key
, value_base
, false /* pending */);
854 if (FLAGS_injest_error_severity
>= 2) {
855 if (!is_db_stopped_
&& s
.severity() >= Status::Severity::kFatalError
) {
856 is_db_stopped_
= true;
857 } else if (!is_db_stopped_
||
858 s
.severity() < Status::Severity::kFatalError
) {
859 fprintf(stderr
, "put or merge error: %s\n", s
.ToString().c_str());
863 fprintf(stderr
, "put or merge error: %s\n", s
.ToString().c_str());
868 thread
->stats
.AddBytesForWrites(1, sz
);
869 PrintKeyValue(rand_column_family
, static_cast<uint32_t>(rand_key
), value
,
874 Status
TestDelete(ThreadState
* thread
, WriteOptions
& write_opts
,
875 const std::vector
<int>& rand_column_families
,
876 const std::vector
<int64_t>& rand_keys
) override
{
877 int64_t rand_key
= rand_keys
[0];
878 int rand_column_family
= rand_column_families
[0];
879 auto shared
= thread
->shared
;
881 std::unique_ptr
<MutexLock
> lock(
882 new MutexLock(shared
->GetMutexForKey(rand_column_family
, rand_key
)));
885 std::string write_ts_str
= GetNowNanos();
886 Slice write_ts
= write_ts_str
;
888 std::string key_str
= Key(rand_key
);
890 auto cfh
= column_families_
[rand_column_family
];
892 // Use delete if the key may be overwritten and a single deletion
895 if (shared
->AllowsOverwrite(rand_key
)) {
896 shared
->Delete(rand_column_family
, rand_key
, true /* pending */);
897 if (!FLAGS_use_txn
) {
898 if (FLAGS_user_timestamp_size
== 0) {
899 s
= db_
->Delete(write_opts
, cfh
, key
);
901 s
= db_
->Delete(write_opts
, cfh
, key
, write_ts
);
906 s
= NewTxn(write_opts
, &txn
);
908 s
= txn
->Delete(cfh
, key
);
910 s
= CommitTxn(txn
, thread
);
915 shared
->Delete(rand_column_family
, rand_key
, false /* pending */);
916 thread
->stats
.AddDeletes(1);
918 if (FLAGS_injest_error_severity
>= 2) {
919 if (!is_db_stopped_
&&
920 s
.severity() >= Status::Severity::kFatalError
) {
921 is_db_stopped_
= true;
922 } else if (!is_db_stopped_
||
923 s
.severity() < Status::Severity::kFatalError
) {
924 fprintf(stderr
, "delete error: %s\n", s
.ToString().c_str());
928 fprintf(stderr
, "delete error: %s\n", s
.ToString().c_str());
933 shared
->SingleDelete(rand_column_family
, rand_key
, true /* pending */);
934 if (!FLAGS_use_txn
) {
935 if (FLAGS_user_timestamp_size
== 0) {
936 s
= db_
->SingleDelete(write_opts
, cfh
, key
);
938 s
= db_
->SingleDelete(write_opts
, cfh
, key
, write_ts
);
943 s
= NewTxn(write_opts
, &txn
);
945 s
= txn
->SingleDelete(cfh
, key
);
947 s
= CommitTxn(txn
, thread
);
952 shared
->SingleDelete(rand_column_family
, rand_key
, false /* pending */);
953 thread
->stats
.AddSingleDeletes(1);
955 if (FLAGS_injest_error_severity
>= 2) {
956 if (!is_db_stopped_
&&
957 s
.severity() >= Status::Severity::kFatalError
) {
958 is_db_stopped_
= true;
959 } else if (!is_db_stopped_
||
960 s
.severity() < Status::Severity::kFatalError
) {
961 fprintf(stderr
, "single delete error: %s\n", s
.ToString().c_str());
965 fprintf(stderr
, "single delete error: %s\n", s
.ToString().c_str());
973 Status
TestDeleteRange(ThreadState
* thread
, WriteOptions
& write_opts
,
974 const std::vector
<int>& rand_column_families
,
975 const std::vector
<int64_t>& rand_keys
) override
{
976 // OPERATION delete range
977 std::vector
<std::unique_ptr
<MutexLock
>> range_locks
;
978 // delete range does not respect disallowed overwrites. the keys for
979 // which overwrites are disallowed are randomly distributed so it
980 // could be expensive to find a range where each key allows
982 int64_t rand_key
= rand_keys
[0];
983 int rand_column_family
= rand_column_families
[0];
984 auto shared
= thread
->shared
;
985 int64_t max_key
= shared
->GetMaxKey();
986 if (rand_key
> max_key
- FLAGS_range_deletion_width
) {
988 thread
->rand
.Next() % (max_key
- FLAGS_range_deletion_width
+ 1);
990 for (int j
= 0; j
< FLAGS_range_deletion_width
; ++j
) {
992 ((rand_key
+ j
) & ((1 << FLAGS_log2_keys_per_lock
) - 1)) == 0) {
993 range_locks
.emplace_back(new MutexLock(
994 shared
->GetMutexForKey(rand_column_family
, rand_key
+ j
)));
997 shared
->DeleteRange(rand_column_family
, rand_key
,
998 rand_key
+ FLAGS_range_deletion_width
,
1001 std::string keystr
= Key(rand_key
);
1003 auto cfh
= column_families_
[rand_column_family
];
1004 std::string end_keystr
= Key(rand_key
+ FLAGS_range_deletion_width
);
1005 Slice end_key
= end_keystr
;
1006 std::string write_ts_str
;
1009 if (FLAGS_user_timestamp_size
) {
1010 write_ts_str
= GetNowNanos();
1011 write_ts
= write_ts_str
;
1012 s
= db_
->DeleteRange(write_opts
, cfh
, key
, end_key
, write_ts
);
1014 s
= db_
->DeleteRange(write_opts
, cfh
, key
, end_key
);
1017 if (FLAGS_injest_error_severity
>= 2) {
1018 if (!is_db_stopped_
&& s
.severity() >= Status::Severity::kFatalError
) {
1019 is_db_stopped_
= true;
1020 } else if (!is_db_stopped_
||
1021 s
.severity() < Status::Severity::kFatalError
) {
1022 fprintf(stderr
, "delete range error: %s\n", s
.ToString().c_str());
1026 fprintf(stderr
, "delete range error: %s\n", s
.ToString().c_str());
1030 int covered
= shared
->DeleteRange(rand_column_family
, rand_key
,
1031 rand_key
+ FLAGS_range_deletion_width
,
1032 false /* pending */);
1033 thread
->stats
.AddRangeDeletions(1);
1034 thread
->stats
.AddCoveredByRangeDeletions(covered
);
1039 void TestIngestExternalFile(
1040 ThreadState
* /* thread */,
1041 const std::vector
<int>& /* rand_column_families */,
1042 const std::vector
<int64_t>& /* rand_keys */) override
{
1045 "RocksDB lite does not support "
1046 "TestIngestExternalFile\n");
1050 void TestIngestExternalFile(ThreadState
* thread
,
1051 const std::vector
<int>& rand_column_families
,
1052 const std::vector
<int64_t>& rand_keys
) override
{
1053 const std::string sst_filename
=
1054 FLAGS_db
+ "/." + std::to_string(thread
->tid
) + ".sst";
1056 if (db_stress_env
->FileExists(sst_filename
).ok()) {
1057 // Maybe we terminated abnormally before, so cleanup to give this file
1058 // ingestion a clean slate
1059 s
= db_stress_env
->DeleteFile(sst_filename
);
1062 SstFileWriter
sst_file_writer(EnvOptions(options_
), options_
);
1064 s
= sst_file_writer
.Open(sst_filename
);
1066 int64_t key_base
= rand_keys
[0];
1067 int column_family
= rand_column_families
[0];
1068 std::vector
<std::unique_ptr
<MutexLock
>> range_locks
;
1069 range_locks
.reserve(FLAGS_ingest_external_file_width
);
1070 std::vector
<int64_t> keys
;
1071 keys
.reserve(FLAGS_ingest_external_file_width
);
1072 std::vector
<uint32_t> values
;
1073 values
.reserve(FLAGS_ingest_external_file_width
);
1074 SharedState
* shared
= thread
->shared
;
1076 assert(FLAGS_nooverwritepercent
< 100);
1077 // Grab locks, set pending state on expected values, and add keys
1078 for (int64_t key
= key_base
;
1079 s
.ok() && key
< shared
->GetMaxKey() &&
1080 static_cast<int32_t>(keys
.size()) < FLAGS_ingest_external_file_width
;
1082 if (key
== key_base
||
1083 (key
& ((1 << FLAGS_log2_keys_per_lock
) - 1)) == 0) {
1084 range_locks
.emplace_back(
1085 new MutexLock(shared
->GetMutexForKey(column_family
, key
)));
1087 if (!shared
->AllowsOverwrite(key
)) {
1088 // We could alternatively include `key` on the condition its current
1089 // value is `DELETION_SENTINEL`.
1092 keys
.push_back(key
);
1094 uint32_t value_base
= thread
->rand
.Next() % shared
->UNKNOWN_SENTINEL
;
1095 values
.push_back(value_base
);
1096 shared
->Put(column_family
, key
, value_base
, true /* pending */);
1099 size_t value_len
= GenerateValue(value_base
, value
, sizeof(value
));
1100 auto key_str
= Key(key
);
1101 s
= sst_file_writer
.Put(Slice(key_str
), Slice(value
, value_len
));
1104 if (s
.ok() && keys
.empty()) {
1109 s
= sst_file_writer
.Finish();
1112 s
= db_
->IngestExternalFile(column_families_
[column_family
],
1113 {sst_filename
}, IngestExternalFileOptions());
1116 fprintf(stderr
, "file ingestion error: %s\n", s
.ToString().c_str());
1119 for (size_t i
= 0; i
< keys
.size(); ++i
) {
1120 shared
->Put(column_family
, keys
[i
], values
[i
], false /* pending */);
1123 #endif // ROCKSDB_LITE
1125 // Given a key K, this creates an iterator which scans the range
1126 // [K, K + FLAGS_num_iterations) forward and backward.
1127 // Then does a random sequence of Next/Prev operations.
1128 Status
TestIterateAgainstExpected(
1129 ThreadState
* thread
, const ReadOptions
& read_opts
,
1130 const std::vector
<int>& rand_column_families
,
1131 const std::vector
<int64_t>& rand_keys
) override
{
1133 assert(!rand_column_families
.empty());
1134 assert(!rand_keys
.empty());
1136 auto shared
= thread
->shared
;
1139 int64_t max_key
= shared
->GetMaxKey();
1141 const int64_t num_iter
= static_cast<int64_t>(FLAGS_num_iterations
);
1143 int64_t lb
= rand_keys
[0];
1144 if (lb
> max_key
- num_iter
) {
1145 lb
= thread
->rand
.Next() % (max_key
- num_iter
+ 1);
1148 const int64_t ub
= lb
+ num_iter
;
1150 // Lock the whole range over which we might iterate to ensure it doesn't
1152 const int rand_column_family
= rand_column_families
[0];
1153 std::vector
<std::unique_ptr
<MutexLock
>> range_locks
=
1154 shared
->GetLocksForKeyRange(rand_column_family
, lb
, ub
);
1156 ReadOptions
ro(read_opts
);
1157 ro
.total_order_seek
= true;
1159 std::string read_ts_str
;
1161 if (FLAGS_user_timestamp_size
> 0) {
1162 read_ts_str
= GetNowNanos();
1163 read_ts
= read_ts_str
;
1164 ro
.timestamp
= &read_ts
;
1167 std::string max_key_str
;
1168 Slice max_key_slice
;
1169 if (!FLAGS_destroy_db_initially
) {
1170 max_key_str
= Key(max_key
);
1171 max_key_slice
= max_key_str
;
1172 // to restrict iterator from reading keys written in batched_op_stress
1173 // that do not have expected state updated and may not be parseable by
1175 ro
.iterate_upper_bound
= &max_key_slice
;
1178 ColumnFamilyHandle
* const cfh
= column_families_
[rand_column_family
];
1181 std::unique_ptr
<Iterator
> iter(db_
->NewIterator(ro
, cfh
));
1183 std::string op_logs
;
1185 auto check_columns
= [&]() {
1187 assert(iter
->Valid());
1189 const WideColumns expected_columns
= GenerateExpectedWideColumns(
1190 GetValueBase(iter
->value()), iter
->value());
1191 if (iter
->columns() != expected_columns
) {
1192 shared
->SetVerificationFailure();
1195 "Verification failed for key %s: "
1196 "Value and columns inconsistent: %s\n",
1197 Slice(iter
->key()).ToString(/* hex */ true).c_str(),
1198 DebugString(iter
->value(), iter
->columns(), expected_columns
)
1200 fprintf(stderr
, "Column family: %s, op_logs: %s\n",
1201 cfh
->GetName().c_str(), op_logs
.c_str());
1203 thread
->stats
.AddErrors(1);
1211 auto check_no_key_in_range
= [&](int64_t start
, int64_t end
) {
1212 for (auto j
= std::max(start
, lb
); j
< std::min(end
, ub
); ++j
) {
1213 auto expected_value
=
1214 shared
->Get(rand_column_family
, static_cast<int64_t>(j
));
1215 if (expected_value
!= shared
->DELETION_SENTINEL
&&
1216 expected_value
!= shared
->UNKNOWN_SENTINEL
) {
1217 // Fail fast to preserve the DB state.
1218 thread
->shared
->SetVerificationFailure();
1219 if (iter
->Valid()) {
1221 "Expected state has key %s, iterator is at key %s\n",
1222 Slice(Key(j
)).ToString(true).c_str(),
1223 iter
->key().ToString(true).c_str());
1225 fprintf(stderr
, "Expected state has key %s, iterator is invalid\n",
1226 Slice(Key(j
)).ToString(true).c_str());
1228 fprintf(stderr
, "Column family: %s, op_logs: %s\n",
1229 cfh
->GetName().c_str(), op_logs
.c_str());
1230 thread
->stats
.AddErrors(1);
1237 // Forward and backward scan to ensure we cover the entire range [lb, ub).
1238 // The random sequence Next and Prev test below tends to be very short
1240 int64_t last_key
= lb
- 1;
1242 std::string key_str
= Key(lb
);
1243 iter
->Seek(key_str
);
1245 op_logs
+= "S " + Slice(key_str
).ToString(true) + " ";
1249 if (!iter
->Valid()) {
1250 if (!iter
->status().ok()) {
1251 thread
->shared
->SetVerificationFailure();
1252 fprintf(stderr
, "TestIterate against expected state error: %s\n",
1253 iter
->status().ToString().c_str());
1254 fprintf(stderr
, "Column family: %s, op_logs: %s\n",
1255 cfh
->GetName().c_str(), op_logs
.c_str());
1256 thread
->stats
.AddErrors(1);
1257 return iter
->status();
1259 if (!check_no_key_in_range(last_key
+ 1, ub
)) {
1260 return Status::OK();
1265 if (!check_columns()) {
1266 return Status::OK();
1269 // iter is valid, the range (last_key, current key) was skipped
1270 GetIntVal(iter
->key().ToString(), &curr
);
1271 if (!check_no_key_in_range(last_key
+ 1, static_cast<int64_t>(curr
))) {
1272 return Status::OK();
1275 last_key
= static_cast<int64_t>(curr
);
1276 if (last_key
>= ub
- 1) {
1286 key_str
= Key(ub
- 1);
1287 iter
->SeekForPrev(key_str
);
1289 op_logs
+= " SFP " + Slice(key_str
).ToString(true) + " ";
1293 if (!iter
->Valid()) {
1294 if (!iter
->status().ok()) {
1295 thread
->shared
->SetVerificationFailure();
1296 fprintf(stderr
, "TestIterate against expected state error: %s\n",
1297 iter
->status().ToString().c_str());
1298 fprintf(stderr
, "Column family: %s, op_logs: %s\n",
1299 cfh
->GetName().c_str(), op_logs
.c_str());
1300 thread
->stats
.AddErrors(1);
1301 return iter
->status();
1303 if (!check_no_key_in_range(lb
, last_key
)) {
1304 return Status::OK();
1309 if (!check_columns()) {
1310 return Status::OK();
1313 // the range (current key, last key) was skipped
1314 GetIntVal(iter
->key().ToString(), &curr
);
1315 if (!check_no_key_in_range(static_cast<int64_t>(curr
+ 1), last_key
)) {
1316 return Status::OK();
1319 last_key
= static_cast<int64_t>(curr
);
1320 if (last_key
<= lb
) {
1329 if (thread
->rand
.OneIn(2)) {
1330 // Refresh after forward/backward scan to allow higher chance of SV
1331 // change. It is safe to refresh since the testing key range is locked.
1335 // start from middle of [lb, ub) otherwise it is easy to iterate out of
1337 const int64_t mid
= lb
+ num_iter
/ 2;
1340 const Slice
key(key_str
);
1342 if (thread
->rand
.OneIn(2)) {
1344 op_logs
+= " S " + key
.ToString(true) + " ";
1345 if (!iter
->Valid() && iter
->status().ok()) {
1346 if (!check_no_key_in_range(mid
, ub
)) {
1347 return Status::OK();
1351 iter
->SeekForPrev(key
);
1352 op_logs
+= " SFP " + key
.ToString(true) + " ";
1353 if (!iter
->Valid() && iter
->status().ok()) {
1354 // iterator says nothing <= mid
1355 if (!check_no_key_in_range(lb
, mid
+ 1)) {
1356 return Status::OK();
1361 for (int64_t i
= 0; i
< num_iter
&& iter
->Valid(); ++i
) {
1362 if (!check_columns()) {
1363 return Status::OK();
1366 GetIntVal(iter
->key().ToString(), &curr
);
1367 if (static_cast<int64_t>(curr
) < lb
) {
1370 } else if (static_cast<int64_t>(curr
) >= ub
) {
1374 const uint32_t expected_value
=
1375 shared
->Get(rand_column_family
, static_cast<int64_t>(curr
));
1376 if (expected_value
== shared
->DELETION_SENTINEL
) {
1377 // Fail fast to preserve the DB state.
1378 thread
->shared
->SetVerificationFailure();
1379 fprintf(stderr
, "Iterator has key %s, but expected state does not.\n",
1380 iter
->key().ToString(true).c_str());
1381 fprintf(stderr
, "Column family: %s, op_logs: %s\n",
1382 cfh
->GetName().c_str(), op_logs
.c_str());
1383 thread
->stats
.AddErrors(1);
1387 if (thread
->rand
.OneIn(2)) {
1390 if (!iter
->Valid()) {
1394 GetIntVal(iter
->key().ToString(), &next
);
1395 if (!check_no_key_in_range(static_cast<int64_t>(curr
+ 1),
1396 static_cast<int64_t>(next
))) {
1397 return Status::OK();
1402 if (!iter
->Valid()) {
1406 GetIntVal(iter
->key().ToString(), &prev
);
1407 if (!check_no_key_in_range(static_cast<int64_t>(prev
+ 1),
1408 static_cast<int64_t>(curr
))) {
1409 return Status::OK();
1415 if (!iter
->status().ok()) {
1416 thread
->shared
->SetVerificationFailure();
1417 fprintf(stderr
, "TestIterate against expected state error: %s\n",
1418 iter
->status().ToString().c_str());
1419 fprintf(stderr
, "Column family: %s, op_logs: %s\n",
1420 cfh
->GetName().c_str(), op_logs
.c_str());
1421 thread
->stats
.AddErrors(1);
1422 return iter
->status();
1425 thread
->stats
.AddIterations(1);
1427 return Status::OK();
1430 bool VerifyOrSyncValue(int cf
, int64_t key
, const ReadOptions
& /*opts*/,
1431 SharedState
* shared
, const std::string
& value_from_db
,
1432 const Status
& s
, bool strict
= false) const {
1433 if (shared
->HasVerificationFailedYet()) {
1436 // compare value_from_db with the value in the shared state
1437 uint32_t value_base
= shared
->Get(cf
, key
);
1438 if (value_base
== SharedState::UNKNOWN_SENTINEL
) {
1440 // Value exists in db, update state to reflect that
1441 Slice
slice(value_from_db
);
1442 value_base
= GetValueBase(slice
);
1443 shared
->Put(cf
, key
, value_base
, false);
1444 } else if (s
.IsNotFound()) {
1445 // Value doesn't exist in db, update state to reflect that
1446 shared
->SingleDelete(cf
, key
, false);
1450 if (value_base
== SharedState::DELETION_SENTINEL
&& !strict
) {
1455 char value
[kValueMaxLen
];
1456 if (value_base
== SharedState::DELETION_SENTINEL
) {
1457 VerificationAbort(shared
, "Unexpected value found", cf
, key
,
1461 size_t sz
= GenerateValue(value_base
, value
, sizeof(value
));
1462 if (value_from_db
.length() != sz
) {
1463 VerificationAbort(shared
, "Length of value read is not equal", cf
, key
,
1464 value_from_db
, Slice(value
, sz
));
1467 if (memcmp(value_from_db
.data(), value
, sz
) != 0) {
1468 VerificationAbort(shared
, "Contents of value read don't match", cf
, key
,
1469 value_from_db
, Slice(value
, sz
));
1473 if (value_base
!= SharedState::DELETION_SENTINEL
) {
1474 char value
[kValueMaxLen
];
1475 size_t sz
= GenerateValue(value_base
, value
, sizeof(value
));
1476 VerificationAbort(shared
, "Value not found: " + s
.ToString(), cf
, key
,
1477 "", Slice(value
, sz
));
1484 #ifndef ROCKSDB_LITE
1485 void PrepareTxnDbOptions(SharedState
* shared
,
1486 TransactionDBOptions
& txn_db_opts
) override
{
1487 txn_db_opts
.rollback_deletion_type_callback
=
1488 [shared
](TransactionDB
*, ColumnFamilyHandle
*, const Slice
& key
) {
1490 uint64_t key_num
= 0;
1491 bool ok
= GetIntVal(key
.ToString(), &key_num
);
1494 return !shared
->AllowsOverwrite(key_num
);
1497 #endif // ROCKSDB_LITE
1500 StressTest
* CreateNonBatchedOpsStressTest() {
1501 return new NonBatchedOpsStressTest();
1504 } // namespace ROCKSDB_NAMESPACE