1 | // Copyright (c) 2011 The LevelDB Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. See the AUTHORS file for names of contributors. |
4 | |
5 | #include "leveldb/c.h" |
6 | |
7 | #include <string.h> |
8 | |
9 | #include <cstdint> |
10 | #include <cstdlib> |
11 | |
12 | #include "leveldb/cache.h" |
13 | #include "leveldb/comparator.h" |
14 | #include "leveldb/db.h" |
15 | #include "leveldb/env.h" |
16 | #include "leveldb/filter_policy.h" |
17 | #include "leveldb/iterator.h" |
18 | #include "leveldb/options.h" |
19 | #include "leveldb/status.h" |
20 | #include "leveldb/write_batch.h" |
21 | |
22 | using leveldb::Cache; |
23 | using leveldb::Comparator; |
24 | using leveldb::CompressionType; |
25 | using leveldb::DB; |
26 | using leveldb::Env; |
27 | using leveldb::FileLock; |
28 | using leveldb::FilterPolicy; |
29 | using leveldb::Iterator; |
30 | using leveldb::kMajorVersion; |
31 | using leveldb::kMinorVersion; |
32 | using leveldb::Logger; |
33 | using leveldb::NewBloomFilterPolicy; |
34 | using leveldb::NewLRUCache; |
35 | using leveldb::Options; |
36 | using leveldb::RandomAccessFile; |
37 | using leveldb::Range; |
38 | using leveldb::ReadOptions; |
39 | using leveldb::SequentialFile; |
40 | using leveldb::Slice; |
41 | using leveldb::Snapshot; |
42 | using leveldb::Status; |
43 | using leveldb::WritableFile; |
44 | using leveldb::WriteBatch; |
45 | using leveldb::WriteOptions; |
46 | |
47 | extern "C" { |
48 | |
49 | struct leveldb_t { |
50 | DB* rep; |
51 | }; |
52 | struct leveldb_iterator_t { |
53 | Iterator* rep; |
54 | }; |
55 | struct leveldb_writebatch_t { |
56 | WriteBatch rep; |
57 | }; |
58 | struct leveldb_snapshot_t { |
59 | const Snapshot* rep; |
60 | }; |
61 | struct leveldb_readoptions_t { |
62 | ReadOptions rep; |
63 | }; |
64 | struct leveldb_writeoptions_t { |
65 | WriteOptions rep; |
66 | }; |
67 | struct leveldb_options_t { |
68 | Options rep; |
69 | }; |
70 | struct leveldb_cache_t { |
71 | Cache* rep; |
72 | }; |
73 | struct leveldb_seqfile_t { |
74 | SequentialFile* rep; |
75 | }; |
76 | struct leveldb_randomfile_t { |
77 | RandomAccessFile* rep; |
78 | }; |
79 | struct leveldb_writablefile_t { |
80 | WritableFile* rep; |
81 | }; |
82 | struct leveldb_logger_t { |
83 | Logger* rep; |
84 | }; |
85 | struct leveldb_filelock_t { |
86 | FileLock* rep; |
87 | }; |
88 | |
89 | struct leveldb_comparator_t : public Comparator { |
90 | ~leveldb_comparator_t() override { (*destructor_)(state_); } |
91 | |
92 | int Compare(const Slice& a, const Slice& b) const override { |
93 | return (*compare_)(state_, a.data(), a.size(), b.data(), b.size()); |
94 | } |
95 | |
96 | const char* Name() const override { return (*name_)(state_); } |
97 | |
98 | // No-ops since the C binding does not support key shortening methods. |
99 | void FindShortestSeparator(std::string*, const Slice&) const override {} |
100 | void FindShortSuccessor(std::string* key) const override {} |
101 | |
102 | void* state_; |
103 | void (*destructor_)(void*); |
104 | int (*compare_)(void*, const char* a, size_t alen, const char* b, |
105 | size_t blen); |
106 | const char* (*name_)(void*); |
107 | }; |
108 | |
109 | struct leveldb_filterpolicy_t : public FilterPolicy { |
110 | ~leveldb_filterpolicy_t() override { (*destructor_)(state_); } |
111 | |
112 | const char* Name() const override { return (*name_)(state_); } |
113 | |
114 | void CreateFilter(const Slice* keys, int n, std::string* dst) const override { |
115 | std::vector<const char*> key_pointers(n); |
116 | std::vector<size_t> key_sizes(n); |
117 | for (int i = 0; i < n; i++) { |
118 | key_pointers[i] = keys[i].data(); |
119 | key_sizes[i] = keys[i].size(); |
120 | } |
121 | size_t len; |
122 | char* filter = (*create_)(state_, &key_pointers[0], &key_sizes[0], n, &len); |
123 | dst->append(filter, len); |
124 | std::free(filter); |
125 | } |
126 | |
127 | bool KeyMayMatch(const Slice& key, const Slice& filter) const override { |
128 | return (*key_match_)(state_, key.data(), key.size(), filter.data(), |
129 | filter.size()); |
130 | } |
131 | |
132 | void* state_; |
133 | void (*destructor_)(void*); |
134 | const char* (*name_)(void*); |
135 | char* (*create_)(void*, const char* const* key_array, |
136 | const size_t* key_length_array, int num_keys, |
137 | size_t* filter_length); |
138 | uint8_t (*key_match_)(void*, const char* key, size_t length, |
139 | const char* filter, size_t filter_length); |
140 | }; |
141 | |
142 | struct leveldb_env_t { |
143 | Env* rep; |
144 | bool is_default; |
145 | }; |
146 | |
147 | static bool SaveError(char** errptr, const Status& s) { |
148 | assert(errptr != nullptr); |
149 | if (s.ok()) { |
150 | return false; |
151 | } else if (*errptr == nullptr) { |
152 | *errptr = strdup(s.ToString().c_str()); |
153 | } else { |
154 | // TODO(sanjay): Merge with existing error? |
155 | std::free(*errptr); |
156 | *errptr = strdup(s.ToString().c_str()); |
157 | } |
158 | return true; |
159 | } |
160 | |
161 | static char* CopyString(const std::string& str) { |
162 | char* result = |
163 | reinterpret_cast<char*>(std::malloc(sizeof(char) * str.size())); |
164 | std::memcpy(result, str.data(), sizeof(char) * str.size()); |
165 | return result; |
166 | } |
167 | |
168 | leveldb_t* leveldb_open(const leveldb_options_t* options, const char* name, |
169 | char** errptr) { |
170 | DB* db; |
171 | if (SaveError(errptr, DB::Open(options->rep, std::string(name), &db))) { |
172 | return nullptr; |
173 | } |
174 | leveldb_t* result = new leveldb_t; |
175 | result->rep = db; |
176 | return result; |
177 | } |
178 | |
179 | void leveldb_close(leveldb_t* db) { |
180 | delete db->rep; |
181 | delete db; |
182 | } |
183 | |
184 | void leveldb_put(leveldb_t* db, const leveldb_writeoptions_t* options, |
185 | const char* key, size_t keylen, const char* val, size_t vallen, |
186 | char** errptr) { |
187 | SaveError(errptr, |
188 | db->rep->Put(options->rep, Slice(key, keylen), Slice(val, vallen))); |
189 | } |
190 | |
191 | void leveldb_delete(leveldb_t* db, const leveldb_writeoptions_t* options, |
192 | const char* key, size_t keylen, char** errptr) { |
193 | SaveError(errptr, db->rep->Delete(options->rep, Slice(key, keylen))); |
194 | } |
195 | |
196 | void leveldb_write(leveldb_t* db, const leveldb_writeoptions_t* options, |
197 | leveldb_writebatch_t* batch, char** errptr) { |
198 | SaveError(errptr, db->rep->Write(options->rep, &batch->rep)); |
199 | } |
200 | |
201 | char* leveldb_get(leveldb_t* db, const leveldb_readoptions_t* options, |
202 | const char* key, size_t keylen, size_t* vallen, |
203 | char** errptr) { |
204 | char* result = nullptr; |
205 | std::string tmp; |
206 | Status s = db->rep->Get(options->rep, Slice(key, keylen), &tmp); |
207 | if (s.ok()) { |
208 | *vallen = tmp.size(); |
209 | result = CopyString(tmp); |
210 | } else { |
211 | *vallen = 0; |
212 | if (!s.IsNotFound()) { |
213 | SaveError(errptr, s); |
214 | } |
215 | } |
216 | return result; |
217 | } |
218 | |
219 | leveldb_iterator_t* leveldb_create_iterator( |
220 | leveldb_t* db, const leveldb_readoptions_t* options) { |
221 | leveldb_iterator_t* result = new leveldb_iterator_t; |
222 | result->rep = db->rep->NewIterator(options->rep); |
223 | return result; |
224 | } |
225 | |
226 | const leveldb_snapshot_t* leveldb_create_snapshot(leveldb_t* db) { |
227 | leveldb_snapshot_t* result = new leveldb_snapshot_t; |
228 | result->rep = db->rep->GetSnapshot(); |
229 | return result; |
230 | } |
231 | |
232 | void leveldb_release_snapshot(leveldb_t* db, |
233 | const leveldb_snapshot_t* snapshot) { |
234 | db->rep->ReleaseSnapshot(snapshot->rep); |
235 | delete snapshot; |
236 | } |
237 | |
238 | char* leveldb_property_value(leveldb_t* db, const char* propname) { |
239 | std::string tmp; |
240 | if (db->rep->GetProperty(Slice(propname), &tmp)) { |
241 | // We use strdup() since we expect human readable output. |
242 | return strdup(tmp.c_str()); |
243 | } else { |
244 | return nullptr; |
245 | } |
246 | } |
247 | |
248 | void leveldb_approximate_sizes(leveldb_t* db, int num_ranges, |
249 | const char* const* range_start_key, |
250 | const size_t* range_start_key_len, |
251 | const char* const* range_limit_key, |
252 | const size_t* range_limit_key_len, |
253 | uint64_t* sizes) { |
254 | Range* ranges = new Range[num_ranges]; |
255 | for (int i = 0; i < num_ranges; i++) { |
256 | ranges[i].start = Slice(range_start_key[i], range_start_key_len[i]); |
257 | ranges[i].limit = Slice(range_limit_key[i], range_limit_key_len[i]); |
258 | } |
259 | db->rep->GetApproximateSizes(ranges, num_ranges, sizes); |
260 | delete[] ranges; |
261 | } |
262 | |
263 | void leveldb_compact_range(leveldb_t* db, const char* start_key, |
264 | size_t start_key_len, const char* limit_key, |
265 | size_t limit_key_len) { |
266 | Slice a, b; |
267 | db->rep->CompactRange( |
268 | // Pass null Slice if corresponding "const char*" is null |
269 | (start_key ? (a = Slice(start_key, start_key_len), &a) : nullptr), |
270 | (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : nullptr)); |
271 | } |
272 | |
273 | void leveldb_destroy_db(const leveldb_options_t* options, const char* name, |
274 | char** errptr) { |
275 | SaveError(errptr, DestroyDB(name, options->rep)); |
276 | } |
277 | |
278 | void leveldb_repair_db(const leveldb_options_t* options, const char* name, |
279 | char** errptr) { |
280 | SaveError(errptr, RepairDB(name, options->rep)); |
281 | } |
282 | |
283 | void leveldb_iter_destroy(leveldb_iterator_t* iter) { |
284 | delete iter->rep; |
285 | delete iter; |
286 | } |
287 | |
288 | uint8_t leveldb_iter_valid(const leveldb_iterator_t* iter) { |
289 | return iter->rep->Valid(); |
290 | } |
291 | |
292 | void leveldb_iter_seek_to_first(leveldb_iterator_t* iter) { |
293 | iter->rep->SeekToFirst(); |
294 | } |
295 | |
296 | void leveldb_iter_seek_to_last(leveldb_iterator_t* iter) { |
297 | iter->rep->SeekToLast(); |
298 | } |
299 | |
300 | void leveldb_iter_seek(leveldb_iterator_t* iter, const char* k, size_t klen) { |
301 | iter->rep->Seek(Slice(k, klen)); |
302 | } |
303 | |
304 | void leveldb_iter_next(leveldb_iterator_t* iter) { iter->rep->Next(); } |
305 | |
306 | void leveldb_iter_prev(leveldb_iterator_t* iter) { iter->rep->Prev(); } |
307 | |
308 | const char* leveldb_iter_key(const leveldb_iterator_t* iter, size_t* klen) { |
309 | Slice s = iter->rep->key(); |
310 | *klen = s.size(); |
311 | return s.data(); |
312 | } |
313 | |
314 | const char* leveldb_iter_value(const leveldb_iterator_t* iter, size_t* vlen) { |
315 | Slice s = iter->rep->value(); |
316 | *vlen = s.size(); |
317 | return s.data(); |
318 | } |
319 | |
320 | void leveldb_iter_get_error(const leveldb_iterator_t* iter, char** errptr) { |
321 | SaveError(errptr, iter->rep->status()); |
322 | } |
323 | |
324 | leveldb_writebatch_t* leveldb_writebatch_create() { |
325 | return new leveldb_writebatch_t; |
326 | } |
327 | |
328 | void leveldb_writebatch_destroy(leveldb_writebatch_t* b) { delete b; } |
329 | |
330 | void leveldb_writebatch_clear(leveldb_writebatch_t* b) { b->rep.Clear(); } |
331 | |
332 | void leveldb_writebatch_put(leveldb_writebatch_t* b, const char* key, |
333 | size_t klen, const char* val, size_t vlen) { |
334 | b->rep.Put(Slice(key, klen), Slice(val, vlen)); |
335 | } |
336 | |
337 | void leveldb_writebatch_delete(leveldb_writebatch_t* b, const char* key, |
338 | size_t klen) { |
339 | b->rep.Delete(Slice(key, klen)); |
340 | } |
341 | |
342 | void leveldb_writebatch_iterate(const leveldb_writebatch_t* b, void* state, |
343 | void (*put)(void*, const char* k, size_t klen, |
344 | const char* v, size_t vlen), |
345 | void (*deleted)(void*, const char* k, |
346 | size_t klen)) { |
347 | class H : public WriteBatch::Handler { |
348 | public: |
349 | void* state_; |
350 | void (*put_)(void*, const char* k, size_t klen, const char* v, size_t vlen); |
351 | void (*deleted_)(void*, const char* k, size_t klen); |
352 | void Put(const Slice& key, const Slice& value) override { |
353 | (*put_)(state_, key.data(), key.size(), value.data(), value.size()); |
354 | } |
355 | void Delete(const Slice& key) override { |
356 | (*deleted_)(state_, key.data(), key.size()); |
357 | } |
358 | }; |
359 | H handler; |
360 | handler.state_ = state; |
361 | handler.put_ = put; |
362 | handler.deleted_ = deleted; |
363 | b->rep.Iterate(&handler); |
364 | } |
365 | |
366 | void leveldb_writebatch_append(leveldb_writebatch_t* destination, |
367 | const leveldb_writebatch_t* source) { |
368 | destination->rep.Append(source->rep); |
369 | } |
370 | |
371 | leveldb_options_t* leveldb_options_create() { return new leveldb_options_t; } |
372 | |
373 | void leveldb_options_destroy(leveldb_options_t* options) { delete options; } |
374 | |
375 | void leveldb_options_set_comparator(leveldb_options_t* opt, |
376 | leveldb_comparator_t* cmp) { |
377 | opt->rep.comparator = cmp; |
378 | } |
379 | |
380 | void leveldb_options_set_filter_policy(leveldb_options_t* opt, |
381 | leveldb_filterpolicy_t* policy) { |
382 | opt->rep.filter_policy = policy; |
383 | } |
384 | |
385 | void leveldb_options_set_create_if_missing(leveldb_options_t* opt, uint8_t v) { |
386 | opt->rep.create_if_missing = v; |
387 | } |
388 | |
389 | void leveldb_options_set_error_if_exists(leveldb_options_t* opt, uint8_t v) { |
390 | opt->rep.error_if_exists = v; |
391 | } |
392 | |
393 | void leveldb_options_set_paranoid_checks(leveldb_options_t* opt, uint8_t v) { |
394 | opt->rep.paranoid_checks = v; |
395 | } |
396 | |
397 | void leveldb_options_set_env(leveldb_options_t* opt, leveldb_env_t* env) { |
398 | opt->rep.env = (env ? env->rep : nullptr); |
399 | } |
400 | |
401 | void leveldb_options_set_info_log(leveldb_options_t* opt, leveldb_logger_t* l) { |
402 | opt->rep.info_log = (l ? l->rep : nullptr); |
403 | } |
404 | |
405 | void leveldb_options_set_write_buffer_size(leveldb_options_t* opt, size_t s) { |
406 | opt->rep.write_buffer_size = s; |
407 | } |
408 | |
409 | void leveldb_options_set_max_open_files(leveldb_options_t* opt, int n) { |
410 | opt->rep.max_open_files = n; |
411 | } |
412 | |
413 | void leveldb_options_set_cache(leveldb_options_t* opt, leveldb_cache_t* c) { |
414 | opt->rep.block_cache = c->rep; |
415 | } |
416 | |
417 | void leveldb_options_set_block_size(leveldb_options_t* opt, size_t s) { |
418 | opt->rep.block_size = s; |
419 | } |
420 | |
421 | void leveldb_options_set_block_restart_interval(leveldb_options_t* opt, int n) { |
422 | opt->rep.block_restart_interval = n; |
423 | } |
424 | |
425 | void leveldb_options_set_max_file_size(leveldb_options_t* opt, size_t s) { |
426 | opt->rep.max_file_size = s; |
427 | } |
428 | |
429 | void leveldb_options_set_compression(leveldb_options_t* opt, int t) { |
430 | opt->rep.compression = static_cast<CompressionType>(t); |
431 | } |
432 | |
433 | leveldb_comparator_t* leveldb_comparator_create( |
434 | void* state, void (*destructor)(void*), |
435 | int (*compare)(void*, const char* a, size_t alen, const char* b, |
436 | size_t blen), |
437 | const char* (*name)(void*)) { |
438 | leveldb_comparator_t* result = new leveldb_comparator_t; |
439 | result->state_ = state; |
440 | result->destructor_ = destructor; |
441 | result->compare_ = compare; |
442 | result->name_ = name; |
443 | return result; |
444 | } |
445 | |
446 | void leveldb_comparator_destroy(leveldb_comparator_t* cmp) { delete cmp; } |
447 | |
448 | leveldb_filterpolicy_t* leveldb_filterpolicy_create( |
449 | void* state, void (*destructor)(void*), |
450 | char* (*create_filter)(void*, const char* const* key_array, |
451 | const size_t* key_length_array, int num_keys, |
452 | size_t* filter_length), |
453 | uint8_t (*key_may_match)(void*, const char* key, size_t length, |
454 | const char* filter, size_t filter_length), |
455 | const char* (*name)(void*)) { |
456 | leveldb_filterpolicy_t* result = new leveldb_filterpolicy_t; |
457 | result->state_ = state; |
458 | result->destructor_ = destructor; |
459 | result->create_ = create_filter; |
460 | result->key_match_ = key_may_match; |
461 | result->name_ = name; |
462 | return result; |
463 | } |
464 | |
465 | void leveldb_filterpolicy_destroy(leveldb_filterpolicy_t* filter) { |
466 | delete filter; |
467 | } |
468 | |
469 | leveldb_filterpolicy_t* leveldb_filterpolicy_create_bloom(int bits_per_key) { |
470 | // Make a leveldb_filterpolicy_t, but override all of its methods so |
471 | // they delegate to a NewBloomFilterPolicy() instead of user |
472 | // supplied C functions. |
473 | struct Wrapper : public leveldb_filterpolicy_t { |
474 | static void DoNothing(void*) {} |
475 | |
476 | ~Wrapper() { delete rep_; } |
477 | const char* Name() const { return rep_->Name(); } |
478 | void CreateFilter(const Slice* keys, int n, std::string* dst) const { |
479 | return rep_->CreateFilter(keys, n, dst); |
480 | } |
481 | bool KeyMayMatch(const Slice& key, const Slice& filter) const { |
482 | return rep_->KeyMayMatch(key, filter); |
483 | } |
484 | |
485 | const FilterPolicy* rep_; |
486 | }; |
487 | Wrapper* wrapper = new Wrapper; |
488 | wrapper->rep_ = NewBloomFilterPolicy(bits_per_key); |
489 | wrapper->state_ = nullptr; |
490 | wrapper->destructor_ = &Wrapper::DoNothing; |
491 | return wrapper; |
492 | } |
493 | |
494 | leveldb_readoptions_t* leveldb_readoptions_create() { |
495 | return new leveldb_readoptions_t; |
496 | } |
497 | |
498 | void leveldb_readoptions_destroy(leveldb_readoptions_t* opt) { delete opt; } |
499 | |
500 | void leveldb_readoptions_set_verify_checksums(leveldb_readoptions_t* opt, |
501 | uint8_t v) { |
502 | opt->rep.verify_checksums = v; |
503 | } |
504 | |
505 | void leveldb_readoptions_set_fill_cache(leveldb_readoptions_t* opt, uint8_t v) { |
506 | opt->rep.fill_cache = v; |
507 | } |
508 | |
509 | void leveldb_readoptions_set_snapshot(leveldb_readoptions_t* opt, |
510 | const leveldb_snapshot_t* snap) { |
511 | opt->rep.snapshot = (snap ? snap->rep : nullptr); |
512 | } |
513 | |
514 | leveldb_writeoptions_t* leveldb_writeoptions_create() { |
515 | return new leveldb_writeoptions_t; |
516 | } |
517 | |
518 | void leveldb_writeoptions_destroy(leveldb_writeoptions_t* opt) { delete opt; } |
519 | |
520 | void leveldb_writeoptions_set_sync(leveldb_writeoptions_t* opt, uint8_t v) { |
521 | opt->rep.sync = v; |
522 | } |
523 | |
524 | leveldb_cache_t* leveldb_cache_create_lru(size_t capacity) { |
525 | leveldb_cache_t* c = new leveldb_cache_t; |
526 | c->rep = NewLRUCache(capacity); |
527 | return c; |
528 | } |
529 | |
530 | void leveldb_cache_destroy(leveldb_cache_t* cache) { |
531 | delete cache->rep; |
532 | delete cache; |
533 | } |
534 | |
535 | leveldb_env_t* leveldb_create_default_env() { |
536 | leveldb_env_t* result = new leveldb_env_t; |
537 | result->rep = Env::Default(); |
538 | result->is_default = true; |
539 | return result; |
540 | } |
541 | |
542 | void leveldb_env_destroy(leveldb_env_t* env) { |
543 | if (!env->is_default) delete env->rep; |
544 | delete env; |
545 | } |
546 | |
547 | char* leveldb_env_get_test_directory(leveldb_env_t* env) { |
548 | std::string result; |
549 | if (!env->rep->GetTestDirectory(&result).ok()) { |
550 | return nullptr; |
551 | } |
552 | |
553 | char* buffer = static_cast<char*>(std::malloc(result.size() + 1)); |
554 | std::memcpy(buffer, result.data(), result.size()); |
555 | buffer[result.size()] = '\0'; |
556 | return buffer; |
557 | } |
558 | |
559 | void leveldb_free(void* ptr) { std::free(ptr); } |
560 | |
561 | int leveldb_major_version() { return kMajorVersion; } |
562 | |
563 | int leveldb_minor_version() { return kMinorVersion; } |
564 | |
565 | } // end extern "C" |
566 | |