You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
6.3 KiB

  1. #include <assert.h>
  2. #include <db.h>
  3. #include <errno.h>
  4. #include <db_cxx.h>
  5. #define do_maybe_error(errno)
  6. Db::Db(DbEnv *env, u_int32_t flags)
  7. : the_Env(env)
  8. {
  9. the_db = 0;
  10. is_private_env = (the_Env == 0);
  11. DB *tmp_db;
  12. int ret = db_create(&tmp_db, the_Env->get_DB_ENV(), flags & ~(DB_CXX_NO_EXCEPTIONS));
  13. if (ret!=0) {
  14. the_Env->maybe_throw_error(ret);
  15. // Otherwise cannot do much
  16. return;
  17. }
  18. the_db = tmp_db;
  19. tmp_db->api_internal = this;
  20. if (is_private_env) {
  21. the_Env = new DbEnv(tmp_db->dbenv, flags & DB_CXX_NO_EXCEPTIONS);
  22. }
  23. }
  24. Db::~Db() {
  25. if (the_db) {
  26. close(0); // the user should have called close, but we do it here if not done.
  27. assert(the_db==0);
  28. }
  29. if (is_private_env && the_Env) {
  30. the_Env->close(0);
  31. delete the_Env;
  32. }
  33. }
  34. int Db::set_flags(u_int32_t flags) {
  35. int ret = the_db->set_flags(the_db, flags);
  36. return the_Env->maybe_throw_error(ret);
  37. }
  38. int Db::get_flags(u_int32_t *flags) {
  39. int ret = the_db->get_flags(the_db, flags);
  40. return the_Env->maybe_throw_error(ret);
  41. }
  42. int Db::close (u_int32_t flags) {
  43. if (!the_db) {
  44. return the_Env->maybe_throw_error(EINVAL);
  45. }
  46. the_db->api_internal = 0;
  47. int ret = the_db->close(the_db, flags);
  48. the_db = 0;
  49. int no_exceptions = the_Env->do_no_exceptions; // Get this out before possibly deleting the env
  50. if (is_private_env) {
  51. // The env was closed by the_db->close, we have to tell the DbEnv that the DB_ENV is gone, and delete it.
  52. the_Env->the_env = 0;
  53. delete the_Env;
  54. the_Env=0;
  55. }
  56. // Do we need to clean up "private environments"?
  57. // What about cursors? They should be cleaned up already, but who did it?
  58. // This maybe_throw must be the static one because the env is gone.
  59. return DbEnv::maybe_throw_error(ret, NULL, no_exceptions);
  60. }
  61. int Db::open(DbTxn *txn, const char *filename, const char *subname, DBTYPE typ, u_int32_t flags, int mode) {
  62. int ret = the_db->open(the_db, txn->get_DB_TXN(), filename, subname, typ, flags, mode);
  63. return the_Env->maybe_throw_error(ret);
  64. }
  65. int Db::del(DbTxn *txn, Dbt *key, u_int32_t flags) {
  66. int ret = the_db->del(the_db, txn->get_DB_TXN(), key->get_DBT(), flags);
  67. return the_Env->maybe_throw_error(ret);
  68. }
  69. int Db::get(DbTxn *txn, Dbt *key, Dbt *data, u_int32_t flags) {
  70. int ret = the_db->get(the_db, txn->get_DB_TXN(), key->get_DBT(), data->get_DBT(), flags);
  71. return the_Env->maybe_throw_error(ret);
  72. }
  73. int Db::pget(DbTxn *txn, Dbt *key, Dbt *pkey, Dbt *data, u_int32_t flags) {
  74. int ret = the_db->pget(the_db, txn->get_DB_TXN(), key->get_DBT(), pkey->get_DBT(), data->get_DBT(), flags);
  75. return the_Env->maybe_throw_error(ret);
  76. }
  77. int Db::put(DbTxn *txn, Dbt *key, Dbt *data, u_int32_t flags) {
  78. int ret = the_db->put(the_db, txn->get_DB_TXN(), key->get_DBT(), data->get_DBT(), flags);
  79. return the_Env->maybe_throw_error(ret);
  80. }
  81. int Db::cursor(DbTxn *txn, Dbc **cursorp, u_int32_t flags) {
  82. int ret = the_db->cursor(the_db, txn->get_DB_TXN(), (DBC**)cursorp, flags);
  83. return the_Env->maybe_throw_error(ret);
  84. }
  85. int Db::set_pagesize(u_int32_t size) {
  86. int ret = the_db->set_pagesize(the_db, size);
  87. return the_Env->maybe_throw_error(ret);
  88. }
  89. int Db::remove(const char *file, const char *database, u_int32_t flags) {
  90. int ret = the_db->remove(the_db, file, database, flags);
  91. the_db = 0;
  92. return the_Env->maybe_throw_error(ret);
  93. }
  94. extern "C" int toku_bt_compare_callback_c(DB *db_c, const DBT *a, const DBT *b) {
  95. Db *db_cxx=Db::get_Db(db_c);
  96. return db_cxx->bt_compare_callback_cxx(db_cxx, Dbt::get_const_Dbt(a), Dbt::get_const_Dbt(b));
  97. }
  98. int Db::set_bt_compare(int (*bt_compare_callback)(Db *, const Dbt *, const Dbt *)) {
  99. bt_compare_callback_cxx = bt_compare_callback;
  100. int ret = the_db->set_bt_compare(the_db, toku_bt_compare_callback_c);
  101. return the_Env->maybe_throw_error(ret);
  102. }
  103. int Db::set_bt_compare(bt_compare_fcn_type bt_compare_fcn) {
  104. int ret = the_db->set_bt_compare(the_db, bt_compare_fcn);
  105. return the_Env->maybe_throw_error(ret);
  106. }
  107. int Db::set_dup_compare(dup_compare_fcn_type dup_compare_fcn) {
  108. int ret = the_db->set_dup_compare(the_db, dup_compare_fcn);
  109. return the_Env->maybe_throw_error(ret);
  110. }
  111. int Db::fd(int *fdp) {
  112. int ret = the_db->fd(the_db, fdp);
  113. return the_Env->maybe_throw_error(ret);
  114. }
  115. extern "C" int toku_dup_compare_callback_c(DB *db_c, const DBT *a, const DBT *b) {
  116. Db *db_cxx=Db::get_Db(db_c);
  117. return db_cxx->dup_compare_callback_cxx(db_cxx, Dbt::get_const_Dbt(a), Dbt::get_const_Dbt(b));
  118. }
  119. int Db::set_dup_compare(int (*dup_compare_callback)(Db *, const Dbt *, const Dbt *)) {
  120. dup_compare_callback_cxx = dup_compare_callback;
  121. int ret = the_db->set_dup_compare(the_db, toku_dup_compare_callback_c);
  122. return the_Env->maybe_throw_error(ret);
  123. }
  124. // Q: How to convert callback types in the most simple way?
  125. // A: (Bradley) I see three ways to do this: The issue is that we have a C++ callback function, and we want to pass it to a C function.
  126. // The fastest way is wrong: You cannot just pass the C++ function pointer since you cannot mix function pointers to C and C++.
  127. // The "right" way is to declare an "extern C" function and do all the conversions. Create a Dbt from a DBT, and then call the C function. For returned data we would have do something too. But it turns out that DBT and Dbt pointers are interchangable so that leads to
  128. // The "fast" way. Declare an "extern C" function, and then use Dbt::get_const_Dbt() to do the conversion quickly.
  129. extern "C" int toku_associate_callback_c (DB*db_c, const DBT *k, const DBT *d, DBT *result) {
  130. assert(db_c!=0);
  131. Db *db_cxx=Db::get_Db(db_c);
  132. assert(db_cxx);
  133. return (*db_cxx->associate_callback_cxx)(db_cxx, Dbt::get_const_Dbt(k), Dbt::get_const_Dbt(d), Dbt::get_Dbt(result));
  134. }
  135. int Db::associate(DbTxn *txnid, Db *secondary, int (*callback)(Db *secondary, const Dbt *key, const Dbt *data, Dbt *result), u_int32_t flags) {
  136. // secondary->set_associate_callback(callback);
  137. secondary->associate_callback_cxx = callback;
  138. int ret = the_db->associate(the_db, txnid->get_DB_TXN(), secondary->get_DB(), toku_associate_callback_c, flags);
  139. return the_Env->maybe_throw_error(ret);
  140. }
  141. void Db::set_errpfx(const char *errpfx) {
  142. the_Env->set_errpfx(errpfx);
  143. }
  144. void Db::set_error_stream(std::ostream *new_error_stream) {
  145. the_Env->set_error_stream(new_error_stream);
  146. }