db_am.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: db_am.c,v 11.42 2001/01/11 18:19:50 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "db_page.h"
  17. #include "db_shash.h"
  18. #include "btree.h"
  19. #include "hash.h"
  20. #include "qam.h"
  21. #include "lock.h"
  22. #include "mp.h"
  23. #include "txn.h"
  24. #include "db_am.h"
  25. #include "db_ext.h"
  26. /*
  27.  * __db_cursor --
  28.  * Allocate and return a cursor.
  29.  *
  30.  * PUBLIC: int __db_cursor __P((DB *, DB_TXN *, DBC **, u_int32_t));
  31.  */
  32. int
  33. __db_cursor(dbp, txn, dbcp, flags)
  34. DB *dbp;
  35. DB_TXN *txn;
  36. DBC **dbcp;
  37. u_int32_t flags;
  38. {
  39. DB_ENV *dbenv;
  40. DBC *dbc;
  41. db_lockmode_t mode;
  42. u_int32_t op;
  43. int ret;
  44. dbenv = dbp->dbenv;
  45. PANIC_CHECK(dbenv);
  46. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->cursor");
  47. /* Check for invalid flags. */
  48. if ((ret = __db_cursorchk(dbp, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0)
  49. return (ret);
  50. if ((ret =
  51.     __db_icursor(dbp, txn, dbp->type, PGNO_INVALID, 0, dbcp)) != 0)
  52. return (ret);
  53. dbc = *dbcp;
  54. /*
  55.  * If this is CDB, do all the locking in the interface, which is
  56.  * right here.
  57.  */
  58. if (CDB_LOCKING(dbenv)) {
  59. op = LF_ISSET(DB_OPFLAGS_MASK);
  60. mode = (op == DB_WRITELOCK) ? DB_LOCK_WRITE :
  61.     ((op == DB_WRITECURSOR) ? DB_LOCK_IWRITE : DB_LOCK_READ);
  62. if ((ret = lock_get(dbenv, dbc->locker, 0,
  63.     &dbc->lock_dbt, mode, &dbc->mylock)) != 0) {
  64. (void)__db_c_close(dbc);
  65. return (ret);
  66. }
  67. if (op == DB_WRITECURSOR)
  68. F_SET(dbc, DBC_WRITECURSOR);
  69. if (op == DB_WRITELOCK)
  70. F_SET(dbc, DBC_WRITER);
  71. }
  72. return (0);
  73. }
  74. /*
  75.  * __db_icursor --
  76.  * Internal version of __db_cursor.  If dbcp is
  77.  * non-NULL it is assumed to point to an area to
  78.  * initialize as a cursor.
  79.  *
  80.  * PUBLIC: int __db_icursor
  81.  * PUBLIC:     __P((DB *, DB_TXN *, DBTYPE, db_pgno_t, int, DBC **));
  82.  */
  83. int
  84. __db_icursor(dbp, txn, dbtype, root, is_opd, dbcp)
  85. DB *dbp;
  86. DB_TXN *txn;
  87. DBTYPE dbtype;
  88. db_pgno_t root;
  89. int is_opd;
  90. DBC **dbcp;
  91. {
  92. DBC *dbc, *adbc;
  93. DBC_INTERNAL *cp;
  94. DB_ENV *dbenv;
  95. int allocated, ret;
  96. dbenv = dbp->dbenv;
  97. allocated = 0;
  98. /*
  99.  * Take one from the free list if it's available.  Take only the
  100.  * right type.  With off page dups we may have different kinds
  101.  * of cursors on the queue for a single database.
  102.  */
  103. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  104. for (dbc = TAILQ_FIRST(&dbp->free_queue);
  105.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links))
  106. if (dbtype == dbc->dbtype) {
  107. TAILQ_REMOVE(&dbp->free_queue, dbc, links);
  108. dbc->flags = 0;
  109. break;
  110. }
  111. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  112. if (dbc == NULL) {
  113. if ((ret = __os_calloc(dbp->dbenv, 1, sizeof(DBC), &dbc)) != 0)
  114. return (ret);
  115. allocated = 1;
  116. dbc->flags = 0;
  117. dbc->dbp = dbp;
  118. /* Set up locking information. */
  119. if (LOCKING_ON(dbenv)) {
  120. /*
  121.  * If we are not threaded, then there is no need to
  122.  * create new locker ids.  We know that no one else
  123.  * is running concurrently using this DB, so we can
  124.  * take a peek at any cursors on the active queue.
  125.  */
  126. if (!DB_IS_THREADED(dbp) &&
  127.     (adbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
  128. dbc->lid = adbc->lid;
  129. else
  130. if ((ret = lock_id(dbenv, &dbc->lid)) != 0)
  131. goto err;
  132. memcpy(dbc->lock.fileid, dbp->fileid, DB_FILE_ID_LEN);
  133. if (CDB_LOCKING(dbenv)) {
  134. if (F_ISSET(dbenv, DB_ENV_CDB_ALLDB)) {
  135. /*
  136.  * If we are doing a single lock per
  137.  * environment, set up the global
  138.  * lock object just like we do to
  139.  * single thread creates.
  140.  */
  141. DB_ASSERT(sizeof(db_pgno_t) ==
  142.     sizeof(u_int32_t));
  143. dbc->lock_dbt.size = sizeof(u_int32_t);
  144. dbc->lock_dbt.data = &dbc->lock.pgno;
  145. dbc->lock.pgno = 0;
  146. } else {
  147. dbc->lock_dbt.size = DB_FILE_ID_LEN;
  148. dbc->lock_dbt.data = dbc->lock.fileid;
  149. }
  150. } else {
  151. dbc->lock.type = DB_PAGE_LOCK;
  152. dbc->lock_dbt.size = sizeof(dbc->lock);
  153. dbc->lock_dbt.data = &dbc->lock;
  154. }
  155. }
  156. /* Init the DBC internal structure. */
  157. switch (dbtype) {
  158. case DB_BTREE:
  159. case DB_RECNO:
  160. if ((ret = __bam_c_init(dbc, dbtype)) != 0)
  161. goto err;
  162. break;
  163. case DB_HASH:
  164. if ((ret = __ham_c_init(dbc)) != 0)
  165. goto err;
  166. break;
  167. case DB_QUEUE:
  168. if ((ret = __qam_c_init(dbc)) != 0)
  169. goto err;
  170. break;
  171. default:
  172. ret = __db_unknown_type(dbp->dbenv,
  173.     "__db_icursor", dbtype);
  174. goto err;
  175. }
  176. cp = dbc->internal;
  177. }
  178. /* Refresh the DBC structure. */
  179. dbc->dbtype = dbtype;
  180. if ((dbc->txn = txn) == NULL)
  181. dbc->locker = dbc->lid;
  182. else {
  183. dbc->locker = txn->txnid;
  184. txn->cursors++;
  185. }
  186. if (is_opd)
  187. F_SET(dbc, DBC_OPD);
  188. if (F_ISSET(dbp, DB_AM_RECOVER))
  189. F_SET(dbc, DBC_RECOVER);
  190. /* Refresh the DBC internal structure. */
  191. cp = dbc->internal;
  192. cp->opd = NULL;
  193. cp->indx = 0;
  194. cp->page = NULL;
  195. cp->pgno = PGNO_INVALID;
  196. cp->root = root;
  197. switch (dbtype) {
  198. case DB_BTREE:
  199. case DB_RECNO:
  200. if ((ret = __bam_c_refresh(dbc)) != 0)
  201. goto err;
  202. break;
  203. case DB_HASH:
  204. case DB_QUEUE:
  205. break;
  206. default:
  207. ret = __db_unknown_type(dbp->dbenv, "__db_icursor", dbp->type);
  208. goto err;
  209. }
  210. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  211. TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links);
  212. F_SET(dbc, DBC_ACTIVE);
  213. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  214. *dbcp = dbc;
  215. return (0);
  216. err: if (allocated)
  217. __os_free(dbc, sizeof(*dbc));
  218. return (ret);
  219. }
  220. #ifdef DEBUG
  221. /*
  222.  * __db_cprint --
  223.  * Display the current cursor list.
  224.  *
  225.  * PUBLIC: int __db_cprint __P((DB *));
  226.  */
  227. int
  228. __db_cprint(dbp)
  229. DB *dbp;
  230. {
  231. static const FN fn[] = {
  232. { DBC_ACTIVE, "active" },
  233. { DBC_OPD, "off-page-dup" },
  234. { DBC_RECOVER, "recover" },
  235. { DBC_RMW, "read-modify-write" },
  236. { DBC_WRITECURSOR, "write cursor" },
  237. { DBC_WRITEDUP, "internally dup'ed write cursor" },
  238. { DBC_WRITER, "short-term write cursor" },
  239. { 0, NULL }
  240. };
  241. DBC *dbc;
  242. DBC_INTERNAL *cp;
  243. char *s;
  244. MUTEX_THREAD_LOCK(dbp->dbenv, dbp->mutexp);
  245. for (dbc = TAILQ_FIRST(&dbp->active_queue);
  246.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
  247. switch (dbc->dbtype) {
  248. case DB_BTREE:
  249. s = "btree";
  250. break;
  251. case DB_HASH:
  252. s = "hash";
  253. break;
  254. case DB_RECNO:
  255. s = "recno";
  256. break;
  257. case DB_QUEUE:
  258. s = "queue";
  259. break;
  260. default:
  261. DB_ASSERT(0);
  262. return (1);
  263. }
  264. cp = dbc->internal;
  265. fprintf(stderr, "%s/%#0lx: opd: %#0lxn",
  266.     s, P_TO_ULONG(dbc), P_TO_ULONG(cp->opd));
  267. fprintf(stderr, "ttxn: %#0lx lid: %lu locker: %lun",
  268.     P_TO_ULONG(dbc->txn),
  269.     (u_long)dbc->lid, (u_long)dbc->locker);
  270. fprintf(stderr, "troot: %lu page/index: %lu/%lu",
  271.     (u_long)cp->root, (u_long)cp->pgno, (u_long)cp->indx);
  272. __db_prflags(dbc->flags, fn, stderr);
  273. fprintf(stderr, "n");
  274. if (dbp->type == DB_BTREE)
  275. __bam_cprint(dbc);
  276. }
  277. for (dbc = TAILQ_FIRST(&dbp->free_queue);
  278.     dbc != NULL; dbc = TAILQ_NEXT(dbc, links))
  279. fprintf(stderr, "free: %#0lx ", P_TO_ULONG(dbc));
  280. fprintf(stderr, "n");
  281. MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp);
  282. return (0);
  283. }
  284. #endif /* DEBUG */
  285. /*
  286.  * db_fd --
  287.  * Return a file descriptor for flock'ing.
  288.  *
  289.  * PUBLIC: int __db_fd __P((DB *, int *));
  290.  */
  291. int
  292. __db_fd(dbp, fdp)
  293. DB *dbp;
  294. int *fdp;
  295. {
  296. DB_FH *fhp;
  297. int ret;
  298. PANIC_CHECK(dbp->dbenv);
  299. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->fd");
  300. /*
  301.  * XXX
  302.  * Truly spectacular layering violation.
  303.  */
  304. if ((ret = __mp_xxx_fh(dbp->mpf, &fhp)) != 0)
  305. return (ret);
  306. if (F_ISSET(fhp, DB_FH_VALID)) {
  307. *fdp = fhp->fd;
  308. return (0);
  309. } else {
  310. *fdp = -1;
  311. __db_err(dbp->dbenv, "DB does not have a valid file handle.");
  312. return (ENOENT);
  313. }
  314. }
  315. /*
  316.  * __db_get --
  317.  * Return a key/data pair.
  318.  *
  319.  * PUBLIC: int __db_get __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
  320.  */
  321. int
  322. __db_get(dbp, txn, key, data, flags)
  323. DB *dbp;
  324. DB_TXN *txn;
  325. DBT *key, *data;
  326. u_int32_t flags;
  327. {
  328. DBC *dbc;
  329. int mode, ret, t_ret;
  330. PANIC_CHECK(dbp->dbenv);
  331. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->get");
  332. if ((ret = __db_getchk(dbp, key, data, flags)) != 0)
  333. return (ret);
  334. mode = 0;
  335. if (flags == DB_CONSUME || flags == DB_CONSUME_WAIT)
  336. mode = DB_WRITELOCK;
  337. if ((ret = dbp->cursor(dbp, txn, &dbc, mode)) != 0)
  338. return (ret);
  339. DEBUG_LREAD(dbc, txn, "__db_get", key, NULL, flags);
  340. /*
  341.  * The DBC_TRANSIENT flag indicates that we're just doing a
  342.  * single operation with this cursor, and that in case of
  343.  * error we don't need to restore it to its old position--we're
  344.  * going to close it right away.  Thus, we can perform the get
  345.  * without duplicating the cursor, saving some cycles in this
  346.  * common case.
  347.  */
  348. F_SET(dbc, DBC_TRANSIENT);
  349. ret = dbc->c_get(dbc, key, data,
  350.     flags == 0 || flags == DB_RMW ? flags | DB_SET : flags);
  351. if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
  352. ret = t_ret;
  353. return (ret);
  354. }
  355. /*
  356.  * __db_put --
  357.  * Store a key/data pair.
  358.  *
  359.  * PUBLIC: int __db_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
  360.  */
  361. int
  362. __db_put(dbp, txn, key, data, flags)
  363. DB *dbp;
  364. DB_TXN *txn;
  365. DBT *key, *data;
  366. u_int32_t flags;
  367. {
  368. DBC *dbc;
  369. DBT tdata;
  370. int ret, t_ret;
  371. PANIC_CHECK(dbp->dbenv);
  372. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->put");
  373. if ((ret = __db_putchk(dbp, key, data,
  374.     flags, F_ISSET(dbp, DB_AM_RDONLY),
  375.     F_ISSET(dbp, DB_AM_DUP) || F_ISSET(key, DB_DBT_DUPOK))) != 0)
  376. return (ret);
  377. DB_CHECK_TXN(dbp, txn);
  378. if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
  379. return (ret);
  380. /*
  381.  * See the comment in __db_get().
  382.  *
  383.  * Note that the c_get in the DB_NOOVERWRITE case is safe to
  384.  * do with this flag set;  if it errors in any way other than
  385.  * DB_NOTFOUND, we're going to close the cursor without doing
  386.  * anything else, and if it returns DB_NOTFOUND then it's safe
  387.  * to do a c_put(DB_KEYLAST) even if an access method moved the
  388.  * cursor, since that's not position-dependent.
  389.  */
  390. F_SET(dbc, DBC_TRANSIENT);
  391. DEBUG_LWRITE(dbc, txn, "__db_put", key, data, flags);
  392. if (flags == DB_NOOVERWRITE) {
  393. flags = 0;
  394. /*
  395.  * Set DB_DBT_USERMEM, this might be a threaded application and
  396.  * the flags checking will catch us.  We don't want the actual
  397.  * data, so request a partial of length 0.
  398.  */
  399. memset(&tdata, 0, sizeof(tdata));
  400. F_SET(&tdata, DB_DBT_USERMEM | DB_DBT_PARTIAL);
  401. /*
  402.  * If we're doing page-level locking, set the read-modify-write
  403.  * flag, we're going to overwrite immediately.
  404.  */
  405. if ((ret = dbc->c_get(dbc, key, &tdata,
  406.     DB_SET | (STD_LOCKING(dbc) ? DB_RMW : 0))) == 0)
  407. ret = DB_KEYEXIST;
  408. else if (ret == DB_NOTFOUND)
  409. ret = 0;
  410. }
  411. if (ret == 0)
  412. ret = dbc->c_put(dbc,
  413.      key, data, flags == 0 ? DB_KEYLAST : flags);
  414. if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
  415. ret = t_ret;
  416. return (ret);
  417. }
  418. /*
  419.  * __db_sync --
  420.  * Flush the database cache.
  421.  *
  422.  * PUBLIC: int __db_sync __P((DB *, u_int32_t));
  423.  */
  424. int
  425. __db_sync(dbp, flags)
  426. DB *dbp;
  427. u_int32_t flags;
  428. {
  429. int ret, t_ret;
  430. PANIC_CHECK(dbp->dbenv);
  431. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->sync");
  432. if ((ret = __db_syncchk(dbp, flags)) != 0)
  433. return (ret);
  434. /* Read-only trees never need to be sync'd. */
  435. if (F_ISSET(dbp, DB_AM_RDONLY))
  436. return (0);
  437. /* If it's a Recno tree, write the backing source text file. */
  438. if (dbp->type == DB_RECNO)
  439. ret = __ram_writeback(dbp);
  440. /* If the tree was never backed by a database file, we're done. */
  441. if (F_ISSET(dbp, DB_AM_INMEM))
  442. return (0);
  443. /* Flush any dirty pages from the cache to the backing file. */
  444. if ((t_ret = memp_fsync(dbp->mpf)) != 0 && ret == 0)
  445. ret = t_ret;
  446. return (ret);
  447. }