/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2000, 2012 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ /* * Do some regression tests for constructors. * Run normally (without arguments) it is a simple regression test. * Run with a numeric argument, it repeats the regression a number * of times, to try to determine if there are memory leaks. */ #include #include #include #include #include #ifndef _MSC_VER #include #endif #include #include using namespace std; #define ERR(a) \ do { \ cout << "FAIL: " << (a) << "\n"; sysexit(1); \ } while (0) #define ERR2(a1,a2) \ do { \ cout << "FAIL: " << (a1) << ": " << (a2) << "\n"; sysexit(1); \ } while (0) #define ERR3(a1,a2,a3) \ do { \ cout << "FAIL: " << (a1) << ": " << (a2) << ": " << (a3) << "\n"; sysexit(1); \ } while (0) #define CHK(a) \ do { \ int _ret; \ if ((_ret = (a)) != 0) { \ ERR3("DB function " #a " has bad return", _ret, DbEnv::strerror(_ret)); \ } \ } while (0) #ifdef VERBOSE #define DEBUGOUT(a) cout << a << "\n" #else #define DEBUGOUT(a) #endif #define CONSTRUCT01_DBNAME "construct01.db" #define CONSTRUCT01_DBDIR "." #define CONSTRUCT01_DBFULLPATH (CONSTRUCT01_DBDIR "/" CONSTRUCT01_DBNAME) int itemcount; // count the number of items in the database // A good place to put a breakpoint... // void sysexit(int status) { exit(status); } void check_file_removed(const char *name, int fatal) { unlink(name); #if 0 if (access(name, 0) == 0) { if (fatal) cout << "FAIL: "; cout << "File \"" << name << "\" still exists after run\n"; if (fatal) sysexit(1); } #endif } // Check that key/data for 0 - count-1 are already present, // and write a key/data for count. The key and data are // both "0123...N" where N == count-1. // // For some reason on Windows, we need to open using the full pathname // of the file when there is no environment, thus the 'has_env' // variable. // void rundb(Db *db, int count, int has_env) { const char *name; if (has_env) name = CONSTRUCT01_DBNAME; else name = CONSTRUCT01_DBFULLPATH; db->set_error_stream(&cerr); // We don't really care about the pagesize, but we do want // to make sure adjusting Db specific variables works before // opening the db. // CHK(db->set_pagesize(1024)); CHK(db->open(NULL, name, NULL, DB_BTREE, count ? 0 : DB_CREATE, 0664)); // The bit map of keys we've seen long bitmap = 0; // The bit map of keys we expect to see long expected = (1 << (count+1)) - 1; char outbuf[10]; int i; for (i=0; iput(0, &key, &data, DB_NOOVERWRITE)); // Acquire a cursor for the table. Dbc *dbcp; CHK(db->cursor(NULL, &dbcp, 0)); // Walk through the table, checking Dbt readkey; Dbt readdata; while (dbcp->get(&readkey, &readdata, DB_NEXT) == 0) { char *key_string = (char *)readkey.get_data(); char *data_string = (char *)readdata.get_data(); DEBUGOUT("Got: " << key_string << ": " << data_string); int len = strlen(key_string); long bit = (1 << len); if (len > count) { ERR("reread length is bad"); } else if (strcmp(data_string, key_string) != 0) { ERR("key/data don't match"); } else if ((bitmap & bit) != 0) { ERR("key already seen"); } else if ((expected & bit) == 0) { ERR("key was not expected"); } else { bitmap |= bit; expected &= ~(bit); for (i=0; iclose()); CHK(db->close(0)); } void t1(int except_flag) { cout << " Running test 1:\n"; Db db(0, except_flag); rundb(&db, itemcount++, 0); cout << " finished.\n"; } void t2(int except_flag) { cout << " Running test 2:\n"; Db db(0, except_flag); rundb(&db, itemcount++, 0); cout << " finished.\n"; } void t3(int except_flag) { cout << " Running test 3:\n"; Db db(0, except_flag); rundb(&db, itemcount++, 0); cout << " finished.\n"; } void t4(int except_flag) { cout << " Running test 4:\n"; DbEnv env(except_flag); CHK(env.open(CONSTRUCT01_DBDIR, DB_CREATE | DB_INIT_MPOOL, 0)); Db db(&env, 0); CHK(db.close(0)); CHK(env.close(0)); cout << " finished.\n"; } void t5(int except_flag) { cout << " Running test 5:\n"; DbEnv env(except_flag); CHK(env.open(CONSTRUCT01_DBDIR, DB_CREATE | DB_INIT_MPOOL, 0)); Db db(&env, 0); rundb(&db, itemcount++, 1); // Note we cannot reuse the old Db! Db anotherdb(&env, 0); anotherdb.set_errpfx("test5"); rundb(&anotherdb, itemcount++, 1); CHK(env.close(0)); cout << " finished.\n"; } void t6(int except_flag) { cout << " Running test 6:\n"; /* From user [#2939] */ int err; DbEnv* penv = new DbEnv(DB_CXX_NO_EXCEPTIONS); penv->set_cachesize(0, 32 * 1024, 0); penv->open(CONSTRUCT01_DBDIR, DB_CREATE | DB_PRIVATE | DB_INIT_MPOOL, 0); //LEAK: remove this block and leak disappears Db* pdb = new Db(penv,0); if ((err = pdb->close(0)) != 0) { fprintf(stderr, "Error closing Db: %s\n", db_strerror(err)); } delete pdb; //LEAK: remove this block and leak disappears if ((err = penv->close(0)) != 0) { fprintf(stderr, "Error closing DbEnv: %s\n", db_strerror(err)); } delete penv; cout << " finished.\n"; } // remove any existing environment or database void removeall() { { DbEnv tmpenv(DB_CXX_NO_EXCEPTIONS); (void)tmpenv.remove(CONSTRUCT01_DBDIR, DB_FORCE); } check_file_removed(CONSTRUCT01_DBFULLPATH, 1); for (int i=0; i<8; i++) { char buf[20]; sprintf(buf, "__db.00%d", i); check_file_removed(buf, 1); } } int doall(int except_flag) { itemcount = 0; try { // before and after the run, removing any // old environment/database. // removeall(); t1(except_flag); t2(except_flag); t3(except_flag); t4(except_flag); t5(except_flag); t6(except_flag); removeall(); return 0; } catch (DbException &dbe) { ERR2("EXCEPTION RECEIVED", dbe.what()); } return 1; } int main(int argc, char *argv[]) { int iterations = 1; if (argc > 1) { iterations = atoi(argv[1]); if (iterations < 0) { ERR("Usage: construct01 count"); } } for (int i=0; i