nhachicha / SnappyDB

A key-value database for Android
1.78k stars 220 forks source link

tow open db with different name #74

Open ayalma opened 8 years ago

ayalma commented 8 years ago

why i can't create tow instance of Snappy db with different name at same time.

andrewborba10 commented 8 years ago

I believe there is a bug that prevents multiple databases from being opened in the same process. I'm surprised this issue hasn't been addressed: https://github.com/nhachicha/SnappyDB/issues/26

It looks like the bug was root caused, but the fix hasn't been released, unfortunately. We'll be moving away from this library given the poor support in light of such a critical issue.

ayalma commented 8 years ago

thank you so much . i aggregate my dbs to one single db. :+1:

gckjdev commented 8 years ago

would like to address the same issue, hopefully it can be fixed in future release?

do you have any plan to fix this?

jacek-marchwicki commented 8 years ago

@nhachicha The change snappydb implementation to support more databases isn't so hard. I implemented similar key value DB with leveldb but only for bytes[] (we don't need to store other types of data to db).

please look on implementation: LevelDB.java and leveldb_jni.cc

In my case LevelDB isn't singleton, and it has private long nativeDB; field that is used only by jni to store pointer to structure:

struct DatabaseNative {
    leveldb::DB* db;
};

when you call java nativeOpen(), jni jni_database_open method will be invoked:

void jni_database_open(JNIEnv *env, jobject thiz, jstring dbpath) {
    struct DatabaseNative *native = (struct DatabaseNative *)malloc(sizeof(struct DatabaseNative)); // allocate structure
    leveldb::DB::Open(options, path, &native->db); // open database and save it to structure
    jclass database_clazz = env->FindClass("com/appunite/leveldb/LevelDB"); // get class
    database_clazz_field_native = env->GetFieldID(database_clazz, "nativeDB", "J"); //get java field
    env->SetLongField(thiz, database_clazz_field_native, (jlong) native_db); // store structure to that field
}

and now in each operation you can get this structure:

void jni_database_put_bytes(JNIEnv *env, jobject thiz, jbyteArray jkey, jbyteArray jvalue) {
    jclass database_clazz = env->FindClass("com/appunite/leveldb/LevelDB"); // get class
    database_clazz_field_native = env->GetFieldID(database_clazz, "nativeDB", "J"); //get java field
    struct DatabaseNative *native = (struct DatabaseNative * )env->GetLongField(thiz, database_clazz_field_native); // get struct from java field

   native->db->Put(leveldb::WriteOptions(), key, value); // write to DB
}

The implementation is pretty straightforward. Simillar solution I wrote quite while ago in https://github.com/appunite/AndroidFFmpeg

btw: usually you don't have to use multiple databases opened because it's necessary. You can always use prefix for index:

database.put("post:" + postId, "your post");
database.put("comment:" + commentId, "your comment");
String post1 = database.get("post:" + "1");

and query for all:

KeysIterator posts = database.findKeysIterator("post:");
while (key.startWith("post:")) {
   // read your post
}

look on KeyValueSnappy.getKeys()