/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * 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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }
/* * __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); }