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

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