xref: /aosp_15_r20/external/leveldb/db/c_test.c (revision 9507f98c5f32dee4b5f9e4a38cd499f3ff5c4490)
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 <stddef.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 const char* phase = "";
13 
StartPhase(const char * name)14 static void StartPhase(const char* name) {
15   fprintf(stderr, "=== Test %s\n", name);
16   phase = name;
17 }
18 
19 #define CheckNoError(err)                                               \
20   if ((err) != NULL) {                                                  \
21     fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, (err)); \
22     abort();                                                            \
23   }
24 
25 #define CheckCondition(cond)                                            \
26   if (!(cond)) {                                                        \
27     fprintf(stderr, "%s:%d: %s: %s\n", __FILE__, __LINE__, phase, #cond); \
28     abort();                                                            \
29   }
30 
CheckEqual(const char * expected,const char * v,size_t n)31 static void CheckEqual(const char* expected, const char* v, size_t n) {
32   if (expected == NULL && v == NULL) {
33     // ok
34   } else if (expected != NULL && v != NULL && n == strlen(expected) &&
35              memcmp(expected, v, n) == 0) {
36     // ok
37     return;
38   } else {
39     fprintf(stderr, "%s: expected '%s', got '%s'\n",
40             phase,
41             (expected ? expected : "(null)"),
42             (v ? v : "(null"));
43     abort();
44   }
45 }
46 
Free(char ** ptr)47 static void Free(char** ptr) {
48   if (*ptr) {
49     free(*ptr);
50     *ptr = NULL;
51   }
52 }
53 
CheckGet(leveldb_t * db,const leveldb_readoptions_t * options,const char * key,const char * expected)54 static void CheckGet(
55     leveldb_t* db,
56     const leveldb_readoptions_t* options,
57     const char* key,
58     const char* expected) {
59   char* err = NULL;
60   size_t val_len;
61   char* val;
62   val = leveldb_get(db, options, key, strlen(key), &val_len, &err);
63   CheckNoError(err);
64   CheckEqual(expected, val, val_len);
65   Free(&val);
66 }
67 
CheckIter(leveldb_iterator_t * iter,const char * key,const char * val)68 static void CheckIter(leveldb_iterator_t* iter,
69                       const char* key, const char* val) {
70   size_t len;
71   const char* str;
72   str = leveldb_iter_key(iter, &len);
73   CheckEqual(key, str, len);
74   str = leveldb_iter_value(iter, &len);
75   CheckEqual(val, str, len);
76 }
77 
78 // Callback from leveldb_writebatch_iterate()
CheckPut(void * ptr,const char * k,size_t klen,const char * v,size_t vlen)79 static void CheckPut(void* ptr,
80                      const char* k, size_t klen,
81                      const char* v, size_t vlen) {
82   int* state = (int*) ptr;
83   CheckCondition(*state < 2);
84   switch (*state) {
85     case 0:
86       CheckEqual("bar", k, klen);
87       CheckEqual("b", v, vlen);
88       break;
89     case 1:
90       CheckEqual("box", k, klen);
91       CheckEqual("c", v, vlen);
92       break;
93   }
94   (*state)++;
95 }
96 
97 // Callback from leveldb_writebatch_iterate()
CheckDel(void * ptr,const char * k,size_t klen)98 static void CheckDel(void* ptr, const char* k, size_t klen) {
99   int* state = (int*) ptr;
100   CheckCondition(*state == 2);
101   CheckEqual("bar", k, klen);
102   (*state)++;
103 }
104 
CmpDestroy(void * arg)105 static void CmpDestroy(void* arg) { }
106 
CmpCompare(void * arg,const char * a,size_t alen,const char * b,size_t blen)107 static int CmpCompare(void* arg, const char* a, size_t alen,
108                       const char* b, size_t blen) {
109   int n = (alen < blen) ? alen : blen;
110   int r = memcmp(a, b, n);
111   if (r == 0) {
112     if (alen < blen) r = -1;
113     else if (alen > blen) r = +1;
114   }
115   return r;
116 }
117 
CmpName(void * arg)118 static const char* CmpName(void* arg) {
119   return "foo";
120 }
121 
122 // Custom filter policy
123 static uint8_t fake_filter_result = 1;
FilterDestroy(void * arg)124 static void FilterDestroy(void* arg) { }
FilterName(void * arg)125 static const char* FilterName(void* arg) {
126   return "TestFilter";
127 }
FilterCreate(void * arg,const char * const * key_array,const size_t * key_length_array,int num_keys,size_t * filter_length)128 static char* FilterCreate(
129     void* arg,
130     const char* const* key_array, const size_t* key_length_array,
131     int num_keys,
132     size_t* filter_length) {
133   *filter_length = 4;
134   char* result = malloc(4);
135   memcpy(result, "fake", 4);
136   return result;
137 }
FilterKeyMatch(void * arg,const char * key,size_t length,const char * filter,size_t filter_length)138 uint8_t FilterKeyMatch(void* arg, const char* key, size_t length,
139                        const char* filter, size_t filter_length) {
140   CheckCondition(filter_length == 4);
141   CheckCondition(memcmp(filter, "fake", 4) == 0);
142   return fake_filter_result;
143 }
144 
main(int argc,char ** argv)145 int main(int argc, char** argv) {
146   leveldb_t* db;
147   leveldb_comparator_t* cmp;
148   leveldb_cache_t* cache;
149   leveldb_env_t* env;
150   leveldb_options_t* options;
151   leveldb_readoptions_t* roptions;
152   leveldb_writeoptions_t* woptions;
153   char* dbname;
154   char* err = NULL;
155   int run = -1;
156 
157   CheckCondition(leveldb_major_version() >= 1);
158   CheckCondition(leveldb_minor_version() >= 1);
159 
160   StartPhase("create_objects");
161   cmp = leveldb_comparator_create(NULL, CmpDestroy, CmpCompare, CmpName);
162   env = leveldb_create_default_env();
163   cache = leveldb_cache_create_lru(100000);
164   dbname = leveldb_env_get_test_directory(env);
165   CheckCondition(dbname != NULL);
166 
167   options = leveldb_options_create();
168   leveldb_options_set_comparator(options, cmp);
169   leveldb_options_set_error_if_exists(options, 1);
170   leveldb_options_set_cache(options, cache);
171   leveldb_options_set_env(options, env);
172   leveldb_options_set_info_log(options, NULL);
173   leveldb_options_set_write_buffer_size(options, 100000);
174   leveldb_options_set_paranoid_checks(options, 1);
175   leveldb_options_set_max_open_files(options, 10);
176   leveldb_options_set_block_size(options, 1024);
177   leveldb_options_set_block_restart_interval(options, 8);
178   leveldb_options_set_max_file_size(options, 3 << 20);
179   leveldb_options_set_compression(options, leveldb_no_compression);
180 
181   roptions = leveldb_readoptions_create();
182   leveldb_readoptions_set_verify_checksums(roptions, 1);
183   leveldb_readoptions_set_fill_cache(roptions, 0);
184 
185   woptions = leveldb_writeoptions_create();
186   leveldb_writeoptions_set_sync(woptions, 1);
187 
188   StartPhase("destroy");
189   leveldb_destroy_db(options, dbname, &err);
190   Free(&err);
191 
192   StartPhase("open_error");
193   db = leveldb_open(options, dbname, &err);
194   CheckCondition(err != NULL);
195   Free(&err);
196 
197   StartPhase("leveldb_free");
198   db = leveldb_open(options, dbname, &err);
199   CheckCondition(err != NULL);
200   leveldb_free(err);
201   err = NULL;
202 
203   StartPhase("open");
204   leveldb_options_set_create_if_missing(options, 1);
205   db = leveldb_open(options, dbname, &err);
206   CheckNoError(err);
207   CheckGet(db, roptions, "foo", NULL);
208 
209   StartPhase("put");
210   leveldb_put(db, woptions, "foo", 3, "hello", 5, &err);
211   CheckNoError(err);
212   CheckGet(db, roptions, "foo", "hello");
213 
214   StartPhase("compactall");
215   leveldb_compact_range(db, NULL, 0, NULL, 0);
216   CheckGet(db, roptions, "foo", "hello");
217 
218   StartPhase("compactrange");
219   leveldb_compact_range(db, "a", 1, "z", 1);
220   CheckGet(db, roptions, "foo", "hello");
221 
222   StartPhase("writebatch");
223   {
224     leveldb_writebatch_t* wb = leveldb_writebatch_create();
225     leveldb_writebatch_put(wb, "foo", 3, "a", 1);
226     leveldb_writebatch_clear(wb);
227     leveldb_writebatch_put(wb, "bar", 3, "b", 1);
228     leveldb_writebatch_put(wb, "box", 3, "c", 1);
229 
230     leveldb_writebatch_t* wb2 = leveldb_writebatch_create();
231     leveldb_writebatch_delete(wb2, "bar", 3);
232     leveldb_writebatch_append(wb, wb2);
233     leveldb_writebatch_destroy(wb2);
234 
235     leveldb_write(db, woptions, wb, &err);
236     CheckNoError(err);
237     CheckGet(db, roptions, "foo", "hello");
238     CheckGet(db, roptions, "bar", NULL);
239     CheckGet(db, roptions, "box", "c");
240 
241     int pos = 0;
242     leveldb_writebatch_iterate(wb, &pos, CheckPut, CheckDel);
243     CheckCondition(pos == 3);
244     leveldb_writebatch_destroy(wb);
245   }
246 
247   StartPhase("iter");
248   {
249     leveldb_iterator_t* iter = leveldb_create_iterator(db, roptions);
250     CheckCondition(!leveldb_iter_valid(iter));
251     leveldb_iter_seek_to_first(iter);
252     CheckCondition(leveldb_iter_valid(iter));
253     CheckIter(iter, "box", "c");
254     leveldb_iter_next(iter);
255     CheckIter(iter, "foo", "hello");
256     leveldb_iter_prev(iter);
257     CheckIter(iter, "box", "c");
258     leveldb_iter_prev(iter);
259     CheckCondition(!leveldb_iter_valid(iter));
260     leveldb_iter_seek_to_last(iter);
261     CheckIter(iter, "foo", "hello");
262     leveldb_iter_seek(iter, "b", 1);
263     CheckIter(iter, "box", "c");
264     leveldb_iter_get_error(iter, &err);
265     CheckNoError(err);
266     leveldb_iter_destroy(iter);
267   }
268 
269   StartPhase("approximate_sizes");
270   {
271     int i;
272     int n = 20000;
273     char keybuf[100];
274     char valbuf[100];
275     uint64_t sizes[2];
276     const char* start[2] = { "a", "k00000000000000010000" };
277     size_t start_len[2] = { 1, 21 };
278     const char* limit[2] = { "k00000000000000010000", "z" };
279     size_t limit_len[2] = { 21, 1 };
280     leveldb_writeoptions_set_sync(woptions, 0);
281     for (i = 0; i < n; i++) {
282       snprintf(keybuf, sizeof(keybuf), "k%020d", i);
283       snprintf(valbuf, sizeof(valbuf), "v%020d", i);
284       leveldb_put(db, woptions, keybuf, strlen(keybuf), valbuf, strlen(valbuf),
285                   &err);
286       CheckNoError(err);
287     }
288     leveldb_approximate_sizes(db, 2, start, start_len, limit, limit_len, sizes);
289     CheckCondition(sizes[0] > 0);
290     CheckCondition(sizes[1] > 0);
291   }
292 
293   StartPhase("property");
294   {
295     char* prop = leveldb_property_value(db, "nosuchprop");
296     CheckCondition(prop == NULL);
297     prop = leveldb_property_value(db, "leveldb.stats");
298     CheckCondition(prop != NULL);
299     Free(&prop);
300   }
301 
302   StartPhase("snapshot");
303   {
304     const leveldb_snapshot_t* snap;
305     snap = leveldb_create_snapshot(db);
306     leveldb_delete(db, woptions, "foo", 3, &err);
307     CheckNoError(err);
308     leveldb_readoptions_set_snapshot(roptions, snap);
309     CheckGet(db, roptions, "foo", "hello");
310     leveldb_readoptions_set_snapshot(roptions, NULL);
311     CheckGet(db, roptions, "foo", NULL);
312     leveldb_release_snapshot(db, snap);
313   }
314 
315   StartPhase("repair");
316   {
317     leveldb_close(db);
318     leveldb_options_set_create_if_missing(options, 0);
319     leveldb_options_set_error_if_exists(options, 0);
320     leveldb_repair_db(options, dbname, &err);
321     CheckNoError(err);
322     db = leveldb_open(options, dbname, &err);
323     CheckNoError(err);
324     CheckGet(db, roptions, "foo", NULL);
325     CheckGet(db, roptions, "bar", NULL);
326     CheckGet(db, roptions, "box", "c");
327     leveldb_options_set_create_if_missing(options, 1);
328     leveldb_options_set_error_if_exists(options, 1);
329   }
330 
331   StartPhase("filter");
332   for (run = 0; run < 2; run++) {
333     // First run uses custom filter, second run uses bloom filter
334     CheckNoError(err);
335     leveldb_filterpolicy_t* policy;
336     if (run == 0) {
337       policy = leveldb_filterpolicy_create(
338           NULL, FilterDestroy, FilterCreate, FilterKeyMatch, FilterName);
339     } else {
340       policy = leveldb_filterpolicy_create_bloom(10);
341     }
342 
343     // Create new database
344     leveldb_close(db);
345     leveldb_destroy_db(options, dbname, &err);
346     leveldb_options_set_filter_policy(options, policy);
347     db = leveldb_open(options, dbname, &err);
348     CheckNoError(err);
349     leveldb_put(db, woptions, "foo", 3, "foovalue", 8, &err);
350     CheckNoError(err);
351     leveldb_put(db, woptions, "bar", 3, "barvalue", 8, &err);
352     CheckNoError(err);
353     leveldb_compact_range(db, NULL, 0, NULL, 0);
354 
355     fake_filter_result = 1;
356     CheckGet(db, roptions, "foo", "foovalue");
357     CheckGet(db, roptions, "bar", "barvalue");
358     if (phase == 0) {
359       // Must not find value when custom filter returns false
360       fake_filter_result = 0;
361       CheckGet(db, roptions, "foo", NULL);
362       CheckGet(db, roptions, "bar", NULL);
363       fake_filter_result = 1;
364 
365       CheckGet(db, roptions, "foo", "foovalue");
366       CheckGet(db, roptions, "bar", "barvalue");
367     }
368     leveldb_options_set_filter_policy(options, NULL);
369     leveldb_filterpolicy_destroy(policy);
370   }
371 
372   StartPhase("cleanup");
373   leveldb_close(db);
374   leveldb_options_destroy(options);
375   leveldb_readoptions_destroy(roptions);
376   leveldb_writeoptions_destroy(woptions);
377   leveldb_free(dbname);
378   leveldb_cache_destroy(cache);
379   leveldb_comparator_destroy(cmp);
380   leveldb_env_destroy(env);
381 
382   fprintf(stderr, "PASS\n");
383   return 0;
384 }
385