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

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.  * This code is derived from software contributed to Sleepycat Software by
  8.  * Frederick G.M. Roeber of Netscape Communications Corp.
  9.  */
  10. #include "db_config.h"
  11. #ifndef lint
  12. static const char revid[] = "$Id: os_vx_map.c,v 1.21 2002/03/06 19:36:58 margo Exp $";
  13. #endif /* not lint */
  14. #ifndef NO_SYSTEM_INCLUDES
  15. #include <sys/types.h>
  16. #include <string.h>
  17. #endif
  18. #include "db_int.h"
  19. /*
  20.  * DB uses memory-mapped files for two things:
  21.  * faster access of read-only databases, and
  22.  * shared memory for process synchronization and locking.
  23.  * The code carefully does not mix the two uses.  The first-case uses are
  24.  * actually written such that memory-mapping isn't really required -- it's
  25.  * merely a convenience -- so we don't have to worry much about it.  In the
  26.  * second case, it's solely used as a shared memory mechanism, so that's
  27.  * all we have to replace.
  28.  *
  29.  * All memory in VxWorks is shared, and a task can allocate memory and keep
  30.  * notes.  So I merely have to allocate memory, remember the "filename" for
  31.  * that memory, and issue small-integer segment IDs which index the list of
  32.  * these shared-memory segments. Subsequent opens are checked against the
  33.  * list of already open segments.
  34.  */
  35. typedef struct {
  36. void *segment; /* Segment address. */
  37. u_int32_t size; /* Segment size. */
  38. char *name; /* Segment name. */
  39. long segid; /* Segment ID. */
  40. } os_segdata_t;
  41. static os_segdata_t *__os_segdata; /* Segment table. */
  42. static int __os_segdata_size; /* Segment table size. */
  43. #define OS_SEGDATA_STARTING_SIZE 16
  44. #define OS_SEGDATA_INCREMENT  16
  45. static int __os_segdata_allocate
  46.        __P((DB_ENV *, const char *, REGINFO *, REGION *));
  47. static int __os_segdata_find_byname
  48.        __P((DB_ENV *, const char *, REGINFO *, REGION *));
  49. static int __os_segdata_init __P((DB_ENV *));
  50. static int __os_segdata_new __P((DB_ENV *, int *));
  51. static int __os_segdata_release __P((DB_ENV *, REGION *, int));
  52. /*
  53.  * __os_r_sysattach --
  54.  * Create/join a shared memory region.
  55.  *
  56.  * PUBLIC: int __os_r_sysattach __P((DB_ENV *, REGINFO *, REGION *));
  57.  */
  58. int
  59. __os_r_sysattach(dbenv, infop, rp)
  60. DB_ENV *dbenv;
  61. REGINFO *infop;
  62. REGION *rp;
  63. {
  64. int ret;
  65. if (__os_segdata == NULL)
  66. __os_segdata_init(dbenv);
  67. DB_BEGIN_SINGLE_THREAD;
  68. /* Try to find an already existing segment. */
  69. ret = __os_segdata_find_byname(dbenv, infop->name, infop, rp);
  70. /*
  71.  * If we are trying to join a region, it is easy, either we
  72.  * found it and we return, or we didn't find it and we return
  73.  * an error that it doesn't exist.
  74.  */
  75. if (!F_ISSET(infop, REGION_CREATE)) {
  76. if (ret != 0) {
  77. __db_err(dbenv, "segment %s does not exist",
  78.     infop->name);
  79. ret = EAGAIN;
  80. }
  81. goto out;
  82. }
  83. /*
  84.  * If we get here, we are trying to create the region.
  85.  * There are several things to consider:
  86.  * - if we have an error (not a found or not-found value), return.
  87.  * - they better have shm_key set.
  88.  * - if the region is already there (ret == 0 from above),
  89.  * assume the application crashed and we're restarting.
  90.  * Delete the old region.
  91.  * - try to create the region.
  92.  */
  93. if (ret != 0 && ret != ENOENT)
  94. goto out;
  95. if (dbenv->shm_key == INVALID_REGION_SEGID) {
  96. __db_err(dbenv, "no base shared memory ID specified");
  97. ret = EAGAIN;
  98. goto out;
  99. }
  100. if (ret == 0 && __os_segdata_release(dbenv, rp, 1) != 0) {
  101. __db_err(dbenv,
  102.     "key: %ld: shared memory region already exists",
  103.     dbenv->shm_key + (infop->id - 1));
  104. ret = EAGAIN;
  105. goto out;
  106. }
  107. ret = __os_segdata_allocate(dbenv, infop->name, infop, rp);
  108. out:
  109. DB_END_SINGLE_THREAD;
  110. return (ret);
  111. }
  112. /*
  113.  * __os_r_sysdetach --
  114.  * Detach from a shared region.
  115.  *
  116.  * PUBLIC: int __os_r_sysdetach __P((DB_ENV *, REGINFO *, int));
  117.  */
  118. int
  119. __os_r_sysdetach(dbenv, infop, destroy)
  120. DB_ENV *dbenv;
  121. REGINFO *infop;
  122. int destroy;
  123. {
  124. /*
  125.  * If just detaching, there is no mapping to discard.
  126.  * If destroying, remove the region.
  127.  */
  128. if (destroy)
  129. return (__os_segdata_release(dbenv, infop->rp, 0));
  130. return (0);
  131. }
  132. /*
  133.  * __os_mapfile --
  134.  * Map in a shared memory file.
  135.  *
  136.  * PUBLIC: int __os_mapfile __P((DB_ENV *,
  137.  * PUBLIC:    char *, DB_FH *, size_t, int, void **));
  138.  */
  139. int
  140. __os_mapfile(dbenv, path, fhp, len, is_rdonly, addrp)
  141. DB_ENV *dbenv;
  142. char *path;
  143. DB_FH *fhp;
  144. int is_rdonly;
  145. size_t len;
  146. void **addrp;
  147. {
  148. /* We cannot map in regular files in VxWorks. */
  149. COMPQUIET(dbenv, NULL);
  150. COMPQUIET(path, NULL);
  151. COMPQUIET(fhp, NULL);
  152. COMPQUIET(is_rdonly, 0);
  153. COMPQUIET(len, 0);
  154. COMPQUIET(addrp, NULL);
  155. return (EINVAL);
  156. }
  157. /*
  158.  * __os_unmapfile --
  159.  * Unmap the shared memory file.
  160.  *
  161.  * PUBLIC: int __os_unmapfile __P((DB_ENV *, void *, size_t));
  162.  */
  163. int
  164. __os_unmapfile(dbenv, addr, len)
  165. DB_ENV *dbenv;
  166. void *addr;
  167. size_t len;
  168. {
  169. /* We cannot map in regular files in VxWorks. */
  170. COMPQUIET(dbenv, NULL);
  171. COMPQUIET(addr, NULL);
  172. COMPQUIET(len, 0);
  173. return (EINVAL);
  174. }
  175. /*
  176.  * __os_segdata_init --
  177.  * Initializes the library's table of shared memory segments.
  178.  * Called once on the first time through __os_segdata_new().
  179.  */
  180. static int
  181. __os_segdata_init(dbenv)
  182. DB_ENV *dbenv;
  183. {
  184. int ret;
  185. if (__os_segdata != NULL) {
  186. __db_err(dbenv, "shared memory segment already exists");
  187. return (EEXIST);
  188. }
  189. /*
  190.  * The lock init call returns a locked lock.
  191.  */
  192. DB_BEGIN_SINGLE_THREAD;
  193. __os_segdata_size = OS_SEGDATA_STARTING_SIZE;
  194. ret = __os_calloc(dbenv,
  195.     __os_segdata_size, sizeof(os_segdata_t), &__os_segdata);
  196. DB_END_SINGLE_THREAD;
  197. return (ret);
  198. }
  199. /*
  200.  * __os_segdata_destroy --
  201.  * Destroys the library's table of shared memory segments.  It also
  202.  * frees all linked data: the segments themselves, and their names.
  203.  * Currently not called.  This function should be called if the
  204.  * user creates a function to unload or shutdown.
  205.  *
  206.  * PUBLIC: int __os_segdata_destroy __P((DB_ENV *));
  207.  */
  208. int
  209. __os_segdata_destroy(dbenv)
  210. DB_ENV *dbenv;
  211. {
  212. os_segdata_t *p;
  213. int i;
  214. if (__os_segdata == NULL)
  215. return (0);
  216. DB_BEGIN_SINGLE_THREAD;
  217. for (i = 0; i < __os_segdata_size; i++) {
  218. p = &__os_segdata[i];
  219. if (p->name != NULL) {
  220. __os_free(dbenv, p->name);
  221. p->name = NULL;
  222. }
  223. if (p->segment != NULL) {
  224. __os_free(dbenv, p->segment);
  225. p->segment = NULL;
  226. }
  227. p->size = 0;
  228. }
  229. __os_free(dbenv, __os_segdata);
  230. __os_segdata = NULL;
  231. __os_segdata_size = 0;
  232. DB_END_SINGLE_THREAD;
  233. return (0);
  234. }
  235. /*
  236.  * __os_segdata_allocate --
  237.  * Creates a new segment of the specified size, optionally with the
  238.  * specified name.
  239.  *
  240.  * Assumes it is called with the SEGDATA lock taken.
  241.  */
  242. static int
  243. __os_segdata_allocate(dbenv, name, infop, rp)
  244. DB_ENV *dbenv;
  245. const char *name;
  246. REGINFO *infop;
  247. REGION *rp;
  248. {
  249. os_segdata_t *p;
  250. int id, ret;
  251. if ((ret = __os_segdata_new(dbenv, &id)) != 0)
  252. return (ret);
  253. p = &__os_segdata[id];
  254. if ((ret = __os_calloc(dbenv, 1, rp->size, &p->segment)) != 0)
  255. return (ret);
  256. if ((ret = __os_strdup(dbenv, name, &p->name)) != 0) {
  257. __os_free(dbenv, p->segment);
  258. p->segment = NULL;
  259. return (ret);
  260. }
  261. p->size = rp->size;
  262. p->segid = dbenv->shm_key + infop->id - 1;
  263. infop->addr = p->segment;
  264. rp->segid = id;
  265. return (0);
  266. }
  267. /*
  268.  * __os_segdata_new --
  269.  * Finds a new segdata slot.  Does not initialise it, so the fd returned
  270.  * is only valid until you call this again.
  271.  *
  272.  * Assumes it is called with the SEGDATA lock taken.
  273.  */
  274. static int
  275. __os_segdata_new(dbenv, segidp)
  276. DB_ENV *dbenv;
  277. int *segidp;
  278. {
  279. os_segdata_t *p;
  280. int i, newsize, ret;
  281. if (__os_segdata == NULL) {
  282. __db_err(dbenv, "shared memory segment not initialized");
  283. return (EAGAIN);
  284. }
  285. for (i = 0; i < __os_segdata_size; i++) {
  286. p = &__os_segdata[i];
  287. if (p->segment == NULL) {
  288. *segidp = i;
  289. return (0);
  290. }
  291. }
  292. /*
  293.  * No more free slots, expand.
  294.  */
  295. newsize = __os_segdata_size + OS_SEGDATA_INCREMENT;
  296. if ((ret = __os_realloc(dbenv, newsize * sizeof(os_segdata_t),
  297.     &__os_segdata)) != 0)
  298. return (ret);
  299. memset(&__os_segdata[__os_segdata_size],
  300.     0, OS_SEGDATA_INCREMENT * sizeof(os_segdata_t));
  301. *segidp = __os_segdata_size;
  302. __os_segdata_size = newsize;
  303. return (0);
  304. }
  305. /*
  306.  * __os_segdata_find_byname --
  307.  * Finds a segment by its name and shm_key.
  308.  *
  309.  * Assumes it is called with the SEGDATA lock taken.
  310.  *
  311.  * PUBLIC: __os_segdata_find_byname
  312.  * PUBLIC:     __P((DB_ENV *, const char *, REGINFO *, REGION *));
  313.  */
  314. static int
  315. __os_segdata_find_byname(dbenv, name, infop, rp)
  316. DB_ENV *dbenv;
  317. const char *name;
  318. REGINFO *infop;
  319. REGION *rp;
  320. {
  321. os_segdata_t *p;
  322. long segid;
  323. int i;
  324. if (__os_segdata == NULL) {
  325. __db_err(dbenv, "shared memory segment not initialized");
  326. return (EAGAIN);
  327. }
  328. if (name == NULL) {
  329. __db_err(dbenv, "no segment name given");
  330. return (EAGAIN);
  331. }
  332. /*
  333.  * If we are creating the region, compute the segid.
  334.  * If we are joining the region, we use the segid in the
  335.  * index we are given.
  336.  */
  337. if (F_ISSET(infop, REGION_CREATE))
  338. segid = dbenv->shm_key + (infop->id - 1);
  339. else {
  340. if (rp->segid >= __os_segdata_size ||
  341.     rp->segid == INVALID_REGION_SEGID) {
  342. __db_err(dbenv, "Invalid segment id given");
  343. return (EAGAIN);
  344. }
  345. segid = __os_segdata[rp->segid].segid;
  346. }
  347. for (i = 0; i < __os_segdata_size; i++) {
  348. p = &__os_segdata[i];
  349. if (p->name != NULL && strcmp(name, p->name) == 0 &&
  350.     p->segid == segid) {
  351. infop->addr = p->segment;
  352. rp->segid = i;
  353. return (0);
  354. }
  355. }
  356. return (ENOENT);
  357. }
  358. /*
  359.  * __os_segdata_release --
  360.  * Free a segdata entry.
  361.  */
  362. static int
  363. __os_segdata_release(dbenv, rp, is_locked)
  364. DB_ENV *dbenv;
  365. REGION *rp;
  366. int is_locked;
  367. {
  368. os_segdata_t *p;
  369. if (__os_segdata == NULL) {
  370. __db_err(dbenv, "shared memory segment not initialized");
  371. return (EAGAIN);
  372. }
  373. if (rp->segid < 0 || rp->segid >= __os_segdata_size) {
  374. __db_err(dbenv, "segment id %ld out of range", rp->segid);
  375. return (EINVAL);
  376. }
  377. if (is_locked == 0)
  378. DB_BEGIN_SINGLE_THREAD;
  379. p = &__os_segdata[rp->segid];
  380. if (p->name != NULL) {
  381. __os_free(dbenv, p->name);
  382. p->name = NULL;
  383. }
  384. if (p->segment != NULL) {
  385. __os_free(dbenv, p->segment);
  386. p->segment = NULL;
  387. }
  388. p->size = 0;
  389. if (is_locked == 0)
  390. DB_END_SINGLE_THREAD;
  391. /* Any shrink-table logic could go here */
  392. return (0);
  393. }