1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1997,2008 Oracle. All rights reserved. 5 * 6 * $Id: cxx_env.cpp,v 12.48 2008/01/12 13:42:35 bostic Exp $ 7 */ 8 9#include "db_config.h" 10 11#include "db_int.h" 12 13#include "db_cxx.h" 14#include "dbinc/cxx_int.h" 15 16#include "dbinc/db_page.h" 17#include "dbinc/db_am.h" 18#include "dbinc/log.h" 19#include "dbinc_auto/common_ext.h" 20#include "dbinc_auto/log_ext.h" 21 22#ifdef HAVE_CXX_STDHEADERS 23using std::cerr; 24#endif 25 26// Helper macros for simple methods that pass through to the 27// underlying C method. They may return an error or raise an exception. 28// These macros expect that input _argspec is an argument 29// list element (e.g., "char *arg") and that _arglist is the arguments 30// that should be passed through to the C method (e.g., "(dbenv, arg)") 31// 32#define DBENV_METHOD_ERR(_name, _argspec, _arglist, _on_err) \ 33int DbEnv::_name _argspec \ 34{ \ 35 DB_ENV *dbenv = unwrap(this); \ 36 int ret; \ 37 \ 38 if ((ret = dbenv->_name _arglist) != 0) { \ 39 _on_err; \ 40 } \ 41 return (ret); \ 42} 43 44#define DBENV_METHOD(_name, _argspec, _arglist) \ 45 DBENV_METHOD_ERR(_name, _argspec, _arglist, \ 46 DB_ERROR(this, "DbEnv::" # _name, ret, error_policy())) 47 48#define DBENV_METHOD_QUIET(_name, _argspec, _arglist) \ 49int DbEnv::_name _argspec \ 50{ \ 51 DB_ENV *dbenv = unwrap(this); \ 52 \ 53 return (dbenv->_name _arglist); \ 54} 55 56#define DBENV_METHOD_VOID(_name, _argspec, _arglist) \ 57void DbEnv::_name _argspec \ 58{ \ 59 DB_ENV *dbenv = unwrap(this); \ 60 \ 61 dbenv->_name _arglist; \ 62} 63 64// The reason for a static variable is that some structures 65// (like Dbts) have no connection to any Db or DbEnv, so when 66// errors occur in their methods, we must have some reasonable 67// way to determine whether to throw or return errors. 68// 69// This variable is taken from flags whenever a DbEnv is constructed. 70// Normally there is only one DbEnv per program, and even if not, 71// there is typically a single policy of throwing or returning. 72// 73static int last_known_error_policy = ON_ERROR_UNKNOWN; 74 75// These 'glue' function are declared as extern "C" so they will 76// be compatible with picky compilers that do not allow mixing 77// of function pointers to 'C' functions with function pointers 78// to C++ functions. 79// 80extern "C" 81void _feedback_intercept_c(DB_ENV *dbenv, int opcode, int pct) 82{ 83 DbEnv::_feedback_intercept(dbenv, opcode, pct); 84} 85 86extern "C" 87void _paniccall_intercept_c(DB_ENV *dbenv, int errval) 88{ 89 DbEnv::_paniccall_intercept(dbenv, errval); 90} 91 92extern "C" 93void _event_func_intercept_c(DB_ENV *dbenv, u_int32_t event, void *event_info) 94{ 95 DbEnv::_event_func_intercept(dbenv, event, event_info); 96} 97 98extern "C" 99void _stream_error_function_c(const DB_ENV *dbenv, 100 const char *prefix, const char *message) 101{ 102 DbEnv::_stream_error_function(dbenv, prefix, message); 103} 104 105extern "C" 106void _stream_message_function_c(const DB_ENV *dbenv, const char *message) 107{ 108 DbEnv::_stream_message_function(dbenv, message); 109} 110 111extern "C" 112int _app_dispatch_intercept_c(DB_ENV *dbenv, DBT *dbt, DB_LSN *lsn, db_recops op) 113{ 114 return (DbEnv::_app_dispatch_intercept(dbenv, dbt, lsn, op)); 115} 116 117extern "C" 118int _rep_send_intercept_c(DB_ENV *dbenv, const DBT *cntrl, const DBT *data, 119 const DB_LSN *lsn, int id, u_int32_t flags) 120{ 121 return (DbEnv::_rep_send_intercept(dbenv, 122 cntrl, data, lsn, id, flags)); 123} 124 125extern "C" 126int _isalive_intercept_c( 127 DB_ENV *dbenv, pid_t pid, db_threadid_t thrid, u_int32_t flags) 128{ 129 return (DbEnv::_isalive_intercept(dbenv, pid, thrid, flags)); 130} 131 132extern "C" 133void _thread_id_intercept_c(DB_ENV *dbenv, pid_t *pidp, db_threadid_t *thridp) 134{ 135 DbEnv::_thread_id_intercept(dbenv, pidp, thridp); 136} 137 138extern "C" 139char *_thread_id_string_intercept_c(DB_ENV *dbenv, pid_t pid, 140 db_threadid_t thrid, char *buf) 141{ 142 return (DbEnv::_thread_id_string_intercept(dbenv, pid, thrid, buf)); 143} 144 145void DbEnv::_feedback_intercept(DB_ENV *dbenv, int opcode, int pct) 146{ 147 DbEnv *cxxenv = DbEnv::get_DbEnv(dbenv); 148 if (cxxenv == 0) { 149 DB_ERROR(0, 150 "DbEnv::feedback_callback", EINVAL, ON_ERROR_UNKNOWN); 151 return; 152 } 153 if (cxxenv->feedback_callback_ == 0) { 154 DB_ERROR(DbEnv::get_DbEnv(dbenv), 155 "DbEnv::feedback_callback", EINVAL, cxxenv->error_policy()); 156 return; 157 } 158 (*cxxenv->feedback_callback_)(cxxenv, opcode, pct); 159} 160 161void DbEnv::_paniccall_intercept(DB_ENV *dbenv, int errval) 162{ 163 DbEnv *cxxenv = DbEnv::get_DbEnv(dbenv); 164 if (cxxenv == 0) { 165 DB_ERROR(0, 166 "DbEnv::paniccall_callback", EINVAL, ON_ERROR_UNKNOWN); 167 return; 168 } 169 if (cxxenv->paniccall_callback_ == 0) { 170 DB_ERROR(cxxenv, "DbEnv::paniccall_callback", EINVAL, 171 cxxenv->error_policy()); 172 return; 173 } 174 (*cxxenv->paniccall_callback_)(cxxenv, errval); 175} 176 177void DbEnv::_event_func_intercept( 178 DB_ENV *dbenv, u_int32_t event, void *event_info) 179{ 180 DbEnv *cxxenv = DbEnv::get_DbEnv(dbenv); 181 if (cxxenv == 0) { 182 DB_ERROR(0, 183 "DbEnv::event_func_callback", EINVAL, ON_ERROR_UNKNOWN); 184 return; 185 } 186 if (cxxenv->event_func_callback_ == 0) { 187 DB_ERROR(cxxenv, "DbEnv::event_func_callback", EINVAL, 188 cxxenv->error_policy()); 189 return; 190 } 191 (*cxxenv->event_func_callback_)(cxxenv, event, event_info); 192} 193 194int DbEnv::_app_dispatch_intercept(DB_ENV *dbenv, DBT *dbt, DB_LSN *lsn, 195 db_recops op) 196{ 197 DbEnv *cxxenv = DbEnv::get_DbEnv(dbenv); 198 if (cxxenv == 0) { 199 DB_ERROR(DbEnv::get_DbEnv(dbenv), 200 "DbEnv::app_dispatch_callback", EINVAL, ON_ERROR_UNKNOWN); 201 return (EINVAL); 202 } 203 if (cxxenv->app_dispatch_callback_ == 0) { 204 DB_ERROR(DbEnv::get_DbEnv(dbenv), 205 "DbEnv::app_dispatch_callback", EINVAL, 206 cxxenv->error_policy()); 207 return (EINVAL); 208 } 209 Dbt *cxxdbt = (Dbt *)dbt; 210 DbLsn *cxxlsn = (DbLsn *)lsn; 211 return ((*cxxenv->app_dispatch_callback_)(cxxenv, cxxdbt, cxxlsn, op)); 212} 213 214int DbEnv::_isalive_intercept( 215 DB_ENV *dbenv, pid_t pid, db_threadid_t thrid, u_int32_t flags) 216{ 217 DbEnv *cxxenv = DbEnv::get_DbEnv(dbenv); 218 if (cxxenv == 0) { 219 DB_ERROR(DbEnv::get_DbEnv(dbenv), 220 "DbEnv::isalive_callback", EINVAL, ON_ERROR_UNKNOWN); 221 return (0); 222 } 223 return ((*cxxenv->isalive_callback_)(cxxenv, pid, thrid, flags)); 224} 225 226int DbEnv::_rep_send_intercept(DB_ENV *dbenv, const DBT *cntrl, const DBT *data, 227 const DB_LSN *lsn, int id, u_int32_t flags) 228{ 229 DbEnv *cxxenv = DbEnv::get_DbEnv(dbenv); 230 if (cxxenv == 0) { 231 DB_ERROR(DbEnv::get_DbEnv(dbenv), 232 "DbEnv::rep_send_callback", EINVAL, ON_ERROR_UNKNOWN); 233 return (EINVAL); 234 } 235 const Dbt *cxxcntrl = (const Dbt *)cntrl; 236 const DbLsn *cxxlsn = (const DbLsn *)lsn; 237 Dbt *cxxdata = (Dbt *)data; 238 return ((*cxxenv->rep_send_callback_)(cxxenv, 239 cxxcntrl, cxxdata, cxxlsn, id, flags)); 240} 241 242void DbEnv::_thread_id_intercept(DB_ENV *dbenv, 243 pid_t *pidp, db_threadid_t *thridp) 244{ 245 DbEnv *cxxenv = DbEnv::get_DbEnv(dbenv); 246 if (cxxenv == 0) { 247 DB_ERROR(DbEnv::get_DbEnv(dbenv), 248 "DbEnv::thread_id_callback", EINVAL, ON_ERROR_UNKNOWN); 249 } else 250 cxxenv->thread_id_callback_(cxxenv, pidp, thridp); 251} 252 253char *DbEnv::_thread_id_string_intercept(DB_ENV *dbenv, 254 pid_t pid, db_threadid_t thrid, char *buf) 255{ 256 DbEnv *cxxenv = DbEnv::get_DbEnv(dbenv); 257 if (cxxenv == 0) { 258 DB_ERROR(DbEnv::get_DbEnv(dbenv), 259 "DbEnv::thread_id_string_callback", EINVAL, 260 ON_ERROR_UNKNOWN); 261 return (NULL); 262 } 263 return (cxxenv->thread_id_string_callback_(cxxenv, pid, thrid, buf)); 264} 265 266// A truism for the DbEnv object is that there is a valid 267// DB_ENV handle from the constructor until close(). 268// After the close, the DB_ENV handle is invalid and 269// no operations are permitted on the DbEnv (other than 270// destructor). Leaving the DbEnv handle open and not 271// doing a close is generally considered an error. 272// 273// We used to allow DbEnv objects to be closed and reopened. 274// This implied always keeping a valid DB_ENV object, and 275// coordinating the open objects between Db/DbEnv turned 276// out to be overly complicated. Now we do not allow this. 277 278DbEnv::DbEnv(u_int32_t flags) 279: imp_(0) 280, construct_error_(0) 281, construct_flags_(flags) 282, error_stream_(0) 283, message_stream_(0) 284, app_dispatch_callback_(0) 285, feedback_callback_(0) 286, paniccall_callback_(0) 287, event_func_callback_(0) 288, rep_send_callback_(0) 289{ 290 if ((construct_error_ = initialize(0)) != 0) 291 DB_ERROR(this, "DbEnv::DbEnv", construct_error_, 292 error_policy()); 293} 294 295DbEnv::DbEnv(DB_ENV *dbenv, u_int32_t flags) 296: imp_(0) 297, construct_error_(0) 298, construct_flags_(flags) 299, error_stream_(0) 300, message_stream_(0) 301, app_dispatch_callback_(0) 302, feedback_callback_(0) 303, paniccall_callback_(0) 304, event_func_callback_(0) 305, rep_send_callback_(0) 306{ 307 if ((construct_error_ = initialize(dbenv)) != 0) 308 DB_ERROR(this, "DbEnv::DbEnv", construct_error_, 309 error_policy()); 310} 311 312// If the DB_ENV handle is still open, we close it. This is to make stack 313// allocation of DbEnv objects easier so that they are cleaned up in the error 314// path. Note that the C layer catches cases where handles are open in the 315// environment at close time and reports an error. Applications should call 316// close explicitly in normal (non-exceptional) cases to check the return 317// value. 318// 319DbEnv::~DbEnv() 320{ 321 DB_ENV *dbenv = unwrap(this); 322 323 if (dbenv != NULL) { 324 (void)dbenv->close(dbenv, 0); 325 cleanup(); 326 } 327} 328 329// called by destructors before the DB_ENV is destroyed. 330void DbEnv::cleanup() 331{ 332 imp_ = 0; 333} 334 335int DbEnv::close(u_int32_t flags) 336{ 337 int ret; 338 DB_ENV *dbenv = unwrap(this); 339 340 ret = dbenv->close(dbenv, flags); 341 342 // after a close (no matter if success or failure), 343 // the underlying DB_ENV object must not be accessed. 344 cleanup(); 345 346 // It's safe to throw an error after the close, 347 // since our error mechanism does not peer into 348 // the DB* structures. 349 // 350 if (ret != 0) 351 DB_ERROR(this, "DbEnv::close", ret, error_policy()); 352 353 return (ret); 354} 355 356DBENV_METHOD(dbremove, 357 (DbTxn *txn, const char *name, const char *subdb, u_int32_t flags), 358 (dbenv, unwrap(txn), name, subdb, flags)) 359DBENV_METHOD(dbrename, (DbTxn *txn, const char *name, const char *subdb, 360 const char *newname, u_int32_t flags), 361 (dbenv, unwrap(txn), name, subdb, newname, flags)) 362 363void DbEnv::err(int error, const char *format, ...) 364{ 365 DB_ENV *dbenv = unwrap(this); 366 367 DB_REAL_ERR(dbenv, error, DB_ERROR_SET, 1, format); 368} 369 370// Return a tristate value corresponding to whether we should 371// throw exceptions on errors: 372// ON_ERROR_RETURN 373// ON_ERROR_THROW 374// ON_ERROR_UNKNOWN 375// 376int DbEnv::error_policy() 377{ 378 if ((construct_flags_ & DB_CXX_NO_EXCEPTIONS) != 0) { 379 return (ON_ERROR_RETURN); 380 } 381 else { 382 return (ON_ERROR_THROW); 383 } 384} 385 386void DbEnv::errx(const char *format, ...) 387{ 388 DB_ENV *dbenv = unwrap(this); 389 390 DB_REAL_ERR(dbenv, 0, DB_ERROR_NOT_SET, 1, format); 391} 392 393void *DbEnv::get_app_private() const 394{ 395 return unwrapConst(this)->app_private; 396} 397 398DBENV_METHOD(failchk, (u_int32_t flags), (dbenv, flags)) 399DBENV_METHOD(fileid_reset, (const char *file, u_int32_t flags), 400 (dbenv, file, flags)) 401DBENV_METHOD(get_home, (const char **homep), (dbenv, homep)) 402DBENV_METHOD(get_open_flags, (u_int32_t *flagsp), (dbenv, flagsp)) 403DBENV_METHOD(get_data_dirs, (const char ***dirspp), (dbenv, dirspp)) 404 405bool DbEnv::is_bigendian() 406{ 407 return unwrap(this)->is_bigendian() ? true : false; 408} 409 410DBENV_METHOD(get_thread_count, (u_int32_t *count), (dbenv, count)) 411DBENV_METHOD(set_thread_count, (u_int32_t count), (dbenv, count)) 412 413// used internally during constructor 414// to associate an existing DB_ENV with this DbEnv, 415// or create a new one. 416// 417int DbEnv::initialize(DB_ENV *dbenv) 418{ 419 int ret; 420 421 last_known_error_policy = error_policy(); 422 423 if (dbenv == 0) { 424 // Create a new DB_ENV environment. 425 if ((ret = ::db_env_create(&dbenv, 426 construct_flags_ & ~DB_CXX_NO_EXCEPTIONS)) != 0) 427 return (ret); 428 } 429 imp_ = dbenv; 430 dbenv->api1_internal = this; // for DB_ENV* to DbEnv* conversion 431 return (0); 432} 433 434// lock methods 435DBENV_METHOD(lock_detect, (u_int32_t flags, u_int32_t atype, int *aborted), 436 (dbenv, flags, atype, aborted)) 437DBENV_METHOD_ERR(lock_get, 438 (u_int32_t locker, u_int32_t flags, const Dbt *obj, 439 db_lockmode_t lock_mode, DbLock *lock), 440 (dbenv, locker, flags, obj, lock_mode, &lock->lock_), 441 DbEnv::runtime_error_lock_get(this, "DbEnv::lock_get", ret, 442 DB_LOCK_GET, lock_mode, obj, *lock, 443 -1, error_policy())) 444DBENV_METHOD(lock_id, (u_int32_t *idp), (dbenv, idp)) 445DBENV_METHOD(lock_id_free, (u_int32_t id), (dbenv, id)) 446DBENV_METHOD(lock_put, (DbLock *lock), (dbenv, &lock->lock_)) 447DBENV_METHOD(lock_stat, (DB_LOCK_STAT **statp, u_int32_t flags), 448 (dbenv, statp, flags)) 449DBENV_METHOD(lock_stat_print, (u_int32_t flags), (dbenv, flags)) 450DBENV_METHOD_ERR(lock_vec, 451 (u_int32_t locker, u_int32_t flags, DB_LOCKREQ list[], 452 int nlist, DB_LOCKREQ **elist_returned), 453 (dbenv, locker, flags, list, nlist, elist_returned), 454 DbEnv::runtime_error_lock_get(this, "DbEnv::lock_vec", ret, 455 (*elist_returned)->op, (*elist_returned)->mode, 456 Dbt::get_Dbt((*elist_returned)->obj), DbLock((*elist_returned)->lock), 457 (*elist_returned) - list, error_policy())) 458// log methods 459DBENV_METHOD(log_archive, (char **list[], u_int32_t flags), 460 (dbenv, list, flags)) 461 462int DbEnv::log_compare(const DbLsn *lsn0, const DbLsn *lsn1) 463{ 464 return (::log_compare(lsn0, lsn1)); 465} 466 467// The following cast implies that DbLogc can be no larger than DB_LOGC 468DBENV_METHOD(log_cursor, (DbLogc **cursorp, u_int32_t flags), 469 (dbenv, (DB_LOGC **)cursorp, flags)) 470DBENV_METHOD(log_file, (DbLsn *lsn, char *namep, size_t len), 471 (dbenv, lsn, namep, len)) 472DBENV_METHOD(log_flush, (const DbLsn *lsn), (dbenv, lsn)) 473DBENV_METHOD(log_get_config, (u_int32_t which, int *onoffp), 474 (dbenv, which, onoffp)) 475DBENV_METHOD(log_put, (DbLsn *lsn, const Dbt *data, u_int32_t flags), 476 (dbenv, lsn, data, flags)) 477 478int DbEnv::log_printf(DbTxn *txn, const char *fmt, ...) 479{ 480 DB_ENV *dbenv = unwrap(this); 481 va_list ap; 482 int ret; 483 484 va_start(ap, fmt); 485 ret = __log_printf_pp(dbenv, unwrap(txn), fmt, ap); 486 va_end(ap); 487 488 return (ret); 489} 490 491DBENV_METHOD(log_set_config, (u_int32_t which, int onoff), 492 (dbenv, which, onoff)) 493DBENV_METHOD(log_stat, (DB_LOG_STAT **spp, u_int32_t flags), 494 (dbenv, spp, flags)) 495DBENV_METHOD(log_stat_print, (u_int32_t flags), (dbenv, flags)) 496 497DBENV_METHOD(lsn_reset, (const char *file, u_int32_t flags), 498 (dbenv, file, flags)) 499 500int DbEnv::memp_fcreate(DbMpoolFile **dbmfp, u_int32_t flags) 501{ 502 DB_ENV *dbenv = unwrap(this); 503 int ret; 504 DB_MPOOLFILE *mpf; 505 506 if (dbenv == NULL) 507 ret = EINVAL; 508 else 509 ret = dbenv->memp_fcreate(dbenv, &mpf, flags); 510 511 if (DB_RETOK_STD(ret)) { 512 *dbmfp = new DbMpoolFile(); 513 (*dbmfp)->imp_ = mpf; 514 } else 515 DB_ERROR(this, "DbMpoolFile::f_create", ret, ON_ERROR_UNKNOWN); 516 517 return (ret); 518} 519 520DBENV_METHOD(memp_register, 521 (int ftype, pgin_fcn_type pgin_fcn, pgout_fcn_type pgout_fcn), 522 (dbenv, ftype, pgin_fcn, pgout_fcn)) 523 524// memory pool methods 525DBENV_METHOD(memp_stat, 526 (DB_MPOOL_STAT **gsp, DB_MPOOL_FSTAT ***fsp, u_int32_t flags), 527 (dbenv, gsp, fsp, flags)) 528DBENV_METHOD(memp_stat_print, (u_int32_t flags), (dbenv, flags)) 529DBENV_METHOD(memp_sync, (DbLsn *sn), (dbenv, sn)) 530DBENV_METHOD(memp_trickle, (int pct, int *nwrotep), (dbenv, pct, nwrotep)) 531 532// If an error occurred during the constructor, report it now. 533// Otherwise, call the underlying DB->open method. 534// 535int DbEnv::open(const char *db_home, u_int32_t flags, int mode) 536{ 537 int ret; 538 DB_ENV *dbenv = unwrap(this); 539 540 if (construct_error_ != 0) 541 ret = construct_error_; 542 else 543 ret = dbenv->open(dbenv, db_home, flags, mode); 544 545 if (!DB_RETOK_STD(ret)) 546 DB_ERROR(this, "DbEnv::open", ret, error_policy()); 547 548 return (ret); 549} 550 551int DbEnv::remove(const char *db_home, u_int32_t flags) 552{ 553 int ret; 554 DB_ENV *dbenv = unwrap(this); 555 556 ret = dbenv->remove(dbenv, db_home, flags); 557 558 // after a remove (no matter if success or failure), 559 // the underlying DB_ENV object must not be accessed, 560 // so we clean up in advance. 561 // 562 cleanup(); 563 564 if (ret != 0) 565 DB_ERROR(this, "DbEnv::remove", ret, error_policy()); 566 567 return (ret); 568} 569 570// Report an error associated with the DbEnv. 571// error_policy is one of: 572// ON_ERROR_THROW throw an error 573// ON_ERROR_RETURN do nothing here, the caller will return an error 574// ON_ERROR_UNKNOWN defer the policy to policy saved in DbEnv::DbEnv 575// 576void DbEnv::runtime_error(DbEnv *dbenv, 577 const char *caller, int error, int error_policy) 578{ 579 if (error_policy == ON_ERROR_UNKNOWN) 580 error_policy = last_known_error_policy; 581 if (error_policy == ON_ERROR_THROW) { 582 // Creating and throwing the object in two separate 583 // statements seems to be necessary for HP compilers. 584 switch (error) { 585 case DB_LOCK_DEADLOCK: 586 { 587 DbDeadlockException dl_except(caller); 588 dl_except.set_env(dbenv); 589 throw dl_except; 590 } 591 case DB_LOCK_NOTGRANTED: 592 { 593 DbLockNotGrantedException lng_except(caller); 594 lng_except.set_env(dbenv); 595 throw lng_except; 596 } 597 case DB_REP_HANDLE_DEAD: 598 { 599 DbRepHandleDeadException hd_except(caller); 600 hd_except.set_env(dbenv); 601 throw hd_except; 602 } 603 case DB_RUNRECOVERY: 604 { 605 DbRunRecoveryException rr_except(caller); 606 rr_except.set_env(dbenv); 607 throw rr_except; 608 } 609 default: 610 { 611 DbException except(caller, error); 612 except.set_env(dbenv); 613 throw except; 614 } 615 } 616 } 617} 618 619// Like DbEnv::runtime_error, but issue a DbMemoryException 620// based on the fact that this Dbt is not large enough. 621void DbEnv::runtime_error_dbt(DbEnv *dbenv, 622 const char *caller, Dbt *dbt, int error_policy) 623{ 624 if (error_policy == ON_ERROR_UNKNOWN) 625 error_policy = last_known_error_policy; 626 if (error_policy == ON_ERROR_THROW) { 627 // Creating and throwing the object in two separate 628 // statements seems to be necessary for HP compilers. 629 DbMemoryException except(caller, dbt); 630 except.set_env(dbenv); 631 throw except; 632 } 633} 634 635// Like DbEnv::runtime_error, but issue a DbLockNotGrantedException, 636// or a regular runtime error. 637// call regular runtime_error if it 638void DbEnv::runtime_error_lock_get(DbEnv *dbenv, 639 const char *caller, int error, 640 db_lockop_t op, db_lockmode_t mode, const Dbt *obj, 641 DbLock lock, int index, int error_policy) 642{ 643 if (error != DB_LOCK_NOTGRANTED) { 644 runtime_error(dbenv, caller, error, error_policy); 645 return; 646 } 647 648 if (error_policy == ON_ERROR_UNKNOWN) 649 error_policy = last_known_error_policy; 650 if (error_policy == ON_ERROR_THROW) { 651 // Creating and throwing the object in two separate 652 // statements seems to be necessary for HP compilers. 653 DbLockNotGrantedException except(caller, op, mode, 654 obj, lock, index); 655 except.set_env(dbenv); 656 throw except; 657 } 658} 659 660void DbEnv::_stream_error_function( 661 const DB_ENV *dbenv, const char *prefix, const char *message) 662{ 663 const DbEnv *cxxenv = DbEnv::get_const_DbEnv(dbenv); 664 if (cxxenv == 0) { 665 DB_ERROR(0, 666 "DbEnv::stream_error", EINVAL, ON_ERROR_UNKNOWN); 667 return; 668 } 669 670 if (cxxenv->error_callback_) 671 cxxenv->error_callback_(cxxenv, prefix, message); 672 else if (cxxenv->error_stream_) { 673 // HP compilers need the extra casts, we don't know why. 674 if (prefix) { 675 (*cxxenv->error_stream_) << prefix; 676 (*cxxenv->error_stream_) << (const char *)": "; 677 } 678 if (message) 679 (*cxxenv->error_stream_) << (const char *)message; 680 (*cxxenv->error_stream_) << (const char *)"\n"; 681 } 682} 683 684void DbEnv::_stream_message_function(const DB_ENV *dbenv, const char *message) 685{ 686 const DbEnv *cxxenv = DbEnv::get_const_DbEnv(dbenv); 687 if (cxxenv == 0) { 688 DB_ERROR(0, 689 "DbEnv::stream_message", EINVAL, ON_ERROR_UNKNOWN); 690 return; 691 } 692 693 if (cxxenv->message_callback_) 694 cxxenv->message_callback_(cxxenv, message); 695 else if (cxxenv->message_stream_) { 696 // HP compilers need the extra casts, we don't know why. 697 (*cxxenv->message_stream_) << (const char *)message; 698 (*cxxenv->message_stream_) << (const char *)"\n"; 699 } 700} 701 702// static method 703char *DbEnv::strerror(int error) 704{ 705 return (db_strerror(error)); 706} 707 708// We keep these alphabetical by field name, 709// for comparison with Java's list. 710// 711DBENV_METHOD(set_data_dir, (const char *dir), (dbenv, dir)) 712DBENV_METHOD(get_encrypt_flags, (u_int32_t *flagsp), 713 (dbenv, flagsp)) 714DBENV_METHOD(set_encrypt, (const char *passwd, u_int32_t flags), 715 (dbenv, passwd, flags)) 716DBENV_METHOD_VOID(get_errfile, (FILE **errfilep), (dbenv, errfilep)) 717DBENV_METHOD_VOID(set_errfile, (FILE *errfile), (dbenv, errfile)) 718DBENV_METHOD_VOID(get_errpfx, (const char **errpfxp), (dbenv, errpfxp)) 719DBENV_METHOD_VOID(set_errpfx, (const char *errpfx), (dbenv, errpfx)) 720DBENV_METHOD(get_intermediate_dir_mode, (const char **modep), (dbenv, modep)) 721DBENV_METHOD(set_intermediate_dir_mode, (const char *mode), (dbenv, mode)) 722DBENV_METHOD(get_lg_bsize, (u_int32_t *bsizep), (dbenv, bsizep)) 723DBENV_METHOD(set_lg_bsize, (u_int32_t bsize), (dbenv, bsize)) 724DBENV_METHOD(get_lg_dir, (const char **dirp), (dbenv, dirp)) 725DBENV_METHOD(set_lg_dir, (const char *dir), (dbenv, dir)) 726DBENV_METHOD(get_lg_filemode, (int *modep), (dbenv, modep)) 727DBENV_METHOD(set_lg_filemode, (int mode), (dbenv, mode)) 728DBENV_METHOD(get_lg_max, (u_int32_t *maxp), (dbenv, maxp)) 729DBENV_METHOD(set_lg_max, (u_int32_t max), (dbenv, max)) 730DBENV_METHOD(get_lg_regionmax, (u_int32_t *regionmaxp), (dbenv, regionmaxp)) 731DBENV_METHOD(set_lg_regionmax, (u_int32_t regionmax), (dbenv, regionmax)) 732DBENV_METHOD(get_lk_conflicts, (const u_int8_t **lk_conflictsp, int *lk_maxp), 733 (dbenv, lk_conflictsp, lk_maxp)) 734DBENV_METHOD(set_lk_conflicts, (u_int8_t *lk_conflicts, int lk_max), 735 (dbenv, lk_conflicts, lk_max)) 736DBENV_METHOD(get_lk_detect, (u_int32_t *detectp), (dbenv, detectp)) 737DBENV_METHOD(set_lk_detect, (u_int32_t detect), (dbenv, detect)) 738DBENV_METHOD(get_lk_max_lockers, (u_int32_t *max_lockersp), 739 (dbenv, max_lockersp)) 740DBENV_METHOD(set_lk_max_lockers, (u_int32_t max_lockers), (dbenv, max_lockers)) 741DBENV_METHOD(get_lk_max_locks, (u_int32_t *max_locksp), (dbenv, max_locksp)) 742DBENV_METHOD(set_lk_max_locks, (u_int32_t max_locks), (dbenv, max_locks)) 743DBENV_METHOD(get_lk_max_objects, (u_int32_t *max_objectsp), 744 (dbenv, max_objectsp)) 745DBENV_METHOD(set_lk_max_objects, (u_int32_t max_objects), (dbenv, max_objects)) 746DBENV_METHOD(get_mp_max_openfd, (int *maxopenfdp), (dbenv, maxopenfdp)) 747DBENV_METHOD(set_mp_max_openfd, (int maxopenfd), (dbenv, maxopenfd)) 748DBENV_METHOD(get_mp_max_write, (int *maxwritep, db_timeout_t *maxwrite_sleepp), 749 (dbenv, maxwritep, maxwrite_sleepp)) 750DBENV_METHOD(set_mp_max_write, (int maxwrite, db_timeout_t maxwrite_sleep), 751 (dbenv, maxwrite, maxwrite_sleep)) 752DBENV_METHOD(get_mp_mmapsize, (size_t *mmapsizep), (dbenv, mmapsizep)) 753DBENV_METHOD(set_mp_mmapsize, (size_t mmapsize), (dbenv, mmapsize)) 754DBENV_METHOD_VOID(get_msgfile, (FILE **msgfilep), (dbenv, msgfilep)) 755DBENV_METHOD_VOID(set_msgfile, (FILE *msgfile), (dbenv, msgfile)) 756DBENV_METHOD(get_tmp_dir, (const char **tmp_dirp), (dbenv, tmp_dirp)) 757DBENV_METHOD(set_tmp_dir, (const char *tmp_dir), (dbenv, tmp_dir)) 758DBENV_METHOD(get_tx_max, (u_int32_t *tx_maxp), (dbenv, tx_maxp)) 759DBENV_METHOD(set_tx_max, (u_int32_t tx_max), (dbenv, tx_max)) 760 761DBENV_METHOD(stat_print, (u_int32_t flags), (dbenv, flags)) 762 763DBENV_METHOD_QUIET(set_alloc, 764 (db_malloc_fcn_type malloc_fcn, db_realloc_fcn_type realloc_fcn, 765 db_free_fcn_type free_fcn), 766 (dbenv, malloc_fcn, realloc_fcn, free_fcn)) 767 768void DbEnv::set_app_private(void *value) 769{ 770 unwrap(this)->app_private = value; 771} 772 773DBENV_METHOD(get_cachesize, 774 (u_int32_t *gbytesp, u_int32_t *bytesp, int *ncachep), 775 (dbenv, gbytesp, bytesp, ncachep)) 776DBENV_METHOD(set_cachesize, 777 (u_int32_t gbytes, u_int32_t bytes, int ncache), 778 (dbenv, gbytes, bytes, ncache)) 779DBENV_METHOD(get_cache_max, (u_int32_t *gbytesp, u_int32_t *bytesp), 780 (dbenv, gbytesp, bytesp)) 781DBENV_METHOD(set_cache_max, (u_int32_t gbytes, u_int32_t bytes), 782 (dbenv, gbytes, bytes)) 783 784void DbEnv::set_errcall(void (*arg)(const DbEnv *, const char *, const char *)) 785{ 786 DB_ENV *dbenv = unwrap(this); 787 788 error_callback_ = arg; 789 error_stream_ = 0; 790 791 dbenv->set_errcall(dbenv, (arg == 0) ? 0 : 792 _stream_error_function_c); 793} 794 795__DB_STD(ostream) *DbEnv::get_error_stream() 796{ 797 return (error_stream_); 798} 799 800void DbEnv::set_error_stream(__DB_STD(ostream) *stream) 801{ 802 DB_ENV *dbenv = unwrap(this); 803 804 error_stream_ = stream; 805 error_callback_ = 0; 806 807 dbenv->set_errcall(dbenv, (stream == 0) ? 0 : 808 _stream_error_function_c); 809} 810 811int DbEnv::set_feedback(void (*arg)(DbEnv *, int, int)) 812{ 813 DB_ENV *dbenv = unwrap(this); 814 815 feedback_callback_ = arg; 816 817 return (dbenv->set_feedback(dbenv, 818 arg == 0 ? 0 : _feedback_intercept_c)); 819} 820 821DBENV_METHOD(get_flags, (u_int32_t *flagsp), (dbenv, flagsp)) 822DBENV_METHOD(set_flags, (u_int32_t flags, int onoff), (dbenv, flags, onoff)) 823 824void DbEnv::set_msgcall(void (*arg)(const DbEnv *, const char *)) 825{ 826 DB_ENV *dbenv = unwrap(this); 827 828 message_callback_ = arg; 829 message_stream_ = 0; 830 831 dbenv->set_msgcall(dbenv, (arg == 0) ? 0 : 832 _stream_message_function_c); 833} 834 835__DB_STD(ostream) *DbEnv::get_message_stream() 836{ 837 return (message_stream_); 838} 839 840void DbEnv::set_message_stream(__DB_STD(ostream) *stream) 841{ 842 DB_ENV *dbenv = unwrap(this); 843 844 message_stream_ = stream; 845 message_callback_ = 0; 846 847 dbenv->set_msgcall(dbenv, (stream == 0) ? 0 : 848 _stream_message_function_c); 849} 850 851int DbEnv::set_paniccall(void (*arg)(DbEnv *, int)) 852{ 853 DB_ENV *dbenv = unwrap(this); 854 855 paniccall_callback_ = arg; 856 857 return (dbenv->set_paniccall(dbenv, 858 arg == 0 ? 0 : _paniccall_intercept_c)); 859} 860 861int DbEnv::set_event_notify(void (*arg)(DbEnv *, u_int32_t, void *)) 862{ 863 DB_ENV *dbenv = unwrap(this); 864 865 event_func_callback_ = arg; 866 867 return (dbenv->set_event_notify(dbenv, 868 arg == 0 ? 0 : _event_func_intercept_c)); 869} 870 871DBENV_METHOD(set_rpc_server, 872 (void *cl, char *host, long tsec, long ssec, u_int32_t flags), 873 (dbenv, cl, host, tsec, ssec, flags)) 874DBENV_METHOD(get_shm_key, (long *shm_keyp), (dbenv, shm_keyp)) 875DBENV_METHOD(set_shm_key, (long shm_key), (dbenv, shm_key)) 876 877int DbEnv::set_app_dispatch 878 (int (*arg)(DbEnv *, Dbt *, DbLsn *, db_recops)) 879{ 880 DB_ENV *dbenv = unwrap(this); 881 int ret; 882 883 app_dispatch_callback_ = arg; 884 if ((ret = dbenv->set_app_dispatch(dbenv, 885 arg == 0 ? 0 : _app_dispatch_intercept_c)) != 0) 886 DB_ERROR(this, "DbEnv::set_app_dispatch", ret, error_policy()); 887 888 return (ret); 889} 890 891int DbEnv::set_isalive 892 (int (*arg)(DbEnv *, pid_t, db_threadid_t, u_int32_t)) 893{ 894 DB_ENV *dbenv = unwrap(this); 895 int ret; 896 897 isalive_callback_ = arg; 898 if ((ret = dbenv->set_isalive(dbenv, 899 arg == 0 ? 0 : _isalive_intercept_c)) != 0) 900 DB_ERROR(this, "DbEnv::set_isalive", ret, error_policy()); 901 902 return (ret); 903} 904 905DBENV_METHOD(get_tx_timestamp, (time_t *timestamp), (dbenv, timestamp)) 906DBENV_METHOD(set_tx_timestamp, (time_t *timestamp), (dbenv, timestamp)) 907DBENV_METHOD(get_verbose, (u_int32_t which, int *onoffp), 908 (dbenv, which, onoffp)) 909DBENV_METHOD(set_verbose, (u_int32_t which, int onoff), (dbenv, which, onoff)) 910 911DBENV_METHOD(mutex_alloc, 912 (u_int32_t flags, db_mutex_t *mutexp), (dbenv, flags, mutexp)) 913DBENV_METHOD(mutex_free, (db_mutex_t mutex), (dbenv, mutex)) 914DBENV_METHOD(mutex_get_align, (u_int32_t *argp), (dbenv, argp)) 915DBENV_METHOD(mutex_get_increment, (u_int32_t *argp), (dbenv, argp)) 916DBENV_METHOD(mutex_get_max, (u_int32_t *argp), (dbenv, argp)) 917DBENV_METHOD(mutex_get_tas_spins, (u_int32_t *argp), (dbenv, argp)) 918DBENV_METHOD(mutex_lock, (db_mutex_t mutex), (dbenv, mutex)) 919DBENV_METHOD(mutex_set_align, (u_int32_t arg), (dbenv, arg)) 920DBENV_METHOD(mutex_set_increment, (u_int32_t arg), (dbenv, arg)) 921DBENV_METHOD(mutex_set_max, (u_int32_t arg), (dbenv, arg)) 922DBENV_METHOD(mutex_set_tas_spins, (u_int32_t arg), (dbenv, arg)) 923DBENV_METHOD(mutex_stat, 924 (DB_MUTEX_STAT **statp, u_int32_t flags), (dbenv, statp, flags)) 925DBENV_METHOD(mutex_stat_print, (u_int32_t flags), (dbenv, flags)) 926DBENV_METHOD(mutex_unlock, (db_mutex_t mutex), (dbenv, mutex)) 927 928int DbEnv::set_thread_id(void (*arg)(DbEnv *, pid_t *, db_threadid_t *)) 929{ 930 DB_ENV *dbenv = unwrap(this); 931 int ret; 932 933 thread_id_callback_ = arg; 934 if ((ret = dbenv->set_thread_id(dbenv, 935 arg == 0 ? 0 : _thread_id_intercept_c)) != 0) 936 DB_ERROR(this, "DbEnv::set_thread_id", ret, error_policy()); 937 938 return (ret); 939} 940 941int DbEnv::set_thread_id_string( 942 char *(*arg)(DbEnv *, pid_t, db_threadid_t, char *)) 943{ 944 DB_ENV *dbenv = unwrap(this); 945 int ret; 946 947 thread_id_string_callback_ = arg; 948 if ((ret = dbenv->set_thread_id_string(dbenv, 949 arg == 0 ? 0 : _thread_id_string_intercept_c)) != 0) 950 DB_ERROR(this, "DbEnv::set_thread_id_string", ret, 951 error_policy()); 952 953 return (ret); 954} 955 956int DbEnv::cdsgroup_begin(DbTxn **tid) 957{ 958 DB_ENV *dbenv = unwrap(this); 959 DB_TXN *txn; 960 int ret; 961 962 ret = dbenv->cdsgroup_begin(dbenv, &txn); 963 if (DB_RETOK_STD(ret)) 964 *tid = new DbTxn(txn); 965 else 966 DB_ERROR(this, "DbEnv::cdsgroup_begin", ret, error_policy()); 967 968 return (ret); 969} 970 971int DbEnv::txn_begin(DbTxn *pid, DbTxn **tid, u_int32_t flags) 972{ 973 DB_ENV *dbenv = unwrap(this); 974 DB_TXN *txn; 975 int ret; 976 977 ret = dbenv->txn_begin(dbenv, unwrap(pid), &txn, flags); 978 if (DB_RETOK_STD(ret)) 979 *tid = new DbTxn(txn); 980 else 981 DB_ERROR(this, "DbEnv::txn_begin", ret, error_policy()); 982 983 return (ret); 984} 985 986DBENV_METHOD(txn_checkpoint, (u_int32_t kbyte, u_int32_t min, u_int32_t flags), 987 (dbenv, kbyte, min, flags)) 988 989int DbEnv::txn_recover(DbPreplist *preplist, long count, 990 long *retp, u_int32_t flags) 991{ 992 DB_ENV *dbenv = unwrap(this); 993 DB_PREPLIST *c_preplist; 994 long i; 995 int ret; 996 997 /* 998 * We need to allocate some local storage for the 999 * returned preplist, and that requires us to do 1000 * our own argument validation. 1001 */ 1002 if (count <= 0) 1003 ret = EINVAL; 1004 else 1005 ret = __os_malloc(dbenv->env, sizeof(DB_PREPLIST) * count, 1006 &c_preplist); 1007 1008 if (ret != 0) { 1009 DB_ERROR(this, "DbEnv::txn_recover", ret, error_policy()); 1010 return (ret); 1011 } 1012 1013 if ((ret = 1014 dbenv->txn_recover(dbenv, c_preplist, count, retp, flags)) != 0) { 1015 __os_free(dbenv->env, c_preplist); 1016 DB_ERROR(this, "DbEnv::txn_recover", ret, error_policy()); 1017 return (ret); 1018 } 1019 1020 for (i = 0; i < *retp; i++) { 1021 preplist[i].txn = new DbTxn(); 1022 preplist[i].txn->imp_ = c_preplist[i].txn; 1023 memcpy(preplist[i].gid, c_preplist[i].gid, 1024 sizeof(preplist[i].gid)); 1025 } 1026 1027 __os_free(dbenv->env, c_preplist); 1028 1029 return (0); 1030} 1031 1032DBENV_METHOD(txn_stat, (DB_TXN_STAT **statp, u_int32_t flags), 1033 (dbenv, statp, flags)) 1034DBENV_METHOD(txn_stat_print, (u_int32_t flags), (dbenv, flags)) 1035 1036int DbEnv::rep_set_transport(int myid, int (*arg)(DbEnv *, 1037 const Dbt *, const Dbt *, const DbLsn *, int, u_int32_t)) 1038{ 1039 DB_ENV *dbenv = unwrap(this); 1040 int ret; 1041 1042 rep_send_callback_ = arg; 1043 if ((ret = dbenv->rep_set_transport(dbenv, myid, 1044 arg == 0 ? 0 : _rep_send_intercept_c)) != 0) 1045 DB_ERROR(this, "DbEnv::rep_set_transport", ret, error_policy()); 1046 1047 return (ret); 1048} 1049 1050DBENV_METHOD(rep_elect, (u_int32_t nsites, u_int32_t nvotes, u_int32_t flags), 1051 (dbenv, nsites, nvotes, flags)) 1052DBENV_METHOD(rep_flush, (), (dbenv)) 1053DBENV_METHOD(rep_get_config, (u_int32_t which, int *onoffp), 1054 (dbenv, which, onoffp)) 1055DBENV_METHOD(rep_get_request, (u_int32_t *min, u_int32_t *max), 1056 (dbenv, min, max)) 1057DBENV_METHOD(rep_set_request, (u_int32_t min, u_int32_t max), (dbenv, min, max)) 1058 1059int DbEnv::rep_process_message(Dbt *control, 1060 Dbt *rec, int id, DbLsn *ret_lsnp) 1061{ 1062 DB_ENV *dbenv = unwrap(this); 1063 int ret; 1064 1065 ret = dbenv->rep_process_message(dbenv, control, rec, id, ret_lsnp); 1066 if (!DB_RETOK_REPPMSG(ret)) 1067 DB_ERROR(this, "DbEnv::rep_process_message", ret, 1068 error_policy()); 1069 1070 return (ret); 1071} 1072 1073DBENV_METHOD(rep_set_config, 1074 (u_int32_t which, int onoff), (dbenv, which, onoff)) 1075DBENV_METHOD(rep_start, 1076 (Dbt *cookie, u_int32_t flags), 1077 (dbenv, (DBT *)cookie, flags)) 1078 1079DBENV_METHOD(rep_stat, (DB_REP_STAT **statp, u_int32_t flags), 1080 (dbenv, statp, flags)) 1081DBENV_METHOD(rep_stat_print, (u_int32_t flags), (dbenv, flags)) 1082DBENV_METHOD(rep_sync, (u_int32_t flags), (dbenv, flags)) 1083 1084DBENV_METHOD(rep_get_clockskew, (u_int32_t *fast_clockp, u_int32_t *slow_clockp), 1085 (dbenv, fast_clockp, slow_clockp)) 1086DBENV_METHOD(rep_set_clockskew, (u_int32_t fast_clock, u_int32_t slow_clock), 1087 (dbenv, fast_clock, slow_clock)) 1088DBENV_METHOD(rep_get_limit, (u_int32_t *gbytesp, u_int32_t *bytesp), 1089 (dbenv, gbytesp, bytesp)) 1090DBENV_METHOD(rep_set_limit, (u_int32_t gbytes, u_int32_t bytes), 1091 (dbenv, gbytes, bytes)) 1092 1093// 1094// Begin advanced replication API method implementations 1095DBENV_METHOD(rep_get_nsites, (u_int32_t *n), (dbenv, n)) 1096DBENV_METHOD(rep_set_nsites, (u_int32_t n), (dbenv, n)) 1097DBENV_METHOD(rep_get_priority, (u_int32_t *priority), 1098 (dbenv, priority)) 1099DBENV_METHOD(rep_set_priority, (u_int32_t priority), 1100 (dbenv, priority)) 1101DBENV_METHOD(rep_get_timeout, (int which, db_timeout_t * timeout), 1102 (dbenv, which, timeout)) 1103DBENV_METHOD(rep_set_timeout, (int which, db_timeout_t timeout), 1104 (dbenv, which, timeout)) 1105DBENV_METHOD(repmgr_add_remote_site, (const char* host, u_int16_t port, 1106 int * eidp, u_int32_t flags), (dbenv, host, port, eidp, flags)) 1107DBENV_METHOD(repmgr_get_ack_policy, (int *policy), (dbenv, policy)) 1108DBENV_METHOD(repmgr_set_ack_policy, (int policy), (dbenv, policy)) 1109DBENV_METHOD(repmgr_set_local_site, (const char* host, u_int16_t port, 1110 u_int32_t flags), (dbenv, host, port, flags)) 1111DBENV_METHOD(repmgr_site_list, (u_int *countp, DB_REPMGR_SITE **listp), 1112 (dbenv, countp, listp)) 1113DBENV_METHOD(repmgr_start, (int nthreads, u_int32_t flags), 1114 (dbenv, nthreads, flags)) 1115DBENV_METHOD(repmgr_stat, (DB_REPMGR_STAT **statp, u_int32_t flags), 1116 (dbenv, statp, flags)) 1117DBENV_METHOD(repmgr_stat_print, (u_int32_t flags), (dbenv, flags)) 1118 1119// End advanced replication API method implementations. 1120 1121DBENV_METHOD(get_timeout, 1122 (db_timeout_t *timeoutp, u_int32_t flags), 1123 (dbenv, timeoutp, flags)) 1124DBENV_METHOD(set_timeout, 1125 (db_timeout_t timeout, u_int32_t flags), 1126 (dbenv, timeout, flags)) 1127 1128// static method 1129char *DbEnv::version(int *major, int *minor, int *patch) 1130{ 1131 return (db_version(major, minor, patch)); 1132} 1133 1134// static method 1135DbEnv *DbEnv::wrap_DB_ENV(DB_ENV *dbenv) 1136{ 1137 DbEnv *wrapped_env = get_DbEnv(dbenv); 1138 return (wrapped_env != NULL) ? wrapped_env : new DbEnv(dbenv, 0); 1139} 1140