Пример #1
0
/*
 * __meta_track_unroll --
 *	Undo the changes in a metadata tracking record.
 */
static int
__meta_track_unroll(WT_SESSION_IMPL *session, WT_META_TRACK *trk)
{
	WT_DECL_RET;

	switch (trk->op) {
	case WT_ST_EMPTY:	/* Unused slot */
		break;
	case WT_ST_CHECKPOINT:	/* Checkpoint, see above */
		break;
	case WT_ST_DROP_COMMIT:
		break;
	case WT_ST_LOCK:	/* Handle lock, see above */
		if (trk->created)
			F_SET(trk->dhandle, WT_DHANDLE_DISCARD);
		WT_WITH_DHANDLE(session, trk->dhandle,
		    ret = __wt_session_release_btree(session));
		break;
	case WT_ST_FILEOP:	/* File operation */
		/*
		 * For renames, both a and b are set.
		 * For creates, a is NULL.
		 * For removes, b is NULL.
		 */
		if (trk->a != NULL && trk->b != NULL &&
		    (ret = __wt_fs_rename(session,
		    trk->b + strlen("file:"), trk->a + strlen("file:"),
		    true)) != 0)
			__wt_err(session, ret,
			    "metadata unroll rename %s to %s", trk->b, trk->a);

		if (trk->a == NULL &&
		    (ret = __wt_fs_remove(session,
		    trk->b + strlen("file:"), false)) != 0)
			__wt_err(session, ret,
			    "metadata unroll create %s", trk->b);

		/*
		 * We can't undo removes yet: that would imply
		 * some kind of temporary rename and remove in
		 * roll forward.
		 */
		break;
	case WT_ST_REMOVE:	/* Remove trk.a */
		if ((ret = __wt_metadata_remove(session, trk->a)) != 0)
			__wt_err(session, ret,
			    "metadata unroll remove: %s", trk->a);
		break;
	case WT_ST_SET:		/* Set trk.a to trk.b */
		if ((ret = __wt_metadata_update(session, trk->a, trk->b)) != 0)
			__wt_err(session, ret,
			    "metadata unroll update %s to %s", trk->a, trk->b);
		break;
	}

	__meta_track_clear(session, trk);
	return (ret);
}
Пример #2
0
/*
 * __wt_block_checkpoint_resolve --
 *	Resolve a checkpoint.
 */
int
__wt_block_checkpoint_resolve(
    WT_SESSION_IMPL *session, WT_BLOCK *block, bool failed)
{
	WT_BLOCK_CKPT *ci;
	WT_DECL_RET;

	ci = &block->live;

	/*
	 * Resolve the checkpoint after our caller has written the checkpoint
	 * information to stable storage.
	 */
	__wt_spin_lock(session, &block->live_lock);
	switch (block->ckpt_state) {
	case WT_CKPT_INPROGRESS:
		/* Something went wrong, but it's recoverable at our level. */
		goto done;
	case WT_CKPT_NONE:
	case WT_CKPT_SALVAGE:
		__wt_err(session, EINVAL,
		    "%s: an unexpected checkpoint resolution: the checkpoint "
		    "was never started or completed, or configured for salvage",
		    block->name);
		ret = __wt_block_panic(session);
		break;
	case WT_CKPT_PANIC_ON_FAILURE:
		if (!failed)
			break;
		__wt_err(session, EINVAL,
		    "%s: the checkpoint failed, the system must restart",
		    block->name);
		ret = __wt_block_panic(session);
		break;
	}
	WT_ERR(ret);

	if ((ret = __wt_block_extlist_merge(
	    session, block, &ci->ckpt_avail, &ci->avail)) != 0) {
		__wt_err(session, ret,
		    "%s: fatal checkpoint failure during extent list merge",
		    block->name);
		ret = __wt_block_panic(session);
	}
	__wt_spin_unlock(session, &block->live_lock);

	/* Discard the lists remaining after the checkpoint call. */
	__wt_block_extlist_free(session, &ci->ckpt_avail);
	__wt_block_extlist_free(session, &ci->ckpt_alloc);
	__wt_block_extlist_free(session, &ci->ckpt_discard);

	__wt_spin_lock(session, &block->live_lock);
done:	block->ckpt_state = WT_CKPT_NONE;
err:	__wt_spin_unlock(session, &block->live_lock);

	return (ret);
}
Пример #3
0
/*
 * __wt_close --
 *	Close a file handle.
 */
int
__wt_close(WT_SESSION_IMPL *session, WT_FH **fhp)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_FH *fh;
	uint64_t bucket;

	conn = S2C(session);

	if (*fhp == NULL)
		return (0);
	fh = *fhp;
	*fhp = NULL;

	__wt_spin_lock(session, &conn->fh_lock);
	if (fh == NULL || fh->ref == 0 || --fh->ref > 0) {
		__wt_spin_unlock(session, &conn->fh_lock);
		return (0);
	}

	/* Remove from the list. */
	bucket = fh->name_hash % WT_HASH_ARRAY_SIZE;
	WT_CONN_FILE_REMOVE(conn, fh, bucket);
	(void)WT_ATOMIC_SUB4(conn->open_file_count, 1);

	__wt_spin_unlock(session, &conn->fh_lock);

	/* Discard the memory.
	 * Note: For directories, we do not open valid directory handles on
	 * windows since it is not possible to sync a directory
	 */
	if (fh->filehandle != INVALID_HANDLE_VALUE &&
	    CloseHandle(fh->filehandle) == 0) {
		ret = __wt_errno();
		__wt_err(session, ret, "CloseHandle: %s", fh->name);
	}

	if (fh->filehandle_secondary != INVALID_HANDLE_VALUE &&
	    CloseHandle(fh->filehandle_secondary) == 0) {
		ret = __wt_errno();
		__wt_err(session, ret, "CloseHandle: secondary: %s", fh->name);
	}

	__wt_free(session, fh->name);
	__wt_free(session, fh);
	return (ret);
}
Пример #4
0
/*
 * __wt_win_fs_size --
 *	Get the size of a file in bytes, by file name.
 */
int
__wt_win_fs_size(WT_FILE_SYSTEM *file_system,
    WT_SESSION *wt_session, const char *name, wt_off_t *sizep)
{
	DWORD windows_error;
	WIN32_FILE_ATTRIBUTE_DATA data;
	WT_DECL_ITEM(name_wide);
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	WT_UNUSED(file_system);
	session = (WT_SESSION_IMPL *)wt_session;

	WT_RET(__wt_to_utf16_string(session, name, &name_wide));

	if (GetFileAttributesExW(
	    name_wide->data, GetFileExInfoStandard, &data) == 0) {
		windows_error = __wt_getlasterror();
		ret = __wt_map_windows_error(windows_error);
		__wt_err(session, ret,
		    "%s: file-size: GetFileAttributesEx: %s",
		    name, __wt_formatmessage(session, windows_error));
		WT_ERR(ret);
	}

	*sizep = ((int64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow;

err:	__wt_scr_free(session, &name_wide);
	return (ret);
}
Пример #5
0
/*
 * __log_wrlsn_server --
 *	The log wrlsn server thread.
 */
static WT_THREAD_RET
__log_wrlsn_server(void *arg)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_LOG *log;
	WT_SESSION_IMPL *session;
	int locked, yield;

	session = arg;
	conn = S2C(session);
	log = conn->log;
	locked = yield = 0;
	while (F_ISSET(conn, WT_CONN_LOG_SERVER_RUN)) {
		__wt_spin_lock(session, &log->log_slot_lock);
		locked = 1;
		WT_ERR(__wt_log_wrlsn(session, NULL, &yield));
		locked = 0;
		__wt_spin_unlock(session, &log->log_slot_lock);
		if (++yield < 1000)
			__wt_yield();
		else
			WT_ERR(__wt_cond_wait(session,
			    conn->log_wrlsn_cond, 100000));
	}
	if (0) {
err:		__wt_err(session, ret, "log wrlsn server error");
	}
	if (locked)
		__wt_spin_unlock(session, &log->log_slot_lock);
	return (WT_THREAD_RET_VALUE);
}
Пример #6
0
/*
 * __wt_dlclose --
 *	Close a dynamic library
 */
int
__wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh)
{
	int ret;

	ret = 0;

	/*
	 * FreeBSD dies inside __cxa_finalize when closing handles.
	 *
	 * For now, just skip the dlclose: this may leak some resources until
	 * the process exits, but that is preferable to hard-to-debug crashes
	 * during exit.
	 */
#ifndef __FreeBSD__
	if (dlclose(dlh->handle) != 0) {
		ret = __wt_errno();
		__wt_err(session, ret, "dlclose: %s", dlerror());
	}
#endif

	__wt_free(session, dlh->name);
	__wt_free(session, dlh);
	return (ret);
}
Пример #7
0
/*
 * __posix_directory_sync --
 *	Flush a directory to ensure file creation is durable.
 */
static int
__posix_directory_sync(
    WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *path)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;
	int fd, tret;

	WT_UNUSED(file_system);

	session = (WT_SESSION_IMPL *)wt_session;

	WT_SYSCALL_RETRY((
	    (fd = open(path, O_RDONLY, 0444)) == -1 ? -1 : 0), ret);
	if (ret != 0)
		WT_RET_MSG(session, ret, "%s: directory-sync: open", path);

	ret = __posix_sync(session, fd, path, "directory-sync");

	WT_SYSCALL(close(fd), tret);
	if (tret != 0) {
		__wt_err(session, tret, "%s: directory-sync: close", path);
		if (ret == 0)
			ret = tret;
	}
	return (ret);
}
Пример #8
0
/*
 * __log_wrlsn_server --
 *	The log wrlsn server thread.
 */
static WT_THREAD_RET
__log_wrlsn_server(void *arg)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	session = arg;
	conn = S2C(session);
	while (F_ISSET(conn, WT_CONN_LOG_SERVER_RUN)) {
		/*
		 * Write out any log record buffers.
		 */
		WT_ERR(__wt_log_wrlsn(session));
		WT_ERR(__wt_cond_wait(session, conn->log_wrlsn_cond, 10000));
	}
	/*
	 * On close we need to do this one more time because there could
	 * be straggling log writes that need to be written.
	 */
	WT_ERR(__wt_log_force_write(session, 1));
	WT_ERR(__wt_log_wrlsn(session));
	if (0) {
err:		__wt_err(session, ret, "log wrlsn server error");
	}
	return (WT_THREAD_RET_VALUE);
}
Пример #9
0
/*
 * __wt_close --
 *	Close a file handle.
 */
int
__wt_close(WT_SESSION_IMPL *session, WT_FH *fh)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;

	conn = S2C(session);

	__wt_spin_lock(session, &conn->fh_lock);
	if (fh == NULL || fh->refcnt == 0 || --fh->refcnt > 0) {
		__wt_spin_unlock(session, &conn->fh_lock);
		return (0);
	}

	/* Remove from the list. */
	TAILQ_REMOVE(&conn->fhqh, fh, q);
	WT_STAT_FAST_CONN_DECR(session, file_open);

	__wt_spin_unlock(session, &conn->fh_lock);

	/* Discard the memory. */
	if (close(fh->fd) != 0) {
		ret = __wt_errno();
		__wt_err(session, ret, "%s", fh->name);
	}

	__wt_free(session, fh->name);
	__wt_free(session, fh);
	return (ret);
}
Пример #10
0
/*
 * __sweep_server --
 *	The handle sweep server thread.
 */
static void *
__sweep_server(void *arg)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	session = arg;
	conn = S2C(session);

	/*
	 * Sweep for dead handles.
	 */
	while (F_ISSET(conn, WT_CONN_SERVER_RUN) &&
	    F_ISSET(conn, WT_CONN_SERVER_SWEEP)) {

		/* Wait until the next event. */
		WT_ERR_TIMEDOUT_OK(
		    __wt_cond_wait(session, conn->sweep_cond, 30 * WT_MILLION));

		/* Sweep the handles. */
		WT_ERR(__sweep(session));
	}

	if (0) {
err:		__wt_err(session, ret, "handle sweep server error");
	}
	return (NULL);
}
Пример #11
0
/*
 * __meta_track_apply --
 *	Apply the changes in a metadata tracking record.
 */
static int
__meta_track_apply(WT_SESSION_IMPL *session, WT_META_TRACK *trk)
{
	WT_BM *bm;
	WT_BTREE *btree;
	WT_DECL_RET;

	switch (trk->op) {
	case WT_ST_EMPTY:	/* Unused slot */
		break;
	case WT_ST_CHECKPOINT:	/* Checkpoint, see above */
		btree = trk->dhandle->handle;
		bm = btree->bm;
		WT_WITH_DHANDLE(session, trk->dhandle,
		    ret = bm->checkpoint_resolve(bm, session));
		break;
	case WT_ST_DROP_COMMIT:
		if ((ret =
		    __wt_block_manager_drop(session, trk->a, false)) != 0)
			__wt_err(session, ret,
			    "metadata remove dropped file %s", trk->a);
		break;
	case WT_ST_LOCK:
		WT_WITH_DHANDLE(session, trk->dhandle,
		    ret = __wt_session_release_btree(session));
		break;
	case WT_ST_FILEOP:
	case WT_ST_REMOVE:
	case WT_ST_SET:
		break;
	}

	__meta_track_clear(session, trk);
	return (ret);
}
Пример #12
0
/*
 * __win_fs_remove --
 *	Remove a file.
 */
static int
__win_fs_remove(WT_FILE_SYSTEM *file_system,
    WT_SESSION *wt_session, const char *name, uint32_t flags)
{
	DWORD windows_error;
	WT_DECL_ITEM(name_wide);
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	WT_UNUSED(file_system);
	WT_UNUSED(flags);

	session = (WT_SESSION_IMPL *)wt_session;

	WT_RET(__wt_to_utf16_string(session, name, &name_wide));

	if (DeleteFileW(name_wide->data) == FALSE) {
		windows_error = __wt_getlasterror();
		ret = __wt_map_windows_error(windows_error);
		__wt_err(session, ret,
		    "%s: file-remove: DeleteFileW: %s",
		    name, __wt_formatmessage(session, windows_error));
		WT_ERR(ret);
	}

err:	__wt_scr_free(session, &name_wide);
	return (ret);
}
Пример #13
0
/*
 * __ckpt_server --
 *	The checkpoint server thread.
 */
static void *
__ckpt_server(void *arg)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_SESSION *wt_session;
	WT_SESSION_IMPL *session;

	session = arg;
	conn = S2C(session);
	wt_session = (WT_SESSION *)session;

	while (F_ISSET(conn, WT_CONN_SERVER_RUN) &&
	    F_ISSET(conn, WT_CONN_SERVER_CHECKPOINT)) {
		/* Checkpoint the database. */
		WT_ERR(wt_session->checkpoint(wt_session, conn->ckpt_config));

		/* Wait... */
		WT_ERR_TIMEDOUT_OK(
		    __wt_cond_wait(session, conn->ckpt_cond, conn->ckpt_usecs));
	}

	if (0) {
err:		__wt_err(session, ret, "checkpoint server error");
	}
	return (NULL);
}
Пример #14
0
/*
 * __win_file_sync --
 *	MSVC fsync.
 */
static int
__win_file_sync(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session)
{
	DWORD windows_error;
	WT_DECL_RET;
	WT_FILE_HANDLE_WIN *win_fh;
	WT_SESSION_IMPL *session;

	win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
	session = (WT_SESSION_IMPL *)wt_session;

	/*
	 * We don't open Windows system handles when opening directories
	 * for flushing, as it is not necessary (or possible) to flush
	 * a directory on Windows. Confirm the file handle is set before
	 * attempting to sync it.
	 */
	if (win_fh->filehandle == INVALID_HANDLE_VALUE)
		return (0);

	if (FlushFileBuffers(win_fh->filehandle) == FALSE) {
		windows_error = __wt_getlasterror();
		ret = __wt_map_windows_error(windows_error);
		__wt_err(session, ret,
		    "%s handle-sync: FlushFileBuffers: %s",
		    file_handle->name,
		    __wt_formatmessage(session, windows_error));
		return (ret);
	}
	return (0);
}
Пример #15
0
/*
 * __win_file_size --
 *	Get the size of a file in bytes, by file handle.
 */
static int
__win_file_size(
    WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t *sizep)
{
	DWORD windows_error;
	LARGE_INTEGER size;
	WT_DECL_RET;
	WT_FILE_HANDLE_WIN *win_fh;
	WT_SESSION_IMPL *session;

	win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
	session = (WT_SESSION_IMPL *)wt_session;

	if (GetFileSizeEx(win_fh->filehandle, &size) != 0) {
		*sizep = size.QuadPart;
		return (0);
	}

	windows_error = __wt_getlasterror();
	ret = __wt_map_windows_error(windows_error);
	__wt_err(session, ret,
	    "%s: handle-size: GetFileSizeEx: %s",
	    file_handle->name, __wt_formatmessage(session, windows_error));
	return (ret);
}
Пример #16
0
/*
 * __log_wrlsn_server --
 *	The log wrlsn server thread.
 */
static WT_THREAD_RET
__log_wrlsn_server(void *arg)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_LOG *log;
	WT_LSN prev;
	WT_SESSION_IMPL *session;
	int yield;
	bool did_work;

	session = arg;
	conn = S2C(session);
	log = conn->log;
	yield = 0;
	WT_INIT_LSN(&prev);
	did_work = false;
	while (F_ISSET(conn, WT_CONN_LOG_SERVER_RUN)) {
		/*
		 * Write out any log record buffers if anything was done
		 * since last time.  Only call the function to walk the
		 * slots if the system is not idle.  On an idle system
		 * the alloc_lsn will not advance and the written lsn will
		 * match the alloc_lsn.
		 */
		if (__wt_log_cmp(&prev, &log->alloc_lsn) != 0 ||
		    __wt_log_cmp(&log->write_lsn, &log->alloc_lsn) != 0)
			WT_ERR(__wt_log_wrlsn(session, &yield));
		else
			WT_STAT_FAST_CONN_INCR(session, log_write_lsn_skip);
		prev = log->alloc_lsn;
		if (yield == 0)
			did_work = true;
		else
			did_work = false;
		/*
		 * If __wt_log_wrlsn did work we want to yield instead of sleep.
		 */
		if (yield++ < WT_THOUSAND)
			__wt_yield();
		else
			/*
			 * Send in false because if we did any work we would
			 * not be on this path.
			 */
			WT_ERR(__wt_cond_auto_wait(
			    session, conn->log_wrlsn_cond, did_work));
	}
	/*
	 * On close we need to do this one more time because there could
	 * be straggling log writes that need to be written.
	 */
	WT_ERR(__wt_log_force_write(session, 1, NULL));
	WT_ERR(__wt_log_wrlsn(session, NULL));
	if (0) {
err:		__wt_err(session, ret, "log wrlsn server error");
	}
	return (WT_THREAD_RET_VALUE);
}
Пример #17
0
/*
 * __log_prealloc_once --
 *	Perform one iteration of log pre-allocation.
 */
static int
__log_prealloc_once(WT_SESSION_IMPL *session)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_LOG *log;
	u_int i, reccount;
	char **recfiles;

	conn = S2C(session);
	log = conn->log;
	reccount = 0;
	recfiles = NULL;

	/*
	 * Allocate up to the maximum number, accounting for any existing
	 * files that may not have been used yet.
	 */
	WT_ERR(__wt_dirlist(session, conn->log_path,
	    WT_LOG_PREPNAME, WT_DIRLIST_INCLUDE,
	    &recfiles, &reccount));
	__wt_log_files_free(session, recfiles, reccount);
	recfiles = NULL;
	/*
	 * Adjust the number of files to pre-allocate if we find that
	 * the critical path had to allocate them since we last ran.
	 */
	if (log->prep_missed > 0) {
		conn->log_prealloc += log->prep_missed;
		WT_ERR(__wt_verbose(session, WT_VERB_LOG,
		    "Missed %" PRIu32 ". Now pre-allocating up to %" PRIu32,
		    log->prep_missed, conn->log_prealloc));
	}
	WT_STAT_FAST_CONN_SET(session,
	    log_prealloc_max, conn->log_prealloc);
	/*
	 * Allocate up to the maximum number that we just computed and detected.
	 */
	for (i = reccount; i < (u_int)conn->log_prealloc; i++) {
		WT_ERR(__wt_log_allocfile(
		    session, ++log->prep_fileid, WT_LOG_PREPNAME, 1));
		WT_STAT_FAST_CONN_INCR(session, log_prealloc_files);
	}
	/*
	 * Reset the missed count now.  If we missed during pre-allocating
	 * the log files, it means the allocation is not keeping up, not that
	 * we didn't allocate enough.  So we don't just want to keep adding
	 * in more.
	 */
	log->prep_missed = 0;

	if (0)
err:		__wt_err(session, ret, "log pre-alloc server error");
	if (recfiles != NULL)
		__wt_log_files_free(session, recfiles, reccount);
	return (ret);
}
Пример #18
0
/*
 * __win_file_close --
 *	ANSI C close.
 */
static int
__win_file_close(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session)
{
	DWORD windows_error;
	WT_DECL_RET;
	WT_FILE_HANDLE_WIN *win_fh;
	WT_SESSION_IMPL *session;

	win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
	session = (WT_SESSION_IMPL *)wt_session;

	/*
	 * Close the primary and secondary handles.
	 *
	 * We don't open Windows system handles when opening directories for
	 * flushing, as it's not necessary (or possible) to flush a directory
	 * on Windows. Confirm the file handle is open before closing it.
	 */
	if (win_fh->filehandle != INVALID_HANDLE_VALUE &&
	    CloseHandle(win_fh->filehandle) == 0) {
		windows_error = __wt_getlasterror();
		ret = __wt_map_windows_error(windows_error);
		__wt_err(session, ret,
		    "%s: handle-close: CloseHandle: %s",
		    file_handle->name,
		    __wt_formatmessage(session, windows_error));
	}

	if (win_fh->filehandle_secondary != INVALID_HANDLE_VALUE &&
	    CloseHandle(win_fh->filehandle_secondary) == 0) {
		windows_error = __wt_getlasterror();
		ret = __wt_map_windows_error(windows_error);
		__wt_err(session, ret,
		    "%s: handle-close: secondary: CloseHandle: %s",
		    file_handle->name,
		    __wt_formatmessage(session, windows_error));
	}

	__wt_free(session, file_handle->name);
	__wt_free(session, win_fh);
	return (ret);
}
Пример #19
0
/*
 * __win_file_lock --
 *	Lock/unlock a file.
 */
static int
__win_file_lock(
    WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, bool lock)
{
	DWORD windows_error;
	WT_DECL_RET;
	WT_FILE_HANDLE_WIN *win_fh;
	WT_SESSION_IMPL *session;

	win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
	session = (WT_SESSION_IMPL *)wt_session;

	/*
	 * WiredTiger requires this function be able to acquire locks past
	 * the end of file.
	 *
	 * http://msdn.microsoft.com/
	 *    en-us/library/windows/desktop/aa365202%28v=vs.85%29.aspx
	 *
	 * You can lock bytes that are beyond the end of the current file.
	 * This is useful to coordinate adding records to the end of a file.
	 */
	if (lock) {
		if (LockFile(win_fh->filehandle, 0, 0, 1, 0) == FALSE) {
			windows_error = __wt_getlasterror();
			ret = __wt_map_windows_error(windows_error);
			__wt_err(session, ret,
			    "%s: handle-lock: LockFile: %s",
			    file_handle->name,
			    __wt_formatmessage(session, windows_error));
		}
	} else
		if (UnlockFile(win_fh->filehandle, 0, 0, 1, 0) == FALSE) {
			windows_error = __wt_getlasterror();
			ret = __wt_map_windows_error(windows_error);
			__wt_err(session, ret,
			    "%s: handle-lock: UnlockFile: %s",
			    file_handle->name,
			    __wt_formatmessage(session, windows_error));
		}
	return (ret);
}
Пример #20
0
/*
 * __wt_close --
 *	Close a file handle.
 */
int
__wt_close(WT_SESSION_IMPL *session, WT_FH *fh)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;

	conn = S2C(session);

	__wt_spin_lock(session, &conn->fh_lock);
	if (fh == NULL || fh->ref == 0 || --fh->ref > 0) {
		__wt_spin_unlock(session, &conn->fh_lock);
		return (0);
	}

	/* Remove from the list. */
	TAILQ_REMOVE(&conn->fhqh, fh, q);
	WT_STAT_FAST_CONN_DECR(session, file_open);

	__wt_spin_unlock(session, &conn->fh_lock);

	/* Discard the memory.
	 * Note: For directories, we do not open valid directory handles on
	 * windows since it is not possible to sync a directory
	 */
	if (fh->filehandle != INVALID_HANDLE_VALUE &&
	    !CloseHandle(fh->filehandle) != 0) {
		ret = __wt_errno();
		__wt_err(session, ret, "CloseHandle: %s", fh->name);
	}

	if (fh->filehandle_secondary != INVALID_HANDLE_VALUE &&
	    !CloseHandle(fh->filehandle_secondary) != 0) {
		ret = __wt_errno();
		__wt_err(session, ret, "CloseHandle: secondary: %s", fh->name);
	}

	__wt_free(session, fh->name);
	__wt_free(session, fh);
	return (ret);
}
Пример #21
0
/*
 * localtime_r --
 *	Return the current local time.
 */
struct tm *
localtime_r(const time_t *timer, struct tm *result)
{
	errno_t err;

	err = localtime_s(result, timer);
	if (err != 0) {
		__wt_err(NULL, err, "localtime_s");
		return (NULL);
	}

	return (result);
}
Пример #22
0
/*
 * __wt_dlclose --
 *	Close a dynamic library
 */
int
__wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh)
{
	WT_DECL_RET;

	if ((ret = FreeLibrary(dlh->handle)) == FALSE) {
		__wt_err(session, __wt_errno(), "FreeLibrary");
	}

	/* Windows returns 0 on failure, WT expects 0 on success */
	ret = !ret;

	__wt_free(session, dlh->name);
	__wt_free(session, dlh);
	return (ret);
}
Пример #23
0
/*
 * __log_server --
 *	The log server thread.
 */
static WT_THREAD_RET
__log_server(void *arg)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_LOG *log;
	WT_SESSION_IMPL *session;
	u_int locked;

	session = arg;
	conn = S2C(session);
	log = conn->log;
	locked = 0;
	while (F_ISSET(conn, WT_CONN_LOG_SERVER_RUN)) {
		/*
		 * Perform log pre-allocation.
		 */
		if (conn->log_prealloc > 0)
			WT_ERR(__log_prealloc_once(session));

		/*
		 * Perform the archive.
		 */
		if (FLD_ISSET(conn->log_flags, WT_CONN_LOG_ARCHIVE)) {
			if (__wt_try_writelock(
			    session, log->log_archive_lock) == 0) {
				locked = 1;
				WT_ERR(__log_archive_once(session, 0));
				WT_ERR(	__wt_writeunlock(
				    session, log->log_archive_lock));
				locked = 0;
			} else
				WT_ERR(__wt_verbose(session, WT_VERB_LOG,
				    "log_archive: Blocked due to open log "
				    "cursor holding archive lock"));
		}
		/* Wait until the next event. */
		WT_ERR(__wt_cond_wait(session, conn->log_cond, WT_MILLION));
	}

	if (0) {
err:		__wt_err(session, ret, "log server error");
	}
	if (locked)
		(void)__wt_writeunlock(session, log->log_archive_lock);
	return (WT_THREAD_RET_VALUE);
}
Пример #24
0
/*
 * __win_file_read --
 *	Read a chunk.
 */
static int
__win_file_read(WT_FILE_HANDLE *file_handle,
    WT_SESSION *wt_session, wt_off_t offset, size_t len, void *buf)
{
	DWORD chunk, nr, windows_error;
	OVERLAPPED overlapped = { 0 };
	WT_DECL_RET;
	WT_FILE_HANDLE_WIN *win_fh;
	WT_SESSION_IMPL *session;
	uint8_t *addr;

	win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
	session = (WT_SESSION_IMPL *)wt_session;

	nr = 0;

	/* Assert direct I/O is aligned and a multiple of the alignment. */
	WT_ASSERT(session,
	    !win_fh->direct_io ||
	    S2C(session)->buffer_alignment == 0 ||
	    (!((uintptr_t)buf &
	    (uintptr_t)(S2C(session)->buffer_alignment - 1)) &&
	    len >= S2C(session)->buffer_alignment &&
	    len % S2C(session)->buffer_alignment == 0));

	/* Break reads larger than 1GB into 1GB chunks. */
	for (addr = buf; len > 0; addr += nr, len -= (size_t)nr, offset += nr) {
		chunk = (DWORD)WT_MIN(len, WT_GIGABYTE);
		overlapped.Offset = UINT32_MAX & offset;
		overlapped.OffsetHigh = UINT32_MAX & (offset >> 32);

		if (!ReadFile(
		    win_fh->filehandle, addr, chunk, &nr, &overlapped)) {
			windows_error = __wt_getlasterror();
			ret = __wt_map_windows_error(windows_error);
			if (ret == WT_ERROR)
				F_SET(S2C(session), WT_CONN_DATA_CORRUPTION);
			__wt_err(session, ret,
			    "%s: handle-read: ReadFile: failed to read %lu "
			    "bytes at offset %" PRIuMAX ": %s",
			    file_handle->name, chunk, (uintmax_t)offset,
			    __wt_formatmessage(session, windows_error));
			return (ret);
		}
	}
	return (0);
}
Пример #25
0
/*
 * __wt_bloom_hash_get --
 *	Tests whether the key (as given by its hash signature) is in the Bloom
 *	filter.  Returns zero if found, WT_NOTFOUND if not.
 */
int
__wt_bloom_hash_get(WT_BLOOM *bloom, WT_BLOOM_HASH *bhash)
{
	WT_CURSOR *c;
	WT_DECL_RET;
	int result;
	uint32_t i;
	uint64_t h1, h2;
	uint8_t bit;

	/* Get operations are only supported by finalized bloom filters. */
	WT_ASSERT(bloom->session, bloom->bitstring == NULL);

	/* Create a cursor on the first time through. */
	WT_ERR(__bloom_open_cursor(bloom, NULL));
	c = bloom->c;

	h1 = bhash->h1;
	h2 = bhash->h2;

	result = 0;
	for (i = 0; i < bloom->k; i++, h1 += h2) {
		/*
		 * Add 1 to the hash because WiredTiger tables are 1 based and
		 * the original bitstring array was 0 based.
		 */
		c->set_key(c, (h1 % bloom->m) + 1);
		WT_ERR(c->search(c));
		WT_ERR(c->get_value(c, &bit));

		if (bit == 0) {
			result = WT_NOTFOUND;
			break;
		}
	}
	WT_ERR(c->reset(c));
	return (result);

err:	/* Don't return WT_NOTFOUND from a failed search. */
	if (ret == WT_NOTFOUND)
		ret = WT_ERROR;
	__wt_err(bloom->session, ret, "Failed lookup in bloom filter.");
	return (ret);
}
Пример #26
0
/*
 * __win_fs_rename --
 *	Rename a file.
 */
static int
__win_fs_rename(WT_FILE_SYSTEM *file_system,
    WT_SESSION *wt_session, const char *from, const char *to, uint32_t flags)
{
	DWORD windows_error;
	WT_DECL_ITEM(from_wide);
	WT_DECL_ITEM(to_wide);
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	WT_UNUSED(file_system);
	WT_UNUSED(flags);
	session = (WT_SESSION_IMPL *)wt_session;

	WT_ERR(__wt_to_utf16_string(session, from, &from_wide));
	WT_ERR(__wt_to_utf16_string(session, to, &to_wide));

	/*
	 * We want an atomic rename, but that's not guaranteed by MoveFileExW
	 * (or by any MSDN API). Don't set the MOVEFILE_COPY_ALLOWED flag to
	 * prevent the system from falling back to a copy and delete process.
	 * Do set the MOVEFILE_WRITE_THROUGH flag so the window is as small
	 * as possible, just in case. WiredTiger renames are done in a single
	 * directory and we expect that to be an atomic metadata update on any
	 * modern filesystem.
	 */
	if (MoveFileExW(from_wide->data, to_wide->data,
	    MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == FALSE) {
		windows_error = __wt_getlasterror();
		ret = __wt_map_windows_error(windows_error);
		__wt_err(session, ret,
		    "%s to %s: file-rename: MoveFileExW: %s",
		    from, to, __wt_formatmessage(session, windows_error));
		WT_ERR(ret);
	}

err:	__wt_scr_free(session, &from_wide);
	__wt_scr_free(session, &to_wide);
	return (ret);
}
Пример #27
0
/*
 * __posix_file_close --
 *	ANSI C close.
 */
static int
__posix_file_close(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session)
{
	WT_DECL_RET;
	WT_FILE_HANDLE_POSIX *pfh;
	WT_SESSION_IMPL *session;

	session = (WT_SESSION_IMPL *)wt_session;
	pfh = (WT_FILE_HANDLE_POSIX *)file_handle;

	/* Close the file handle. */
	if (pfh->fd != -1) {
		WT_SYSCALL(close(pfh->fd), ret);
		if (ret != 0)
			__wt_err(session, ret,
			    "%s: handle-close: close", file_handle->name);
	}

	__wt_free(session, file_handle->name);
	__wt_free(session, pfh);
	return (ret);
}
Пример #28
0
/*
 * __wt_block_checkpoint_start --
 *	Start a checkpoint.
 */
int
__wt_block_checkpoint_start(WT_SESSION_IMPL *session, WT_BLOCK *block)
{
	WT_DECL_RET;

	__wt_spin_lock(session, &block->live_lock);
	switch (block->ckpt_state) {
	case WT_CKPT_INPROGRESS:
	case WT_CKPT_PANIC_ON_FAILURE:
	case WT_CKPT_SALVAGE:
		__wt_err(session, EINVAL,
		    "%s: an unexpected checkpoint start: the checkpoint "
		    "has already started or was configured for salvage",
		    block->name);
		ret = __wt_block_panic(session);
		break;
	case WT_CKPT_NONE:
		block->ckpt_state = WT_CKPT_INPROGRESS;
		break;
	}
	__wt_spin_unlock(session, &block->live_lock);
	return (ret);
}
Пример #29
0
/*
 * __posix_directory_sync --
 *	Flush a directory to ensure file creation, remove or rename is durable.
 */
static int
__posix_directory_sync(WT_SESSION_IMPL *session, const char *path)
{
	WT_DECL_ITEM(tmp);
	WT_DECL_RET;
	int fd, tret;
	char *dir;

	WT_RET(__wt_scr_alloc(session, 0, &tmp));
	WT_ERR(__wt_buf_setstr(session, tmp, path));

	/*
	 * This layer should never see a path that doesn't include a trailing
	 * path separator, this code asserts that fact.
	 */
	dir = tmp->mem;
	strrchr(dir, '/')[1] = '\0';

	fd = -1;			/* -Wconditional-uninitialized */
	WT_SYSCALL_RETRY((
	    (fd = open(dir, O_RDONLY, 0444)) == -1 ? -1 : 0), ret);
	if (ret != 0)
		WT_ERR_MSG(session, ret, "%s: directory-sync: open", dir);

	ret = __posix_sync(session, fd, dir, "directory-sync");

	WT_SYSCALL(close(fd), tret);
	if (tret != 0) {
		__wt_err(session, tret, "%s: directory-sync: close", dir);
		if (ret == 0)
			ret = tret;
	}

err:	__wt_scr_free(session, &tmp);
	return (ret);
}
Пример #30
-1
/*
 * __win_file_set_end --
 *	Truncate or extend a file.
 */
static int
__win_file_set_end(
    WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t len)
{
	DWORD windows_error;
	LARGE_INTEGER largeint;
	WT_DECL_RET;
	WT_FILE_HANDLE_WIN *win_fh;
	WT_SESSION_IMPL *session;

	win_fh = (WT_FILE_HANDLE_WIN *)file_handle;
	session = (WT_SESSION_IMPL *)wt_session;

	largeint.QuadPart = len;

	if (win_fh->filehandle_secondary == INVALID_HANDLE_VALUE)
		WT_RET_MSG(session, EINVAL,
		    "%s: handle-set-end: no secondary handle",
		    file_handle->name);

	if (SetFilePointerEx(win_fh->filehandle_secondary,
	    largeint, NULL, FILE_BEGIN) == FALSE) {
		windows_error = __wt_getlasterror();
		ret = __wt_map_windows_error(windows_error);
		__wt_err(session, ret,
		    "%s: handle-set-end: SetFilePointerEx: %s",
		    file_handle->name,
		    __wt_formatmessage(session, windows_error));
		return (ret);
	}

	if (SetEndOfFile(win_fh->filehandle_secondary) == FALSE) {
		if (GetLastError() == ERROR_USER_MAPPED_FILE)
			return (__wt_set_return(session, EBUSY));
		windows_error = __wt_getlasterror();
		ret = __wt_map_windows_error(windows_error);
		__wt_err(session, ret,
		    "%s: handle-set-end: SetEndOfFile: %s",
		    file_handle->name,
		    __wt_formatmessage(session, windows_error));
		return (ret);
	}
	return (0);
}