mp_method.c 17.2 KB
Newer Older
unknown's avatar
unknown committed
1 2 3
/*-
 * See the file LICENSE for redistribution information.
 *
unknown's avatar
unknown committed
4
 * Copyright (c) 1996-2005
unknown's avatar
unknown committed
5
 *	Sleepycat Software.  All rights reserved.
unknown's avatar
unknown committed
6
 *
unknown's avatar
unknown committed
7
 * $Id: mp_method.c,v 12.15 2005/10/12 12:45:10 margo Exp $
unknown's avatar
unknown committed
8 9
 */

unknown's avatar
unknown committed
10
#include "db_config.h"
unknown's avatar
unknown committed
11 12 13 14

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

unknown's avatar
unknown committed
15 16 17
#include <string.h>
#endif

unknown's avatar
unknown committed
18
#include "db_int.h"
unknown's avatar
unknown committed
19 20
#include "dbinc/db_shash.h"
#include "dbinc/mp.h"
unknown's avatar
unknown committed
21 22 23 24 25 26 27 28 29 30 31 32

/*
 * __memp_dbenv_create --
 *	Mpool specific creation of the DB_ENV structure.
 *
 * PUBLIC: void __memp_dbenv_create __P((DB_ENV *));
 */
void
__memp_dbenv_create(dbenv)
	DB_ENV *dbenv;
{
	/*
unknown's avatar
unknown committed
33 34 35 36 37
	 * !!!
	 * Our caller has not yet had the opportunity to reset the panic
	 * state or turn off mutex locking, and so we can neither check
	 * the panic state or acquire a mutex in the DB_ENV create path.
	 *
unknown's avatar
unknown committed
38 39 40 41
	 * We default to 32 8K pages.  We don't default to a flat 256K, because
	 * some systems require significantly more memory to hold 32 pages than
	 * others.  For example, HP-UX with POSIX pthreads needs 88 bytes for
	 * a POSIX pthread mutex and almost 200 bytes per buffer header, while
unknown's avatar
unknown committed
42 43
	 * Solaris needs 24 and 52 bytes for the same structures.  The minimum
	 * number of hash buckets is 37.  These contain a mutex also.
unknown's avatar
unknown committed
44
	 */
unknown's avatar
unknown committed
45 46
	dbenv->mp_bytes =
	    32 * ((8 * 1024) + sizeof(BH)) + 37 * sizeof(DB_MPOOL_HASH);
unknown's avatar
unknown committed
47
	dbenv->mp_ncache = 1;
unknown's avatar
unknown committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
}

/*
 * __memp_get_cachesize --
 *	{DB_ENV,DB}->get_cachesize.
 *
 * PUBLIC: int __memp_get_cachesize
 * PUBLIC:         __P((DB_ENV *, u_int32_t *, u_int32_t *, int *));
 */
int
__memp_get_cachesize(dbenv, gbytesp, bytesp, ncachep)
	DB_ENV *dbenv;
	u_int32_t *gbytesp, *bytesp;
	int *ncachep;
{
	MPOOL *mp;

	ENV_NOT_CONFIGURED(dbenv,
	    dbenv->mp_handle, "DB_ENV->get_cachesize", DB_INIT_MPOOL);

	if (MPOOL_ON(dbenv)) {
		/* Cannot be set after open, no lock required to read. */
		mp = ((DB_MPOOL *)dbenv->mp_handle)->reginfo[0].primary;
		if (gbytesp != NULL)
			*gbytesp = mp->stat.st_gbytes;
		if (bytesp != NULL)
			*bytesp = mp->stat.st_bytes;
		if (ncachep != NULL)
			*ncachep = (int)mp->nreg;
	} else {
		if (gbytesp != NULL)
			*gbytesp = dbenv->mp_gbytes;
		if (bytesp != NULL)
			*bytesp = dbenv->mp_bytes;
		if (ncachep != NULL)
			*ncachep = (int)dbenv->mp_ncache;
unknown's avatar
unknown committed
84
	}
unknown's avatar
unknown committed
85
	return (0);
unknown's avatar
unknown committed
86 87 88 89
}

/*
 * __memp_set_cachesize --
unknown's avatar
unknown committed
90 91 92
 *	{DB_ENV,DB}->set_cachesize.
 *
 * PUBLIC: int __memp_set_cachesize __P((DB_ENV *, u_int32_t, u_int32_t, int));
unknown's avatar
unknown committed
93
 */
unknown's avatar
unknown committed
94 95
int
__memp_set_cachesize(dbenv, gbytes, bytes, arg_ncache)
unknown's avatar
unknown committed
96 97
	DB_ENV *dbenv;
	u_int32_t gbytes, bytes;
unknown's avatar
unknown committed
98
	int arg_ncache;
unknown's avatar
unknown committed
99
{
unknown's avatar
unknown committed
100
	u_int ncache;
unknown's avatar
unknown committed
101

unknown's avatar
unknown committed
102 103 104 105
	ENV_ILLEGAL_AFTER_OPEN(dbenv, "DB_ENV->set_cachesize");

	/* Normalize the cache count. */
	ncache = arg_ncache <= 0 ? 1 : (u_int)arg_ncache;
unknown's avatar
unknown committed
106 107

	/*
unknown's avatar
unknown committed
108 109 110
	 * You can only store 4GB-1 in an unsigned 32-bit value, so correct for
	 * applications that specify 4GB cache sizes -- we know what they meant.
	 */
unknown's avatar
unknown committed
111
	if (sizeof(roff_t) == 4 && gbytes / ncache == 4 && bytes == 0) {
unknown's avatar
unknown committed
112 113 114 115 116 117 118
		--gbytes;
		bytes = GIGABYTE - 1;
	} else {
		gbytes += bytes / GIGABYTE;
		bytes %= GIGABYTE;
	}

unknown's avatar
unknown committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
	/*
	 * !!!
	 * With 32-bit region offsets, individual cache regions must be smaller
	 * than 4GB.  Also, cache sizes larger than 10TB would cause 32-bit
	 * wrapping in the calculation of the number of hash buckets.  See
	 * __memp_open for details.
	 */
	if (sizeof(roff_t) <= 4) {
		if (gbytes / ncache >= 4) {
			__db_err(dbenv,
			    "individual cache size too large: maximum is 4GB");
			return (EINVAL);
		}
	} else
		if (gbytes / ncache > 10000) {
			__db_err(dbenv,
			    "individual cache size too large: maximum is 10TB");
			return (EINVAL);
		}
unknown's avatar
unknown committed
138 139 140 141 142 143 144 145 146

	/*
	 * If the application requested less than 500Mb, increase the cachesize
	 * by 25% and factor in the size of the hash buckets to account for our
	 * overhead.  (I'm guessing caches over 500Mb are specifically sized,
	 * that is, it's a large server and the application actually knows how
	 * much memory is available.  We only document the 25% overhead number,
	 * not the hash buckets, but I don't see a reason to confuse the issue,
	 * it shouldn't matter to an application.)
unknown's avatar
unknown committed
147 148 149
	 *
	 * There is a minimum cache size, regardless.
	 */
unknown's avatar
unknown committed
150 151 152 153 154
	if (gbytes == 0) {
		if (bytes < 500 * MEGABYTE)
			bytes += (bytes / 4) + 37 * sizeof(DB_MPOOL_HASH);
		if (bytes / ncache < DB_CACHESIZE_MIN)
			bytes = ncache * DB_CACHESIZE_MIN;
unknown's avatar
unknown committed
155 156
	}

unknown's avatar
unknown committed
157 158 159 160
	dbenv->mp_gbytes = gbytes;
	dbenv->mp_bytes = bytes;
	dbenv->mp_ncache = ncache;

unknown's avatar
unknown committed
161 162 163
	return (0);
}

unknown's avatar
unknown committed
164 165 166 167
/*
 * PUBLIC: int __memp_get_mp_max_openfd __P((DB_ENV *, int *));
 */
int
unknown's avatar
unknown committed
168 169 170 171 172 173 174 175 176 177 178 179 180
__memp_get_mp_max_openfd(dbenv, maxopenfdp)
	DB_ENV *dbenv;
	int *maxopenfdp;
{
	DB_MPOOL *dbmp;
	MPOOL *mp;

	ENV_NOT_CONFIGURED(dbenv,
	    dbenv->mp_handle, "DB_ENV->get_mp_max_openfd", DB_INIT_MPOOL);

	if (MPOOL_ON(dbenv)) {
		dbmp = dbenv->mp_handle;
		mp = dbmp->reginfo[0].primary;
unknown's avatar
unknown committed
181
		MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
182
		*maxopenfdp = mp->mp_maxopenfd;
unknown's avatar
unknown committed
183
		MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
184 185 186 187 188
	} else
		*maxopenfdp = dbenv->mp_maxopenfd;
	return (0);
}

unknown's avatar
unknown committed
189
/*
unknown's avatar
unknown committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
 * __memp_set_mp_max_openfd --
 *	Set the maximum number of open fd's when flushing the cache.
 * PUBLIC: int __memp_set_mp_max_openfd __P((DB_ENV *, int));
 */
int
__memp_set_mp_max_openfd(dbenv, maxopenfd)
	DB_ENV *dbenv;
	int maxopenfd;
{
	DB_MPOOL *dbmp;
	MPOOL *mp;

	ENV_NOT_CONFIGURED(dbenv,
	    dbenv->mp_handle, "DB_ENV->set_mp_max_openfd", DB_INIT_MPOOL);

	if (MPOOL_ON(dbenv)) {
		dbmp = dbenv->mp_handle;
		mp = dbmp->reginfo[0].primary;
unknown's avatar
unknown committed
208
		MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
209
		mp->mp_maxopenfd = maxopenfd;
unknown's avatar
unknown committed
210
		MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
211 212 213 214 215
	} else
		dbenv->mp_maxopenfd = maxopenfd;
	return (0);
}

unknown's avatar
unknown committed
216 217 218 219
/*
 * PUBLIC: int __memp_get_mp_max_write __P((DB_ENV *, int *, int *));
 */
int
unknown's avatar
unknown committed
220 221 222 223 224 225 226 227
__memp_get_mp_max_write(dbenv, maxwritep, maxwrite_sleepp)
	DB_ENV *dbenv;
	int *maxwritep, *maxwrite_sleepp;
{
	DB_MPOOL *dbmp;
	MPOOL *mp;

	ENV_NOT_CONFIGURED(dbenv,
unknown's avatar
unknown committed
228
	    dbenv->mp_handle, "DB_ENV->get_mp_max_write", DB_INIT_MPOOL);
unknown's avatar
unknown committed
229 230 231 232

	if (MPOOL_ON(dbenv)) {
		dbmp = dbenv->mp_handle;
		mp = dbmp->reginfo[0].primary;
unknown's avatar
unknown committed
233
		MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
234 235
		*maxwritep = mp->mp_maxwrite;
		*maxwrite_sleepp = mp->mp_maxwrite_sleep;
unknown's avatar
unknown committed
236
		MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
237 238 239 240 241 242 243 244 245 246 247 248
	} else {
		*maxwritep = dbenv->mp_maxwrite;
		*maxwrite_sleepp = dbenv->mp_maxwrite_sleep;
	}
	return (0);
}

/*
 * __memp_set_mp_max_write --
 *	Set the maximum continuous I/O count.
 *
 * PUBLIC: int __memp_set_mp_max_write __P((DB_ENV *, int, int));
unknown's avatar
unknown committed
249
 */
unknown's avatar
unknown committed
250 251 252 253 254 255 256 257 258
int
__memp_set_mp_max_write(dbenv, maxwrite, maxwrite_sleep)
	DB_ENV *dbenv;
	int maxwrite, maxwrite_sleep;
{
	DB_MPOOL *dbmp;
	MPOOL *mp;

	ENV_NOT_CONFIGURED(dbenv,
unknown's avatar
unknown committed
259
	    dbenv->mp_handle, "DB_ENV->get_mp_max_write", DB_INIT_MPOOL);
unknown's avatar
unknown committed
260 261 262 263

	if (MPOOL_ON(dbenv)) {
		dbmp = dbenv->mp_handle;
		mp = dbmp->reginfo[0].primary;
unknown's avatar
unknown committed
264
		MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
265 266
		mp->mp_maxwrite = maxwrite;
		mp->mp_maxwrite_sleep = maxwrite_sleep;
unknown's avatar
unknown committed
267
		MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
268 269 270 271 272 273 274
	} else {
		dbenv->mp_maxwrite = maxwrite;
		dbenv->mp_maxwrite_sleep = maxwrite_sleep;
	}
	return (0);
}

unknown's avatar
unknown committed
275 276 277 278
/*
 * PUBLIC: int __memp_get_mp_mmapsize __P((DB_ENV *, size_t *));
 */
int
unknown's avatar
unknown committed
279 280 281 282 283 284 285 286 287 288 289 290 291
__memp_get_mp_mmapsize(dbenv, mp_mmapsizep)
	DB_ENV *dbenv;
	size_t *mp_mmapsizep;
{
	DB_MPOOL *dbmp;
	MPOOL *mp;

	ENV_NOT_CONFIGURED(dbenv,
	    dbenv->mp_handle, "DB_ENV->get_mp_max_mmapsize", DB_INIT_MPOOL);

	if (MPOOL_ON(dbenv)) {
		dbmp = dbenv->mp_handle;
		mp = dbmp->reginfo[0].primary;
unknown's avatar
unknown committed
292
		MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
293
		*mp_mmapsizep = mp->mp_mmapsize;
unknown's avatar
unknown committed
294
		MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
295 296 297 298 299 300 301 302 303 304 305 306 307
	} else
		*mp_mmapsizep = dbenv->mp_mmapsize;
	return (0);
}

/*
 * __memp_set_mp_mmapsize --
 *	DB_ENV->set_mp_mmapsize.
 *
 * PUBLIC: int __memp_set_mp_mmapsize __P((DB_ENV *, size_t));
 */
int
__memp_set_mp_mmapsize(dbenv, mp_mmapsize)
unknown's avatar
unknown committed
308 309 310
	DB_ENV *dbenv;
	size_t mp_mmapsize;
{
unknown's avatar
unknown committed
311 312 313 314 315 316 317 318 319
	DB_MPOOL *dbmp;
	MPOOL *mp;

	ENV_NOT_CONFIGURED(dbenv,
	    dbenv->mp_handle, "DB_ENV->get_mp_max_mmapsize", DB_INIT_MPOOL);

	if (MPOOL_ON(dbenv)) {
		dbmp = dbenv->mp_handle;
		mp = dbmp->reginfo[0].primary;
unknown's avatar
unknown committed
320
		MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
321
		mp->mp_mmapsize = mp_mmapsize;
unknown's avatar
unknown committed
322
		MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
323 324 325 326 327 328 329 330 331 332
	} else
		dbenv->mp_mmapsize = mp_mmapsize;
	return (0);
}

/*
 * __memp_nameop
 *	Remove or rename a file in the pool.
 *
 * PUBLIC: int __memp_nameop __P((DB_ENV *,
unknown's avatar
unknown committed
333
 * PUBLIC:     u_int8_t *, const char *, const char *, const char *, int));
unknown's avatar
unknown committed
334 335 336 337 338
 *
 * XXX
 * Undocumented interface: DB private.
 */
int
unknown's avatar
unknown committed
339
__memp_nameop(dbenv, fileid, newname, fullold, fullnew, inmem)
unknown's avatar
unknown committed
340 341 342
	DB_ENV *dbenv;
	u_int8_t *fileid;
	const char *newname, *fullold, *fullnew;
unknown's avatar
unknown committed
343
	int inmem;
unknown's avatar
unknown committed
344 345 346
{
	DB_MPOOL *dbmp;
	MPOOL *mp;
unknown's avatar
unknown committed
347
	MPOOLFILE *save_mfp, *mfp;
unknown's avatar
unknown committed
348
	roff_t newname_off;
unknown's avatar
unknown committed
349
	int is_remove, locked, ret;
unknown's avatar
unknown committed
350 351
	void *p;

unknown's avatar
unknown committed
352
	ret = locked = 0;
unknown's avatar
unknown committed
353
	dbmp = NULL;
unknown's avatar
unknown committed
354 355
	save_mfp = mfp = NULL;
	is_remove = newname == NULL;
unknown's avatar
unknown committed
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
	if (!MPOOL_ON(dbenv))
		goto fsop;

	dbmp = dbenv->mp_handle;
	mp = dbmp->reginfo[0].primary;

	/*
	 * Remove or rename a file that the mpool might know about.  We assume
	 * that the fop layer has the file locked for exclusive access, so we
	 * don't worry about locking except for the mpool mutexes.  Checkpoint
	 * can happen at any time, independent of file locking, so we have to
	 * do the actual unlink or rename system call to avoid any race.
	 *
	 * If this is a rename, allocate first, because we can't recursively
	 * grab the region lock.
	 */
unknown's avatar
unknown committed
372
	if (is_remove) {
unknown's avatar
unknown committed
373 374 375 376 377 378 379 380 381 382
		p = NULL;
		COMPQUIET(newname_off, INVALID_ROFF);
	} else {
		if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
		    NULL, strlen(newname) + 1, &newname_off, &p)) != 0)
			return (ret);
		memcpy(p, newname, strlen(newname) + 1);
	}

	locked = 1;
unknown's avatar
unknown committed
383
	MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
384 385

	/*
unknown's avatar
unknown committed
386 387 388 389 390
	 * Find the file -- if mpool doesn't know about this file, that may
	 * not be an error -- if the file is not a memory-only file and it
	 * is not open, it won't show up here.  If this is a memory file
	 * then on a rename, we need to make sure that the new name does
	 * not exist.
unknown's avatar
unknown committed
391 392 393 394 395 396 397
	 */
	for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
	    mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {
		/* Ignore non-active files. */
		if (mfp->deadfile || F_ISSET(mfp, MP_TEMP))
			continue;

unknown's avatar
unknown committed
398 399 400 401 402 403 404 405
		if (!is_remove && inmem && mfp->no_backing_file &&
		    strcmp(newname, R_ADDR(dbmp->reginfo, mfp->path_off))
		    == 0) {
			ret = EEXIST;
			goto err;
		}

		/* Try to match on fileid. */
unknown's avatar
unknown committed
406 407 408 409
		if (memcmp(fileid, R_ADDR(
		    dbmp->reginfo, mfp->fileid_off), DB_FILE_ID_LEN) != 0)
			continue;

unknown's avatar
unknown committed
410 411 412 413 414 415 416 417 418 419
		if (is_remove) {
			MUTEX_LOCK(dbenv, mfp->mutex);
			/*
			 * In-memory dbs have an artificially incremented
			 * ref count so that they do not ever get reclaimed
			 * as long as they exist.  Since we are now deleting
			 * the database, we need to dec that count.
			 */
			if (mfp->no_backing_file)
				mfp->mpf_cnt--;
unknown's avatar
unknown committed
420
			mfp->deadfile = 1;
unknown's avatar
unknown committed
421
			MUTEX_UNLOCK(dbenv, mfp->mutex);
unknown's avatar
unknown committed
422 423 424 425 426 427 428 429
		} else {
			/*
			 * Else, it's a rename.  We've allocated memory
			 * for the new name.  Swap it with the old one.
			 */
			p = R_ADDR(dbmp->reginfo, mfp->path_off);
			mfp->path_off = newname_off;
		}
unknown's avatar
unknown committed
430 431 432
		save_mfp = mfp;
		if (!inmem || is_remove)
			break;
unknown's avatar
unknown committed
433 434 435 436 437 438
	}

	/* Delete the memory we no longer need. */
	if (p != NULL)
		__db_shalloc_free(&dbmp->reginfo[0], p);

unknown's avatar
unknown committed
439 440 441 442
fsop:	if (save_mfp == NULL && inmem) {
		ret = ENOENT;
		goto err;
	}
unknown's avatar
unknown committed
443

unknown's avatar
unknown committed
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
	/*
	 * If this is a real file, then save_mfp could be NULL, because
	 * mpool isn't turned on, and we still need to do the file ops.
	 */
	if (save_mfp == NULL || !save_mfp->no_backing_file) {
		if (is_remove) {
			/*
			 * !!!
			 * Replication may ask us to unlink a file that's been
			 * renamed.  Don't complain if it doesn't exist.
			 */
			if ((ret = __os_unlink(dbenv, fullold)) == ENOENT)
				ret = 0;
		} else {
			/*
			 * Defensive only, fullname should never be
			 * NULL.
			 */
			DB_ASSERT(fullnew != NULL);
			if (fullnew == NULL)
				return (EINVAL);
			ret = __os_rename(dbenv, fullold, fullnew, 1);
		}
unknown's avatar
unknown committed
467 468
	}

unknown's avatar
unknown committed
469 470
err:	if (locked)
		MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498

	return (ret);
}

/*
 * __memp_get_refcnt
 *	Return a reference count, given a fileid.
 *
 * PUBLIC: int __memp_get_refcnt __P((DB_ENV *, u_int8_t *, u_int32_t *));
 */
int
__memp_get_refcnt(dbenv, fileid, refp)
	DB_ENV *dbenv;
	u_int8_t *fileid;
	u_int32_t *refp;
{
	DB_MPOOL *dbmp;
	MPOOL *mp;
	MPOOLFILE *mfp;

	*refp = 0;

	if (!MPOOL_ON(dbenv))
		return (0);

	dbmp = dbenv->mp_handle;
	mp = dbmp->reginfo[0].primary;

unknown's avatar
unknown committed
499
	MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
	/*
	 * Find the file -- if mpool doesn't know about this file, the
	 * reference count is 0.
	 */
	for (mfp = SH_TAILQ_FIRST(&mp->mpfq, __mpoolfile);
	    mfp != NULL; mfp = SH_TAILQ_NEXT(mfp, q, __mpoolfile)) {

		/* Ignore non-active files. */
		if (mfp->deadfile || F_ISSET(mfp, MP_TEMP))
			continue;

		/* Ignore non-matching files. */
		if (memcmp(fileid, R_ADDR(
		    dbmp->reginfo, mfp->fileid_off), DB_FILE_ID_LEN) != 0)
			continue;

unknown's avatar
unknown committed
516
		MUTEX_LOCK(dbenv, mfp->mutex);
unknown's avatar
unknown committed
517
		*refp = mfp->mpf_cnt;
unknown's avatar
unknown committed
518
		MUTEX_UNLOCK(dbenv, mfp->mutex);
unknown's avatar
unknown committed
519 520
		break;
	}
unknown's avatar
unknown committed
521
	MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
522

unknown's avatar
unknown committed
523 524
	return (0);
}
unknown's avatar
unknown committed
525

unknown's avatar
unknown committed
526
#ifdef HAVE_FTRUNCATE
unknown's avatar
unknown committed
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
/*
 * __memp_ftruncate __
 *	Truncate the file.
 *
 * PUBLIC: int __memp_ftruncate __P((DB_MPOOLFILE *, db_pgno_t, u_int32_t));
 */
int
__memp_ftruncate(dbmfp, pgno, flags)
	DB_MPOOLFILE *dbmfp;
	db_pgno_t pgno;
	u_int32_t flags;
{
	DB_ENV *dbenv;
	void *pagep;
	db_pgno_t last_pgno, pg;
unknown's avatar
unknown committed
542
	u_int32_t mbytes, bytes, pgsize;
unknown's avatar
unknown committed
543 544 545 546
	int ret;

	dbenv = dbmfp->dbenv;

unknown's avatar
unknown committed
547
	MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
548
	last_pgno = dbmfp->mfp->last_pgno;
unknown's avatar
unknown committed
549
	MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
550 551

	if (pgno > last_pgno) {
unknown's avatar
unknown committed
552 553
		if (LF_ISSET(MP_TRUNC_RECOVER))
			return (0);
unknown's avatar
unknown committed
554 555 556 557 558 559 560 561 562 563 564
		__db_err(dbenv, "Truncate beyond the end of file");
		return (EINVAL);
	}

	pg = pgno;
	do {
		if ((ret =
		    __memp_fget(dbmfp, &pg, DB_MPOOL_FREE, &pagep)) != 0)
			return (ret);
	} while (pg++ < last_pgno);

unknown's avatar
unknown committed
565 566 567 568 569 570 571
	/*
	 * If we are aborting an extend of a file, the call to __os_truncate
	 * could extend the file if the new page(s) had not yet been written
	 * to disk.  If we are out of disk space, avoid generating an error on
	 * the truncate if we are actually extending the file. [#12743]
	 */
	if (!F_ISSET(dbmfp->mfp, MP_TEMP) && !dbmfp->mfp->no_backing_file &&
unknown's avatar
unknown committed
572
	    (ret = __os_truncate(dbenv,
unknown's avatar
unknown committed
573 574 575 576 577 578 579 580 581
	    dbmfp->fhp, pgno, dbmfp->mfp->stat.st_pagesize)) != 0) {
		if ((__os_ioinfo(dbenv,
		    NULL, dbmfp->fhp, &mbytes, &bytes, NULL)) != 0)
			return (ret);
		pgsize = dbmfp->mfp->stat.st_pagesize;
		if (pgno < (mbytes * (MEGABYTE / pgsize)) + (bytes / pgsize))
			return (ret);
		ret = 0;
	}
unknown's avatar
unknown committed
582

unknown's avatar
unknown committed
583 584 585 586 587 588
	/*
	 * This set could race with another thread of control that extending
	 * the file.  It's not a problem because we should have the page
	 * locked at a higher level of the system.
	 */
	MPOOL_SYSTEM_LOCK(dbenv);
unknown's avatar
unknown committed
589
	dbmfp->mfp->last_pgno = pgno - 1;
unknown's avatar
unknown committed
590
	MPOOL_SYSTEM_UNLOCK(dbenv);
unknown's avatar
unknown committed
591 592 593

	return (ret);
}
unknown's avatar
unknown committed
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753

/*
 * Support routines for maintaining a sorted freelist
 * while we try to rearrange and truncate the file.
 */

/*
 * __memp_alloc_freelist -- allocate mpool space for the freelist.
 *
 * PUBLIC: int __memp_alloc_freelist __P((DB_MPOOLFILE *,
 * PUBLIC:	 u_int32_t, db_pgno_t **));
 */
int
__memp_alloc_freelist(dbmfp, nelems, listp)
	DB_MPOOLFILE *dbmfp;
	u_int32_t nelems;
	db_pgno_t **listp;
{
	DB_ENV *dbenv;
	DB_MPOOL *dbmp;
	MPOOLFILE *mfp;
	void *retp;
	int ret;

	dbenv = dbmfp->dbenv;
	dbmp = dbenv->mp_handle;
	mfp = dbmfp->mfp;

	*listp = NULL;

	/*
	 * These fields are protected because the database layer
	 * has the metapage locked while manipulating them.
	 */
	mfp->free_ref++;
	if (mfp->free_size != 0)
		return (EBUSY);

	/* Allocate at least a few slots. */
	mfp->free_cnt = nelems;
	if (nelems == 0)
		nelems = 50;

	if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
	    NULL, nelems * sizeof(db_pgno_t), &mfp->free_list, &retp)) != 0)
		return (ret);

	mfp->free_size = nelems * sizeof(db_pgno_t);

	*listp = retp;

	return (0);
}

/*
 * __memp_free_freelist -- free the list.
 *
 * PUBLIC: void __memp_free_freelist __P((DB_MPOOLFILE *));
 */
void
__memp_free_freelist(dbmfp)
	DB_MPOOLFILE *dbmfp;
{
	DB_ENV *dbenv;
	DB_MPOOL *dbmp;
	MPOOLFILE *mfp;

	dbenv = dbmfp->dbenv;
	dbmp = dbenv->mp_handle;
	mfp = dbmfp->mfp;

	DB_ASSERT(mfp->free_ref > 0);
	if (--mfp->free_ref > 0)
		return;

	DB_ASSERT(mfp->free_size != 0);

	__db_shalloc_free(dbmp->reginfo, R_ADDR(dbmp->reginfo, mfp->free_list));

	mfp->free_cnt = 0;
	mfp->free_list = 0;
	mfp->free_size = 0;
}

/*
 * __memp_get_freelst -- return current list.
 *
 * PUBLIC: int __memp_get_freelist __P((
 * PUBLIC:	DB_MPOOLFILE *, u_int32_t *, db_pgno_t **));
 */
int
__memp_get_freelist(dbmfp, nelemp, listp)
	DB_MPOOLFILE *dbmfp;
	u_int32_t *nelemp;
	db_pgno_t **listp;
{
	MPOOLFILE *mfp;
	DB_ENV *dbenv;
	DB_MPOOL *dbmp;

	dbenv = dbmfp->dbenv;
	dbmp = dbenv->mp_handle;
	mfp = dbmfp->mfp;

	if (mfp->free_size == 0) {
		*nelemp = 0;
		*listp = NULL;
		return (0);
	}

	*nelemp = mfp->free_cnt;
	*listp = R_ADDR(dbmp->reginfo, mfp->free_list);

	return (0);
}

/*
 * __memp_extend_freelist -- extend the list.
 *
 * PUBLIC: int __memp_extend_freelist __P((
 * PUBLIC:	DB_MPOOLFILE *, u_int32_t , db_pgno_t **));
 */
int
__memp_extend_freelist(dbmfp, count, listp)
	DB_MPOOLFILE *dbmfp;
	u_int32_t count;
	db_pgno_t **listp;
{
	DB_ENV *dbenv;
	DB_MPOOL *dbmp;
	MPOOLFILE *mfp;
	int ret;
	void *retp;

	dbenv = dbmfp->dbenv;
	dbmp = dbenv->mp_handle;
	mfp = dbmfp->mfp;

	if (mfp->free_size == 0)
		return (EINVAL);

	if (count * sizeof(db_pgno_t) > mfp->free_size) {
		mfp->free_size =
		     (size_t)DB_ALIGN(count * sizeof(db_pgno_t), 512);
		*listp = R_ADDR(dbmp->reginfo, mfp->free_list);
		if ((ret = __memp_alloc(dbmp, dbmp->reginfo,
		    NULL, mfp->free_size, &mfp->free_list, &retp)) != 0)
			return (ret);

		memcpy(retp, *listp, mfp->free_cnt * sizeof(db_pgno_t));

		__db_shalloc_free(dbmp->reginfo, *listp);
	}

	mfp->free_cnt = count;
	*listp = R_ADDR(dbmp->reginfo, mfp->free_list);

	return (0);
}
#endif