qam_method.c 7.67 KB
Newer Older
1 2 3
/*-
 * See the file LICENSE for redistribution information.
 *
jimw@mysql.com's avatar
jimw@mysql.com committed
4
 * Copyright (c) 1999-2005
5
 *	Sleepycat Software.  All rights reserved.
jimw@mysql.com's avatar
jimw@mysql.com committed
6
 *
jimw@mysql.com's avatar
jimw@mysql.com committed
7
 * $Id: qam_method.c,v 12.2 2005/09/28 17:45:01 margo Exp $
8 9 10 11 12 13 14 15 16
 */

#include "db_config.h"

#ifndef NO_SYSTEM_INCLUDES
#include <sys/types.h>
#endif

#include "db_int.h"
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
17 18 19 20
#include "dbinc/db_page.h"
#include "dbinc/db_shash.h"
#include "dbinc/db_am.h"
#include "dbinc/lock.h"
jimw@mysql.com's avatar
jimw@mysql.com committed
21
#include "dbinc/mp.h"
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
22 23
#include "dbinc/qam.h"
#include "dbinc/txn.h"
24

jimw@mysql.com's avatar
jimw@mysql.com committed
25 26
static int __qam_rr __P((DB *, DB_TXN *,
	       const char *, const char *, const char *, qam_name_op));
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
static int __qam_set_extentsize __P((DB *, u_int32_t));

/*
 * __qam_db_create --
 *	Queue specific initialization of the DB structure.
 *
 * PUBLIC: int __qam_db_create __P((DB *));
 */
int
__qam_db_create(dbp)
	DB *dbp;
{
	QUEUE *t;
	int ret;

	/* Allocate and initialize the private queue structure. */
	if ((ret = __os_calloc(dbp->dbenv, 1, sizeof(QUEUE), &t)) != 0)
		return (ret);
	dbp->q_internal = t;
jimw@mysql.com's avatar
jimw@mysql.com committed
46
	dbp->get_q_extentsize = __qam_get_extentsize;
47 48 49 50 51 52 53 54 55 56 57
	dbp->set_q_extentsize = __qam_set_extentsize;

	t->re_pad = ' ';

	return (0);
}

/*
 * __qam_db_close --
 *	Queue specific discard of the DB structure.
 *
jimw@mysql.com's avatar
jimw@mysql.com committed
58
 * PUBLIC: int __qam_db_close __P((DB *, u_int32_t));
59 60
 */
int
jimw@mysql.com's avatar
jimw@mysql.com committed
61
__qam_db_close(dbp, flags)
62
	DB *dbp;
jimw@mysql.com's avatar
jimw@mysql.com committed
63
	u_int32_t flags;
64 65 66 67 68 69 70 71 72
{
	DB_MPOOLFILE *mpf;
	MPFARRAY *array;
	QUEUE *t;
	struct __qmpf *mpfp;
	u_int32_t i;
	int ret, t_ret;

	ret = 0;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
73 74
	if ((t = dbp->q_internal) == NULL)
		return (0);
75 76 77 78 79 80 81 82 83

	array = &t->array1;
again:
	mpfp = array->mpfarray;
	if (mpfp != NULL) {
		for (i = array->low_extent;
		    i <= array->hi_extent; i++, mpfp++) {
			mpf = mpfp->mpf;
			mpfp->mpf = NULL;
jimw@mysql.com's avatar
jimw@mysql.com committed
84 85 86
			if (mpf != NULL && (t_ret = __memp_fclose(mpf,
			    LF_ISSET(DB_AM_DISCARD) ? DB_MPOOL_DISCARD : 0))
			    != 0 && ret == 0)
87 88
				ret = t_ret;
		}
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
89
		__os_free(dbp->dbenv, array->mpfarray);
90 91 92 93 94 95 96
	}
	if (t->array2.n_extent != 0) {
		array = &t->array2;
		array->n_extent = 0;
		goto again;
	}

jimw@mysql.com's avatar
jimw@mysql.com committed
97 98 99 100 101
	if (LF_ISSET(DB_AM_DISCARD) &&
	     (t_ret = __qam_nameop(dbp, NULL,
	     NULL, QAM_NAME_DISCARD)) != 0 && ret == 0)
		ret = t_ret;

102
	if (t->path != NULL)
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
103 104
		__os_free(dbp->dbenv, t->path);
	__os_free(dbp->dbenv, t);
105 106 107 108 109
	dbp->q_internal = NULL;

	return (ret);
}

jimw@mysql.com's avatar
jimw@mysql.com committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
/*
 * __qam_get_extentsize --
 *	The DB->q_get_extentsize method.
 *
 * PUBLIC: int __qam_get_extentsize __P((DB *, u_int32_t *));
 */
int
__qam_get_extentsize(dbp, q_extentsizep)
	DB *dbp;
	u_int32_t *q_extentsizep;
{
	*q_extentsizep = ((QUEUE*)dbp->q_internal)->page_ext;
	return (0);
}

125 126 127 128 129
static int
__qam_set_extentsize(dbp, extentsize)
	DB *dbp;
	u_int32_t extentsize;
{
jimw@mysql.com's avatar
jimw@mysql.com committed
130
	DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_extentsize");
131 132

	if (extentsize < 1) {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
133
		__db_err(dbp->dbenv, "Extent size must be at least 1");
134 135 136 137 138 139 140 141 142
		return (EINVAL);
	}

	((QUEUE*)dbp->q_internal)->page_ext = extentsize;

	return (0);
}

/*
jimw@mysql.com's avatar
jimw@mysql.com committed
143 144
 * __queue_pageinfo -
 *	Given a dbp, get first/last page information about a queue.
145
 *
jimw@mysql.com's avatar
jimw@mysql.com committed
146 147
 * PUBLIC: int __queue_pageinfo __P((DB *, db_pgno_t *, db_pgno_t *,
 * PUBLIC:       int *, int, u_int32_t));
148 149
 */
int
jimw@mysql.com's avatar
jimw@mysql.com committed
150
__queue_pageinfo(dbp, firstp, lastp, emptyp, prpage, flags)
151
	DB *dbp;
jimw@mysql.com's avatar
jimw@mysql.com committed
152 153 154
	db_pgno_t *firstp, *lastp;
	int *emptyp;
	int prpage;
155 156
	u_int32_t flags;
{
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
157
	DB_MPOOLFILE *mpf;
158
	QMETA *meta;
jimw@mysql.com's avatar
jimw@mysql.com committed
159 160
	db_pgno_t first, i, last;
	int empty, ret, t_ret;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
161 162

	mpf = dbp->mpf;
163 164 165

	/* Find out the page number of the last page in the database. */
	i = PGNO_BASE_MD;
jimw@mysql.com's avatar
jimw@mysql.com committed
166
	if ((ret = __memp_fget(mpf, &i, 0, &meta)) != 0)
167 168 169
		return (ret);

	first = QAM_RECNO_PAGE(dbp, meta->first_recno);
jimw@mysql.com's avatar
jimw@mysql.com committed
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
	last = QAM_RECNO_PAGE(
	    dbp, meta->cur_recno == 1 ? 1 : meta->cur_recno - 1);

	empty = meta->cur_recno == meta->first_recno;
	if (firstp != NULL)
		*firstp = first;
	if (lastp != NULL)
		*lastp = last;
	if (emptyp != NULL)
		*emptyp = empty;
#ifdef HAVE_STATISTICS
	if (prpage)
		ret = __db_prpage(dbp, (PAGE *)meta, flags);
#else
	COMPQUIET(prpage, 0);
	COMPQUIET(flags, 0);
#endif
187

jimw@mysql.com's avatar
jimw@mysql.com committed
188
	if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0)
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
189 190
		ret = t_ret;

jimw@mysql.com's avatar
jimw@mysql.com committed
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
	return (ret);
}

#ifdef HAVE_STATISTICS
/*
 * __db_prqueue --
 *	Print out a queue
 *
 * PUBLIC: int __db_prqueue __P((DB *, u_int32_t));
 */
int
__db_prqueue(dbp, flags)
	DB *dbp;
	u_int32_t flags;
{
	PAGE *h;
	db_pgno_t first, i, last, pg_ext, stop;
	int empty, ret;

	if ((ret = __queue_pageinfo(dbp, &first, &last, &empty, 1, flags)) != 0)
		return (ret);

	if (empty || ret != 0)
214 215 216 217
		return (ret);

	i = first;
	if (first > last)
jimw@mysql.com's avatar
jimw@mysql.com committed
218
		stop = QAM_RECNO_PAGE(dbp, UINT32_MAX);
219 220 221 222 223 224
	else
		stop = last;

	/* Dump each page. */
begin:
	for (; i <= stop; ++i) {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
225
		if ((ret = __qam_fget(dbp, &i, 0, &h)) != 0) {
226 227
			pg_ext = ((QUEUE *)dbp->q_internal)->page_ext;
			if (pg_ext == 0) {
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
228
				if (ret == DB_PAGE_NOTFOUND && first == last)
229 230 231
					return (0);
				return (ret);
			}
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
232
			if (ret == ENOENT || ret == DB_PAGE_NOTFOUND) {
jimw@mysql.com's avatar
jimw@mysql.com committed
233
				i += (pg_ext - ((i - 1) % pg_ext)) - 1;
234 235 236 237
				continue;
			}
			return (ret);
		}
jimw@mysql.com's avatar
jimw@mysql.com committed
238
		(void)__db_prpage(dbp, h, flags);
239 240 241 242 243 244 245 246 247 248 249 250
		if ((ret = __qam_fput(dbp, i, h, 0)) != 0)
			return (ret);
	}

	if (first > last) {
		i = 1;
		stop = last;
		first = last;
		goto begin;
	}
	return (0);
}
jimw@mysql.com's avatar
jimw@mysql.com committed
251
#endif
252 253

/*
jimw@mysql.com's avatar
jimw@mysql.com committed
254
 * __qam_remove --
255 256
 *	Remove method for a Queue.
 *
jimw@mysql.com's avatar
jimw@mysql.com committed
257
 * PUBLIC: int __qam_remove __P((DB *, DB_TXN *, const char *, const char *));
258 259
 */
int
jimw@mysql.com's avatar
jimw@mysql.com committed
260
__qam_remove(dbp, txn, name, subdb)
261
	DB *dbp;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
262
	DB_TXN *txn;
263
	const char *name, *subdb;
jimw@mysql.com's avatar
jimw@mysql.com committed
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
{
	return (__qam_rr(dbp, txn, name, subdb, NULL, QAM_NAME_REMOVE));
}

/*
 * __qam_rename --
 *	Rename method for a Queue.
 *
 * PUBLIC: int __qam_rename __P((DB *,
 * PUBLIC:         DB_TXN *, const char *, const char *, const char *));
 */
int
__qam_rename(dbp, txn, name, subdb, newname)
	DB *dbp;
	DB_TXN *txn;
	const char *name, *subdb, *newname;
{
	return (__qam_rr(dbp, txn, name, subdb, newname, QAM_NAME_RENAME));
}

/*
 * __qam_rr --
 *	Remove/Rename method for a Queue.
 */
static int
__qam_rr(dbp, txn, name, subdb, newname, op)
	DB *dbp;
	DB_TXN *txn;
	const char *name, *subdb, *newname;
	qam_name_op op;
294 295
{
	DB_ENV *dbenv;
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
296
	DB *tmpdbp;
297
	QUEUE *qp;
jimw@mysql.com's avatar
jimw@mysql.com committed
298
	int ret, t_ret;
299 300 301 302 303 304

	dbenv = dbp->dbenv;
	ret = 0;

	PANIC_CHECK(dbenv);

jimw@mysql.com's avatar
jimw@mysql.com committed
305
	if (subdb != NULL && name != NULL) {
306
		__db_err(dbenv,
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
307
		    "Queue does not support multiple databases per file");
jimw@mysql.com's avatar
jimw@mysql.com committed
308
		return (EINVAL);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
309 310 311
	}

	/*
jimw@mysql.com's avatar
jimw@mysql.com committed
312
	 * Since regular rename no longer opens the database, we may have
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
313 314 315 316 317 318 319
	 * to do it here.
	 */
	if (F_ISSET(dbp, DB_AM_OPEN_CALLED))
		tmpdbp = dbp;
	else {
		if ((ret = db_create(&tmpdbp, dbenv, 0)) != 0)
			return (ret);
jimw@mysql.com's avatar
jimw@mysql.com committed
320

ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
321 322 323 324 325
		/*
		 * We need to make sure we don't self-deadlock, so give
		 * this dbp the same locker as the incoming one.
		 */
		tmpdbp->lid = dbp->lid;
jimw@mysql.com's avatar
jimw@mysql.com committed
326 327
		if ((ret = __db_open(tmpdbp, txn,
		    name, NULL, DB_QUEUE, DB_RDONLY, 0, PGNO_BASE_MD)) != 0)
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
328
			goto err;
329 330
	}

ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
331
	qp = (QUEUE *)tmpdbp->q_internal;
jimw@mysql.com's avatar
jimw@mysql.com committed
332 333
	if (qp->page_ext != 0)
		ret = __qam_nameop(tmpdbp, txn, newname, op);
334

jimw@mysql.com's avatar
jimw@mysql.com committed
335 336 337
	if (!F_ISSET(dbp, DB_AM_OPEN_CALLED)) {
err:		/*
		 * Since we copied the locker ID from the dbp, we'd better not
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
338 339 340 341
		 * free it here.
		 */
		tmpdbp->lid = DB_LOCK_INVALIDID;

jimw@mysql.com's avatar
jimw@mysql.com committed
342
		/* We need to remove the lock event we associated with this. */
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
343 344 345 346 347
		if (txn != NULL)
			__txn_remlock(dbenv,
			    txn, &tmpdbp->handle_lock, DB_LOCK_INVALIDID);

		if ((t_ret =
jimw@mysql.com's avatar
jimw@mysql.com committed
348
		    __db_close(tmpdbp, txn, DB_NOSYNC)) != 0 && ret == 0)
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
349 350
			ret = t_ret;
	}
351 352 353 354
	return (ret);
}

/*
jimw@mysql.com's avatar
jimw@mysql.com committed
355 356
 * __qam_map_flags --
 *	Map queue-specific flags from public to the internal values.
357
 *
jimw@mysql.com's avatar
jimw@mysql.com committed
358
 * PUBLIC: void __qam_map_flags __P((DB *, u_int32_t *, u_int32_t *));
359
 */
jimw@mysql.com's avatar
jimw@mysql.com committed
360 361
void
__qam_map_flags(dbp, inflagsp, outflagsp)
362
	DB *dbp;
jimw@mysql.com's avatar
jimw@mysql.com committed
363
	u_int32_t *inflagsp, *outflagsp;
364
{
jimw@mysql.com's avatar
jimw@mysql.com committed
365
	COMPQUIET(dbp, NULL);
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
366

jimw@mysql.com's avatar
jimw@mysql.com committed
367 368 369
	if (FLD_ISSET(*inflagsp, DB_INORDER)) {
		FLD_SET(*outflagsp, DB_AM_INORDER);
		FLD_CLR(*inflagsp, DB_INORDER);
370
	}
jimw@mysql.com's avatar
jimw@mysql.com committed
371
}
372

jimw@mysql.com's avatar
jimw@mysql.com committed
373 374 375 376 377 378 379 380 381 382 383
/*
 * __qam_set_flags --
 *	Set queue-specific flags.
 *
 * PUBLIC: int __qam_set_flags __P((DB *, u_int32_t *flagsp));
 */
int
__qam_set_flags(dbp, flagsp)
	DB *dbp;
	u_int32_t *flagsp;
{
ram@mysql.r18.ru's avatar
ram@mysql.r18.ru committed
384

jimw@mysql.com's avatar
jimw@mysql.com committed
385 386
	__qam_map_flags(dbp, flagsp, &dbp->flags);
	return (0);
387
}