00001 /*- 00002 * See the file LICENSE for redistribution information. 00003 * 00004 * Copyright (c) 2000 00005 * Sleepycat Software. All rights reserved. 00006 */ 00007 00008 #include "config.h" 00009 00010 #ifndef lint 00011 static const char revid[] = "$Id: db__cam_8c-source.html,v 1.1 2008年06月08日 10:17:22 sebdiaz Exp $"; 00012 #endif /* not lint */ 00013 00014 #ifndef NO_SYSTEM_INCLUDES 00015 #include <sys/types.h> 00016 #include <string.h> 00017 #include <errno.h> 00018 #endif 00019 00020 #include "db_int.h" 00021 #include "db_page.h" 00022 #include "db_shash.h" 00023 #include "lock.h" 00024 #include "btree.h" 00025 #include "hash.h" 00026 #include "qam.h" 00027 #include "db_ext.h" 00028 00029 static int __db_c_cleanup __P((DBC *, DBC *, int)); 00030 static int __db_c_idup __P((DBC *, DBC **, u_int32_t)); 00031 static int __db_wrlock_err __P((DB_ENV *)); 00032 00033 #define LOCKING_INIT(dbp, dbc) \ 00034 /* \ 00035 * If we are running CDB, this had better be either a write \ 00036 * cursor or an immediate writer. If it's a regular writer, \ 00037 * that means we have an IWRITE lock and we need to upgrade \ 00038 * it to a write lock. \ 00039 */ \ 00040 if (LOCKING((dbp)->dbenv)) { \ 00041 if (!F_ISSET(dbc, DBC_WRITECURSOR | DBC_WRITER)) \ 00042 return(__db_wrlock_err(dbp->dbenv)); \ 00043 \ 00044 if (F_ISSET(dbc, DBC_WRITECURSOR) && \ 00045 (ret = CDB_lock_get((dbp)->dbenv, (dbc)->locker, \ 00046 DB_LOCK_UPGRADE, &(dbc)->lock_dbt, DB_LOCK_WRITE, \ 00047 &(dbc)->mylock)) != 0) \ 00048 return (ret); \ 00049 } 00050 #define LOCKING_DONE(dbp, dbc) \ 00051 /* Release the upgraded lock. */ \ 00052 if (F_ISSET(dbc, DBC_WRITECURSOR)) \ 00053 (void)CDB___lock_downgrade( \ 00054 (dbp)->dbenv, &(dbc)->mylock, DB_LOCK_IWRITE, 0); 00055 00056 #define IS_INITIALIZED(dbc) ((dbc)->internal->pgno != PGNO_INVALID) 00057 00058 /* 00059 * CDB___db_c_close -- 00060 * Close the cursor. 00061 * 00062 * PUBLIC: int CDB___db_c_close __P((DBC *)); 00063 */ 00064 int 00065 CDB___db_c_close(dbc) 00066 DBC *dbc; 00067 { 00068 DB *dbp; 00069 DBC *opd; 00070 DBC_INTERNAL *cp; 00071 int ret, t_ret; 00072 00073 dbp = dbc->dbp; 00074 ret = 0; 00075 00076 PANIC_CHECK(dbp->dbenv); 00077 00078 /* 00079 * If the cursor is already closed we have a serious problem, and we 00080 * assume that the cursor isn't on the active queue. Don't do any of 00081 * the remaining cursor close processing. 00082 */ 00083 if (!F_ISSET(dbc, DBC_ACTIVE)) { 00084 if (dbp && dbp->dbenv) 00085 CDB___db_err(dbp->dbenv, "Closing closed cursor"); 00086 DB_ASSERT(0); 00087 return (EINVAL); 00088 } 00089 00090 cp = dbc->internal; 00091 opd = cp->opd; 00092 00093 /* 00094 * Remove the cursor(s) from the active queue. We may be closing two 00095 * cursors at once here, a top-level one and a lower-level, off-page 00096 * duplicate one. The acess-method specific cursor close routine must 00097 * close both of them in a single call. 00098 * 00099 * !!! 00100 * Cursors must be removed from the active queue before calling the 00101 * access specific cursor close routine, btree depends on having that 00102 * order of operations. It must also happen before any action that 00103 * can fail and cause CDB___db_c_close to return an error, or else calls 00104 * here from CDB___db_close may loop indefinitely. 00105 */ 00106 MUTEX_THREAD_LOCK(dbp->mutexp); 00107 00108 if (opd != NULL) { 00109 F_CLR(opd, DBC_ACTIVE); 00110 TAILQ_REMOVE(&dbp->active_queue, opd, links); 00111 } 00112 F_CLR(dbc, DBC_ACTIVE); 00113 TAILQ_REMOVE(&dbp->active_queue, dbc, links); 00114 00115 MUTEX_THREAD_UNLOCK(dbp->mutexp); 00116 00117 /* Call the access specific cursor close routine. */ 00118 if ((t_ret = 00119 dbc->c_am_close(dbc, PGNO_INVALID, NULL)) != 0 && ret == 0) 00120 ret = t_ret; 00121 00122 /* 00123 * Release the lock after calling the access method specific close 00124 * routine, a Btree cursor may have had pending deletes. 00125 */ 00126 if (LOCKING(dbc->dbp->dbenv)) { 00127 /* 00128 * If DBC_WRITEDUP is set, the cursor is an internally 00129 * duplicated write cursor and the lock isn't ours to put. 00130 */ 00131 if (!F_ISSET(dbc, DBC_WRITEDUP) && 00132 dbc->mylock.off != LOCK_INVALID) { 00133 if ((t_ret = CDB_lock_put(dbc->dbp->dbenv, 00134 &dbc->mylock)) != 0 && ret == 0) 00135 ret = t_ret; 00136 dbc->mylock.off = LOCK_INVALID; 00137 } 00138 00139 /* For safety's sake, since this is going on the free queue. */ 00140 memset(&dbc->mylock, 0, sizeof(dbc->mylock)); 00141 F_CLR(dbc, DBC_WRITEDUP); 00142 } 00143 00144 /* Move the cursor(s) to the free queue. */ 00145 MUTEX_THREAD_LOCK(dbp->mutexp); 00146 if (opd != NULL) { 00147 TAILQ_INSERT_TAIL(&dbp->free_queue, opd, links); 00148 opd = NULL; 00149 } 00150 TAILQ_INSERT_TAIL(&dbp->free_queue, dbc, links); 00151 MUTEX_THREAD_UNLOCK(dbp->mutexp); 00152 00153 return (ret); 00154 } 00155 00156 /* 00157 * CDB___db_c_destroy -- 00158 * Destroy the cursor, called after DBC->c_close. 00159 * 00160 * PUBLIC: int CDB___db_c_destroy __P((DBC *)); 00161 */ 00162 int 00163 CDB___db_c_destroy(dbc) 00164 DBC *dbc; 00165 { 00166 DB *dbp; 00167 DBC_INTERNAL *cp; 00168 int ret; 00169 00170 dbp = dbc->dbp; 00171 cp = dbc->internal; 00172 00173 /* Remove the cursor from the free queue. */ 00174 MUTEX_THREAD_LOCK(dbp->mutexp); 00175 TAILQ_REMOVE(&dbp->free_queue, dbc, links); 00176 MUTEX_THREAD_UNLOCK(dbp->mutexp); 00177 00178 /* Free up allocated memory. */ 00179 if (dbc->rkey.data != NULL) 00180 CDB___os_free(dbc->rkey.data, dbc->rkey.ulen); 00181 if (dbc->rdata.data != NULL) 00182 CDB___os_free(dbc->rdata.data, dbc->rdata.ulen); 00183 00184 /* Call the access specific cursor destroy routine. */ 00185 ret = dbc->c_am_destroy == NULL ? 0 : dbc->c_am_destroy(dbc); 00186 00187 CDB___os_free(dbc, sizeof(*dbc)); 00188 00189 return (ret); 00190 } 00191 00192 /* 00193 * CDB___db_c_count -- 00194 * Return a count of duplicate data items. 00195 * 00196 * PUBLIC: int CDB___db_c_count __P((DBC *, db_recno_t *, u_int32_t)); 00197 */ 00198 int 00199 CDB___db_c_count(dbc, recnop, flags) 00200 DBC *dbc; 00201 db_recno_t *recnop; 00202 u_int32_t flags; 00203 { 00204 DB *dbp; 00205 int ret; 00206 00207 /* 00208 * Cursor Cleanup Note: 00209 * All of the cursors passed to the underlying access methods by this 00210 * routine are not duplicated and will not be cleaned up on return. 00211 * So, pages/locks that the cursor references must be resolved by the 00212 * underlying functions. 00213 */ 00214 dbp = dbc->dbp; 00215 00216 PANIC_CHECK(dbp->dbenv); 00217 00218 /* Check for invalid flags. */ 00219 if ((ret = CDB___db_ccountchk(dbp, flags, IS_INITIALIZED(dbc))) != 0) 00220 return (ret); 00221 00222 switch (dbc->dbtype) { 00223 case DB_QUEUE: 00224 case DB_RECNO: 00225 *recnop = 1; 00226 break; 00227 case DB_HASH: 00228 if (dbc->internal->opd == NULL) { 00229 if ((ret = CDB___ham_c_count(dbc, recnop)) != 0) 00230 return (ret); 00231 break; 00232 } 00233 /* FALLTHROUGH */ 00234 case DB_BTREE: 00235 if ((ret = CDB___bam_c_count(dbc, recnop)) != 0) 00236 return (ret); 00237 break; 00238 default: 00239 return (CDB___db_unknown_type(dbp->dbenv, 00240 "CDB___db_c_count", dbp->type)); 00241 } 00242 return (0); 00243 } 00244 00245 /* 00246 * CDB___db_c_del -- 00247 * Delete using a cursor. 00248 * 00249 * PUBLIC: int CDB___db_c_del __P((DBC *, u_int32_t)); 00250 */ 00251 int 00252 CDB___db_c_del(dbc, flags) 00253 DBC *dbc; 00254 u_int32_t flags; 00255 { 00256 DB *dbp; 00257 DBC *opd; 00258 int ret; 00259 00260 /* 00261 * Cursor Cleanup Note: 00262 * All of the cursors passed to the underlying access methods by this 00263 * routine are not duplicated and will not be cleaned up on return. 00264 * So, pages/locks that the cursor references must be resolved by the 00265 * underlying functions. 00266 */ 00267 dbp = dbc->dbp; 00268 00269 PANIC_CHECK(dbp->dbenv); 00270 00271 /* Check for invalid flags. */ 00272 if ((ret = CDB___db_cdelchk(dbp, flags, 00273 F_ISSET(dbp, DB_AM_RDONLY), IS_INITIALIZED(dbc))) != 0) 00274 return (ret); 00275 00276 DEBUG_LWRITE(dbc, dbc->txn, "db_c_del", NULL, NULL, flags); 00277 00278 LOCKING_INIT(dbp, dbc); 00279 00280 /* 00281 * Off-page duplicate trees are locked in the primary tree, that is, 00282 * we acquire a write lock in the primary tree and no locks in the 00283 * off-page dup tree. If the del operation is done in an off-page 00284 * duplicate tree, call the primary cursor's upgrade routine first. 00285 */ 00286 opd = dbc->internal->opd; 00287 if (opd == NULL) 00288 ret = dbc->c_am_del(dbc); 00289 else 00290 if ((ret = dbc->c_am_writelock(dbc)) == 0) 00291 ret = opd->c_am_del(opd); 00292 00293 LOCKING_DONE(dbp, dbc); 00294 00295 return (ret); 00296 } 00297 00298 /* 00299 * CDB___db_c_dup -- 00300 * Duplicate a cursor 00301 * 00302 * PUBLIC: int CDB___db_c_dup __P((DBC *, DBC **, u_int32_t)); 00303 */ 00304 int 00305 CDB___db_c_dup(dbc_orig, dbcp, flags) 00306 DBC *dbc_orig; 00307 DBC **dbcp; 00308 u_int32_t flags; 00309 { 00310 DB_ENV *dbenv; 00311 DB *dbp; 00312 DBC *dbc_n, *dbc_nopd; 00313 int ret; 00314 00315 dbp = dbc_orig->dbp; 00316 dbenv = dbp->dbenv; 00317 dbc_n = dbc_nopd = NULL; 00318 00319 PANIC_CHECK(dbp->dbenv); 00320 00321 /* 00322 * We can never have two write cursors open in CDB, so do not 00323 * allow duplication of a write cursor. 00324 */ 00325 if (flags != DB_POSITIONI && 00326 F_ISSET(dbc_orig, DBC_WRITER | DBC_WRITECURSOR)) { 00327 CDB___db_err(dbenv, "Cannot duplicate writeable cursor"); 00328 return (EINVAL); 00329 } 00330 00331 /* Allocate a new cursor and initialize it. */ 00332 if ((ret = __db_c_idup(dbc_orig, &dbc_n, flags)) != 0) 00333 goto err; 00334 *dbcp = dbc_n; 00335 00336 /* 00337 * If we're in CDB, and this isn't an internal duplication (in which 00338 * case we're explicitly overriding CDB locking), the duplicated 00339 * cursor needs its own read lock. (We know it's not a write cursor 00340 * because we wouldn't have made it this far; you can't dup them.) 00341 */ 00342 if (LOCKING(dbenv) && flags != DB_POSITIONI) { 00343 DB_ASSERT(!F_ISSET(dbc_orig, DBC_WRITER | DBC_WRITECURSOR)); 00344 00345 if ((ret = CDB_lock_get(dbenv, dbc_n->locker, 0, 00346 &dbc_n->lock_dbt, DB_LOCK_READ, &dbc_n->mylock)) != 0) { 00347 (void)CDB___db_c_close(dbc_n); 00348 return (ret); 00349 } 00350 } 00351 00352 /* 00353 * If the cursor references an off-page duplicate tree, allocate a 00354 * new cursor for that tree and initialize it. 00355 */ 00356 if (dbc_orig->internal->opd != NULL) { 00357 if ((ret = 00358 __db_c_idup(dbc_orig->internal->opd, &dbc_nopd, flags)) != 0) 00359 goto err; 00360 dbc_n->internal->opd = dbc_nopd; 00361 } 00362 00363 return (0); 00364 00365 err: if (dbc_n != NULL) 00366 (void)dbc_n->c_close(dbc_n); 00367 if (dbc_nopd != NULL) 00368 (void)dbc_nopd->c_close(dbc_nopd); 00369 00370 return (ret); 00371 } 00372 00373 /* 00374 * __db_c_idup -- 00375 * Internal version of CDB___db_c_dup. 00376 */ 00377 static int 00378 __db_c_idup(dbc_orig, dbcp, flags) 00379 DBC *dbc_orig, **dbcp; 00380 u_int32_t flags; 00381 { 00382 DB *dbp; 00383 DBC *dbc_n; 00384 DBC_INTERNAL *int_n, *int_orig; 00385 int ret; 00386 00387 dbp = dbc_orig->dbp; 00388 dbc_n = *dbcp; 00389 00390 if ((ret = CDB___db_icursor(dbp, dbc_orig->txn, dbc_orig->dbtype, 00391 dbc_orig->internal->root, F_ISSET(dbc_orig, DBC_OPD), &dbc_n)) != 0) 00392 return (ret); 00393 00394 dbc_n->locker = dbc_orig->locker; 00395 00396 /* If the user wants the cursor positioned, do it here. */ 00397 if (flags == DB_POSITION || flags == DB_POSITIONI) { 00398 int_n = dbc_n->internal; 00399 int_orig = dbc_orig->internal; 00400 00401 dbc_n->flags = dbc_orig->flags; 00402 00403 int_n->indx = int_orig->indx; 00404 int_n->pgno = int_orig->pgno; 00405 int_n->root = int_orig->root; 00406 00407 switch (dbc_orig->dbtype) { 00408 case DB_QUEUE: 00409 if ((ret = CDB___qam_c_dup(dbc_orig, dbc_n)) != 0) 00410 goto err; 00411 break; 00412 case DB_BTREE: 00413 case DB_RECNO: 00414 if ((ret = CDB___bam_c_dup(dbc_orig, dbc_n)) != 0) 00415 goto err; 00416 break; 00417 case DB_HASH: 00418 if ((ret = CDB___ham_c_dup(dbc_orig, dbc_n)) != 0) 00419 goto err; 00420 break; 00421 default: 00422 ret = CDB___db_unknown_type(dbp->dbenv, 00423 "__db_c_idup", dbc_orig->dbtype); 00424 goto err; 00425 } 00426 } 00427 00428 *dbcp = dbc_n; 00429 return (0); 00430 00431 err: (void)dbc_n->c_close(dbc_n); 00432 return (ret); 00433 } 00434 00435 /* 00436 * CDB___db_c_get -- 00437 * Get using a cursor. 00438 * 00439 * PUBLIC: int CDB___db_c_get __P((DBC *, DBT *, DBT *, u_int32_t)); 00440 */ 00441 int 00442 CDB___db_c_get(dbc_arg, key, data, flags) 00443 DBC *dbc_arg; 00444 DBT *key, *data; 00445 u_int32_t flags; 00446 { 00447 DB *dbp; 00448 DBC *dbc, *dbc_n, *opd; 00449 DBC_INTERNAL *cp, *cp_n; 00450 db_pgno_t pgno; 00451 u_int32_t tmp_flags, tmp_rmw; 00452 u_int8_t type; 00453 int ret, t_ret; 00454 00455 /* 00456 * Cursor Cleanup Note: 00457 * All of the cursors passed to the underlying access methods by this 00458 * routine are duplicated cursors. On return, any referenced pages 00459 * will be discarded, and, if the cursor is not intended to be used 00460 * again, the close function will be called. So, pages/locks that 00461 * the cursor references do not need to be resolved by the underlying 00462 * functions. 00463 */ 00464 dbp = dbc_arg->dbp; 00465 dbc_n = NULL; 00466 opd = NULL; 00467 00468 PANIC_CHECK(dbp->dbenv); 00469 00470 /* Check for invalid flags. */ 00471 if ((ret = 00472 CDB___db_cgetchk(dbp, key, data, flags, IS_INITIALIZED(dbc_arg))) != 0) 00473 return (ret); 00474 00475 /* Clear OR'd in additional bits so we can check for flag equality. */ 00476 tmp_rmw = LF_ISSET(DB_RMW); 00477 LF_CLR(DB_RMW); 00478 00479 DEBUG_LREAD(dbc_arg, dbc_arg->txn, "db_c_get", 00480 flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags); 00481 00482 /* 00483 * Return a cursor's record number. It has nothing to do with the 00484 * cursor get code except that it was put into the interface. 00485 */ 00486 if (flags == DB_GET_RECNO) 00487 return (CDB___bam_c_rget(dbc_arg, data, flags | tmp_rmw)); 00488 00489 /* 00490 * If we have an off-page duplicates cursor, and the operation applies 00491 * to it, perform the operation. Duplicate the cursor and call the 00492 * underlying function. 00493 * 00494 * Off-page duplicate trees are locked in the primary tree, that is, 00495 * we acquire a write lock in the primary tree and no locks in the 00496 * off-page dup tree. If the DB_RMW flag was specified and the get 00497 * operation is done in an off-page duplicate tree, call the primary 00498 * cursor's upgrade routine first. 00499 */ 00500 cp = dbc_arg->internal; 00501 if (cp->opd != NULL && 00502 (flags == DB_CURRENT || flags == DB_GET_BOTHC || 00503 flags == DB_NEXT || flags == DB_NEXT_DUP || flags == DB_PREV)) { 00504 if (tmp_rmw && (ret = dbc_arg->c_am_writelock(dbc_arg)) != 0) 00505 return (ret); 00506 if ((ret = __db_c_idup(cp->opd, &opd, DB_POSITIONI)) != 0) 00507 return (ret); 00508 00509 /* 00510 * If we're in CDB, the newly dup'ed off-page dup cursor 00511 * may need the original outer cursor's locking info. 00512 */ 00513 if (LOCKING(dbp->dbenv)) 00514 (void)CDB___db_cdb_cdup(dbc_arg, opd); 00515 00516 switch (ret = opd->c_am_get( 00517 opd, key, data, flags, NULL)) { 00518 case 0: 00519 goto done; 00520 case DB_NOTFOUND: 00521 /* 00522 * Translate DB_NOTFOUND failures for the DB_NEXT and 00523 * DB_PREV operations into a subsequent operation on 00524 * the parent cursor. 00525 */ 00526 if (flags == DB_NEXT || flags == DB_PREV) { 00527 if ((ret = opd->c_close(opd)) != 0) 00528 goto err; 00529 opd = NULL; 00530 break; 00531 } 00532 goto err; 00533 default: 00534 goto err; 00535 } 00536 } 00537 00538 /* 00539 * Perform an operation on the CDB_main cursor. Duplicate the cursor, 00540 * upgrade the lock as required, and call the underlying function. 00541 */ 00542 switch (flags) { 00543 case DB_CURRENT: 00544 case DB_GET_BOTHC: 00545 case DB_NEXT: 00546 case DB_NEXT_DUP: 00547 case DB_NEXT_NODUP: 00548 case DB_PREV: 00549 case DB_PREV_NODUP: 00550 tmp_flags = DB_POSITIONI; 00551 break; 00552 default: 00553 tmp_flags = 0; 00554 break; 00555 } 00556 if ((ret = __db_c_idup(dbc_arg, &dbc_n, tmp_flags)) != 0) 00557 goto err; 00558 00559 /* 00560 * If we're in CDB, the new cursor may need the old cursor's locking 00561 * info. 00562 */ 00563 if (LOCKING(dbp->dbenv)) 00564 (void)CDB___db_cdb_cdup(dbc_arg, dbc_n); 00565 00566 if (tmp_rmw) 00567 F_SET(dbc_n, DBC_RMW); 00568 pgno = PGNO_INVALID; 00569 ret = dbc_n->c_am_get(dbc_n, key, data, flags, &pgno); 00570 if (tmp_rmw) 00571 F_CLR(dbc_n, DBC_RMW); 00572 if (ret != 0) 00573 goto err; 00574 00575 cp_n = dbc_n->internal; 00576 00577 /* 00578 * We may be referencing a new off-page duplicates tree. Acquire 00579 * a new cursor and call the underlying function. 00580 */ 00581 if (pgno != PGNO_INVALID) { 00582 if ((ret = CDB___db_icursor(dbp, dbc_arg->txn, 00583 dbp->dup_compare == NULL ? DB_RECNO : DB_BTREE, 00584 pgno, 1, &cp_n->opd)) != 0) 00585 goto err; 00586 00587 switch (flags) { 00588 case DB_FIRST: 00589 case DB_NEXT: 00590 case DB_NEXT_NODUP: 00591 case DB_SET: 00592 case DB_SET_RECNO: 00593 case DB_SET_RANGE: 00594 tmp_flags = DB_FIRST; 00595 break; 00596 case DB_LAST: 00597 case DB_PREV: 00598 case DB_PREV_NODUP: 00599 tmp_flags = DB_LAST; 00600 break; 00601 case DB_GET_BOTH: 00602 tmp_flags = DB_GET_BOTH; 00603 break; 00604 case DB_GET_BOTHC: 00605 tmp_flags = DB_GET_BOTHC; 00606 break; 00607 default: 00608 ret = 00609 CDB___db_unknown_flag(dbp->dbenv, "CDB___db_c_get", flags); 00610 goto err; 00611 } 00612 if ((ret = cp_n->opd->c_am_get( 00613 cp_n->opd, key, data, tmp_flags, NULL)) != 0) 00614 goto err; 00615 } 00616 00617 done: /* 00618 * Return a key/data item. The only exception is that we don't return 00619 * a key if the user already gave us one, that is, if the DB_SET flag 00620 * was set. The DB_SET flag is necessary. In a Btree, the user's key 00621 * doesn't have to be the same as the key stored the tree, depending on 00622 * the magic performed by the comparison function. As we may not have 00623 * done any key-oriented operation here, the page reference may not be 00624 * valid. Fill it in as necessary. We don't have to worry about any 00625 * locks, the cursor must already be holding appropriate locks. 00626 * 00627 * XXX 00628 * If not a Btree and DB_SET_RANGE is set, we shouldn't return a key 00629 * either, should we? 00630 */ 00631 cp_n = dbc_n == NULL ? dbc_arg->internal : dbc_n->internal; 00632 if (!F_ISSET(key, DB_DBT_ISSET)) { 00633 if (cp_n->page == NULL && (ret = 00634 CDB_memp_fget(dbp->mpf, &cp_n->pgno, 0, &cp_n->page)) != 0) 00635 goto err; 00636 00637 if ((ret = CDB___db_ret(dbp, cp_n->page, cp_n->indx, 00638 key, &dbc_arg->rkey.data, &dbc_arg->rkey.ulen)) != 0) 00639 goto err; 00640 } 00641 dbc = opd != NULL ? opd : cp_n->opd != NULL ? cp_n->opd : dbc_n; 00642 if (!F_ISSET(data, DB_DBT_ISSET)) { 00643 type = TYPE(dbc->internal->page); 00644 ret = CDB___db_ret(dbp, dbc->internal->page, dbc->internal->indx + 00645 (type == P_LBTREE || type == P_HASH ? O_INDX : 0), 00646 data, &dbc_arg->rdata.data, &dbc_arg->rdata.ulen); 00647 } 00648 00649 err: /* Don't pass DB_DBT_ISSET back to application level, error or no. */ 00650 F_CLR(key, DB_DBT_ISSET); 00651 F_CLR(data, DB_DBT_ISSET); 00652 00653 /* Cleanup and cursor resolution. */ 00654 if (opd != NULL) { 00655 if ((t_ret = 00656 __db_c_cleanup(dbc_arg->internal->opd, 00657 opd, ret)) != 0 && ret == 0) 00658 ret = t_ret; 00659 00660 } 00661 00662 if ((t_ret = __db_c_cleanup(dbc_arg, dbc_n, ret)) != 0 && ret == 0) 00663 ret = t_ret; 00664 00665 return (ret); 00666 } 00667 00668 /* 00669 * CDB___db_c_put -- 00670 * Put using a cursor. 00671 * 00672 * PUBLIC: int CDB___db_c_put __P((DBC *, DBT *, DBT *, u_int32_t)); 00673 */ 00674 int 00675 CDB___db_c_put(dbc_arg, key, data, flags) 00676 DBC *dbc_arg; 00677 DBT *key, *data; 00678 u_int32_t flags; 00679 { 00680 DB *dbp; 00681 DBC *dbc_n, *opd; 00682 db_pgno_t pgno; 00683 u_int32_t tmp_flags; 00684 int ret, t_ret; 00685 00686 /* 00687 * Cursor Cleanup Note: 00688 * All of the cursors passed to the underlying access methods by this 00689 * routine are duplicated cursors. On return, any referenced pages 00690 * will be discarded, and, if the cursor is not intended to be used 00691 * again, the close function will be called. So, pages/locks that 00692 * the cursor references do not need to be resolved by the underlying 00693 * functions. 00694 */ 00695 dbp = dbc_arg->dbp; 00696 dbc_n = NULL; 00697 00698 PANIC_CHECK(dbp->dbenv); 00699 00700 /* Check for invalid flags. */ 00701 if ((ret = CDB___db_cputchk(dbp, key, data, flags, 00702 F_ISSET(dbp, DB_AM_RDONLY), IS_INITIALIZED(dbc_arg))) != 0) 00703 return (ret); 00704 00705 DEBUG_LWRITE(dbc_arg, dbc_arg->txn, "db_c_put", 00706 flags == DB_KEYFIRST || flags == DB_KEYLAST || 00707 flags == DB_NODUPDATA ? key : NULL, data, flags); 00708 00709 LOCKING_INIT(dbp, dbc_arg); 00710 00711 /* 00712 * If we have an off-page duplicates cursor, and the operation applies 00713 * to it, perform the operation. Duplicate the cursor and call the 00714 * underlying function. 00715 * 00716 * Off-page duplicate trees are locked in the primary tree, that is, 00717 * we acquire a write lock in the primary tree and no locks in the 00718 * off-page dup tree. If the put operation is done in an off-page 00719 * duplicate tree, call the primary cursor's upgrade routine first. 00720 */ 00721 if (dbc_arg->internal->opd != NULL && 00722 (flags == DB_AFTER || flags == DB_BEFORE || flags == DB_CURRENT)) { 00723 if ((ret = dbc_arg->c_am_writelock(dbc_arg)) != 0) 00724 return (ret); 00725 if ((ret = CDB___db_c_dup(dbc_arg, &dbc_n, DB_POSITIONI)) != 0) 00726 goto err; 00727 opd = dbc_n->internal->opd; 00728 if ((ret = opd->c_am_put( 00729 opd, key, data, flags, NULL)) != 0) 00730 goto err; 00731 goto done; 00732 } 00733 00734 /* 00735 * Perform an operation on the CDB_main cursor. Duplicate the cursor, 00736 * and call the underlying function. 00737 * 00738 * XXX: MARGO 00739 * 00740 tmp_flags = flags == DB_AFTER || 00741 flags == DB_BEFORE || flags == DB_CURRENT ? DB_POSITIONI : 0; 00742 */ 00743 tmp_flags = DB_POSITIONI; 00744 00745 if ((ret = __db_c_idup(dbc_arg, &dbc_n, tmp_flags)) != 0) 00746 goto err; 00747 pgno = PGNO_INVALID; 00748 if ((ret = dbc_n->c_am_put(dbc_n, key, data, flags, &pgno)) != 0) 00749 goto err; 00750 00751 /* 00752 * We may be referencing a new off-page duplicates tree. Acquire 00753 * a new cursor and call the underlying function. 00754 */ 00755 if (pgno != PGNO_INVALID) { 00756 if ((ret = CDB___db_icursor(dbp, dbc_arg->txn, 00757 dbp->dup_compare == NULL ? DB_RECNO : DB_BTREE, 00758 pgno, 1, &dbc_n->internal->opd)) != 0) 00759 goto err; 00760 00761 opd = dbc_n->internal->opd; 00762 if ((ret = opd->c_am_put( 00763 opd, key, data, flags, NULL)) != 0) 00764 goto err; 00765 } 00766 00767 done: 00768 err: /* Cleanup and cursor resolution. */ 00769 if ((t_ret = __db_c_cleanup(dbc_arg, dbc_n, ret)) != 0 && ret == 0) 00770 ret = t_ret; 00771 00772 LOCKING_DONE(dbp, dbc_arg); 00773 00774 return (ret); 00775 } 00776 00777 /* 00778 * CDB___db_duperr() 00779 * Error message: we don't currently support sorted duplicate duplicates. 00780 * PUBLIC: int CDB___db_duperr __P((DB *, u_int32_t)); 00781 */ 00782 int 00783 CDB___db_duperr(dbp, flags) 00784 DB *dbp; 00785 u_int32_t flags; 00786 { 00787 if (flags != DB_NODUPDATA) 00788 CDB___db_err(dbp->dbenv, 00789 "Duplicate data items are not supported with sorted data"); 00790 return (DB_KEYEXIST); 00791 } 00792 00793 /* 00794 * __db_c_cleanup -- 00795 * Clean up duplicate cursors. 00796 */ 00797 static int 00798 __db_c_cleanup(dbc, dbc_n, failed) 00799 DBC *dbc, *dbc_n; 00800 int failed; 00801 { 00802 DB *dbp; 00803 DBC *opd; 00804 DBC_INTERNAL *internal; 00805 int ret, t_ret; 00806 00807 dbp = dbc->dbp; 00808 internal = dbc->internal; 00809 ret = 0; 00810 00811 /* Discard any pages we're holding. */ 00812 if (internal->page != NULL) { 00813 if ((t_ret = 00814 CDB_memp_fput(dbp->mpf, internal->page, 0)) != 0 && ret == 0) 00815 ret = t_ret; 00816 internal->page = NULL; 00817 } 00818 opd = internal->opd; 00819 if (opd != NULL && opd->internal->page != NULL) { 00820 if ((t_ret = CDB_memp_fput(dbp->mpf, 00821 opd->internal->page, 0)) != 0 && ret == 0) 00822 ret = t_ret; 00823 opd->internal->page = NULL; 00824 } 00825 00826 if (dbc_n == NULL) 00827 return (ret); 00828 00829 if (dbc_n->internal->page != NULL) { 00830 if ((t_ret = CDB_memp_fput(dbp->mpf, 00831 dbc_n->internal->page, 0)) != 0 && ret == 0) 00832 ret = t_ret; 00833 dbc_n->internal->page = NULL; 00834 } 00835 opd = dbc_n->internal->opd; 00836 if (opd != NULL && opd->internal->page != NULL) { 00837 if ((t_ret = CDB_memp_fput(dbp->mpf, 00838 opd->internal->page, 0)) != 0 && ret == 0) 00839 ret = t_ret; 00840 opd->internal->page = NULL; 00841 } 00842 00843 /* 00844 * If we didn't fail before entering this routine or just now when 00845 * freeing pages, swap the interesting contents of the old and new 00846 * cursors. 00847 */ 00848 if (!failed && ret == 0) { 00849 dbc->internal = dbc_n->internal; 00850 dbc_n->internal = internal; 00851 } 00852 00853 /* 00854 * Close the cursor we don't care about anymore. The close can fail, 00855 * but we only expect DB_LOCK_DEADLOCK failures. This violates our 00856 * "the cursor is unchanged on error" semantics, but since all you can 00857 * do with a DB_LOCK_DEADLOCK failure is close the cursor, I believe 00858 * that's OK. 00859 * 00860 * XXX 00861 * There's no way to recover from failure to close the old cursor. 00862 * All we can do is move to the new position and return an error. 00863 * 00864 * XXX 00865 * We might want to consider adding a flag to the cursor, so that any 00866 * subsequent operations other than close just return an error? 00867 */ 00868 if ((t_ret = dbc_n->c_close(dbc_n)) != 0 && ret == 0) 00869 ret = t_ret; 00870 00871 return (ret); 00872 } 00873 00874 /* 00875 * CDB___db_cdb_cdup -- 00876 * Duplicate the internal lock of a CDB write cursor. The method- 00877 * independent cursor get and put code duplicate the cursor before 00878 * performing operations on it, using the internal cursor interface, which 00879 * does no CDB locking. Under normal circumstances this is desirable; 00880 * there's no need for an additional lock, as the original cursor 00881 * is extant--and its lock is held--throughout, and there's never a 00882 * need to perform locking operations on the new cursor. 00883 * 00884 * The sole exception to this is in the case of a DBC->c_get with a 00885 * write cursor. Here, the cursor holds only an IWRITE lock when it 00886 * is duplicated; in the common case, there's never a need to 00887 * perform a write. If, however, the cursor moves away from a 00888 * deleted item in a btree, the btree close method will attempt to 00889 * upgrade the lock to a WRITE. This close happens on the _duplicated_ 00890 * cursor, so we use this function to provide it with a copy of the 00891 * lock. (The lock structure itself doesn't change on an 00892 * upgrade/downgrade, so simply copying and later discarding is 00893 * sufficient.) 00894 * 00895 * PUBLIC: int CDB___db_cdb_cdup __P((DBC *, DBC *)); 00896 */ 00897 int 00898 CDB___db_cdb_cdup(dbc_orig, dbc_n) 00899 DBC *dbc_orig, *dbc_n; 00900 { 00901 if (F_ISSET(dbc_orig, DBC_WRITECURSOR | DBC_WRITEDUP)) { 00902 memcpy(&dbc_n->mylock, &dbc_orig->mylock, 00903 sizeof(dbc_orig->mylock)); 00904 00905 /* 00906 * dbc_n's locker may be different, since if it's an off-page 00907 * duplicate it may not be an idup'ed copy of dbc_orig. It's 00908 * not meaningful, though, so overwrite it with dbc_orig's so 00909 * we don't self-deadlock. 00910 */ 00911 dbc_n->locker = dbc_orig->locker; 00912 00913 /* 00914 * Flag that this lock isn't ours to put; just discard it 00915 * in c_close. 00916 */ 00917 F_SET(dbc_n, DBC_WRITEDUP); 00918 } 00919 00920 return (0); 00921 } 00922 00923 /* 00924 * __db_wrlock_err -- do not have a write lock. 00925 */ 00926 static int 00927 __db_wrlock_err(dbenv) 00928 DB_ENV *dbenv; 00929 { 00930 CDB___db_err(dbenv, "Write attempted on read-only cursor"); 00931 return (EPERM); 00932 }