1 
2 
3 #include "lsmtest.h"
4 #include <stdlib.h>
5 
6 #ifdef HAVE_KYOTOCABINET
7 #include "kcpolydb.h"
8 extern "C" {
9   struct KcDb {
10     TestDb base;
11     kyotocabinet::TreeDB* db;
12     char *pVal;
13   };
14 }
15 
test_kc_open(const char * zFilename,int bClear,TestDb ** ppDb)16 int test_kc_open(const char *zFilename, int bClear, TestDb **ppDb){
17   KcDb *pKcDb;
18   int ok;
19   int rc = 0;
20 
21   if( bClear ){
22     char *zCmd = sqlite3_mprintf("rm -rf %s\n", zFilename);
23     system(zCmd);
24     sqlite3_free(zCmd);
25   }
26 
27   pKcDb = (KcDb *)malloc(sizeof(KcDb));
28   memset(pKcDb, 0, sizeof(KcDb));
29 
30 
31   pKcDb->db = new kyotocabinet::TreeDB();
32   pKcDb->db->tune_page(TESTDB_DEFAULT_PAGE_SIZE);
33   pKcDb->db->tune_page_cache(
34       TESTDB_DEFAULT_PAGE_SIZE * TESTDB_DEFAULT_CACHE_SIZE
35   );
36   ok = pKcDb->db->open(zFilename,
37       kyotocabinet::PolyDB::OWRITER | kyotocabinet::PolyDB::OCREATE
38   );
39   if( ok==0 ){
40     free(pKcDb);
41     pKcDb = 0;
42     rc = 1;
43   }
44 
45   *ppDb = (TestDb *)pKcDb;
46   return rc;
47 }
48 
test_kc_close(TestDb * pDb)49 int test_kc_close(TestDb *pDb){
50   KcDb *pKcDb = (KcDb *)pDb;
51   if( pKcDb->pVal ){
52     delete [] pKcDb->pVal;
53   }
54   pKcDb->db->close();
55   delete pKcDb->db;
56   free(pKcDb);
57   return 0;
58 }
59 
test_kc_write(TestDb * pDb,void * pKey,int nKey,void * pVal,int nVal)60 int test_kc_write(TestDb *pDb, void *pKey, int nKey, void *pVal, int nVal){
61   KcDb *pKcDb = (KcDb *)pDb;
62   int ok;
63 
64   ok = pKcDb->db->set((const char *)pKey, nKey, (const char *)pVal, nVal);
65   return (ok ? 0 : 1);
66 }
67 
test_kc_delete(TestDb * pDb,void * pKey,int nKey)68 int test_kc_delete(TestDb *pDb, void *pKey, int nKey){
69   KcDb *pKcDb = (KcDb *)pDb;
70   int ok;
71 
72   ok = pKcDb->db->remove((const char *)pKey, nKey);
73   return (ok ? 0 : 1);
74 }
75 
test_kc_delete_range(TestDb * pDb,void * pKey1,int nKey1,void * pKey2,int nKey2)76 int test_kc_delete_range(
77   TestDb *pDb,
78   void *pKey1, int nKey1,
79   void *pKey2, int nKey2
80 ){
81   int res;
82   KcDb *pKcDb = (KcDb *)pDb;
83   kyotocabinet::DB::Cursor* pCur = pKcDb->db->cursor();
84 
85   if( pKey1 ){
86     res = pCur->jump((const char *)pKey1, nKey1);
87   }else{
88     res = pCur->jump();
89   }
90 
91   while( 1 ){
92     const char *pKey; size_t nKey;
93     const char *pVal; size_t nVal;
94 
95     pKey = pCur->get(&nKey, &pVal, &nVal);
96     if( pKey==0 ) break;
97 
98 #ifndef NDEBUG
99     if( pKey1 ){
100       res = memcmp(pKey, pKey1, MIN((size_t)nKey1, nKey));
101       assert( res>0 || (res==0 && nKey>nKey1) );
102     }
103 #endif
104 
105     if( pKey2 ){
106       res = memcmp(pKey, pKey2, MIN((size_t)nKey2, nKey));
107       if( res>0 || (res==0 && (size_t)nKey2<nKey) ){
108         delete [] pKey;
109         break;
110       }
111     }
112     pCur->remove();
113     delete [] pKey;
114   }
115 
116   delete pCur;
117   return 0;
118 }
119 
test_kc_fetch(TestDb * pDb,void * pKey,int nKey,void ** ppVal,int * pnVal)120 int test_kc_fetch(
121   TestDb *pDb,
122   void *pKey,
123   int nKey,
124   void **ppVal,
125   int *pnVal
126 ){
127   KcDb *pKcDb = (KcDb *)pDb;
128   size_t nVal;
129 
130   if( pKcDb->pVal ){
131     delete [] pKcDb->pVal;
132     pKcDb->pVal = 0;
133   }
134 
135   pKcDb->pVal = pKcDb->db->get((const char *)pKey, nKey, &nVal);
136   if( pKcDb->pVal ){
137     *ppVal = pKcDb->pVal;
138     *pnVal = nVal;
139   }else{
140     *ppVal = 0;
141     *pnVal = -1;
142   }
143 
144   return 0;
145 }
146 
test_kc_scan(TestDb * pDb,void * pCtx,int bReverse,void * pKey1,int nKey1,void * pKey2,int nKey2,void (* xCallback)(void * pCtx,void * pKey,int nKey,void * pVal,int nVal))147 int test_kc_scan(
148   TestDb *pDb,                    /* Database handle */
149   void *pCtx,                     /* Context pointer to pass to xCallback */
150   int bReverse,                   /* True for a reverse order scan */
151   void *pKey1, int nKey1,         /* Start of search */
152   void *pKey2, int nKey2,         /* End of search */
153   void (*xCallback)(void *pCtx, void *pKey, int nKey, void *pVal, int nVal)
154 ){
155   KcDb *pKcDb = (KcDb *)pDb;
156   kyotocabinet::DB::Cursor* pCur = pKcDb->db->cursor();
157   int res;
158 
159   if( bReverse==0 ){
160     if( pKey1 ){
161       res = pCur->jump((const char *)pKey1, nKey1);
162     }else{
163       res = pCur->jump();
164     }
165   }else{
166     if( pKey2 ){
167       res = pCur->jump_back((const char *)pKey2, nKey2);
168     }else{
169       res = pCur->jump_back();
170     }
171   }
172 
173   while( res ){
174     const char *pKey; size_t nKey;
175     const char *pVal; size_t nVal;
176     pKey = pCur->get(&nKey, &pVal, &nVal);
177 
178     if( bReverse==0 && pKey2 ){
179       res = memcmp(pKey, pKey2, MIN((size_t)nKey2, nKey));
180       if( res>0 || (res==0 && (size_t)nKey2<nKey) ){
181         delete [] pKey;
182         break;
183       }
184     }else if( bReverse!=0 && pKey1 ){
185       res = memcmp(pKey, pKey1, MIN((size_t)nKey1, nKey));
186       if( res<0 || (res==0 && (size_t)nKey1>nKey) ){
187         delete [] pKey;
188         break;
189       }
190     }
191 
192     xCallback(pCtx, (void *)pKey, (int)nKey, (void *)pVal, (int)nVal);
193     delete [] pKey;
194 
195     if( bReverse ){
196       res = pCur->step_back();
197     }else{
198       res = pCur->step();
199     }
200   }
201 
202   delete pCur;
203   return 0;
204 }
205 #endif /* HAVE_KYOTOCABINET */
206 
207 #ifdef HAVE_MDB
208 #include "lmdb.h"
209 
210 extern "C" {
211   struct MdbDb {
212     TestDb base;
213     MDB_env *env;
214     MDB_dbi dbi;
215   };
216 }
217 
test_mdb_open(const char * zSpec,const char * zFilename,int bClear,TestDb ** ppDb)218 int test_mdb_open(
219   const char *zSpec,
220   const char *zFilename,
221   int bClear,
222   TestDb **ppDb
223 ){
224   MDB_txn *txn;
225   MdbDb *pMdb;
226   int rc;
227 
228   if( bClear ){
229     char *zCmd = sqlite3_mprintf("rm -rf %s\n", zFilename);
230     system(zCmd);
231     sqlite3_free(zCmd);
232   }
233 
234   pMdb = (MdbDb *)malloc(sizeof(MdbDb));
235   memset(pMdb, 0, sizeof(MdbDb));
236 
237   rc = mdb_env_create(&pMdb->env);
238   if( rc==0 ) rc = mdb_env_set_mapsize(pMdb->env, 1*1024*1024*1024);
239   if( rc==0 ) rc = mdb_env_open(pMdb->env, zFilename, MDB_NOSYNC|MDB_NOSUBDIR, 0600);
240   if( rc==0 ) rc = mdb_txn_begin(pMdb->env, NULL, 0, &txn);
241   if( rc==0 ){
242     rc = mdb_open(txn, NULL, 0, &pMdb->dbi);
243     mdb_txn_commit(txn);
244   }
245 
246   *ppDb = (TestDb *)pMdb;
247   return rc;
248 }
249 
test_mdb_close(TestDb * pDb)250 int test_mdb_close(TestDb *pDb){
251   MdbDb *pMdb = (MdbDb *)pDb;
252 
253   mdb_close(pMdb->env, pMdb->dbi);
254   mdb_env_close(pMdb->env);
255   free(pMdb);
256   return 0;
257 }
258 
test_mdb_write(TestDb * pDb,void * pKey,int nKey,void * pVal,int nVal)259 int test_mdb_write(TestDb *pDb, void *pKey, int nKey, void *pVal, int nVal){
260   int rc;
261   MdbDb *pMdb = (MdbDb *)pDb;
262   MDB_val val;
263   MDB_val key;
264   MDB_txn *txn;
265 
266   val.mv_size = nVal;
267   val.mv_data = pVal;
268   key.mv_size = nKey;
269   key.mv_data = pKey;
270 
271   rc = mdb_txn_begin(pMdb->env, NULL, 0, &txn);
272   if( rc==0 ){
273     rc = mdb_put(txn, pMdb->dbi, &key, &val, 0);
274     if( rc==0 ){
275       rc = mdb_txn_commit(txn);
276     }else{
277       mdb_txn_abort(txn);
278     }
279   }
280 
281   return rc;
282 }
283 
test_mdb_delete(TestDb * pDb,void * pKey,int nKey)284 int test_mdb_delete(TestDb *pDb, void *pKey, int nKey){
285   int rc;
286   MdbDb *pMdb = (MdbDb *)pDb;
287   MDB_val key;
288   MDB_txn *txn;
289 
290   key.mv_size = nKey;
291   key.mv_data = pKey;
292   rc = mdb_txn_begin(pMdb->env, NULL, 0, &txn);
293   if( rc==0 ){
294     rc = mdb_del(txn, pMdb->dbi, &key, 0);
295     if( rc==0 ){
296       rc = mdb_txn_commit(txn);
297     }else{
298       mdb_txn_abort(txn);
299     }
300   }
301 
302   return rc;
303 }
304 
test_mdb_fetch(TestDb * pDb,void * pKey,int nKey,void ** ppVal,int * pnVal)305 int test_mdb_fetch(
306   TestDb *pDb,
307   void *pKey,
308   int nKey,
309   void **ppVal,
310   int *pnVal
311 ){
312   int rc;
313   MdbDb *pMdb = (MdbDb *)pDb;
314   MDB_val key;
315   MDB_txn *txn;
316 
317   key.mv_size = nKey;
318   key.mv_data = pKey;
319 
320   rc = mdb_txn_begin(pMdb->env, NULL, MDB_RDONLY, &txn);
321   if( rc==0 ){
322     MDB_val val = {0, 0};
323     rc = mdb_get(txn, pMdb->dbi, &key, &val);
324     if( rc==MDB_NOTFOUND ){
325       rc = 0;
326       *ppVal = 0;
327       *pnVal = -1;
328     }else{
329       *ppVal = val.mv_data;
330       *pnVal = val.mv_size;
331     }
332     mdb_txn_commit(txn);
333   }
334 
335   return rc;
336 }
337 
test_mdb_scan(TestDb * pDb,void * pCtx,int bReverse,void * pKey1,int nKey1,void * pKey2,int nKey2,void (* xCallback)(void * pCtx,void * pKey,int nKey,void * pVal,int nVal))338 int test_mdb_scan(
339   TestDb *pDb,                    /* Database handle */
340   void *pCtx,                     /* Context pointer to pass to xCallback */
341   int bReverse,                   /* True for a reverse order scan */
342   void *pKey1, int nKey1,         /* Start of search */
343   void *pKey2, int nKey2,         /* End of search */
344   void (*xCallback)(void *pCtx, void *pKey, int nKey, void *pVal, int nVal)
345 ){
346   MdbDb *pMdb = (MdbDb *)pDb;
347   int rc;
348   MDB_cursor_op op = bReverse ? MDB_PREV : MDB_NEXT;
349   MDB_txn *txn;
350 
351   rc = mdb_txn_begin(pMdb->env, NULL, MDB_RDONLY, &txn);
352   if( rc==0 ){
353     MDB_cursor *csr;
354     MDB_val key = {0, 0};
355     MDB_val val = {0, 0};
356 
357     rc = mdb_cursor_open(txn, pMdb->dbi, &csr);
358     if( rc==0 ){
359       while( mdb_cursor_get(csr, &key, &val, op)==0 ){
360         xCallback(pCtx, key.mv_data, key.mv_size, val.mv_data, val.mv_size);
361       }
362       mdb_cursor_close(csr);
363     }
364   }
365 
366   return rc;
367 }
368 
369 #endif /* HAVE_MDB */
370 
371