void search_and_delete_dbdirent(DDSTAT *ddstat) { BDBCUR *cur; char *key, *value; int size; unsigned long long dir; unsigned long long ent; /* traverse records */ cur = tcbdbcurnew(dbdirent); tcbdbcurfirst(cur); while ((key = tcbdbcurkey2(cur)) != NULL) { memcpy(&dir, key, sizeof(dir)); value = tcbdbcurval(cur, &size);; if (value) { memcpy(&ent, value, sizeof(ent)); if ( ent == ddstat->stbuf.st_ino) { printf("Delete %llu:%llu\n",dir,ent); btdelete_curkey(dbdirent, &dir, sizeof(unsigned long long), &ent, sizeof(unsigned long long)); } free(value); } free(key); tcbdbcurnext(cur); } tcbdbcurdel(cur); }
int check_directory_has_parent(unsigned long long inode) { BDBCUR *cur; char *key, *value; int size; unsigned long long dir; unsigned long long ent; int hasparent=0; /* traverse records */ cur = tcbdbcurnew(dbdirent); tcbdbcurfirst(cur); while ((key = tcbdbcurkey2(cur)) != NULL) { memcpy(&dir, key, sizeof(dir)); value = tcbdbcurval(cur, &size);; if (value) { memcpy(&ent, value, sizeof(ent)); if ( inode == ent ) hasparent=1; free(value); } free(key); tcbdbcurnext(cur); } tcbdbcurdel(cur); return(hasparent); }
static PyObject * list2(PyObject *self,PyObject *args){ const char *dbname; if (!PyArg_ParseTuple(args, "s", &dbname)) return NULL; TCADB *adb = openadb(dbname); PyObject* pList = PyList_New(0); if(!tcadbiterinit(adb)){ return NULL; } BDBCUR *cur = tcbdbcurnew(adb->bdb); TCXSTR *key = tcxstrnew(); TCXSTR *val = tcxstrnew(); if(!tcbdbcurfirst(cur) && tcbdbecode(adb->bdb) != TCENOREC){ return NULL; } while(tcbdbcurrec(cur, key, val)){ PyObject* pList1 = PyList_New(0); PyList_Append(pList1,Py_BuildValue("s",tcxstrptr(key))); PyList_Append(pList1,Py_BuildValue("s",tcxstrptr(val))); PyList_Append(pList,pList1); if(!tcbdbcurnext(cur) && tcbdbecode(adb->bdb) != TCENOREC){ return NULL; } } tcxstrdel(val); tcxstrdel(key); tcbdbcurdel(cur); closeadb(adb); return Py_BuildValue("O",pList); }
IoObject *IoTokyoCabinetCursor_next(IoObject *self, IoObject *locals, IoMessage *m) { /*doc TokyoCabinetCursor next Move cursor to next record. Returns true if there is another key, or false if there is no next record. */ IOASSERT(TokyoCabinetCursor(self), "invalid TokyoCabinetCursor"); return IOBOOL(self, tcbdbcurnext(TokyoCabinetCursor(self))); }
IoObject *IoTokyoCabinetPrefixCursor_next(IoObject *self, IoObject *locals, IoMessage *m) { /*doc TokyoCabinetPrefixCursor next Move cursor to next record. Returns true if there is another key, or false if there is no next record. */ IoSeq *prefix = IoObject_getSlot_(self, IOSYMBOL("prefix")); IOASSERT(ISSEQ(prefix), "prefix must be a sequence"); IOASSERT(TokyoCabinetPrefixCursor(self), "invalid TokyoCabinetPrefixCursor"); tcbdbcurnext(TokyoCabinetPrefixCursor(self)); return IOBOOL(self, IoTokyoCabinetPrefixCursor_keyBeginsWithPrefix_(self, prefix)); }
ex_t db_foreach(void *vhandle, db_foreach_t hook, void *userdata) { int ret = 0; dbh_t *handle = vhandle; TCBDB *dbp = handle->dbp; BDBCUR *cursor; dbv_t dbv_key, dbv_data; int ksiz, dsiz; char *key, *data; cursor = tcbdbcurnew(dbp); ret = tcbdbcurfirst(cursor); if (ret) { while ((key = tcbdbcurkey(cursor, &ksiz))) { data = tcbdbcurval(cursor, &dsiz); if (data) { /* switch to "dbv_t *" variables */ dbv_key.leng = ksiz; dbv_key.data = xmalloc(dbv_key.leng+1); memcpy(dbv_key.data, key, ksiz); ((char *)dbv_key.data)[dbv_key.leng] = '\0'; dbv_data.data = data; dbv_data.leng = dsiz; /* read count */ /* call user function */ ret = hook(&dbv_key, &dbv_data, userdata); xfree(dbv_key.data); if (ret != 0) break; free(data); /* not xfree() as allocated by dpget() */ } free(key); /* not xfree() as allocated by dpiternext() */ tcbdbcurnext(cursor); } } else { print_error(__FILE__, __LINE__, "(tc) tcbdbcurfirst err: %d, %s", tcbdbecode(dbp), tcbdberrmsg(tcbdbecode(dbp))); exit(EX_ERROR); } tcbdbcurdel(cursor); return EX_OK; }
IoObject *IoTokyoCabinetPrefixCursor_first(IoObject *self, IoObject *locals, IoMessage *m) { /*doc TokyoCabinetPrefixCursor first Move cursor to first record. Returns self */ IoSeq *prefix = IoObject_getSlot_(self, IOSYMBOL("prefix")); IOASSERT(ISSEQ(prefix), "prefix must be a sequence"); IOASSERT(TokyoCabinetPrefixCursor(self), "invalid TokyoCabinetPrefixCursor"); tcbdbcurjump(TokyoCabinetPrefixCursor(self), (const void *)IoSeq_rawBytes(prefix), (int)IoSeq_rawSizeInBytes(prefix)); if(!IoTokyoCabinetPrefixCursor_keyBeginsWithPrefix_(self, prefix)) { tcbdbcurnext(TokyoCabinetPrefixCursor(self)); } return IOBOOL(self, IoTokyoCabinetPrefixCursor_keyBeginsWithPrefix_(self, prefix)); }
/* iterators */ dict_si_t dict_sym_iter(dict_t d) { /* uses static state */ static BDBCUR *c; dict_si_t res; const void *vp; int z[1U]; if (UNLIKELY(c == NULL)) { c = tcbdbcurnew(d); tcbdbcurjump(c, SYM_SPACE, sizeof(SYM_SPACE)); } if (UNLIKELY((vp = tcbdbcurval3(c, z)) == NULL)) { goto null; } else if (*z != sizeof(int)) { goto null; } /* otherwise fill res */ res.sid = *(const int*)vp; if (UNLIKELY((vp = tcbdbcurkey3(c, z)) == NULL)) { goto null; } /* or fill */ res.sym = vp; /* also iterate to the next thing */ tcbdbcurnext(c); return res; null: if (LIKELY(c != NULL)) { tcbdbcurdel(c); } c = NULL; return (dict_si_t){}; }
int main() { void *bdb1, *bdb2; char *key1, *key2, *val1, *val2; char *key, *value; BDBCUR *cur1, *cur2; char str_key[FRML_ID_CMP_LEN + 1]; char str_val[FRML_ID_CMP_LEN + 2]; unsigned int cnt, dup, steps; int cmp_res; FILE *f1, *f2; bdb1 = bdb_init2("./test1.bdb", &frml_id_cmp); bdb2 = bdb_init2("./test2.bdb", &frml_id_cmp); if (bdb1 == NULL || bdb2 == NULL) return; #if 0 srand(92019); printf("put db1...\n"); cnt = 0; while (cnt < 10000) { snprintf(str_key, FRML_ID_CMP_LEN + 1, "%0*d\n", FRML_ID_CMP_LEN, rand()); sprintf(str_val, "v%s", str_key); bdb_put2(bdb1, str_key, str_val); cnt ++; } printf("put db2...\n"); cnt = 0; while (cnt < 1000090) { snprintf(str_key, FRML_ID_CMP_LEN + 1, "%0*d\n", FRML_ID_CMP_LEN, rand()); sprintf(str_val, "v%s", str_key); bdb_put2(bdb2, str_key, str_val); cnt ++; } /* f1 = fopen("log1.txt", "w"); f2 = fopen("log2.txt", "w"); cur1 = tcbdbcurnew(bdb1); tcbdbcurfirst(cur1); while ((key = tcbdbcurkey2(cur1)) != NULL) { value = tcbdbcurval2(cur1); if (value) { fprintf(f1, "%s\n", key); free(value); } free(key); tcbdbcurnext(cur1); } tcbdbcurdel(cur1); cur2 = tcbdbcurnew(bdb2); tcbdbcurfirst(cur2); while ((key = tcbdbcurkey2(cur2)) != NULL) { value = tcbdbcurval2(cur2); if (value) { fprintf(f2, "%s\n", key); free(value); } free(key); tcbdbcurnext(cur2); } tcbdbcurdel(cur2); fclose(f1); fclose(f2); */ #else #define NUM 10 printf("go one-by-one 100 times...\n"); for (cnt = 0, dup = 0, steps = 0; cnt < NUM; cnt++) { cur1 = tcbdbcurnew(bdb1); tcbdbcurfirst(cur1); while ((key = tcbdbcurkey2(cur1)) != NULL) { value = tcbdbcurval2(cur1); if (value) { //printf("one-by-one: %s\n", key); if (bdb_get2(bdb2, key)) { //printf("%s duplicated.\n", key); dup ++; } free(value); } free(key); tcbdbcurnext(cur1); steps ++; } tcbdbcurdel(cur1); } printf("%d duplicates in %d steps.\n", dup, steps); printf("go jumping 100 times...\n"); for (dup = 0, cnt = 0, steps = 0; cnt < NUM; cnt++) { cur1 = tcbdbcurnew(bdb1); cur2 = tcbdbcurnew(bdb2); tcbdbcurfirst(cur1); tcbdbcurfirst(cur2); do { key1 = tcbdbcurkey2(cur1); key2 = tcbdbcurkey2(cur2); if (key1 == NULL || key2 == NULL) { if (key1) free(key1); else free(key2); break; } cmp_res = frml_id_cmp_(key1, key2); //printf("jumping %s and %s\n", key1, key2); steps ++; if (cmp_res == 0) { val1 = tcbdbcurval2(cur1); val2 = tcbdbcurval2(cur2); dup ++; tcbdbcurnext(cur1); free(val1); free(val2); } else if (cmp_res > 0) /* key1 is larger */ { tcbdbcurjump2(cur2, key1); } else /* key2 is larger */ { tcbdbcurjump2(cur1, key2); } free(key1); free(key2); } while (1); } printf("%d duplicates in %d steps.\n", dup, steps); #endif bdb_release(bdb1); bdb_release(bdb2); }
void check_directory_structure() { BDBCUR *cur; char *key, *value; int size; int hasparent; unsigned long long dir; unsigned long long lastdir=0; unsigned long long ent; int multi=0; DBT *data; /* traverse records */ recheck: cur = tcbdbcurnew(dbdirent); tcbdbcurfirst(cur); while ((key = tcbdbcurkey2(cur)) != NULL) { show_progress(); memcpy(&dir, key, sizeof(dir)); if ( lastdir == dir ) { if ( multi == 2 ) { tcbdbcurnext(cur); continue; } else { multi=1; } } else multi=0; value = tcbdbcurval(cur, &size);; if (value) { memcpy(&ent, value, sizeof(ent)); data = search_dbdata(dbp, &ent, sizeof(unsigned long long)); if (NULL == data) { printf("%ccheck_directory_structure : delete inode %llu present in dbdirent but not found in dbp.\n", BACKSPACE,ent); btdelete_curkey(dbdirent, &dir, sizeof(unsigned long long), &ent, sizeof(unsigned long long)); free(value); free(key); tcbdbcurdel(cur); goto recheck; } DBTfree(data); free(value); if ( multi == 1 ) { multi++; if ( dir > 1 ) { // Skip the root directory. // This is a directory, check if it is linked. hasparent=check_directory_has_parent(dir); if ( hasparent == 0 ) { printf("Directory with inode number %llu is orphaned, relink to lost+found\n", dir); btbin_write_dup(dbdirent, &lafinode, sizeof(unsigned long long), &dir, sizeof(unsigned long long)); } } } } lastdir=dir; free(key); tcbdbcurnext(cur); } tcbdbcurdel(cur); }
/* perform list command */ static int proclist(const char *path, TCCMP cmp, int omode, int max, bool pv, bool px, bool bk, const char *jstr, const char *bstr, const char *estr, const char *fmstr) { TCBDB *bdb = tcbdbnew(); if (!INVALIDHANDLE(g_dbgfd)) tcbdbsetdbgfd(bdb, g_dbgfd); if (cmp && !tcbdbsetcmpfunc(bdb, cmp, NULL)) printerr(bdb); if (!tcbdbsetcodecfunc(bdb, _tc_recencode, NULL, _tc_recdecode, NULL)) printerr(bdb); if (!tcbdbopen(bdb, path, BDBOREADER | omode)) { printerr(bdb); tcbdbdel(bdb); return 1; } bool err = false; if (bstr || fmstr) { TCLIST *keys = fmstr ? tcbdbfwmkeys2(bdb, fmstr, max) : tcbdbrange(bdb, bstr, strlen(bstr), true, estr, strlen(estr), true, max); int cnt = 0; for (int i = 0; i < tclistnum(keys); i++) { int ksiz; const char *kbuf = tclistval(keys, i, &ksiz); if (pv) { TCLIST *vals = tcbdbget4(bdb, kbuf, ksiz); if (vals) { for (int j = 0; j < tclistnum(vals); j++) { int vsiz; const char *vbuf = tclistval(vals, j, &vsiz); printdata(kbuf, ksiz, px); putchar('\t'); printdata(vbuf, vsiz, px); putchar('\n'); if (max >= 0 && ++cnt >= max) break; } tclistdel(vals); } } else { int num = tcbdbvnum(bdb, kbuf, ksiz); for (int j = 0; j < num; j++) { printdata(kbuf, ksiz, px); putchar('\n'); if (max >= 0 && ++cnt >= max) break; } } if (max >= 0 && cnt >= max) break; } tclistdel(keys); } else { BDBCUR *cur = tcbdbcurnew(bdb); if (bk) { if (jstr) { if (!tcbdbcurjumpback(cur, jstr, strlen(jstr)) && tcbdbecode(bdb) != TCENOREC) { printerr(bdb); err = true; } } else { if (!tcbdbcurlast(cur) && tcbdbecode(bdb) != TCENOREC) { printerr(bdb); err = true; } } } else { if (jstr) { if (!tcbdbcurjump(cur, jstr, strlen(jstr)) && tcbdbecode(bdb) != TCENOREC) { printerr(bdb); err = true; } } else { if (!tcbdbcurfirst(cur) && tcbdbecode(bdb) != TCENOREC) { printerr(bdb); err = true; } } } TCXSTR *key = tcxstrnew(); TCXSTR *val = tcxstrnew(); int cnt = 0; while (tcbdbcurrec(cur, key, val)) { printdata(tcxstrptr(key), tcxstrsize(key), px); if (pv) { putchar('\t'); printdata(tcxstrptr(val), tcxstrsize(val), px); } putchar('\n'); if (bk) { if (!tcbdbcurprev(cur) && tcbdbecode(bdb) != TCENOREC) { printerr(bdb); err = true; } } else { if (!tcbdbcurnext(cur) && tcbdbecode(bdb) != TCENOREC) { printerr(bdb); err = true; } } if (max >= 0 && ++cnt >= max) break; } tcxstrdel(val); tcxstrdel(key); tcbdbcurdel(cur); } if (!tcbdbclose(bdb)) { if (!err) printerr(bdb); err = true; } tcbdbdel(bdb); return err ? 1 : 0; }
static int control(ErlDrvData handle, unsigned int command, char* buf, int count, char** res, int res_size) { tcbdb_drv_t *driver = (tcbdb_drv_t*)handle; TCBDB *bdb = driver->bdb; int index = 1, tp, sz, version; char key[MAX_KEY_SIZE], value[MAX_VALUE_SIZE]; long key_size, value_size; long long long_tmp; bool rs; const char *value_tmp = NULL; ei_x_buff x; ei_x_new_with_version(&x); if (bdb == NULL && command != OPEN) return ei_error(&x, "database_not_opened", res, res_size); ei_decode_version(buf, &index, &version); switch (command) { case OPEN: // open(Filepath::string()) if (bdb == NULL) { ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_STRING_EXT) return ei_error(&x, "invalid_argument", res, res_size); TCBDB *bdb = tcbdbnew(); tcbdbsetmutex(bdb); tcbdbsetcache(bdb, 104800, 51200); tcbdbsetxmsiz(bdb, 1048576); tcbdbtune(bdb, 0, 0, 0, 7, -1, BDBTLARGE); char *file = driver_alloc(sz + 1); ei_decode_string(buf, &index, file); rs = tcbdbopen(bdb, file, BDBOWRITER | BDBOCREAT); driver_free(file); if (!rs) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); driver->bdb = bdb; ei_x_encode_atom(&x, "ok"); } else return ei_error(&x, "database already opened", res, res_size); break; case CLOSE: tcbdbclose(bdb); tcbdbdel(bdb); driver->bdb = NULL; ei_x_encode_atom(&x, "ok"); break; case PUT: case PUTDUP: case PUTCAT: case PUTKEEP: // put({Key::binary(), Value::binary()}) ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_SMALL_TUPLE_EXT || sz != 2) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_tuple_header(buf, &index, &sz); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT) return ei_error(&x, "invalid_argument", res, res_size); if (sz <= MAX_VALUE_SIZE) { ei_decode_binary(buf, &index, &value[0], &value_size); switch (command) { case PUT: rs = tcbdbput(bdb, &key[0], key_size, &value[0], value_size); break; case PUTDUP: rs = tcbdbputdup(bdb, &key[0], key_size, &value[0], value_size); break; case PUTCAT: rs = tcbdbputcat(bdb, &key[0], key_size, &value[0], value_size); break; default: rs = tcbdbputkeep(bdb, &key[0], key_size, &value[0], value_size); } } else { void *p = driver_alloc(sz); if (p) { ei_decode_binary(buf, &index, p, &value_size); switch (command) { case PUT: rs = tcbdbput(bdb, &key[0], key_size, p, value_size); break; case PUTDUP: rs = tcbdbputdup(bdb, &key[0], key_size, p, value_size); break; case PUTCAT: rs = tcbdbputcat(bdb, &key[0], key_size, p, value_size); break; default: rs = tcbdbputkeep(bdb, &key[0], key_size, p, value_size); } driver_free(p); } else return ei_error(&x, "too long value", res, res_size); }; if (!rs) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); ei_x_encode_atom(&x, "ok"); break; case GET: // get(Key::binary()) -> {ok, Value} | {error, not_found} ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); value_tmp = tcbdbget3(bdb, &key[0], key_size, &sz); ei_x_encode_tuple_header(&x, 2); if (value_tmp != NULL) { ei_x_encode_atom(&x, "ok"); ei_x_encode_binary(&x, value_tmp, sz); } else { ei_x_encode_atom(&x, "error"); ei_x_encode_atom(&x, "not_found"); } break; case GETDUP: // get(Key::binary()) -> {ok, Values} ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); TCLIST *vals = tcbdbget4(bdb, key, key_size); if (vals) { ei_x_encode_tuple_header(&x, 2); ei_x_encode_atom(&x, "ok"); int j; for (j=0; j<tclistnum(vals); j++) { value_tmp = tclistval(vals, j, &sz); ei_x_encode_list_header(&x, 1); ei_x_encode_binary(&x, value_tmp, sz); } tclistdel(vals); ei_x_encode_empty_list(&x); } else { ei_x_encode_tuple_header(&x, 2); ei_x_encode_atom(&x, "ok"); ei_x_encode_empty_list(&x); } break; case REMOVE: // remove(Keys::list()) // remove(Key::binary()) // remove({Key::binary(), Value::binary()}) ei_get_type(buf, &index, &tp, &sz); if (tp == ERL_LIST_EXT) { int count, j; ei_decode_list_header(buf, &index, &count); for (j=0; j<count; j++) { ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); if (!tcbdbout3(bdb, &key[0], key_size)) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); } ei_x_encode_atom(&x, "ok"); } else if (tp == ERL_BINARY_EXT && sz <= MAX_KEY_SIZE) { ei_decode_binary(buf, &index, &key[0], &key_size); tcbdbout3(bdb, &key[0], key_size); ei_x_encode_atom(&x, "ok"); } else if (tp == ERL_SMALL_TUPLE_EXT && sz == 2) { ei_decode_tuple_header(buf, &index, &sz); // get key ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &key[0], &key_size); // get value ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_VALUE_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &value[0], &value_size); // remove by key&value BDBCUR *cur = tcbdbcurnew(bdb); if (!tcbdbcurjump(cur, &key[0], key_size)) return ei_error(&x, "record_not_found", res, res_size); bool removed = false, not_found = false; while (!removed && !not_found) { int cur_key_size, cur_val_size; const void *curkey = tcbdbcurkey3(cur, &cur_key_size); if (cur_key_size == key_size && memcmp(curkey, key, key_size) == 0) { const void *curval = tcbdbcurval3(cur, &cur_val_size); if (cur_val_size == value_size && memcmp(curval, value, value_size) == 0) { tcbdbcurout(cur); removed = true; } else if (!tcbdbcurnext(cur)) not_found = true; } else not_found = true; } if (not_found) ei_x_encode_atom(&x, "not_found"); else ei_x_encode_atom(&x, "ok"); } else return ei_error(&x, "invalid_argument", res, res_size); break; case RANGE: /* * range({Prefix::binary(), limit:integer()}) * range({StartKey::binary(), BeginInclusion::boolean(), EndKey::binary(), EndInclusion::binary(), limit:integer()}) */ ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_SMALL_TUPLE_EXT || sz < 2) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_tuple_header(buf, &index, &sz); ei_get_type(buf, &index, &tp, &sz); if (tp == ERL_BINARY_EXT && sz <= MAX_KEY_SIZE) { char keys[MAX_KEY_SIZE], keyf[MAX_KEY_SIZE]; long keys_size, keyf_size; int keys_inc, keyf_inc; long max = -1; TCLIST *range; ei_decode_binary(buf, &index, &keys[0], &keys_size); ei_get_type(buf, &index, &tp, &sz); if (tp == ERL_ATOM_EXT) { // range ei_decode_boolean(buf, &index, &keys_inc); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_BINARY_EXT || sz > MAX_KEY_SIZE) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_binary(buf, &index, &keyf[0], &keyf_size); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_ATOM_EXT) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_boolean(buf, &index, &keyf_inc); ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_INTEGER_EXT) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_long(buf, &index, &max); range = tcbdbrange(bdb, &keys[0], keys_size, keys_inc == 1, &keyf[0], keyf_size, keyf_inc == 1, max); } else if (tp == ERL_INTEGER_EXT) { // prefix ei_get_type(buf, &index, &tp, &sz); if (tp != ERL_INTEGER_EXT) return ei_error(&x, "invalid_argument", res, res_size); ei_decode_long(buf, &index, &max); range = tcbdbfwmkeys(bdb, &keys[0], keys_size, max); } else return ei_error(&x, "invalid_argument", res, res_size); const char *key; int key_size, value_size; int idx, cnt = 0, rcount = tclistnum(range); ei_x_encode_tuple_header(&x, 2); ei_x_encode_atom(&x, "ok"); BDBCUR *cur = tcbdbcurnew(bdb); for (idx=0; idx<rcount; idx++) { key = tclistval(range, idx, &key_size); TCLIST *vals = tcbdbget4(bdb, key, key_size); if (vals) { int j; for (j=0; j<tclistnum(vals); j++) { ei_x_encode_list_header(&x, 1); value_tmp = tclistval(vals, j, &value_size); ei_x_encode_binary(&x, value_tmp, value_size); if (max >= 0 && ++cnt >= max) break; } tclistdel(vals); } idx++; } tcbdbcurdel(cur); tclistdel(range); ei_x_encode_empty_list(&x); } else return ei_error(&x, "invalid_argument", res, res_size); break; case SYNC: // sync() if (!tcbdbsync(bdb)) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); ei_x_encode_atom(&x, "ok"); break; case INFO: // info() ei_x_encode_tuple_header(&x, 3); ei_x_encode_atom(&x, "ok"); long_tmp = tcbdbrnum(bdb); ei_x_encode_longlong(&x, long_tmp); long_tmp = tcbdbfsiz(bdb); ei_x_encode_longlong(&x, long_tmp); break; case ITERATE: // Read(none) -> {ok, Key} | {error, not_found} // Read(Key::binary()) -> {ok, Key} | {error, not_found} ei_get_type(buf, &index, &tp, &sz); BDBCUR *cur = tcbdbcurnew(bdb); if (tp == ERL_BINARY_EXT && sz <= MAX_KEY_SIZE) { ei_decode_binary(buf, &index, &key[0], &key_size); rs = tcbdbcurjump(cur, &key[0], key_size) && tcbdbcurnext(cur); } else rs = tcbdbcurfirst(cur); if (rs) { int key_size; const char *key = tcbdbcurkey3(cur, &key_size); ei_x_encode_tuple_header(&x, 2); ei_x_encode_atom(&x, "ok"); ei_x_encode_binary(&x, key, key_size); tcbdbcurdel(cur); } else { tcbdbcurdel(cur); return ei_error(&x, "not_found", res, res_size); } break; case VANISH: // vanish() -> ok if (!tcbdbvanish(bdb)) return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); ei_x_encode_atom(&x, "ok"); break; case BACKUP: // backup(path::string()) -> ok | {error, Reason} ei_get_type(buf, &index, &tp, &sz); if (tp == ERL_STRING_EXT) { char *file = driver_alloc(sz + 1); ei_decode_string(buf, &index, file); if (tcbdbcopy(driver->bdb, file)) ei_x_encode_atom(&x, "ok"); else return ei_error(&x, tcbdberrmsg(tcbdbecode(bdb)), res, res_size); } else return ei_error(&x, "invalid_argument", res, res_size); break; default: return ei_error(&x, "invalid_command", res, res_size); } if (res_size < x.index) (*res) = (char *)driver_alloc(x.index); int n = x.index; memcpy(*res, x.buff, x.index); ei_x_free(&x); return n; };
/* next */ JNIEXPORT jboolean JNICALL Java_tokyocabinet_BDBCUR_next (JNIEnv *env, jobject self){ BDBCUR *cur = (BDBCUR *)(intptr_t)(*env)->GetLongField(env, self, bdbcur_fid_ptr); return tcbdbcurnext(cur); }