]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/fuzz/db_map_fuzzer.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rocksdb / fuzz / db_map_fuzzer.cc
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).
5
6 #include <algorithm>
7 #include <iostream>
8 #include <map>
9 #include <string>
10
11 #include "proto/gen/db_operation.pb.h"
12 #include "rocksdb/db.h"
13 #include "rocksdb/file_system.h"
14 #include "src/libfuzzer/libfuzzer_macro.h"
15 #include "util.h"
16
17 protobuf_mutator::libfuzzer::PostProcessorRegistration<DBOperations> reg = {
18 [](DBOperations* input, unsigned int /* seed */) {
19 const ROCKSDB_NAMESPACE::Comparator* comparator =
20 ROCKSDB_NAMESPACE::BytewiseComparator();
21 auto ops = input->mutable_operations();
22 // Make sure begin <= end for DELETE_RANGE.
23 for (DBOperation& op : *ops) {
24 if (op.type() == OpType::DELETE_RANGE) {
25 auto begin = op.key();
26 auto end = op.value();
27 if (comparator->Compare(begin, end) > 0) {
28 std::swap(begin, end);
29 op.set_key(begin);
30 op.set_value(end);
31 }
32 }
33 }
34 }};
35
36 // Execute randomly generated operations on both a DB and a std::map,
37 // then reopen the DB and make sure that iterating the DB produces the
38 // same key-value pairs as iterating through the std::map.
39 DEFINE_PROTO_FUZZER(DBOperations& input) {
40 if (input.operations().empty()) {
41 return;
42 }
43
44 const std::string kDbPath = "/tmp/db_map_fuzzer_test";
45 auto fs = ROCKSDB_NAMESPACE::FileSystem::Default();
46 if (fs->FileExists(kDbPath, ROCKSDB_NAMESPACE::IOOptions(), /*dbg=*/nullptr)
47 .ok()) {
48 std::cerr << "db path " << kDbPath << " already exists" << std::endl;
49 abort();
50 }
51
52 std::map<std::string, std::string> kv;
53 ROCKSDB_NAMESPACE::DB* db = nullptr;
54 ROCKSDB_NAMESPACE::Options options;
55 options.create_if_missing = true;
56 CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options, kDbPath, &db));
57
58 for (const DBOperation& op : input.operations()) {
59 switch (op.type()) {
60 case OpType::PUT: {
61 CHECK_OK(
62 db->Put(ROCKSDB_NAMESPACE::WriteOptions(), op.key(), op.value()));
63 kv[op.key()] = op.value();
64 break;
65 }
66 case OpType::MERGE: {
67 break;
68 }
69 case OpType::DELETE: {
70 CHECK_OK(db->Delete(ROCKSDB_NAMESPACE::WriteOptions(), op.key()));
71 kv.erase(op.key());
72 break;
73 }
74 case OpType::DELETE_RANGE: {
75 // [op.key(), op.value()) corresponds to [begin, end).
76 CHECK_OK(db->DeleteRange(ROCKSDB_NAMESPACE::WriteOptions(),
77 db->DefaultColumnFamily(), op.key(),
78 op.value()));
79 kv.erase(kv.lower_bound(op.key()), kv.lower_bound(op.value()));
80 break;
81 }
82 default: {
83 std::cerr << "Unsupported operation" << static_cast<int>(op.type());
84 return;
85 }
86 }
87 }
88 CHECK_OK(db->Close());
89 delete db;
90 db = nullptr;
91
92 CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options, kDbPath, &db));
93 auto kv_it = kv.begin();
94 ROCKSDB_NAMESPACE::Iterator* it =
95 db->NewIterator(ROCKSDB_NAMESPACE::ReadOptions());
96 for (it->SeekToFirst(); it->Valid(); it->Next(), kv_it++) {
97 CHECK_TRUE(kv_it != kv.end());
98 CHECK_EQ(it->key().ToString(), kv_it->first);
99 CHECK_EQ(it->value().ToString(), kv_it->second);
100 }
101 CHECK_TRUE(kv_it == kv.end());
102 delete it;
103
104 CHECK_OK(db->Close());
105 delete db;
106 CHECK_OK(ROCKSDB_NAMESPACE::DestroyDB(kDbPath, options));
107 }