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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  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.21 2000/11/30 00:58:44 ubell Exp $";
  10. #endif /* not lint */
  11. #ifdef HAVE_RPC
  12. #ifndef NO_SYSTEM_INCLUDES
  13. #include <sys/types.h>
  14. #include <rpc/rpc.h>
  15. #include <ctype.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <unistd.h>
  19. #endif
  20. #include "db_server.h"
  21. #include "db_int.h"
  22. #include "txn.h"
  23. #include "gen_client_ext.h"
  24. #include "rpc_client_ext.h"
  25. /*
  26.  * __dbclenv_server --
  27.  * Initialize an environment's server.
  28.  *
  29.  * PUBLIC: int __dbcl_envserver __P((DB_ENV *, char *, long, long, u_int32_t));
  30.  */
  31. int
  32. __dbcl_envserver(dbenv, host, tsec, ssec, flags)
  33. DB_ENV *dbenv;
  34. char *host;
  35. long tsec, ssec;
  36. u_int32_t flags;
  37. {
  38. CLIENT *cl;
  39. __env_create_msg req;
  40. __env_create_reply *replyp;
  41. struct timeval tp;
  42. int ret;
  43. COMPQUIET(flags, 0);
  44. #ifdef HAVE_VXWORKS
  45. if ((ret = rpcTaskInit()) != 0) {
  46. __db_err(dbenv, "Could not initialize VxWorks RPC");
  47. return (ERROR);
  48. }
  49. #endif
  50. if ((cl =
  51.     clnt_create(host, DB_SERVERPROG, DB_SERVERVERS, "tcp")) == NULL) {
  52. __db_err(dbenv, clnt_spcreateerror(host));
  53. return (DB_NOSERVER);
  54. }
  55. dbenv->cl_handle = cl;
  56. if (tsec != 0) {
  57. tp.tv_sec = tsec;
  58. tp.tv_usec = 0;
  59. (void)clnt_control(cl, CLSET_TIMEOUT, (char *)&tp);
  60. }
  61. req.timeout = ssec;
  62. /*
  63.  * CALL THE SERVER
  64.  */
  65. if ((replyp = __db_env_create_1(&req, cl)) == NULL) {
  66. __db_err(dbenv, clnt_sperror(cl, "Berkeley DB"));
  67. return (DB_NOSERVER);
  68. }
  69. /*
  70.  * Process reply and free up our space from request
  71.  * SUCCESS:  Store ID from server.
  72.  */
  73. if ((ret = replyp->status) != 0)
  74. return (ret);
  75. dbenv->cl_id = replyp->envcl_id;
  76. return (0);
  77. }
  78. /*
  79.  * __dbcl_refresh --
  80.  * Clean up an environment.
  81.  *
  82.  * PUBLIC: int __dbcl_refresh __P((DB_ENV *));
  83.  */
  84. int
  85. __dbcl_refresh(dbenv)
  86. DB_ENV *dbenv;
  87. {
  88. CLIENT *cl;
  89. int ret;
  90. cl = (CLIENT *)dbenv->cl_handle;
  91. ret = 0;
  92. if (dbenv->tx_handle != NULL) {
  93. /*
  94.  * We only need to free up our stuff, the caller
  95.  * of this function will call the server who will
  96.  * do all the real work.
  97.  */
  98. ret = __dbcl_txn_close(dbenv);
  99. dbenv->tx_handle = NULL;
  100. }
  101. if (cl != NULL)
  102. clnt_destroy(cl);
  103. dbenv->cl_handle = NULL;
  104. return (ret);
  105. }
  106. /*
  107.  * __dbcl_txn_close --
  108.  * Clean up an environment's transactions.
  109.  *
  110.  * PUBLIC: int __dbcl_txn_close __P((DB_ENV *));
  111.  */
  112. int
  113. __dbcl_txn_close(dbenv)
  114. DB_ENV *dbenv;
  115. {
  116. DB_TXN *txnp;
  117. DB_TXNMGR *tmgrp;
  118. int ret;
  119. ret = 0;
  120. tmgrp = dbenv->tx_handle;
  121. /*
  122.  * This function can only be called once per process (i.e., not
  123.  * once per thread), so no synchronization is required.
  124.  * Also this function is called *after* the server has been called,
  125.  * so the server has already closed/aborted any transactions that
  126.  * were open on its side.  We only need to do local cleanup.
  127.  */
  128. while ((txnp = TAILQ_FIRST(&tmgrp->txn_chain)) != NULL)
  129. __dbcl_txn_end(txnp);
  130. __os_free(tmgrp, sizeof(*tmgrp));
  131. return (ret);
  132. }
  133. /*
  134.  * __dbcl_txn_end --
  135.  * Clean up an transaction.
  136.  * RECURSIVE FUNCTION:  Clean up nested transactions.
  137.  *
  138.  * PUBLIC: void __dbcl_txn_end __P((DB_TXN *));
  139.  */
  140. void
  141. __dbcl_txn_end(txnp)
  142. DB_TXN *txnp;
  143. {
  144. DB_ENV *dbenv;
  145. DB_TXN *kids;
  146. DB_TXNMGR *mgr;
  147. mgr = txnp->mgrp;
  148. dbenv = mgr->dbenv;
  149. /*
  150.  * First take care of any kids we have
  151.  */
  152. for (kids = TAILQ_FIRST(&txnp->kids);
  153.     kids != NULL;
  154.     kids = TAILQ_FIRST(&txnp->kids))
  155. __dbcl_txn_end(kids);
  156. /*
  157.  * We are ending this transaction no matter what the parent
  158.  * may eventually do, if we have a parent.  All those details
  159.  * are taken care of by the server.  We only need to make sure
  160.  * that we properly release resources.
  161.  */
  162. if (txnp->parent != NULL)
  163. TAILQ_REMOVE(&txnp->parent->kids, txnp, klinks);
  164. TAILQ_REMOVE(&mgr->txn_chain, txnp, links);
  165. __os_free(txnp, sizeof(*txnp));
  166. return;
  167. }
  168. /*
  169.  * __dbcl_c_destroy --
  170.  * Destroy a cursor.
  171.  *
  172.  * PUBLIC: int __dbcl_c_destroy __P((DBC *));
  173.  */
  174. int
  175. __dbcl_c_destroy(dbc)
  176. DBC *dbc;
  177. {
  178. DB *dbp;
  179. dbp = dbc->dbp;
  180. TAILQ_REMOVE(&dbp->free_queue, dbc, links);
  181. __os_free(dbc, sizeof(*dbc));
  182. return (0);
  183. }
  184. /*
  185.  * __dbcl_c_refresh --
  186.  * Refresh a cursor.  Move it from the active queue to the free queue.
  187.  *
  188.  * PUBLIC: void __dbcl_c_refresh __P((DBC *));
  189.  */
  190. void
  191. __dbcl_c_refresh(dbcp)
  192. DBC *dbcp;
  193. {
  194. DB *dbp;
  195. dbp = dbcp->dbp;
  196. dbcp->flags = 0;
  197. dbcp->cl_id = 0;
  198. /*
  199.  * If dbp->cursor fails locally, we use a local dbc so that
  200.  * we can close it.  In that case, dbp will be NULL.
  201.  */
  202. if (dbp != NULL) {
  203. TAILQ_REMOVE(&dbp->active_queue, dbcp, links);
  204. TAILQ_INSERT_TAIL(&dbp->free_queue, dbcp, links);
  205. }
  206. return;
  207. }
  208. /*
  209.  * __dbcl_c_setup --
  210.  * Allocate a cursor.
  211.  *
  212.  * PUBLIC: int __dbcl_c_setup __P((long, DB *, DBC **));
  213.  */
  214. int
  215. __dbcl_c_setup(cl_id, dbp, dbcpp)
  216. long cl_id;
  217. DB *dbp;
  218. DBC **dbcpp;
  219. {
  220. DBC *dbc, tmpdbc;
  221. int ret, t_ret;
  222. if ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
  223. TAILQ_REMOVE(&dbp->free_queue, dbc, links);
  224. else {
  225. if ((ret =
  226.     __os_calloc(dbp->dbenv, 1, sizeof(DBC), &dbc)) != 0) {
  227. /*
  228. * If we die here, set up a tmp dbc to call the
  229. * server to shut down that cursor.
  230. */
  231. tmpdbc.dbp = NULL;
  232. tmpdbc.cl_id = cl_id;
  233. t_ret = __dbcl_dbc_close(&tmpdbc);
  234. return (ret);
  235. }
  236. dbc->c_close = __dbcl_dbc_close;
  237. dbc->c_count = __dbcl_dbc_count;
  238. dbc->c_del = __dbcl_dbc_del;
  239. dbc->c_dup = __dbcl_dbc_dup;
  240. dbc->c_get = __dbcl_dbc_get;
  241. dbc->c_put = __dbcl_dbc_put;
  242. dbc->c_am_destroy = __dbcl_c_destroy;
  243. }
  244. dbc->cl_id = cl_id;
  245. dbc->dbp = dbp;
  246. TAILQ_INSERT_TAIL(&dbp->active_queue, dbc, links);
  247. *dbcpp = dbc;
  248. return (0);
  249. }
  250. /*
  251.  * __dbcl_retcopy --
  252.  * Copy the returned data into the user's DBT, handling special flags
  253.  * as they apply to a client.  Modeled after __db_retcopy().
  254.  *
  255.  * PUBLIC: int __dbcl_retcopy __P((DB_ENV *, DBT *, void *, u_int32_t));
  256.  */
  257. int
  258. __dbcl_retcopy(dbenv, dbt, data, len)
  259. DB_ENV *dbenv;
  260. DBT *dbt;
  261. void *data;
  262. u_int32_t len;
  263. {
  264. int ret;
  265. /*
  266.  * No need to handle DB_DBT_PARTIAL here, server already did.
  267.  */
  268. dbt->size = len;
  269. /*
  270.  * Allocate memory to be owned by the application: DB_DBT_MALLOC
  271.  * and DB_DBT_REALLOC.  Always allocate even if we're copying 0 bytes.
  272.  * Or use memory specified by application: DB_DBT_USERMEM.
  273.  */
  274. if (F_ISSET(dbt, DB_DBT_MALLOC)) {
  275. if ((ret = __os_malloc(dbenv, len, NULL, &dbt->data)) != 0)
  276. return (ret);
  277. } else if (F_ISSET(dbt, DB_DBT_REALLOC)) {
  278. if ((ret = __os_realloc(dbenv, len, NULL, &dbt->data)) != 0)
  279. return (ret);
  280. } else if (F_ISSET(dbt, DB_DBT_USERMEM)) {
  281. if (len != 0 && (dbt->data == NULL || dbt->ulen < len))
  282. return (ENOMEM);
  283. } else {
  284. /*
  285.  * If no user flags, then set the DBT to point to the
  286.  * returned data pointer and return.
  287.  */
  288. dbt->data = data;
  289. return (0);
  290. }
  291. if (len != 0)
  292. memcpy(dbt->data, data, len);
  293. return (0);
  294. }
  295. /*
  296.  * __dbcl_dbclose_common --
  297.  * Common code for closing/cleaning a dbp.
  298.  *
  299.  * PUBLIC: int __dbcl_dbclose_common __P((DB *));
  300.  */
  301. int
  302. __dbcl_dbclose_common(dbp)
  303. DB *dbp;
  304. {
  305. int ret, t_ret;
  306. DBC *dbc;
  307. /*
  308.  * Go through the active cursors and call the cursor recycle routine,
  309.  * which resolves pending operations and moves the cursors onto the
  310.  * free list.  Then, walk the free list and call the cursor destroy
  311.  * routine.
  312.  *
  313.  * NOTE:  We do not need to use the join_queue for join cursors.
  314.  * See comment in __dbcl_dbjoin_ret.
  315.  */
  316. ret = 0;
  317. while ((dbc = TAILQ_FIRST(&dbp->active_queue)) != NULL)
  318. __dbcl_c_refresh(dbc);
  319. while ((dbc = TAILQ_FIRST(&dbp->free_queue)) != NULL)
  320. if ((t_ret = __dbcl_c_destroy(dbc)) != 0 && ret == 0)
  321. ret = t_ret;
  322. TAILQ_INIT(&dbp->free_queue);
  323. TAILQ_INIT(&dbp->active_queue);
  324. memset(dbp, CLEAR_BYTE, sizeof(*dbp));
  325. __os_free(dbp, sizeof(*dbp));
  326. return (ret);
  327. }
  328. #endif /* HAVE_RPC */