8 #include <sys/syscall.h>
9 #include <openssl/sha.h>
12 #include <leveldb/db.h>
21 #include <mabain/db.h>
25 leveldb::DB *db = NULL;
27 kyotocabinet::HashDB *db = NULL;
33 mabain::DB *db = NULL;
36 #define ONE_MILLION 1000000
38 static const char *db_dir = "/var/tmp/db_test/";
39 static int num_kv = 1 * ONE_MILLION;
40 static int n_reader = 7;
41 static int key_type = 0;
42 static bool sync_on_write = false;
43 static unsigned long long memcap = 1024ULL*1024*1024;
45 static void get_sha256_str(int key, char *sha256_str)
47 unsigned char hash[SHA256_DIGEST_LENGTH];
50 SHA256_Update(&sha256, (unsigned char*)&key, 4);
51 SHA256_Final(hash, &sha256);
53 for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
55 sprintf(sha256_str + (i * 2), "%02x", hash[i]);
60 static void get_sha1_str(int key, char *sha1_str)
62 unsigned char hash[SHA_DIGEST_LENGTH];
65 SHA1_Update(&sha1, (unsigned char*)&key, 4);
66 SHA1_Final(hash, &sha1);
68 for(i = 0; i < SHA_DIGEST_LENGTH; i++)
70 sprintf(sha1_str + (i * 2), "%02x", hash[i]);
75 static void print_cpu_info()
77 std::ifstream cpu_info("/proc/cpuinfo", std::fstream::in);
78 if(!cpu_info.is_open()) {
83 std::string model_name;
84 std::string vendor_id;
87 while (std::getline(cpu_info, line))
89 if(line.find("model name") != std::string::npos)
94 else if(line.find("vendor_id") != std::string::npos)
98 else if(line.find("cpu MHz") != std::string::npos)
105 std::cout << "number of CPUs\t: " << n_processor << "\n";
106 std::cout << vendor_id << "\n";
107 std::cout << model_name << "\n";
108 std::cout << cpu_freq << "\n";
111 static void InitTestDir()
115 cmd = std::string("mkdir -p ") + db_dir;
116 if(system(cmd.c_str()) != 0) {
120 std::cout << "===== using leveldb for testing\n";
121 std::string db_dir_tmp = std::string(db_dir) + "/leveldb/";
123 std::cout << "===== using kyotocabinet for testing\n";
124 std::string db_dir_tmp = std::string(db_dir) + "/kyotocabinet/";
126 std::cout << "===== using lmdb for testing\n";
127 std::string db_dir_tmp = std::string(db_dir) + "/lmdb/";
129 std::cout << "===== using mabain for testing\n";
130 std::string db_dir_tmp = std::string(db_dir) + "/mabain/";
132 cmd = std::string("mkdir -p ") + db_dir_tmp;
133 if(system(cmd.c_str()) != 0) {
135 cmd = std::string("rm -rf ") + db_dir_tmp + "*";
136 if(system(cmd.c_str()) != 0) {
141 static void InitDB(bool writer_mode = true)
144 std::string db_dir_tmp = std::string(db_dir) + "/leveldb/";
145 leveldb::Options options;
146 options.create_if_missing = true;
147 leveldb::Status status = leveldb::DB::Open(options, db_dir_tmp, &db);
150 std::string db_file = std::string(db_dir) + "/kyotocabinet/dbbench_hashDB.kch";
151 db = new kyotocabinet::HashDB();
152 int open_options = kyotocabinet::PolyDB::OWRITER |
153 kyotocabinet::PolyDB::OCREATE;
154 db->tune_map(memcap);
155 if(!db->open(db_file, open_options)) {
156 fprintf(stderr, "open error: %s\n", db->error().name());
159 std::string db_dir_tmp = std::string(db_dir) + "/lmdb";
160 mdb_env_create(&env);
161 mdb_env_set_mapsize(env, memcap);
162 mdb_env_open(env, db_dir_tmp.c_str(), 0, 0664);
163 mdb_txn_begin(env, NULL, 0, &txn);
164 mdb_open(txn, NULL, 0, &db);
167 std::string db_dir_tmp = std::string(db_dir) + "/mabain/";
168 int options = mabain::CONSTS::WriterOptions() | mabain::CONSTS::ASYNC_WRITER_MODE;
170 options |= mabain::CONSTS::SYNC_ON_WRITE;
173 options = mabain::CONSTS::ReaderOptions();
174 db = new mabain::DB(db_dir_tmp.c_str(), options, (unsigned long long)(0.6666667*memcap),
175 (unsigned long long)(0.3333333*memcap));
176 assert(db->is_open());
180 static void Add(int n)
185 gettimeofday(&start,NULL);
188 mdb_txn_begin(env, NULL, 0, &txn);
190 for(int i = 0; i < n; i++) {
191 std::string key, val;
193 key = std::to_string(i);
194 val = std::to_string(i);
199 get_sha256_str(i, kv);
206 leveldb::WriteOptions opts = leveldb::WriteOptions();
207 opts.sync = sync_on_write;
208 db->Put(opts, key, val);
210 db->set(key.c_str(), val.c_str());
212 MDB_val lmdb_key, lmdb_val;
213 lmdb_key.mv_size = key.size();
214 lmdb_key.mv_data = (void*) key.data();
215 lmdb_val.mv_size = val.size();
216 lmdb_val.mv_data = (void*) val.data();
219 mdb_txn_begin(env, NULL, 0, &txn);
220 mdb_cursor_open(txn, db, &mc);
221 mdb_cursor_put(mc, &lmdb_key, &lmdb_val, 0);
222 mdb_cursor_close(mc);
225 mdb_cursor_open(txn, db, &mc);
226 mdb_cursor_put(mc, &lmdb_key, &lmdb_val, 0);
227 mdb_cursor_close(mc);
233 if((i+1) % ONE_MILLION == 0) {
234 std::cout << "inserted: " << (i+1) << " key-value pairs\n";
242 gettimeofday(&stop,NULL);
244 uint64_t timediff = (stop.tv_sec - start.tv_sec)*1000000 + (stop.tv_usec - start.tv_usec);
245 std::cout << "===== " << timediff*1.0/n << " micro seconds per insertion\n";
248 static void Lookup(int n)
254 MDB_val lmdb_key, lmdb_value;
256 mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
257 mdb_cursor_open(txn, db, &cursor);
260 gettimeofday(&start,NULL);
261 for(int i = 0; i < n; i++) {
264 key = std::to_string(i);
269 get_sha256_str(i, kv);
276 leveldb::Status s = db->Get(leveldb::ReadOptions(), key, &value);
280 if(db->get(key, &value)) nfound++;
282 lmdb_key.mv_data = (void*) key.data();
283 lmdb_key.mv_size = key.size();
284 if(mdb_cursor_get(cursor, &lmdb_key, &lmdb_value, MDB_SET) == 0)
286 //std::cout<<key<<":"<<std::string((char*)lmdb_value.mv_data, lmdb_value.mv_size)<<"\n";
289 int rval = db->Find(key, mbd);
290 //std::cout<<key<<":"<<std::string((char*)mbd.buff, mbd.data_len)<<"\n";
291 if(rval == 0) nfound++;
294 if((i+1) % ONE_MILLION == 0) {
295 std::cout << "looked up: " << (i+1) << " keys\n";
300 mdb_cursor_close(cursor);
303 gettimeofday(&stop,NULL);
305 std::cout << "found " << nfound << " key-value pairs\n";
306 uint64_t timediff = (stop.tv_sec - start.tv_sec)*1000000 + (stop.tv_usec - start.tv_usec);
307 std::cout << "===== " << timediff*1.0/n << " micro seconds per lookup\n";
310 static void Delete(int n)
318 mdb_txn_begin(env, NULL, 0, &txn);
321 gettimeofday(&start,NULL);
322 for(int i = 0; i < n; i++) {
325 key = std::to_string(i);
330 get_sha256_str(i, kv);
335 leveldb::WriteOptions opts = leveldb::WriteOptions();
336 opts.sync = sync_on_write;
337 leveldb::Status s = db->Delete(opts, key);
341 if(db->remove(key)) nfound++;
344 lmdb_key.mv_size = key.size();
345 lmdb_key.mv_data = (void*) key.data();
347 mdb_txn_begin(env, NULL, 0, &txn);
348 if(mdb_del(txn, db, &lmdb_key, NULL) == 0) nfound++;
351 if(mdb_del(txn, db, &lmdb_key, NULL) == 0) nfound++;
354 int rval = db->Remove(key);
355 if(rval == 0) nfound++;
358 if((i+1) % ONE_MILLION == 0) {
359 std::cout << "deleted: " << (i+1) << " keys\n";
367 gettimeofday(&stop,NULL);
369 std::cout << "deleted " << nfound << " key-value pairs\n";
370 uint64_t timediff = (stop.tv_sec - start.tv_sec)*1000000 + (stop.tv_usec - start.tv_usec);
371 std::cout << "===== " << timediff*1.0/n << " micro seconds per deletion\n";
374 static void *Writer(void *arg)
376 int num = *((int *) arg);
378 int tid = static_cast<int>(syscall(SYS_gettid));
380 std::cout << "\n[writer : " << tid << "] started" << std::endl;
381 for(int i = 0; i < num; i++) {
382 std::string key, val;
384 key = std::to_string(i);
385 val = std::to_string(i);
390 get_sha256_str(i, kv);
397 leveldb::WriteOptions opts = leveldb::WriteOptions();
398 opts.sync = sync_on_write;
399 db->Put(opts, key, val);
401 db->Add(key.c_str(), key.length(), val.c_str(), val.length());
403 if((i+1) % (2*ONE_MILLION)== 0) {
404 std::cout<<"\nRC SCHEDULED " << std::endl;
405 db->CollectResource(1, 1);
410 if((i+1) % ONE_MILLION == 0) {
411 std::cout << "\nwriter inserted " << (i+1) << std::endl;
417 static void *Reader(void *arg)
419 int num = *((int *) arg);
421 int tid = static_cast<int>(syscall(SYS_gettid));
425 std::string db_dir_tmp = std::string(db_dir) + "/mabain/";
426 mabain::DB *db_r = new mabain::DB(db_dir_tmp.c_str(), mabain::CONSTS::ReaderOptions(),
427 (unsigned long long)(0.6666667*memcap),
428 (unsigned long long)(0.3333333*memcap));
429 assert(db_r->is_open());
432 std::cout << "\n[reader : " << tid << "] started" << std::endl;
438 key = std::to_string(i);
443 get_sha256_str(i, kv);
450 leveldb::Status s = db->Get(leveldb::ReadOptions(), key, &value);
456 int rval = db_r->Find(key, mbd);
458 value = std::string((const char *)mbd.buff, mbd.data_len);
463 if(key.compare(value) != 0) {
464 std::cout << "\nVALUE NOT MATCH for key:" << key << ":" << value << "\n";
469 if((i+1) % ONE_MILLION == 0) {
470 std::cout << "\n[reader : " << tid << "] found " << (i+1) << "\n";
481 static void ConcurrencyTest(int num, int n_r)
484 std::cout << "===== concurrency test ignored for kyotocabinet\n";
487 std::cout << "===== concurrency test ignored for lmdb\n";
494 gettimeofday(&start,NULL);
497 if(pthread_create(&wid, NULL, Writer, &num) != 0) {
498 std::cerr << "failed to create writer thread\n";
505 for(int i = 0; i < n_r; i++) {
506 if(pthread_create(&rid[i], NULL, Reader, &num) != 0) {
507 std::cerr << "failed to create writer thread\n";
512 for(int i = 0; i < n_r; i++) {
513 pthread_join(rid[i], NULL);
515 pthread_join(wid, NULL);
517 gettimeofday(&stop,NULL);
519 uint64_t timediff = (stop.tv_sec - start.tv_sec)*1000000 + (stop.tv_usec - start.tv_usec);
520 std::cout << "===== " << timediff*1.0/num_kv << " micro seconds per concurrent insertion/lookup\n";
523 static void DestroyDB()
542 static void RemoveDB()
544 std::string cmd = std::string("rm -rf ") + db_dir;
548 cmd += "kyotocabinet/*";
553 mabain::DB::ClearResources(std::string("/var/tmp/"));
556 if(system(cmd.c_str()) != 0) {
560 int main(int argc, char *argv[])
563 mabain::DB::SetLogFile("/var/tmp/mabain_test/mabain.log");
564 // mabain::DB::SetLogLevel(2);
566 for(int i = 1; i < argc; i++) {
567 if(strcmp(argv[i], "-n") == 0) {
568 if(++i >= argc) abort();
569 num_kv = atoi(argv[i]);
570 } else if(strcmp(argv[i], "-k") == 0) {
571 if(++i >= argc) abort();
572 if(strcmp(argv[i], "int") == 0) {
574 } else if(strcmp(argv[i], "sha1") == 0) {
576 } else if(strcmp(argv[i], "sha2") == 0) {
579 std::cerr << "invalid key type: " << argv[i] << "\n";
582 } else if(strcmp(argv[i], "-t") == 0) {
583 if(++i >= argc) abort();
584 n_reader = atoi(argv[i]);
585 } else if(strcmp(argv[i], "-d") == 0) {
586 if(++i >= argc) abort();
588 } else if(strcmp(argv[i], "-s") == 0) {
589 sync_on_write = true;
590 } else if(strcmp(argv[i], "-m") == 0) {
591 if(++i >= argc) abort();
592 memcap = atoi(argv[i]);
594 std::cerr << "invalid argument: " << argv[i] << "\n";
600 std::cout << "===== Disk sync is on\n";
602 std::cout << "===== Disk sync is off\n";
603 std::cout << "===== Memcap is " << memcap << "\n";
623 ConcurrencyTest(num_kv, n_reader);
627 mabain::DB::CloseLogFile();