1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
6 */
7 #include "config.h"
8
9 #ifndef lint
10 static const char sccsid[] = "@(#)mp_open.c 10.27 (Sleepycat) 10/1/98";
11 #endif /* not lint */
12
13 #ifndef NO_SYSTEM_INCLUDES
14 #include <sys/types.h>
15
16 #include <errno.h>
17 #include <string.h>
18 #endif
19
20 #include "db_int.h"
21 #include "shqueue.h"
22 #include "db_shash.h"
23 #include "mp.h"
24 #include "common_ext.h"
25
26 /*
27 * memp_open --
28 * Initialize and/or join a memory pool.
29 */
30 int
memp_open(path,flags,mode,dbenv,retp)31 memp_open(path, flags, mode, dbenv, retp)
32 const char *path;
33 u_int32_t flags;
34 int mode;
35 DB_ENV *dbenv;
36 DB_MPOOL **retp;
37 {
38 DB_MPOOL *dbmp;
39 size_t cachesize;
40 int is_private, ret;
41
42 /* Validate arguments. */
43 #ifdef HAVE_SPINLOCKS
44 #define OKFLAGS (DB_CREATE | DB_MPOOL_PRIVATE | DB_NOMMAP | DB_THREAD)
45 #else
46 #define OKFLAGS (DB_CREATE | DB_MPOOL_PRIVATE | DB_NOMMAP)
47 #endif
48 if ((ret = __db_fchk(dbenv, "memp_open", flags, OKFLAGS)) != 0)
49 return (ret);
50
51 /* Extract fields from DB_ENV structure. */
52 cachesize = dbenv == NULL ? 0 : dbenv->mp_size;
53
54 /* Create and initialize the DB_MPOOL structure. */
55 if ((ret = __os_calloc(1, sizeof(DB_MPOOL), &dbmp)) != 0)
56 return (ret);
57 LIST_INIT(&dbmp->dbregq);
58 TAILQ_INIT(&dbmp->dbmfq);
59
60 dbmp->dbenv = dbenv;
61
62 /* Decide if it's possible for anyone else to access the pool. */
63 is_private =
64 (dbenv == NULL && path == NULL) || LF_ISSET(DB_MPOOL_PRIVATE);
65
66 /*
67 * Map in the region. We do locking regardless, as portions of it are
68 * implemented in common code (if we put the region in a file, that is).
69 */
70 F_SET(dbmp, MP_LOCKREGION);
71 if ((ret = __memp_ropen(dbmp,
72 path, cachesize, mode, is_private, LF_ISSET(DB_CREATE))) != 0)
73 goto err;
74 F_CLR(dbmp, MP_LOCKREGION);
75
76 /*
77 * If there's concurrent access, then we have to lock the region.
78 * If it's threaded, then we have to lock both the handles and the
79 * region, and we need to allocate a mutex for that purpose.
80 */
81 if (!is_private)
82 F_SET(dbmp, MP_LOCKREGION);
83 if (LF_ISSET(DB_THREAD)) {
84 F_SET(dbmp, MP_LOCKHANDLE | MP_LOCKREGION);
85 LOCKREGION(dbmp);
86 ret = __memp_alloc(dbmp,
87 sizeof(db_mutex_t), NULL, &dbmp->mutexp);
88 UNLOCKREGION(dbmp);
89 if (ret != 0) {
90 (void)memp_close(dbmp);
91 goto err;
92 }
93 LOCKINIT(dbmp, dbmp->mutexp);
94 }
95
96 *retp = dbmp;
97 return (0);
98
99 err: if (dbmp != NULL)
100 __os_free(dbmp, sizeof(DB_MPOOL));
101 return (ret);
102 }
103
104 /*
105 * memp_close --
106 * Close a memory pool.
107 */
108 int
memp_close(dbmp)109 memp_close(dbmp)
110 DB_MPOOL *dbmp;
111 {
112 DB_MPOOLFILE *dbmfp;
113 DB_MPREG *mpreg;
114 int ret, t_ret;
115
116 ret = 0;
117
118 MP_PANIC_CHECK(dbmp);
119
120 /* Discard DB_MPREGs. */
121 while ((mpreg = LIST_FIRST(&dbmp->dbregq)) != NULL) {
122 LIST_REMOVE(mpreg, q);
123 __os_free(mpreg, sizeof(DB_MPREG));
124 }
125
126 /* Discard DB_MPOOLFILEs. */
127 while ((dbmfp = TAILQ_FIRST(&dbmp->dbmfq)) != NULL)
128 if ((t_ret = memp_fclose(dbmfp)) != 0 && ret == 0)
129 ret = t_ret;
130
131 /* Discard thread mutex. */
132 if (F_ISSET(dbmp, MP_LOCKHANDLE)) {
133 LOCKREGION(dbmp);
134 __db_shalloc_free(dbmp->addr, dbmp->mutexp);
135 UNLOCKREGION(dbmp);
136 }
137
138 /* Close the region. */
139 if ((t_ret = __db_rdetach(&dbmp->reginfo)) != 0 && ret == 0)
140 ret = t_ret;
141
142 if (dbmp->reginfo.path != NULL)
143 __os_freestr(dbmp->reginfo.path);
144 __os_free(dbmp, sizeof(DB_MPOOL));
145
146 return (ret);
147 }
148
149 /*
150 * __memp_panic --
151 * Panic a memory pool.
152 *
153 * PUBLIC: void __memp_panic __P((DB_ENV *));
154 */
155 void
__memp_panic(dbenv)156 __memp_panic(dbenv)
157 DB_ENV *dbenv;
158 {
159 if (dbenv->mp_info != NULL)
160 dbenv->mp_info->mp->rlayout.panic = 1;
161 }
162
163 /*
164 * memp_unlink --
165 * Exit a memory pool.
166 */
167 int
memp_unlink(path,force,dbenv)168 memp_unlink(path, force, dbenv)
169 const char *path;
170 int force;
171 DB_ENV *dbenv;
172 {
173 REGINFO reginfo;
174 int ret;
175
176 memset(®info, 0, sizeof(reginfo));
177 reginfo.dbenv = dbenv;
178 reginfo.appname = DB_APP_NONE;
179 if (path != NULL && (ret = __os_strdup(path, ®info.path)) != 0)
180 return (ret);
181 reginfo.file = DB_DEFAULT_MPOOL_FILE;
182 ret = __db_runlink(®info, force);
183 if (reginfo.path != NULL)
184 __os_freestr(reginfo.path);
185 return (ret);
186 }
187
188 /*
189 * memp_register --
190 * Register a file type's pgin, pgout routines.
191 */
192 int
memp_register(dbmp,ftype,pgin,pgout)193 memp_register(dbmp, ftype, pgin, pgout)
194 DB_MPOOL *dbmp;
195 int ftype;
196 int (*pgin) __P((db_pgno_t, void *, DBT *));
197 int (*pgout) __P((db_pgno_t, void *, DBT *));
198 {
199 DB_MPREG *mpr;
200 int ret;
201
202 MP_PANIC_CHECK(dbmp);
203
204 if ((ret = __os_malloc(sizeof(DB_MPREG), NULL, &mpr)) != 0)
205 return (ret);
206
207 mpr->ftype = ftype;
208 mpr->pgin = pgin;
209 mpr->pgout = pgout;
210
211 /*
212 * Insert at the head. Because we do a linear walk, we'll find
213 * the most recent registry in the case of multiple entries, so
214 * we don't have to check for multiple registries.
215 */
216 LOCKHANDLE(dbmp, dbmp->mutexp);
217 LIST_INSERT_HEAD(&dbmp->dbregq, mpr, q);
218 UNLOCKHANDLE(dbmp, dbmp->mutexp);
219
220 return (0);
221 }
222