/* * __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(); __wt_errx(session, "%s: handle-close: CloseHandle: %s", file_handle->name, __wt_formatmessage(session, windows_error)); ret = __wt_map_windows_error(windows_error); } if (win_fh->filehandle_secondary != INVALID_HANDLE_VALUE && CloseHandle(win_fh->filehandle_secondary) == 0) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: handle-close: secondary: CloseHandle: %s", file_handle->name, __wt_formatmessage(session, windows_error)); ret = __wt_map_windows_error(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_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(); __wt_errx(session, "%s: handle-lock: LockFile: %s", file_handle->name, __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); } } else if (UnlockFile(win_fh->filehandle, 0, 0, 1, 0) == FALSE) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: handle-lock: UnlockFile: %s", file_handle->name, __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); } return (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); }
/* * __wt_dlclose -- * Close a dynamic library */ int __wt_dlclose(WT_SESSION_IMPL *session, WT_DLH *dlh) { DWORD windows_error; WT_DECL_RET; if (FreeLibrary(dlh->handle) == FALSE) { windows_error = __wt_getlasterror(); __wt_errx(session, "FreeLibrary: %s: %s", dlh->name, __wt_formatmessage(session, windows_error)); ret = __wt_map_windows_error(windows_error); } __wt_free(session, dlh->name); __wt_free(session, dlh); return (ret); }
/* * __win_file_write -- * Write a chunk. */ static int __win_file_write(WT_FILE_HANDLE *file_handle, WT_SESSION *wt_session, wt_off_t offset, size_t len, const void *buf) { DWORD chunk, nw, windows_error; const uint8_t *addr; OVERLAPPED overlapped = { 0 }; WT_FILE_HANDLE_WIN *win_fh; WT_SESSION_IMPL *session; win_fh = (WT_FILE_HANDLE_WIN *)file_handle; session = (WT_SESSION_IMPL *)wt_session; nw = 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 writes larger than 1GB into 1GB chunks. */ for (addr = buf; len > 0; addr += nw, len -= (size_t)nw, offset += nw) { chunk = (DWORD)WT_MIN(len, WT_GIGABYTE); overlapped.Offset = UINT32_MAX & offset; overlapped.OffsetHigh = UINT32_MAX & (offset >> 32); if (!WriteFile( win_fh->filehandle, addr, chunk, &nw, &overlapped)) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: handle-write: WriteFile: failed to write %lu " "bytes at offset %" PRIuMAX ": %s", file_handle->name, chunk, (uintmax_t)offset, __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); } } return (0); }
/* * __wt_ext_map_windows_error -- * Extension API call to map a Windows system error to a POSIX/ANSI error. */ int __wt_ext_map_windows_error( WT_EXTENSION_API *wt_api, WT_SESSION *wt_session, uint32_t windows_error) { WT_UNUSED(wt_api); WT_UNUSED(wt_session); /* * This extension API only makes sense in Windows builds, but it's hard * to exclude it otherwise (there's no way to return an error, anyway). * Call an underlying function on Windows, else panic so callers figure * out what they're doing wrong. */ #ifdef _WIN32 return (__wt_map_windows_error(windows_error)); #else WT_UNUSED(windows_error); return (WT_PANIC); #endif }
/* * __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_SESSION_IMPL *session; WT_UNUSED(file_system); WT_UNUSED(flags); session = (WT_SESSION_IMPL *)wt_session; if (DeleteFileA(name) == FALSE) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: file-remove: DeleteFileA: %s", name, __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); } return (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); }
/* * __wt_getenv -- * Get a non-NULL, greater than zero-length environment variable. */ int __wt_getenv(WT_SESSION_IMPL *session, const char *variable, const char **envp) { DWORD size, windows_error; *envp = NULL; if ((size = GetEnvironmentVariableA(variable, NULL, 0)) <= 1) return (0); WT_RET(__wt_malloc(session, (size_t)size, envp)); /* We expect the number of bytes not including nul terminator. */ if (GetEnvironmentVariableA(variable, *envp, size) == size - 1) return (0); windows_error = __wt_getlasterror(); __wt_errx(session, "GetEnvironmentVariableA: %s: %s", variable, __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); }
/* * __wt_dlsym -- * Lookup a symbol in a dynamic library. */ int __wt_dlsym(WT_SESSION_IMPL *session, WT_DLH *dlh, const char *name, bool fail, void *sym_ret) { DWORD windows_error; void *sym; *(void **)sym_ret = NULL; sym = GetProcAddress(dlh->handle, name); if (sym == NULL && fail) { windows_error = __wt_getlasterror(); __wt_errx(session, "GetProcAddress: %s in %s: %s", name, dlh->name, __wt_formatmessage(session, windows_error)); WT_RET(__wt_map_windows_error(windows_error)); } *(void **)sym_ret = sym; 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; WT_FILE_HANDLE_WIN *win_fh; WT_SESSION_IMPL *session; LARGE_INTEGER size; 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(); __wt_errx(session, "%s: handle-size: GetFileSizeEx: %s", file_handle->name, __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); }
/* * __wt_thread_join -- * Wait for a thread of control to exit. */ int __wt_thread_join(WT_SESSION_IMPL *session, wt_thread_t *tid) { DWORD windows_error; /* Only attempt to join if thread was created successfully */ if (!tid->created) return (0); tid->created = false; /* * Joining a thread isn't a memory barrier, but WiredTiger commonly * sets flags and or state and then expects worker threads to halt. * Include a barrier to ensure safety in those cases. */ WT_FULL_BARRIER(); if ((windows_error = WaitForSingleObject(tid->id, INFINITE)) != WAIT_OBJECT_0) { if (windows_error == WAIT_FAILED) windows_error = __wt_getlasterror(); __wt_errx(session, "thread join: WaitForSingleObject: %s", __wt_formatmessage(session, windows_error)); /* If we fail to wait, we will leak handles, do not continue. */ return (WT_PANIC); } if (CloseHandle(tid->id) == 0) { windows_error = __wt_getlasterror(); __wt_errx(session, "thread join: CloseHandle: %s", __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); } return (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_SESSION_IMPL *session; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; if (GetFileAttributesExA(name, GetFileExInfoStandard, &data) != 0) { *sizep = ((int64_t)data.nFileSizeHigh << 32) | data.nFileSizeLow; return (0); } windows_error = __wt_getlasterror(); __wt_errx(session, "%s: file-size: GetFileAttributesEx: %s", name, __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); }
/* * __wt_win_directory_list -- * Get a list of files from a directory, MSVC version. */ int __wt_win_directory_list(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *directory, const char *prefix, char ***dirlistp, uint32_t *countp) { DWORD windows_error; HANDLE findhandle; WIN32_FIND_DATAW finddata; WT_DECL_ITEM(pathbuf); WT_DECL_ITEM(file_utf8); WT_DECL_ITEM(pathbuf_wide); WT_DECL_ITEM(prefix_wide); WT_DECL_RET; WT_SESSION_IMPL *session; size_t dirallocsz, pathlen, prefix_widelen; uint32_t count; char *dir_copy, **entries; session = (WT_SESSION_IMPL *)wt_session; *dirlistp = NULL; *countp = 0; findhandle = INVALID_HANDLE_VALUE; dirallocsz = 0; entries = NULL; WT_ERR(__wt_strdup(session, directory, &dir_copy)); pathlen = strlen(dir_copy); if (dir_copy[pathlen - 1] == '\\') dir_copy[pathlen - 1] = '\0'; WT_ERR(__wt_scr_alloc(session, pathlen + 3, &pathbuf)); WT_ERR(__wt_buf_fmt(session, pathbuf, "%s\\*", dir_copy)); WT_ERR(__wt_to_utf16_string(session, pathbuf->data, &pathbuf_wide)); WT_ERR(__wt_to_utf16_string(session, prefix, &prefix_wide)); prefix_widelen = wcslen(prefix_wide->data); findhandle = FindFirstFileW(pathbuf_wide->data, &finddata); if (findhandle == INVALID_HANDLE_VALUE) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: directory-list: FindFirstFile: %s", pathbuf->data, __wt_formatmessage(session, windows_error)); WT_ERR(__wt_map_windows_error(windows_error)); } count = 0; do { /* * Skip . and .. */ if (wcscmp(finddata.cFileName, L".") == 0 || wcscmp(finddata.cFileName, L"..") == 0) continue; /* The list of files is optionally filtered by a prefix. */ if (prefix != NULL && wcsncmp(finddata.cFileName, prefix_wide->data, prefix_widelen) != 0) continue; WT_ERR(__wt_realloc_def( session, &dirallocsz, count + 1, &entries)); WT_ERR(__wt_to_utf8_string( session, finddata.cFileName, &file_utf8)); WT_ERR(__wt_strdup(session, file_utf8->data, &entries[count])); ++count; __wt_scr_free(session, &file_utf8); } while (FindNextFileW(findhandle, &finddata) != 0); *dirlistp = entries; *countp = count; err: if (findhandle != INVALID_HANDLE_VALUE) if (FindClose(findhandle) == 0) { windows_error = __wt_getlasterror(); __wt_errx(session, "%s: directory-list: FindClose: %s", pathbuf->data, __wt_formatmessage(session, windows_error)); if (ret == 0) ret = __wt_map_windows_error(windows_error); } __wt_free(session, dir_copy); __wt_scr_free(session, &pathbuf); __wt_scr_free(session, &file_utf8); __wt_scr_free(session, &pathbuf_wide); __wt_scr_free(session, &prefix_wide); if (ret == 0) return (0); WT_TRET(__wt_win_directory_list_free( file_system, wt_session, entries, count)); WT_RET_MSG(session, ret, "%s: directory-list, prefix \"%s\"", directory, prefix == NULL ? "" : prefix); }
/* * __wt_cond_wait_signal -- * Wait on a mutex, optionally timing out. If we get it * before the time out period expires, let the caller know. */ int __wt_cond_wait_signal( WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool *signalled) { BOOL sleepret; DWORD milliseconds, windows_error; bool locked; uint64_t milliseconds64; locked = false; /* Fast path if already signalled. */ *signalled = true; if (__wt_atomic_addi32(&cond->waiters, 1) == 0) return (0); /* * !!! * This function MUST handle a NULL session handle. */ if (session != NULL) { WT_RET(__wt_verbose(session, WT_VERB_MUTEX, "wait %s cond (%p)", cond->name, cond)); WT_STAT_FAST_CONN_INCR(session, cond_wait); } EnterCriticalSection(&cond->mtx); locked = true; if (usecs > 0) { milliseconds64 = usecs / 1000; /* * Check for 32-bit unsigned integer overflow * INFINITE is max unsigned int on Windows */ if (milliseconds64 >= INFINITE) milliseconds64 = INFINITE - 1; milliseconds = (DWORD)milliseconds64; /* * 0 would mean the CV sleep becomes a TryCV which we do not * want */ if (milliseconds == 0) milliseconds = 1; sleepret = SleepConditionVariableCS( &cond->cond, &cond->mtx, milliseconds); } else sleepret = SleepConditionVariableCS( &cond->cond, &cond->mtx, INFINITE); /* * SleepConditionVariableCS returns non-zero on success, 0 on timeout * or failure. */ if (sleepret == 0) { windows_error = __wt_getlasterror(); if (windows_error == ERROR_TIMEOUT) { *signalled = false; sleepret = 1; } } (void)__wt_atomic_subi32(&cond->waiters, 1); if (locked) LeaveCriticalSection(&cond->mtx); if (sleepret != 0) return (0); __wt_errx(session, "SleepConditionVariableCS: %s", __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); }
/* * __win_open_file -- * Open a file handle. */ static int __win_open_file(WT_FILE_SYSTEM *file_system, WT_SESSION *wt_session, const char *name, WT_FS_OPEN_FILE_TYPE file_type, uint32_t flags, WT_FILE_HANDLE **file_handlep) { DWORD dwCreationDisposition, windows_error; WT_CONNECTION_IMPL *conn; WT_DECL_ITEM(name_wide); WT_DECL_RET; WT_FILE_HANDLE *file_handle; WT_FILE_HANDLE_WIN *win_fh; WT_SESSION_IMPL *session; int desired_access, f; WT_UNUSED(file_system); session = (WT_SESSION_IMPL *)wt_session; conn = S2C(session); *file_handlep = NULL; WT_RET(__wt_calloc_one(session, &win_fh)); win_fh->direct_io = false; /* Set up error handling. */ win_fh->filehandle = win_fh->filehandle_secondary = INVALID_HANDLE_VALUE; WT_ERR(__wt_to_utf16_string(session, name, &name_wide)); /* * Opening a file handle on a directory is only to support filesystems * that require a directory sync for durability, and Windows doesn't * require that functionality: create an empty WT_FH structure with * invalid handles. */ if (file_type == WT_FS_OPEN_FILE_TYPE_DIRECTORY) goto directory_open; desired_access = GENERIC_READ; if (!LF_ISSET(WT_FS_OPEN_READONLY)) desired_access |= GENERIC_WRITE; /* * Security: * The application may spawn a new process, and we don't want another * process to have access to our file handles. * * TODO: Set tighter file permissions but set bInheritHandle to false * to prevent inheritance */ f = FILE_ATTRIBUTE_NORMAL; dwCreationDisposition = 0; if (LF_ISSET(WT_FS_OPEN_CREATE)) { dwCreationDisposition = CREATE_NEW; if (LF_ISSET(WT_FS_OPEN_EXCLUSIVE)) dwCreationDisposition = CREATE_ALWAYS; } else dwCreationDisposition = OPEN_EXISTING; /* Direct I/O. */ if (LF_ISSET(WT_FS_OPEN_DIRECTIO)) { f |= FILE_FLAG_NO_BUFFERING; win_fh->direct_io = true; } /* FILE_FLAG_WRITE_THROUGH does not require aligned buffers */ if (FLD_ISSET(conn->write_through, file_type)) f |= FILE_FLAG_WRITE_THROUGH; if (file_type == WT_FS_OPEN_FILE_TYPE_LOG && FLD_ISSET(conn->txn_logsync, WT_LOG_DSYNC)) f |= FILE_FLAG_WRITE_THROUGH; /* If the user indicated a random workload, disable read-ahead. */ if (file_type == WT_FS_OPEN_FILE_TYPE_DATA && LF_ISSET(WT_FS_OPEN_ACCESS_RAND)) f |= FILE_FLAG_RANDOM_ACCESS; /* If the user indicated a sequential workload, set that. */ if (file_type == WT_FS_OPEN_FILE_TYPE_DATA && LF_ISSET(WT_FS_OPEN_ACCESS_SEQ)) f |= FILE_FLAG_SEQUENTIAL_SCAN; win_fh->filehandle = CreateFileW(name_wide->data, desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, dwCreationDisposition, f, NULL); if (win_fh->filehandle == INVALID_HANDLE_VALUE) { if (LF_ISSET(WT_FS_OPEN_CREATE) && GetLastError() == ERROR_FILE_EXISTS) win_fh->filehandle = CreateFileW(name_wide->data, desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, f, NULL); if (win_fh->filehandle == INVALID_HANDLE_VALUE) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, win_fh->direct_io ? "%s: handle-open: CreateFileW: failed with direct " "I/O configured, some filesystem types do not " "support direct I/O: %s" : "%s: handle-open: CreateFileW: %s", name, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } } /* * Open a second handle to file to support file extension/truncation * concurrently with reads on the file. Writes would also move the * file pointer. */ if (!LF_ISSET(WT_FS_OPEN_READONLY)) { win_fh->filehandle_secondary = CreateFileW(name_wide->data, desired_access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, f, NULL); if (win_fh->filehandle_secondary == INVALID_HANDLE_VALUE) { windows_error = __wt_getlasterror(); ret = __wt_map_windows_error(windows_error); __wt_err(session, ret, "%s: handle-open: Creatively: secondary: %s", name, __wt_formatmessage(session, windows_error)); WT_ERR(ret); } } directory_open: /* Initialize public information. */ file_handle = (WT_FILE_HANDLE *)win_fh; WT_ERR(__wt_strdup(session, name, &file_handle->name)); file_handle->close = __win_file_close; file_handle->fh_lock = __win_file_lock; #ifdef WORDS_BIGENDIAN /* * The underlying objects are little-endian, mapping objects isn't * currently supported on big-endian systems. */ #else file_handle->fh_map = __wt_win_map; file_handle->fh_unmap = __wt_win_unmap; #endif file_handle->fh_read = __win_file_read; file_handle->fh_size = __win_file_size; file_handle->fh_sync = __win_file_sync; /* Extend and truncate share the same implementation. */ file_handle->fh_extend = __win_file_set_end; file_handle->fh_truncate = __win_file_set_end; file_handle->fh_write = __win_file_write; *file_handlep = file_handle; __wt_scr_free(session, &name_wide); return (0); err: __wt_scr_free(session, &name_wide); WT_TRET(__win_file_close((WT_FILE_HANDLE *)win_fh, wt_session)); return (ret); }
/* * __wt_cond_wait_signal -- * Wait on a mutex, optionally timing out. If we get it before the time * out period expires, let the caller know. */ void __wt_cond_wait_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool (*run_func)(WT_SESSION_IMPL *), bool *signalled) { BOOL sleepret; DWORD milliseconds, windows_error; bool locked; uint64_t milliseconds64; locked = false; /* Fast path if already signalled. */ *signalled = true; if (__wt_atomic_addi32(&cond->waiters, 1) == 0) return; __wt_verbose(session, WT_VERB_MUTEX, "wait %s", cond->name); WT_STAT_CONN_INCR(session, cond_wait); EnterCriticalSection(&cond->mtx); locked = true; /* * It's possible to race with threads waking us up. That's not a problem * if there are multiple wakeups because the next wakeup will get us, or * if we're only pausing for a short period. It's a problem if there's * only a single wakeup, our waker is likely waiting for us to exit. * After acquiring the mutex (so we're guaranteed to be awakened by any * future wakeup call), optionally check if we're OK to keep running. * This won't ensure our caller won't just loop and call us again, but * at least it's not our fault. * * Assert we're not waiting longer than a second if not checking the * run status. */ WT_ASSERT(session, run_func != NULL || usecs <= WT_MILLION); if (run_func != NULL && !run_func(session)) goto skipping; if (usecs > 0) { milliseconds64 = usecs / WT_THOUSAND; /* * Check for 32-bit unsigned integer overflow * INFINITE is max unsigned int on Windows */ if (milliseconds64 >= INFINITE) milliseconds64 = INFINITE - 1; milliseconds = (DWORD)milliseconds64; /* * 0 would mean the CV sleep becomes a TryCV which we do not * want */ if (milliseconds == 0) milliseconds = 1; sleepret = SleepConditionVariableCS( &cond->cond, &cond->mtx, milliseconds); } else sleepret = SleepConditionVariableCS( &cond->cond, &cond->mtx, INFINITE); /* * SleepConditionVariableCS returns non-zero on success, 0 on timeout * or failure. */ if (sleepret == 0) { windows_error = __wt_getlasterror(); if (windows_error == ERROR_TIMEOUT) { skipping: *signalled = false; sleepret = 1; } } (void)__wt_atomic_subi32(&cond->waiters, 1); if (locked) LeaveCriticalSection(&cond->mtx); if (sleepret != 0) return; __wt_err(session, __wt_map_windows_error(windows_error), "SleepConditionVariableCS: %s: %s", cond->name, __wt_formatmessage(session, windows_error)); WT_PANIC_MSG(session, __wt_map_windows_error(windows_error), "SleepConditionVariableCS: %s", cond->name); }
/* * __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; WT_FILE_HANDLE_WIN *win_fh; WT_SESSION_IMPL *session; LARGE_INTEGER largeint; 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(); __wt_errx(session, "%s: handle-set-end: SetFilePointerEx: %s", file_handle->name, __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); } if (SetEndOfFile(win_fh->filehandle_secondary) == FALSE) { if (GetLastError() == ERROR_USER_MAPPED_FILE) return (EBUSY); windows_error = __wt_getlasterror(); __wt_errx(session, "%s: handle-set-end: SetEndOfFile: %s", file_handle->name, __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); } return (0); }