db_join.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:23k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1998-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: db_join.c,v 11.55 2002/08/08 03:57:47 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #endif
  16. #include "db_int.h"
  17. #include "dbinc/db_page.h"
  18. #include "dbinc/db_join.h"
  19. #include "dbinc/btree.h"
  20. static int __db_join_close __P((DBC *));
  21. static int __db_join_cmp __P((const void *, const void *));
  22. static int __db_join_del __P((DBC *, u_int32_t));
  23. static int __db_join_get __P((DBC *, DBT *, DBT *, u_int32_t));
  24. static int __db_join_getnext __P((DBC *, DBT *, DBT *, u_int32_t, u_int32_t));
  25. static int __db_join_primget __P((DB *,
  26.     DB_TXN *, u_int32_t, DBT *, DBT *, u_int32_t));
  27. static int __db_join_put __P((DBC *, DBT *, DBT *, u_int32_t));
  28. /*
  29.  * Check to see if the Nth secondary cursor of join cursor jc is pointing
  30.  * to a sorted duplicate set.
  31.  */
  32. #define SORTED_SET(jc, n)   ((jc)->j_curslist[(n)]->dbp->dup_compare != NULL)
  33. /*
  34.  * This is the duplicate-assisted join functionality.  Right now we're
  35.  * going to write it such that we return one item at a time, although
  36.  * I think we may need to optimize it to return them all at once.
  37.  * It should be easier to get it working this way, and I believe that
  38.  * changing it should be fairly straightforward.
  39.  *
  40.  * We optimize the join by sorting cursors from smallest to largest
  41.  * cardinality.  In most cases, this is indeed optimal.  However, if
  42.  * a cursor with large cardinality has very few data in common with the
  43.  * first cursor, it is possible that the join will be made faster by
  44.  * putting it earlier in the cursor list.  Since we have no way to detect
  45.  * cases like this, we simply provide a flag, DB_JOIN_NOSORT, which retains
  46.  * the sort order specified by the caller, who may know more about the
  47.  * structure of the data.
  48.  *
  49.  * The first cursor moves sequentially through the duplicate set while
  50.  * the others search explicitly for the duplicate in question.
  51.  *
  52.  */
  53. /*
  54.  * __db_join --
  55.  * This is the interface to the duplicate-assisted join functionality.
  56.  * In the same way that cursors mark a position in a database, a cursor
  57.  * can mark a position in a join.  While most cursors are created by the
  58.  * cursor method of a DB, join cursors are created through an explicit
  59.  * call to DB->join.
  60.  *
  61.  * The curslist is an array of existing, intialized cursors and primary
  62.  * is the DB of the primary file.  The data item that joins all the
  63.  * cursors in the curslist is used as the key into the primary and that
  64.  * key and data are returned.  When no more items are left in the join
  65.  * set, the  c_next operation off the join cursor will return DB_NOTFOUND.
  66.  *
  67.  * PUBLIC: int __db_join __P((DB *, DBC **, DBC **, u_int32_t));
  68.  */
  69. int
  70. __db_join(primary, curslist, dbcp, flags)
  71. DB *primary;
  72. DBC **curslist, **dbcp;
  73. u_int32_t flags;
  74. {
  75. DB_ENV *dbenv;
  76. DBC *dbc;
  77. JOIN_CURSOR *jc;
  78. int ret;
  79. u_int32_t i;
  80. size_t ncurs, nslots;
  81. COMPQUIET(nslots, 0);
  82. PANIC_CHECK(primary->dbenv);
  83. if ((ret = __db_joinchk(primary, curslist, flags)) != 0)
  84. return (ret);
  85. dbc = NULL;
  86. jc = NULL;
  87. dbenv = primary->dbenv;
  88. if ((ret = __os_calloc(dbenv, 1, sizeof(DBC), &dbc)) != 0)
  89. goto err;
  90. if ((ret = __os_calloc(dbenv,
  91.     1, sizeof(JOIN_CURSOR), &jc)) != 0)
  92. goto err;
  93. if ((ret = __os_malloc(dbenv, 256, &jc->j_key.data)) != 0)
  94. goto err;
  95. jc->j_key.ulen = 256;
  96. F_SET(&jc->j_key, DB_DBT_USERMEM);
  97. F_SET(&jc->j_rdata, DB_DBT_REALLOC);
  98. for (jc->j_curslist = curslist;
  99.     *jc->j_curslist != NULL; jc->j_curslist++)
  100. ;
  101. /*
  102.  * The number of cursor slots we allocate is one greater than
  103.  * the number of cursors involved in the join, because the
  104.  * list is NULL-terminated.
  105.  */
  106. ncurs = jc->j_curslist - curslist;
  107. nslots = ncurs + 1;
  108. /*
  109.  * !!! -- A note on the various lists hanging off jc.
  110.  *
  111.  * j_curslist is the initial NULL-terminated list of cursors passed
  112.  * into __db_join.  The original cursors are not modified; pristine
  113.  * copies are required because, in databases with unsorted dups, we
  114.  * must reset all of the secondary cursors after the first each
  115.  * time the first one is incremented, or else we will lose data
  116.  * which happen to be sorted differently in two different cursors.
  117.  *
  118.  * j_workcurs is where we put those copies that we're planning to
  119.  * work with.  They're lazily c_dup'ed from j_curslist as we need
  120.  * them, and closed when the join cursor is closed or when we need
  121.  * to reset them to their original values (in which case we just
  122.  * c_dup afresh).
  123.  *
  124.  * j_fdupcurs is an array of cursors which point to the first
  125.  * duplicate in the duplicate set that contains the data value
  126.  * we're currently interested in.  We need this to make
  127.  * __db_join_get correctly return duplicate duplicates;  i.e., if a
  128.  * given data value occurs twice in the set belonging to cursor #2,
  129.  * and thrice in the set belonging to cursor #3, and once in all
  130.  * the other cursors, successive calls to __db_join_get need to
  131.  * return that data item six times.  To make this happen, each time
  132.  * cursor N is allowed to advance to a new datum, all cursors M
  133.  * such that M > N have to be reset to the first duplicate with
  134.  * that datum, so __db_join_get will return all the dup-dups again.
  135.  * We could just reset them to the original cursor from j_curslist,
  136.  * but that would be a bit slower in the unsorted case and a LOT
  137.  * slower in the sorted one.
  138.  *
  139.  * j_exhausted is a list of boolean values which represent
  140.  * whether or not their corresponding cursors are "exhausted",
  141.  * i.e. whether the datum under the corresponding cursor has
  142.  * been found not to exist in any unreturned combinations of
  143.  * later secondary cursors, in which case they are ready to be
  144.  * incremented.
  145.  */
  146. /* We don't want to free regions whose callocs have failed. */
  147. jc->j_curslist = NULL;
  148. jc->j_workcurs = NULL;
  149. jc->j_fdupcurs = NULL;
  150. jc->j_exhausted = NULL;
  151. if ((ret = __os_calloc(dbenv, nslots, sizeof(DBC *),
  152.     &jc->j_curslist)) != 0)
  153. goto err;
  154. if ((ret = __os_calloc(dbenv, nslots, sizeof(DBC *),
  155.     &jc->j_workcurs)) != 0)
  156. goto err;
  157. if ((ret = __os_calloc(dbenv, nslots, sizeof(DBC *),
  158.     &jc->j_fdupcurs)) != 0)
  159. goto err;
  160. if ((ret = __os_calloc(dbenv, nslots, sizeof(u_int8_t),
  161.     &jc->j_exhausted)) != 0)
  162. goto err;
  163. for (i = 0; curslist[i] != NULL; i++) {
  164. jc->j_curslist[i] = curslist[i];
  165. jc->j_workcurs[i] = NULL;
  166. jc->j_fdupcurs[i] = NULL;
  167. jc->j_exhausted[i] = 0;
  168. }
  169. jc->j_ncurs = (u_int32_t)ncurs;
  170. /*
  171.  * If DB_JOIN_NOSORT is not set, optimize secondary cursors by
  172.  * sorting in order of increasing cardinality.
  173.  */
  174. if (!LF_ISSET(DB_JOIN_NOSORT))
  175. qsort(jc->j_curslist, ncurs, sizeof(DBC *), __db_join_cmp);
  176. /*
  177.  * We never need to reset the 0th cursor, so there's no
  178.  * solid reason to use workcurs[0] rather than curslist[0] in
  179.  * join_get.  Nonetheless, it feels cleaner to do it for symmetry,
  180.  * and this is the most logical place to copy it.
  181.  *
  182.  * !!!
  183.  * There's no need to close the new cursor if we goto err only
  184.  * because this is the last thing that can fail.  Modifier of this
  185.  * function beware!
  186.  */
  187. if ((ret = jc->j_curslist[0]->c_dup(jc->j_curslist[0], jc->j_workcurs,
  188.     DB_POSITIONI)) != 0)
  189. goto err;
  190. dbc->c_close = __db_join_close;
  191. dbc->c_del = __db_join_del;
  192. dbc->c_get = __db_join_get;
  193. dbc->c_put = __db_join_put;
  194. dbc->internal = (DBC_INTERNAL *) jc;
  195. dbc->dbp = primary;
  196. jc->j_primary = primary;
  197. *dbcp = dbc;
  198. MUTEX_THREAD_LOCK(dbenv, primary->mutexp);
  199. TAILQ_INSERT_TAIL(&primary->join_queue, dbc, links);
  200. MUTEX_THREAD_UNLOCK(dbenv, primary->mutexp);
  201. return (0);
  202. err: if (jc != NULL) {
  203. if (jc->j_curslist != NULL)
  204. __os_free(dbenv, jc->j_curslist);
  205. if (jc->j_workcurs != NULL) {
  206. if (jc->j_workcurs[0] != NULL)
  207. __os_free(dbenv, jc->j_workcurs[0]);
  208. __os_free(dbenv, jc->j_workcurs);
  209. }
  210. if (jc->j_fdupcurs != NULL)
  211. __os_free(dbenv, jc->j_fdupcurs);
  212. if (jc->j_exhausted != NULL)
  213. __os_free(dbenv, jc->j_exhausted);
  214. __os_free(dbenv, jc);
  215. }
  216. if (dbc != NULL)
  217. __os_free(dbenv, dbc);
  218. return (ret);
  219. }
  220. static int
  221. __db_join_put(dbc, key, data, flags)
  222. DBC *dbc;
  223. DBT *key;
  224. DBT *data;
  225. u_int32_t flags;
  226. {
  227. PANIC_CHECK(dbc->dbp->dbenv);
  228. COMPQUIET(key, NULL);
  229. COMPQUIET(data, NULL);
  230. COMPQUIET(flags, 0);
  231. return (EINVAL);
  232. }
  233. static int
  234. __db_join_del(dbc, flags)
  235. DBC *dbc;
  236. u_int32_t flags;
  237. {
  238. PANIC_CHECK(dbc->dbp->dbenv);
  239. COMPQUIET(flags, 0);
  240. return (EINVAL);
  241. }
  242. static int
  243. __db_join_get(dbc, key_arg, data_arg, flags)
  244. DBC *dbc;
  245. DBT *key_arg, *data_arg;
  246. u_int32_t flags;
  247. {
  248. DBT *key_n, key_n_mem;
  249. DB *dbp;
  250. DBC *cp;
  251. JOIN_CURSOR *jc;
  252. int db_manage_data, ret;
  253. u_int32_t i, j, operation, opmods;
  254. dbp = dbc->dbp;
  255. jc = (JOIN_CURSOR *)dbc->internal;
  256. PANIC_CHECK(dbp->dbenv);
  257. operation = LF_ISSET(DB_OPFLAGS_MASK);
  258. /* !!!
  259.  * If the set of flags here changes, check that __db_join_primget
  260.  * is updated to handle them properly.
  261.  */
  262. opmods = LF_ISSET(DB_RMW | DB_DIRTY_READ);
  263. if ((ret = __db_joingetchk(dbp, key_arg, flags)) != 0)
  264. return (ret);
  265. /*
  266.  * Since we are fetching the key as a datum in the secondary indices,
  267.  * we must be careful of caller-specified DB_DBT_* memory
  268.  * management flags.  If necessary, use a stack-allocated DBT;
  269.  * we'll appropriately copy and/or allocate the data later.
  270.  */
  271. if (F_ISSET(key_arg, DB_DBT_USERMEM) ||
  272.     F_ISSET(key_arg, DB_DBT_MALLOC)) {
  273. /* We just use the default buffer;  no need to go malloc. */
  274. key_n = &key_n_mem;
  275. memset(key_n, 0, sizeof(DBT));
  276. } else {
  277. /*
  278.  * Either DB_DBT_REALLOC or the default buffer will work
  279.  * fine if we have to reuse it, as we do.
  280.  */
  281. key_n = key_arg;
  282. }
  283. /*
  284.  * If our last attempt to do a get on the primary key failed,
  285.  * short-circuit the join and try again with the same key.
  286.  */
  287. if (F_ISSET(jc, JOIN_RETRY))
  288. goto samekey;
  289. F_CLR(jc, JOIN_RETRY);
  290. retry: ret = jc->j_workcurs[0]->c_real_get(jc->j_workcurs[0],
  291.     &jc->j_key, key_n,
  292.     opmods | (jc->j_exhausted[0] ? DB_NEXT_DUP : DB_CURRENT));
  293. if (ret == ENOMEM) {
  294. jc->j_key.ulen <<= 1;
  295. if ((ret = __os_realloc(dbp->dbenv,
  296.     jc->j_key.ulen, &jc->j_key.data)) != 0)
  297. goto mem_err;
  298. goto retry;
  299. }
  300. /*
  301.  * If ret == DB_NOTFOUND, we're out of elements of the first
  302.  * secondary cursor.  This is how we finally finish the join
  303.  * if all goes well.
  304.  */
  305. if (ret != 0)
  306. goto err;
  307. /*
  308.  * If jc->j_exhausted[0] == 1, we've just advanced the first cursor,
  309.  * and we're going to want to advance all the cursors that point to
  310.  * the first member of a duplicate duplicate set (j_fdupcurs[1..N]).
  311.  * Close all the cursors in j_fdupcurs;  we'll reopen them the
  312.  * first time through the upcoming loop.
  313.  */
  314. for (i = 1; i < jc->j_ncurs; i++) {
  315. if (jc->j_fdupcurs[i] != NULL &&
  316.     (ret = jc->j_fdupcurs[i]->c_close(jc->j_fdupcurs[i])) != 0)
  317. goto err;
  318. jc->j_fdupcurs[i] = NULL;
  319. }
  320. /*
  321.  * If jc->j_curslist[1] == NULL, we have only one cursor in the join.
  322.  * Thus, we can safely increment that one cursor on each call
  323.  * to __db_join_get, and we signal this by setting jc->j_exhausted[0]
  324.  * right away.
  325.  *
  326.  * Otherwise, reset jc->j_exhausted[0] to 0, so that we don't
  327.  * increment it until we know we're ready to.
  328.  */
  329. if (jc->j_curslist[1] == NULL)
  330. jc->j_exhausted[0] = 1;
  331. else
  332. jc->j_exhausted[0] = 0;
  333. /* We have the first element; now look for it in the other cursors. */
  334. for (i = 1; i < jc->j_ncurs; i++) {
  335. DB_ASSERT(jc->j_curslist[i] != NULL);
  336. if (jc->j_workcurs[i] == NULL)
  337. /* If this is NULL, we need to dup curslist into it. */
  338. if ((ret = jc->j_curslist[i]->c_dup(
  339.     jc->j_curslist[i], jc->j_workcurs + i,
  340.     DB_POSITIONI)) != 0)
  341. goto err;
  342. retry2: cp = jc->j_workcurs[i];
  343. if ((ret = __db_join_getnext(cp, &jc->j_key, key_n,
  344.     jc->j_exhausted[i], opmods)) == DB_NOTFOUND) {
  345. /*
  346.  * jc->j_workcurs[i] has no more of the datum we're
  347.  * interested in.  Go back one cursor and get
  348.  * a new dup.  We can't just move to a new
  349.  * element of the outer relation, because that way
  350.  * we might miss duplicate duplicates in cursor i-1.
  351.  *
  352.  * If this takes us back to the first cursor,
  353.  * -then- we can move to a new element of the outer
  354.  * relation.
  355.  */
  356. --i;
  357. jc->j_exhausted[i] = 1;
  358. if (i == 0) {
  359. for (j = 1; jc->j_workcurs[j] != NULL; j++) {
  360. /*
  361.  * We're moving to a new element of
  362.  * the first secondary cursor.  If
  363.  * that cursor is sorted, then any
  364.  * other sorted cursors can be safely
  365.  * reset to the first duplicate
  366.  * duplicate in the current set if we
  367.  * have a pointer to it (we can't just
  368.  * leave them be, or we'll miss
  369.  * duplicate duplicates in the outer
  370.  * relation).
  371.  *
  372.  * If the first cursor is unsorted, or
  373.  * if cursor j is unsorted, we can
  374.  * make no assumptions about what
  375.  * we're looking for next or where it
  376.  * will be, so we reset to the very
  377.  * beginning (setting workcurs NULL
  378.  * will achieve this next go-round).
  379.  *
  380.  * XXX: This is likely to break
  381.  * horribly if any two cursors are
  382.  * both sorted, but have different
  383.  * specified sort functions.  For,
  384.  * now, we dismiss this as pathology
  385.  * and let strange things happen--we
  386.  * can't make rope childproof.
  387.  */
  388. if ((ret = jc->j_workcurs[j]->c_close(
  389.     jc->j_workcurs[j])) != 0)
  390. goto err;
  391. if (!SORTED_SET(jc, 0) ||
  392.     !SORTED_SET(jc, j) ||
  393.     jc->j_fdupcurs[j] == NULL)
  394. /*
  395.  * Unsafe conditions;
  396.  * reset fully.
  397.  */
  398. jc->j_workcurs[j] = NULL;
  399. else
  400. /* Partial reset suffices. */
  401. if ((jc->j_fdupcurs[j]->c_dup(
  402.     jc->j_fdupcurs[j],
  403.     &jc->j_workcurs[j],
  404.     DB_POSITIONI)) != 0)
  405. goto err;
  406. jc->j_exhausted[j] = 0;
  407. }
  408. goto retry;
  409. /* NOTREACHED */
  410. }
  411. /*
  412.  * We're about to advance the cursor and need to
  413.  * reset all of the workcurs[j] where j>i, so that
  414.  * we don't miss any duplicate duplicates.
  415.  */
  416. for (j = i + 1;
  417.     jc->j_workcurs[j] != NULL;
  418.     j++) {
  419. if ((ret = jc->j_workcurs[j]->c_close(
  420.     jc->j_workcurs[j])) != 0)
  421. goto err;
  422. jc->j_exhausted[j] = 0;
  423. if (jc->j_fdupcurs[j] != NULL &&
  424.     (ret = jc->j_fdupcurs[j]->c_dup(
  425.     jc->j_fdupcurs[j], &jc->j_workcurs[j],
  426.     DB_POSITIONI)) != 0)
  427. goto err;
  428. else
  429. jc->j_workcurs[j] = NULL;
  430. }
  431. goto retry2;
  432. /* NOTREACHED */
  433. }
  434. if (ret == ENOMEM) {
  435. jc->j_key.ulen <<= 1;
  436. if ((ret = __os_realloc(dbp->dbenv, jc->j_key.ulen,
  437.     &jc->j_key.data)) != 0) {
  438. mem_err: __db_err(dbp->dbenv,
  439.     "Allocation failed for join key, len = %lu",
  440.     (u_long)jc->j_key.ulen);
  441. goto err;
  442. }
  443. goto retry2;
  444. }
  445. if (ret != 0)
  446. goto err;
  447. /*
  448.  * If we made it this far, we've found a matching
  449.  * datum in cursor i.  Mark the current cursor
  450.  * unexhausted, so we don't miss any duplicate
  451.  * duplicates the next go-round--unless this is the
  452.  * very last cursor, in which case there are none to
  453.  * miss, and we'll need that exhausted flag to finally
  454.  * get a DB_NOTFOUND and move on to the next datum in
  455.  * the outermost cursor.
  456.  */
  457. if (i + 1 != jc->j_ncurs)
  458. jc->j_exhausted[i] = 0;
  459. else
  460. jc->j_exhausted[i] = 1;
  461. /*
  462.  * If jc->j_fdupcurs[i] is NULL and the ith cursor's dups are
  463.  * sorted, then we're here for the first time since advancing
  464.  * cursor 0, and we have a new datum of interest.
  465.  * jc->j_workcurs[i] points to the beginning of a set of
  466.  * duplicate duplicates;  store this into jc->j_fdupcurs[i].
  467.  */
  468. if (SORTED_SET(jc, i) && jc->j_fdupcurs[i] == NULL && (ret =
  469.     cp->c_dup(cp, &jc->j_fdupcurs[i], DB_POSITIONI)) != 0)
  470. goto err;
  471. }
  472. err: if (ret != 0)
  473. return (ret);
  474. if (0) {
  475. samekey: /*
  476.  * Get the key we tried and failed to return last time;
  477.  * it should be the current datum of all the secondary cursors.
  478.  */
  479. if ((ret = jc->j_workcurs[0]->c_real_get(jc->j_workcurs[0],
  480.     &jc->j_key, key_n, DB_CURRENT | opmods)) != 0)
  481. return (ret);
  482. F_CLR(jc, JOIN_RETRY);
  483. }
  484. /*
  485.  * ret == 0;  we have a key to return.
  486.  *
  487.  * If DB_DBT_USERMEM or DB_DBT_MALLOC is set, we need to copy the key
  488.  * back into the dbt we were given for the key; call __db_retcopy.
  489.  * Otherwise, assert that we do not need to copy anything and proceed.
  490.  */
  491. DB_ASSERT(F_ISSET(
  492.     key_arg, DB_DBT_USERMEM | DB_DBT_MALLOC) || key_n == key_arg);
  493. if (F_ISSET(key_arg, DB_DBT_USERMEM | DB_DBT_MALLOC) &&
  494.     (ret = __db_retcopy(dbp->dbenv,
  495.     key_arg, key_n->data, key_n->size, NULL, NULL)) != 0) {
  496. /*
  497.  * The retcopy failed, most commonly because we have a user
  498.  * buffer for the key which is too small. Set things up to
  499.  * retry next time, and return.
  500.  */
  501. F_SET(jc, JOIN_RETRY);
  502. return (ret);
  503. }
  504. /*
  505.  * If DB_JOIN_ITEM is set, we return it; otherwise we do the lookup
  506.  * in the primary and then return.
  507.  *
  508.  * Note that we use key_arg here;  it is safe (and appropriate)
  509.  * to do so.
  510.  */
  511. if (operation == DB_JOIN_ITEM)
  512. return (0);
  513. /*
  514.  * If data_arg->flags == 0--that is, if DB is managing the
  515.  * data DBT's memory--it's not safe to just pass the DBT
  516.  * through to the primary get call, since we don't want that
  517.  * memory to belong to the primary DB handle (and if the primary
  518.  * is free-threaded, it can't anyway).
  519.  *
  520.  * Instead, use memory that is managed by the join cursor, in
  521.  * jc->j_rdata.
  522.  */
  523. if (!F_ISSET(data_arg, DB_DBT_MALLOC | DB_DBT_REALLOC | DB_DBT_USERMEM))
  524. db_manage_data = 1;
  525. else
  526. db_manage_data = 0;
  527. if ((ret = __db_join_primget(jc->j_primary,
  528.     jc->j_curslist[0]->txn, jc->j_curslist[0]->locker, key_arg,
  529.     db_manage_data ? &jc->j_rdata : data_arg, opmods)) != 0) {
  530. if (ret == DB_NOTFOUND)
  531. /*
  532.  * If ret == DB_NOTFOUND, the primary and secondary
  533.  * are out of sync;  every item in each secondary
  534.  * should correspond to something in the primary,
  535.  * or we shouldn't have done the join this way.
  536.  * Wail.
  537.  */
  538. ret = __db_secondary_corrupt(jc->j_primary);
  539. else
  540. /*
  541.  * The get on the primary failed for some other
  542.  * reason, most commonly because we're using a user
  543.  * buffer that's not big enough.  Flag our failure
  544.  * so we can return the same key next time.
  545.  */
  546. F_SET(jc, JOIN_RETRY);
  547. }
  548. if (db_manage_data && ret == 0) {
  549. data_arg->data = jc->j_rdata.data;
  550. data_arg->size = jc->j_rdata.size;
  551. }
  552. return (ret);
  553. }
  554. static int
  555. __db_join_close(dbc)
  556. DBC *dbc;
  557. {
  558. DB *dbp;
  559. DB_ENV *dbenv;
  560. JOIN_CURSOR *jc;
  561. int ret, t_ret;
  562. u_int32_t i;
  563. jc = (JOIN_CURSOR *)dbc->internal;
  564. dbp = dbc->dbp;
  565. dbenv = dbp->dbenv;
  566. ret = t_ret = 0;
  567. /*
  568.  * Remove from active list of join cursors.  Note that this
  569.  * must happen before any action that can fail and return, or else
  570.  * __db_close may loop indefinitely.
  571.  */
  572. MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
  573. TAILQ_REMOVE(&dbp->join_queue, dbc, links);
  574. MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
  575. PANIC_CHECK(dbenv);
  576. /*
  577.  * Close any open scratch cursors.  In each case, there may
  578.  * not be as many outstanding as there are cursors in
  579.  * curslist, but we want to close whatever's there.
  580.  *
  581.  * If any close fails, there's no reason not to close everything else;
  582.  * we'll just return the error code of the last one to fail.  There's
  583.  * not much the caller can do anyway, since these cursors only exist
  584.  * hanging off a db-internal data structure that they shouldn't be
  585.  * mucking with.
  586.  */
  587. for (i = 0; i < jc->j_ncurs; i++) {
  588. if (jc->j_workcurs[i] != NULL && (t_ret =
  589.     jc->j_workcurs[i]->c_close(jc->j_workcurs[i])) != 0)
  590. ret = t_ret;
  591. if (jc->j_fdupcurs[i] != NULL && (t_ret =
  592.     jc->j_fdupcurs[i]->c_close(jc->j_fdupcurs[i])) != 0)
  593. ret = t_ret;
  594. }
  595. __os_free(dbenv, jc->j_exhausted);
  596. __os_free(dbenv, jc->j_curslist);
  597. __os_free(dbenv, jc->j_workcurs);
  598. __os_free(dbenv, jc->j_fdupcurs);
  599. __os_free(dbenv, jc->j_key.data);
  600. if (jc->j_rdata.data != NULL)
  601. __os_ufree(dbenv, jc->j_rdata.data);
  602. __os_free(dbenv, jc);
  603. __os_free(dbenv, dbc);
  604. return (ret);
  605. }
  606. /*
  607.  * __db_join_getnext --
  608.  * This function replaces the DBC_CONTINUE and DBC_KEYSET
  609.  * functionality inside the various cursor get routines.
  610.  *
  611.  * If exhausted == 0, we're not done with the current datum;
  612.  * return it if it matches "matching", otherwise search
  613.  * using DB_GET_BOTHC (which is faster than iteratively doing
  614.  * DB_NEXT_DUP) forward until we find one that does.
  615.  *
  616.  * If exhausted == 1, we are done with the current datum, so just
  617.  * leap forward to searching NEXT_DUPs.
  618.  *
  619.  * If no matching datum exists, returns DB_NOTFOUND, else 0.
  620.  */
  621. static int
  622. __db_join_getnext(dbc, key, data, exhausted, opmods)
  623. DBC *dbc;
  624. DBT *key, *data;
  625. u_int32_t exhausted, opmods;
  626. {
  627. int ret, cmp;
  628. DB *dbp;
  629. DBT ldata;
  630. int (*func) __P((DB *, const DBT *, const DBT *));
  631. dbp = dbc->dbp;
  632. func = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare;
  633. switch (exhausted) {
  634. case 0:
  635. /*
  636.  * We don't want to step on data->data;  use a new
  637.  * DBT and malloc so we don't step on dbc's rdata memory.
  638.  */
  639. memset(&ldata, 0, sizeof(DBT));
  640. F_SET(&ldata, DB_DBT_MALLOC);
  641. if ((ret = dbc->c_real_get(dbc,
  642.     key, &ldata, opmods | DB_CURRENT)) != 0)
  643. break;
  644. cmp = func(dbp, data, &ldata);
  645. if (cmp == 0) {
  646. /*
  647.  * We have to return the real data value.  Copy
  648.  * it into data, then free the buffer we malloc'ed
  649.  * above.
  650.  */
  651. if ((ret = __db_retcopy(dbp->dbenv, data, ldata.data,
  652.     ldata.size, &data->data, &data->size)) != 0)
  653. return (ret);
  654. __os_ufree(dbp->dbenv, ldata.data);
  655. return (0);
  656. }
  657. /*
  658.  * Didn't match--we want to fall through and search future
  659.  * dups.  We just forget about ldata and free
  660.  * its buffer--data contains the value we're searching for.
  661.  */
  662. __os_ufree(dbp->dbenv, ldata.data);
  663. /* FALLTHROUGH */
  664. case 1:
  665. ret = dbc->c_real_get(dbc, key, data, opmods | DB_GET_BOTHC);
  666. break;
  667. default:
  668. ret = EINVAL;
  669. break;
  670. }
  671. return (ret);
  672. }
  673. /*
  674.  * __db_join_cmp --
  675.  * Comparison function for sorting DBCs in cardinality order.
  676.  */
  677. static int
  678. __db_join_cmp(a, b)
  679. const void *a, *b;
  680. {
  681. DBC *dbca, *dbcb;
  682. db_recno_t counta, countb;
  683. /* In case c_count fails, pretend cursors are equal. */
  684. counta = countb = 0;
  685. dbca = *((DBC * const *)a);
  686. dbcb = *((DBC * const *)b);
  687. if (dbca->c_count(dbca, &counta, 0) != 0 ||
  688.     dbcb->c_count(dbcb, &countb, 0) != 0)
  689. return (0);
  690. return (counta - countb);
  691. }
  692. /*
  693.  * __db_join_primget --
  694.  * Perform a DB->get in the primary, being careful not to use a new
  695.  * locker ID if we're doing CDB locking.
  696.  */
  697. static int
  698. __db_join_primget(dbp, txn, lockerid, key, data, flags)
  699. DB *dbp;
  700. DB_TXN *txn;
  701. u_int32_t lockerid;
  702. DBT *key, *data;
  703. u_int32_t flags;
  704. {
  705. DBC *dbc;
  706. int dirty, ret, rmw, t_ret;
  707. /*
  708.  * The only allowable flags here are the two flags copied into
  709.  * "opmods" in __db_join_get, DB_RMW and DB_DIRTY_READ.  The former
  710.  * is an op on the c_get call, the latter on the cursor call.
  711.  * It's a DB bug if we allow any other flags down in here.
  712.  */
  713. rmw = LF_ISSET(DB_RMW);
  714. dirty = LF_ISSET(DB_DIRTY_READ);
  715. LF_CLR(DB_RMW | DB_DIRTY_READ);
  716. DB_ASSERT(flags == 0);
  717. if ((ret = __db_icursor(dbp,
  718.     txn, dbp->type, PGNO_INVALID, 0, lockerid, &dbc)) != 0)
  719. return (ret);
  720. if (dirty ||
  721.     (txn != NULL && F_ISSET(txn, TXN_DIRTY_READ)))
  722. F_SET(dbc, DBC_DIRTY_READ);
  723. F_SET(dbc, DBC_TRANSIENT);
  724. /*
  725.  * This shouldn't be necessary, thanks to the fact that join cursors
  726.  * swap in their own DB_DBT_REALLOC'ed buffers, but just for form's
  727.  * sake, we mirror what __db_get does.
  728.  */
  729. SET_RET_MEM(dbc, dbp);
  730. ret = dbc->c_get(dbc, key, data, DB_SET | rmw);
  731. if ((t_ret = __db_c_close(dbc)) != 0 && ret == 0)
  732. ret = t_ret;
  733. return (ret);
  734. }