blob: cfc59692c8505ab3ad45e38a964df7e60e36956d [file] [log] [blame]
Marc Kupietz28cc53e2017-12-23 17:24:55 +01001// 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 <typeinfo>
Marc Kupietz4b799e92018-01-02 11:04:56 +01007#define EXPORT __attribute__((visibility("visible")))
8#define IMPORT
Marc Kupietz28cc53e2017-12-23 17:24:55 +01009#include <assert.h>
10#include <memory>
11#include <iostream>
12#include <stdint.h>
13#include "rocksdb/cache.h"
14#include "rocksdb/comparator.h"
15#include "rocksdb/db.h"
16#include "rocksdb/env.h"
17#include <rocksdb/merge_operator.h>
18#include "rocksdb/utilities/db_ttl.h"
19#include "merge_operators.h"
20
21#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100)
22#define encodeCollocation(w1, w2, dist) (((uint64_t)dist << 56) | ((uint64_t)w2 << 24) | w1)
Marc Kupietz18375e12017-12-24 10:11:18 +010023#define W1(key) (uint64_t)(key & 0xffffff)
24#define W2(key) (uint64_t)((key >> 24) & 0xffffff)
25#define DIST(key) (int8_t)((uint64_t)((key >> 56) & 0xff))
Marc Kupietz28cc53e2017-12-23 17:24:55 +010026using namespace rocksdb;
27
Marc Kupietz4b799e92018-01-02 11:04:56 +010028namespace rocksdb {
Marc Kupietz28cc53e2017-12-23 17:24:55 +010029 size_t num_merge_operator_calls;
30 void resetNumMergeOperatorCalls() { num_merge_operator_calls = 0; }
31
32 size_t num_partial_merge_calls;
33 void resetNumPartialMergeCalls() { num_partial_merge_calls = 0; }
Marc Kupietz28cc53e2017-12-23 17:24:55 +010034
35
Marc Kupietz4b799e92018-01-02 11:04:56 +010036 inline void EncodeFixed64(char* buf, uint64_t value) {
37 if (! IS_BIG_ENDIAN) {
38 memcpy(buf, &value, sizeof(value));
39 } else {
40 buf[0] = value & 0xff;
41 buf[1] = (value >> 8) & 0xff;
42 buf[2] = (value >> 16) & 0xff;
43 buf[3] = (value >> 24) & 0xff;
44 buf[4] = (value >> 32) & 0xff;
45 buf[5] = (value >> 40) & 0xff;
46 buf[6] = (value >> 48) & 0xff;
47 buf[7] = (value >> 56) & 0xff;
48 }
Marc Kupietz28cc53e2017-12-23 17:24:55 +010049 }
50
Marc Kupietz4b799e92018-01-02 11:04:56 +010051 inline uint32_t DecodeFixed32(const char* ptr) {
52 if (! IS_BIG_ENDIAN) {
53 // Load the raw bytes
54 uint32_t result;
55 memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load
56 return result;
57 } else {
58 return ((static_cast<uint32_t>(static_cast<unsigned char>(ptr[0])))
59 | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[1])) << 8)
60 | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[2])) << 16)
61 | (static_cast<uint32_t>(static_cast<unsigned char>(ptr[3])) << 24));
62 }
63 }
64
65 inline uint64_t DecodeFixed64(const char* ptr) {
66 if (! IS_BIG_ENDIAN) {
67 // Load the raw bytes
68 uint64_t result;
69 memcpy(&result, ptr, sizeof(result)); // gcc optimizes this to a plain load
70 return result;
71 } else {
72 uint64_t lo = DecodeFixed32(ptr);
73 uint64_t hi = DecodeFixed32(ptr + 4);
74 return (hi << 32) | lo;
75 }
76 }
77
78
79 class CountMergeOperator : public AssociativeMergeOperator {
80 public:
81 CountMergeOperator() {
82 mergeOperator_ = MergeOperators::CreateUInt64AddOperator();
Marc Kupietz28cc53e2017-12-23 17:24:55 +010083 }
84
Marc Kupietz4b799e92018-01-02 11:04:56 +010085 virtual bool Merge(const Slice& key,
86 const Slice* existing_value,
87 const Slice& value,
88 std::string* new_value,
89 Logger* logger) const override {
90 assert(new_value->empty());
91 ++num_merge_operator_calls;
92 if (existing_value == nullptr) {
93 new_value->assign(value.data(), value.size());
94 return true;
95 }
Marc Kupietz28cc53e2017-12-23 17:24:55 +010096
Marc Kupietz4b799e92018-01-02 11:04:56 +010097 return mergeOperator_->PartialMerge(
98 key,
99 *existing_value,
100 value,
101 new_value,
102 logger);
103 }
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100104
Marc Kupietz4b799e92018-01-02 11:04:56 +0100105 virtual const char* Name() const override {
106 return "UInt64AddOperator";
107 }
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100108
Marc Kupietz4b799e92018-01-02 11:04:56 +0100109 private:
110 std::shared_ptr<MergeOperator> mergeOperator_;
111 };
112
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100113
Marc Kupietz4b799e92018-01-02 11:04:56 +0100114 class CollocatorIterator : public Iterator {
115 private:
116 char prefixc[sizeof(uint64_t)];
117 Iterator *base_iterator_;
118
119
120 public:
121 CollocatorIterator(Iterator* base_iterator)
122 : base_iterator_(base_iterator)
123 {}
124
125 ~CollocatorIterator();
126
127 void setPrefix(char *prefix) {
128 memcpy(prefixc, prefix, sizeof(uint64_t));
129 }
130
131 virtual void SeekToFirst() { base_iterator_->SeekToFirst(); }
132 virtual void SeekToLast() { base_iterator_->SeekToLast(); }
133 virtual void Seek(const rocksdb::Slice& s) { base_iterator_->Seek(s); }
134 virtual void Prev() { base_iterator_->Prev(); }
135 virtual void Next() { base_iterator_->Next(); }
136 virtual Slice key() const;
137 virtual Slice value() const;
138 virtual Status status() const;
139 virtual bool Valid() const;
140 bool isValid();
141 uint64_t intValue();
142 uint64_t intKey();
Marc Kupietz18375e12017-12-24 10:11:18 +0100143
Marc Kupietz4b799e92018-01-02 11:04:56 +0100144 };
Marc Kupietz18375e12017-12-24 10:11:18 +0100145
Marc Kupietz4b799e92018-01-02 11:04:56 +0100146 // rocksdb::CollocatorIterator::CollocatorIterator(Iterator* base_iterator) {}
147
148 bool rocksdb::CollocatorIterator::Valid() const {
Marc Kupietz18375e12017-12-24 10:11:18 +0100149 return base_iterator_->Valid() && key().starts_with(std::string(prefixc,3));
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100150 }
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100151
Marc Kupietz4b799e92018-01-02 11:04:56 +0100152 bool rocksdb::CollocatorIterator::isValid() {
153 return base_iterator_->Valid() && key().starts_with(std::string(prefixc,3));
154 }
Marc Kupietz18375e12017-12-24 10:11:18 +0100155
Marc Kupietz4b799e92018-01-02 11:04:56 +0100156 uint64_t rocksdb::CollocatorIterator::intKey() {
157 return DecodeFixed64(base_iterator_->key().data());
158 }
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100159
Marc Kupietz4b799e92018-01-02 11:04:56 +0100160 uint64_t rocksdb::CollocatorIterator::intValue() {
161 return DecodeFixed64(base_iterator_->value().data());
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100162 }
163
Marc Kupietz4b799e92018-01-02 11:04:56 +0100164 class Collocators {
165 private:
166 WriteOptions merge_option_; // for merge
167 char _one[sizeof(uint64_t)];
168 Slice _one_slice;
169
170 protected:
171 std::shared_ptr<DB> db_;
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100172
Marc Kupietz4b799e92018-01-02 11:04:56 +0100173 WriteOptions put_option_;
174 ReadOptions get_option_;
175 WriteOptions delete_option_;
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100176
Marc Kupietz4b799e92018-01-02 11:04:56 +0100177 uint64_t default_;
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100178
Marc Kupietz4b799e92018-01-02 11:04:56 +0100179 std::shared_ptr<DB> OpenDb(const char *dbname);
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100180
Marc Kupietz4b799e92018-01-02 11:04:56 +0100181 public:
182 Collocators(const char *db_name);
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100183
Marc Kupietz4b799e92018-01-02 11:04:56 +0100184 ~Collocators();
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100185
Marc Kupietz4b799e92018-01-02 11:04:56 +0100186 // public interface of Collocators.
187 // All four functions return false
188 // if the underlying level db operation failed.
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100189
Marc Kupietz4b799e92018-01-02 11:04:56 +0100190 // mapped to a levedb Put
191 bool set(const std::string& key, uint64_t value) {
192 // just treat the internal rep of int64 as the string
193 char buf[sizeof(value)];
194 EncodeFixed64(buf, value);
195 Slice slice(buf, sizeof(value));
196 auto s = db_->Put(put_option_, key, slice);
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100197
Marc Kupietz4b799e92018-01-02 11:04:56 +0100198 if (s.ok()) {
199 return true;
200 } else {
201 std::cerr << s.ToString() << std::endl;
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100202 return false;
203 }
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100204 }
Marc Kupietz4b799e92018-01-02 11:04:56 +0100205
206 DB *getDb() {
207 return db_.get();
208 }
209
210 // mapped to a rocksdb Delete
211 bool remove(const std::string& key) {
212 auto s = db_->Delete(delete_option_, key);
213
214 if (s.ok()) {
215 return true;
216 } else {
217 std::cerr << s.ToString() << std::endl;
218 return false;
219 }
220 }
221
222 // mapped to a rocksdb Get
223 bool get(const std::string& key, uint64_t* value) {
224 std::string str;
225 auto s = db_->Get(get_option_, key, &str);
226
227 if (s.IsNotFound()) {
228 // return default value if not found;
229 *value = default_;
230 return true;
231 } else if (s.ok()) {
232 // deserialization
233 if (str.size() != sizeof(uint64_t)) {
234 std::cerr << "value corruption\n";
235 return false;
236 }
237 *value = DecodeFixed64(&str[0]);
238 return true;
239 } else {
240 std::cerr << s.ToString() << std::endl;
241 return false;
242 }
243 }
244
245
246 uint64_t get(const uint32_t w1, const uint32_t w2, const int8_t dist) {
247 char encoded_key[sizeof(uint64_t)];
248 EncodeFixed64(encoded_key, encodeCollocation(w1,w2,dist));
249 uint64_t value = default_;
250 get(std::string(encoded_key, 8), &value);
251 return value;
252 }
253
254 virtual void inc(const std::string& key) {
255 db_->Merge(merge_option_, key, _one_slice);
256 }
257
258 void inc(const uint64_t key) {
259 char encoded_key[sizeof(uint64_t)];
260 EncodeFixed64(encoded_key, key);
261 db_->Merge(merge_option_, std::string(encoded_key, 8), _one_slice);
262 }
263
264 virtual void inc(const uint32_t w1, const uint32_t w2, const uint8_t dist);
265
266
267 // mapped to a rocksdb Merge operation
268 virtual bool add(const std::string& key, uint64_t value) {
269 char encoded[sizeof(uint64_t)];
270 EncodeFixed64(encoded, value);
271 Slice slice(encoded, sizeof(uint64_t));
272 auto s = db_->Merge(merge_option_, key, slice);
273
274 if (s.ok()) {
275 return true;
276 } else {
277 std::cerr << s.ToString() << std::endl;
278 return false;
279 }
280 }
281
282 CollocatorIterator* SeekIterator(uint64_t w1, uint64_t w2, int8_t dist);
283 };
284
285 rocksdb::Collocators::Collocators(const char *db_name) {
286 std::cout << "Test merge-based counters... " << db_name << "\n";
287 db_ = OpenDb(db_name);
288 assert(db_);
289 uint64_t one = 1;
290 EncodeFixed64(_one, one);
291 _one_slice = Slice(_one, sizeof(uint64_t));
292 }
293
294 rocksdb::CollocatorIterator::~CollocatorIterator() {
295 std::cout << "destroying itera\n";
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100296 }
297
Marc Kupietz4b799e92018-01-02 11:04:56 +0100298 rocksdb::Collocators::~Collocators() {
299 std::cout << "destroying coll\n";
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100300 }
301
Marc Kupietz4b799e92018-01-02 11:04:56 +0100302 void rocksdb::Collocators::inc(const uint32_t w1, const uint32_t w2, const uint8_t dist) {
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100303 inc(encodeCollocation(w1, w2, dist));
304 }
Marc Kupietz4b799e92018-01-02 11:04:56 +0100305
306 std::shared_ptr<DB> rocksdb::Collocators::OpenDb(const char *dbname) {
307 std::cout << "Test merge-based counters... " << dbname << "\n";
308 DB* db;
309 Options options;
310 options.create_if_missing = true;
311 options.merge_operator = std::make_shared<CountMergeOperator>();
312 options.max_successive_merges = 0;
313 Status s;
314 // DestroyDB(dbname, Options());
315 s = DB::Open(options, dbname, &db);
316 if (!s.ok()) {
317 std::cerr << s.ToString() << std::endl;
318 assert(false);
319 }
320 return std::shared_ptr<DB>(db);
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100321 }
322
Marc Kupietz4b799e92018-01-02 11:04:56 +0100323 CollocatorIterator* rocksdb::Collocators::SeekIterator(uint64_t w1, uint64_t w2, int8_t dist) {
Marc Kupietz18375e12017-12-24 10:11:18 +0100324 ReadOptions options;
325 options.prefix_same_as_start = true;
326 char prefixc[sizeof(uint64_t)];
327 EncodeFixed64(prefixc, encodeCollocation(w1, w2, dist));
328 Iterator *it = db_->NewIterator(options);
329 CollocatorIterator *cit = new CollocatorIterator(it);
330 cit->Seek(std::string(prefixc,3));// it->Valid() && it->key().starts_with(std::string(prefixc,3)); it->Next()) {
331 cit->setPrefix(prefixc);
332 return cit;
333 }
334
Marc Kupietz4b799e92018-01-02 11:04:56 +0100335 rocksdb::Slice rocksdb::CollocatorIterator::key() const { return base_iterator_->key(); }
336 rocksdb::Slice rocksdb::CollocatorIterator::value() const { return base_iterator_->value(); }
337 rocksdb::Status rocksdb::CollocatorIterator::status() const { return base_iterator_->status(); }
338
Marc Kupietz28cc53e2017-12-23 17:24:55 +0100339};