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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: client.c,v 1.51 2002/08/06 06:18:15 bostic Exp $";
  10. #endif /* not lint */
  11. #ifdef HAVE_RPC
  12. #ifndef NO_SYSTEM_INCLUDES
  13. #include <sys/types.h>
  14. #ifdef HAVE_VXWORKS
  15. #include <rpcLib.h>
  16. #endif
  17. #include <rpc/rpc.h>
  18. #include <ctype.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <unistd.h>
  22. #endif
  23. #include "db_int.h"
  24. #include "dbinc/db_page.h"
  25. #include "dbinc/db_am.h"
  26. #include "dbinc/txn.h"
  27. #include "dbinc_auto/db_server.h"
  28. #include "dbinc_auto/rpc_client_ext.h"
  29. static int __dbcl_c_destroy __P((DBC *));
  30. static int __dbcl_txn_close __P((DB_ENV *));
  31. /*
  32.  * __dbcl_envrpcserver --
  33.  * Initialize an environment's server.
  34.  *
  35.  * PUBLIC: int __dbcl_envrpcserver
  36.  * PUBLIC:     __P((DB_ENV *, void *, const char *, long, long, u_int32_t));
  37.  */
  38. int
  39. __dbcl_envrpcserver(dbenv, clnt, host, tsec, ssec, flags)
  40. DB_ENV *dbenv;
  41. void *clnt;
  42. const char *host;
  43. long tsec, ssec;
  44. u_int32_t flags;
  45. {
  46. CLIENT *cl;
  47. struct timeval tp;
  48. COMPQUIET(flags, 0);
  49. #ifdef HAVE_VXWORKS
  50. if (rpcTaskInit() != 0) {
  51. __db_err(dbenv, "Could not initialize VxWorks RPC");
  52. return (ERROR);
  53. }
  54. #endif
  55. if (RPC_ON(dbenv)) {
  56. __db_err(dbenv, "Already set an RPC handle");
  57. return (EINVAL);
  58. }
  59. /*
  60.  * Only create the client and set its timeout if the user
  61.  * did not pass us a client structure to begin with.
  62.  */
  63. if (clnt == NULL) {
  64. if ((cl = clnt_create((char *)host, DB_RPC_SERVERPROG,
  65.     DB_RPC_SERVERVERS, "tcp")) == NULL) {
  66. __db_err(dbenv, clnt_spcreateerror((char *)host));
  67. return (DB_NOSERVER);
  68. }
  69. if (tsec != 0) {
  70. tp.tv_sec = tsec;
  71. tp.tv_usec = 0;
  72. (void)clnt_control(cl, CLSET_TIMEOUT, (char *)&tp);
  73. }
  74. } else {
  75. cl = (CLIENT *)clnt;
  76. F_SET(dbenv, DB_ENV_RPCCLIENT_GIVEN);
  77. }
  78. dbenv->cl_handle = cl;
  79. return (__dbcl_env_create(dbenv, ssec));
  80. }
  81. /*
  82.  * __dbcl_env_open_wrap --
  83.  * Wrapper function for DB_ENV->open function for clients.
  84.  * We need a wrapper function to deal with DB_USE_ENVIRON* flags
  85.  * and we don't want to complicate the generated code for env_open.
  86.  *
  87.  * PUBLIC: int __dbcl_env_open_wrap
  88.  * PUBLIC:     __P((DB_ENV *, const char *, u_int32_t, int));
  89.  */
  90. int
  91. __dbcl_env_open_wrap(dbenv, home, flags, mode)
  92. DB_ENV * dbenv;
  93. const char * home;
  94. u_int32_t flags;
  95. int mode;
  96. {
  97. int ret;
  98. if (LF_ISSET(DB_THREAD)) {
  99. __db_err(dbenv, "DB_THREAD not allowed on RPC clients");
  100. return (EINVAL);
  101. }
  102. if ((ret = __db_home(dbenv, home, flags)) != 0)
  103. return (ret);
  104. return (__dbcl_env_open(dbenv, dbenv->db_home, flags, mode));
  105. }
  106. /*
  107.  * __dbcl_db_open_wrap --
  108.  * Wrapper function for DB->open function for clients.
  109.  * We need a wrapper function to error on DB_THREAD flag.
  110.  * and we don't want to complicate the generated code.
  111.  *
  112.  * PUBLIC: int __dbcl_db_open_wrap
  113.  * PUBLIC:     __P((DB *, DB_TXN *, const char *, const char *,
  114.  * PUBLIC:     DBTYPE, u_int32_t, int));
  115.  */
  116. int
  117. __dbcl_db_open_wrap(dbp, txnp, name, subdb, type, flags, mode)
  118. DB * dbp;
  119. DB_TXN * txnp;
  120. const char * name;
  121. const char * subdb;
  122. DBTYPE type;
  123. u_int32_t flags;
  124. int mode;
  125. {
  126. if (LF_ISSET(DB_THREAD)) {
  127. __db_err(dbp->dbenv, "DB_THREAD not allowed on RPC clients");
  128. return (EINVAL);
  129. }
  130. return (__dbcl_db_open(dbp, txnp, name, subdb, type, flags, mode));
  131. }
  132. /*
  133.  * __dbcl_refresh --
  134.  * Clean up an environment.
  135.  *
  136.  * PUBLIC: int __dbcl_refresh __P((DB_ENV *));
  137.  */
  138. int
  139. __dbcl_refresh(dbenv)
  140. DB_ENV *dbenv;
  141. {
  142. CLIENT *cl;
  143. int ret;
  144. cl = (CLIENT *)dbenv->cl_handle;
  145. ret = 0;
  146. if (dbenv->tx_handle != NULL) {
  147. /*
  148.  * We only need to free up our stuff, the caller
  149.  * of this function will call the server who will
  150.  * do all the real work.
  151.  */
  152. ret = __dbcl_txn_close(dbenv);
  153. dbenv->tx_handle = NULL;
  154. }
  155. if (!F_ISSET(dbenv, DB_ENV_RPCCLIENT_GIVEN) && cl != NULL)
  156. clnt_destroy(cl);
  157. dbenv->cl_handle = NULL;
  158. if (dbenv->db_home != NULL) {
  159. __os_free(dbenv, dbenv->db_home);
  160. dbenv->db_home = NULL;
  161. }
  162. return (ret);
  163. }
  164. /*
  165.  * __dbcl_retcopy --
  166.  * Copy the returned data into the user's DBT, handling allocation flags,
  167.  * but not DB_DBT_PARTIAL.
  168.  *
  169.  * PUBLIC: int __dbcl_retcopy __P((DB_ENV *, DBT *,
  170.  * PUBLIC:    void *, u_int32_t, void **, u_int32_t *));
  171.  */
  172. int
  173. __dbcl_retcopy(dbenv, dbt, data, len, memp, memsize)
  174. DB_ENV *dbenv;
  175. DBT *dbt;
  176. void *data;
  177. u_int32_t len;
  178. void **memp;
  179. u_int32_t *memsize;
  180. {
  181. int ret;
  182. u_int32_t orig_flags;
  183. /*
  184.  * The RPC server handles DB_DBT_PARTIAL, so we mask it out here to
  185.  * avoid the handling of partials in __db_retcopy.
  186.  */
  187. orig_flags = dbt->flags;
  188. F_CLR(dbt, DB_DBT_PARTIAL);
  189. ret = __db_retcopy(dbenv, dbt, data, len, memp, memsize);
  190. dbt->flags = orig_flags;
  191. return (ret);
  192. }
  193. /*
  194.  * __dbcl_txn_close --
  195.  * Clean up an environment's transactions.
  196.  */
  197. int
  198. __dbcl_txn_close(dbenv)
  199. DB_ENV *dbenv;
  200. {
  201. DB_TXN *txnp;
  202. DB_TXNMGR *tmgrp;
  203. int ret;
  204. ret = 0;
  205. tmgrp = dbenv->tx_handle;
  206. /*
  207.  * This function can only be called once per process (i.e., not
  208.  * once per thread), so no synchronization is required.
  209.  * Also this function is called *after* the server has been called,
  210.  * so the server has already closed/aborted any transactions that
  211.  * were open on its side.  We only need to do local cleanup.
  212.  */
  213. while ((txnp = TAILQ_FIRST(&tmgrp->txn_chain)) != NULL)
  214. __dbcl_txn_end(txnp);
  215. __os_free(dbenv, tmgrp);
  216. return (ret);
  217. }
  218. /*
  219.  * __dbcl_txn_end --
  220.  * Clean up an transaction.
  221.  * RECURSIVE FUNCTION:  Clean up nested transactions.
  222.  *
  223.  * PUBLIC: void __dbcl_txn_end __P((DB_TXN *));
  224.  */
  225. void
  226. __dbcl_txn_end(txnp)
  227. DB_TXN *txnp;
  228. {
  229. DB_ENV *dbenv;
  230. DB_TXN *kids;
  231. DB_TXNMGR *mgr;
  232. mgr = txnp->mgrp;
  233. dbenv = mgr->dbenv;
  234. /*
  235.  * First take care of any kids we have
  236.  */
  237. for (kids = TAILQ_FIRST(&txnp->kids);
  238.     kids != NULL;
  239.     kids = TAILQ_FIRST(&txnp->kids))
  240. __dbcl_txn_end(kids);
  241. /*
  242.  * We are ending this transaction no matter what the parent
  243.  * may eventually do, if we have a parent.  All those details
  244.  * are taken care of by the server.  We only need to make sure
  245.  * that we properly release resources.
  246.  */
  247. if (txnp->parent != NULL)
  248. TAILQ_REMOVE(&txnp->parent->kids, txnp, klinks);
  249. TAILQ_REMOVE(&mgr->txn_chain, txnp, links);
  250. __os_free(dbenv, txnp);
  251. }
  252. /*
  253.  * __dbcl_txn_setup --
  254.  * Setup a client transaction structure.
  255.  *
  256.  * PUBLIC: void __dbcl_txn_setup __P((DB_ENV *, DB_TXN *, DB_TXN *, u_int32_t));
  257.  */
  258. void
  259. __dbcl_txn_setup(dbenv, txn, parent, id)
  260. DB_ENV *dbenv;
  261. DB_TXN *txn;
  262. DB_TXN *parent;
  263. u_int32_t id;
  264. {
  265. txn->mgrp = dbenv->tx_handle;
  266. txn->parent = parent;
  267. txn->txnid = id;
  268. /*
  269.  * XXX
  270.  * In DB library the txn_chain is protected by the mgrp->mutexp.
  271.  * However, that mutex is implemented in the environments shared
  272.  * memory region.  The client library does not support all of the
  273.  * region - that just get forwarded to the server.  Therefore,
  274.  * the chain is unprotected here, but properly protected on the
  275.  * server.
  276.  */
  277. TAILQ_INSERT_TAIL(&txn->mgrp->txn_chain, txn, links);
  278. TAILQ_INIT(&txn->kids);
  279. if (parent != NULL)
  280. TAILQ_INSERT_HEAD(&parent->kids, txn, klinks);
  281. txn->abort = __dbcl_txn_abort;
  282. txn->commit = __dbcl_txn_commit;
  283. txn->discard = __dbcl_txn_discard;
  284. txn->id = __txn_id;
  285. txn->prepare = __dbcl_txn_prepare;
  286. txn->set_timeout = __dbcl_txn_timeout;
  287. txn->flags = TXN_MALLOC;
  288. }
  289. /*
  290.  * __dbcl_c_destroy --
  291.  * Destroy a cursor.
  292.  */
  293. static int
  294. __dbcl_c_destroy(dbc)
  295. DBC *dbc;
  296. {
  297. DB *dbp;
  298. dbp = dbc->dbp;
  299. TAILQ_REMOVE(&dbp->free_queue, dbc, links);
  300. /* Discard any memory used to store returned data. */
  301. if (dbc->my_rskey.data != NULL)
  302. __os_free(dbc->dbp->dbenv, dbc->my_rskey.data);
  303. if (dbc->my_rkey.data != NULL)
  304. __os_free(dbc->dbp->dbenv, dbc->my_rkey.data);
  305. if (dbc->my_rdata.data != NULL)
  306. __os_free(dbc->dbp->dbenv, dbc->my_rdata.data);
  307. __os_free(NULL, dbc);
  308. return (0);
  309. }
  310. /*
  311.  * __dbcl_c_refresh --
  312.  * Refresh a cursor.  Move it from the active queue to the free queue.
  313.  *
  314.  * PUBLIC: void __dbcl_c_refresh __P((DBC *));
  315.  */
  316. void
  317. __dbcl_c_refresh(dbc)
  318. DBC *dbc;
  319. {
  320. DB *dbp;
  321. dbp = dbc->dbp;
  322. dbc->flags = 0;
  323. dbc->cl_id = 0;
  324. /*
  325.  * If dbp->cursor fails locally, we use a local dbc so that
  326.  * we can close it.  In that case, dbp will be NULL.
  327.  */
  328. if (dbp != NULL) {
  329. TAILQ_REMOVE(&dbp->active_queue, dbc, links);
  330. TAILQ_INSERT_TAIL(&dbp->free_queue, dbc, links);
  331. }
  332. }
  333. /*
  334.  * __dbcl_c_setup --
  335.  * Allocate a cursor.
  336.  *
  337.  * PUBLIC: int __dbcl_c_setup __P((long, DB *, DBC **));
  338.  */
  339. int
  340. __dbcl_c_setup(cl_id, dbp, dbcp)
  341. long cl_id;
  342. DB *dbp;
  343. DBC **dbcp;
  344. {
  345. DBC *dbc, tmpdbc;
  346. int ret;
  347. if ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
  348. TAILQ_REMOVE(&dbp->free_queue, dbc, links);
  349. else {
  350. if ((ret =
  351.     __os_calloc(dbp->dbenv, 1, sizeof(DBC), &dbc)) != 0) {
  352. /*
  353.  * If we die here, set up a tmp dbc to call the
  354.  * server to shut down that cursor.
  355.  */
  356. tmpdbc.dbp = NULL;
  357. tmpdbc.cl_id = cl_id;
  358. (void)__dbcl_dbc_close(&tmpdbc);
  359. return (ret);
  360. }
  361. dbc->c_close = __dbcl_dbc_close;
  362. dbc->c_count = __dbcl_dbc_count;
  363. dbc->c_del = __dbcl_dbc_del;
  364. dbc->c_dup = __dbcl_dbc_dup;
  365. dbc->c_get = __dbcl_dbc_get;
  366. dbc->c_pget = __dbcl_dbc_pget;
  367. dbc->c_put = __dbcl_dbc_put;
  368. dbc->c_am_destroy = __dbcl_c_destroy;
  369. }
  370. dbc->cl_id = cl_id;
  371. dbc->dbp = dbp;
  372. TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links);
  373. *dbcp = dbc;
  374. return (0);
  375. }
  376. /*
  377.  * __dbcl_dbclose_common --
  378.  * Common code for closing/cleaning a dbp.
  379.  *
  380.  * PUBLIC: int __dbcl_dbclose_common __P((DB *));
  381.  */
  382. int
  383. __dbcl_dbclose_common(dbp)
  384. DB *dbp;
  385. {
  386. int ret, t_ret;
  387. DBC *dbc;
  388. /*
  389.  * Go through the active cursors and call the cursor recycle routine,
  390.  * which resolves pending operations and moves the cursors onto the
  391.  * free list.  Then, walk the free list and call the cursor destroy
  392.  * routine.
  393.  *
  394.  * NOTE:  We do not need to use the join_queue for join cursors.
  395.  * See comment in __dbcl_dbjoin_ret.
  396.  */
  397. ret = 0;
  398. while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
  399. __dbcl_c_refresh(dbc);
  400. while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
  401. if ((t_ret = __dbcl_c_destroy(dbc)) != 0 && ret == 0)
  402. ret = t_ret;
  403. TAILQ_INIT(&dbp->free_queue);
  404. TAILQ_INIT(&dbp->active_queue);
  405. /* Discard any memory used to store returned data. */
  406. if (dbp->my_rskey.data != NULL)
  407. __os_free(dbp->dbenv, dbp->my_rskey.data);
  408. if (dbp->my_rkey.data != NULL)
  409. __os_free(dbp->dbenv, dbp->my_rkey.data);
  410. if (dbp->my_rdata.data != NULL)
  411. __os_free(dbp->dbenv, dbp->my_rdata.data);
  412. memset(dbp, CLEAR_BYTE, sizeof(*dbp));
  413. __os_free(NULL, dbp);
  414. return (ret);
  415. }
  416. #endif /* HAVE_RPC */