1N/A * See the file LICENSE for redistribution information. 1N/A * Copyright (c) 1996, 1997, 1998 1N/A * Sleepycat Software. All rights reserved. 1N/A#
endif /* not lint */ 1N/A * Write the page associated with a given bucket header. 1N/A * PUBLIC: int __memp_bhwrite 1N/A * PUBLIC: __P((DB_MPOOL *, MPOOLFILE *, BH *, int *, int *)); 1N/A * Walk the process' DB_MPOOLFILE list and find a file descriptor for 1N/A * the file. We also check that the descriptor is open for writing. 1N/A * If we find a descriptor on the file that's not open for writing, we 1N/A * try and upgrade it to make it writeable. If that fails, we're done. 1N/A * Increment the reference count -- see the comment in 1N/A * It's not a page from a file we've opened. If the file requires 1N/A * information as to how to write this type of file. If not, there's 1N/A * nothing we can do. 1N/A * Try and open the file, attaching to the underlying shared area. 1N/A * Don't try to attach to temporary files. There are two problems in 1N/A * trying to do that. First, if we have different privileges than the 1N/A * process that "owns" the temporary file, we might create the backing 1N/A * disk file such that the owning process couldn't read/write its own 1N/A * buffers, e.g., memp_trickle() running as root creating a file owned 1N/A * as root, mode 600. Second, if the temporary file has already been 1N/A * created, we don't have any way of finding out what its real name is, 1N/A * and, even if we did, it was already unlinked (so that it won't be 1N/A * left if the process dies horribly). This decision causes a problem, 1N/A * however: if the temporary file consumes the entire buffer cache, 1N/A * and the owner doesn't flush the buffers to disk, we could end up 1N/A * with resource starvation, and the memp_trickle() thread couldn't do 1N/A * anything about it. That's a pretty unlikely scenario, though. 1N/A * There's no negative cache, so we may repeatedly try and open files 1N/A * that we have previously tried (and failed) to open. 1N/A * Ignore any error, assume it's a permissions problem. 1N/A * Read a page from a file. 1N/A * PUBLIC: int __memp_pgread __P((DB_MPOOLFILE *, BH *, int)); 1N/A * Temporary files may not yet have been created. We don't create 1N/A * them now, we create them when the pages have to be flushed. 1N/A * Ignore read errors if we have permission to create the page. 1N/A * Assume that the page doesn't exist, and that we'll create it 1N/A * when we write it out. 1N/A /* If we had a short read, ret may be 0. */ 1N/A "%s: page %lu doesn't exist, create flag not set",
1N/A * Clear any bytes we didn't read that need to be cleared. If we're 1N/A * running in diagnostic mode, smash any bytes on the page that are 1N/A * unknown quantities for the caller. 1N/A /* Call any pgin function. */ 1N/A /* Unlock the buffer and reacquire the region lock. */ 1N/A * If no errors occurred, the data is now valid, clear the BH_TRASH 1N/A * flag; regardless, clear the lock bit and let other threads proceed. 1N/A /* Update the statistics. */ 1N/A * Write a page to a file. 1N/A * PUBLIC: int __memp_pgwrite __P((DB_MPOOLFILE *, BH *, int *, int *)); 1N/A * Check the dirty bit -- this buffer may have been written since we 1N/A * decided to write it. 1N/A * If there were two writers, we may have just been waiting while the 1N/A * other writer completed I/O on this buffer. Check the dirty bit one 1N/A /* Copy the LSN off the page if we're going to need it. */ 1N/A /* Ensure the appropriate log records are on disk. */ 1N/A * Call any pgout function. We set the callpgin flag so that we flag 1N/A * that the contents of the buffer will need to be passed through pgin 1N/A * before they are reused. 1N/A /* Temporary files may not yet have been created. */ 1N/A "unable to create temporary backing file");
1N/A /* Write the page. */ 1N/A /* Unlock the buffer and reacquire the region lock. */ 1N/A * Clean up the flags based on a successful write. 1N/A * If we rewrote the page, it will need processing by the pgin 1N/A * routine before reuse. 1N/A * If we write a buffer for which a checkpoint is waiting, update 1N/A * the count of pending buffers (both in the mpool as a whole and 1N/A * for this file). If the count for this file goes to zero, set a 1N/A * flag so we flush the writes. 1N/A /* Update I/O statistics. */ 1N/A * Do the sync after everything else has been updated, so any incoming 1N/A * checkpoint doesn't see inconsistent information. 1N/A * Don't lock the region around the sync, fsync(2) has no atomicity 1N/A * We ignore errors from the sync -- it makes no sense to return an 1N/A * error to the calling process, so set a flag causing the checkpoint 1N/A * to be retried later. There is a possibility, of course, that a 1N/A * subsequent checkpoint was started and that we're going to force it 1N/A * to fail. That should be unlikely, and fixing it would be difficult. 1N/Aerr:
/* Unlock the buffer and reacquire the region lock. */ 1N/A * Clean up the flags based on a failure. 1N/A * The page remains dirty but we remove our lock. If we rewrote the 1N/A * page, it will need processing by the pgin routine before reuse. 1N/A * PUBLIC: int __memp_pg __P((DB_MPOOLFILE *, BH *, int)); 1N/A * Free a bucket header and its referenced data. 1N/A * PUBLIC: void __memp_bhfree __P((DB_MPOOL *, MPOOLFILE *, BH *, int)); 1N/A /* Delete the buffer header from the hash bucket queue. */ 1N/A /* Delete the buffer header from the LRU queue. */ 1N/A * If we're not reusing it immediately, free the buffer header 1N/A * and data for real. 1N/A * Upgrade a file descriptor from readonly to readwrite. 1N/A * We expect the handle to already be locked. 1N/A /* Check to see if we've already upgraded. */ 1N/A /* Check to see if we've already failed. */ 1N/A * Calculate the real name for this file and try to open it read/write. 1N/A * We know we have a valid pathname for the file because it's the only 1N/A * way we could have gotten a file descriptor of any kind. 1N/A /* Swap the descriptors and set the upgrade flag. */