return result;
}
+Status WinEnvIO::Truncate(const std::string& fname, size_t size) {
+ Status s;
+ int result = truncate(fname.c_str(), size);
+ if (result != 0) {
+ s = IOError("Failed to truncate: " + fname, errno);
+ }
+ return s;
+}
+
Status WinEnvIO::GetCurrentTime(int64_t* unix_time) {
time_t time = std::time(nullptr);
if (time == (time_t)(-1)) {
// Random access is to disable read-ahead as the system reads too much data
DWORD desired_access = GENERIC_READ | GENERIC_WRITE;
DWORD shared_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
- DWORD creation_disposition = OPEN_ALWAYS; // Create if necessary or open existing
+ DWORD creation_disposition = OPEN_EXISTING; // Fail if file does not exist
DWORD file_flags = FILE_FLAG_RANDOM_ACCESS;
if (options.use_direct_reads && options.use_direct_writes) {
return s;
}
+Status WinEnvIO::NewMemoryMappedFileBuffer(const std::string & fname,
+ std::unique_ptr<MemoryMappedFileBuffer>* result) {
+ Status s;
+ result->reset();
+
+ DWORD fileFlags = FILE_ATTRIBUTE_READONLY;
+
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ {
+ IOSTATS_TIMER_GUARD(open_nanos);
+ hFile = CreateFileA(
+ fname.c_str(), GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING, // Open only if it exists
+ fileFlags,
+ NULL);
+ }
+
+ if (INVALID_HANDLE_VALUE == hFile) {
+ auto lastError = GetLastError();
+ s = IOErrorFromWindowsError("Failed to open NewMemoryMappedFileBuffer: " + fname,
+ lastError);
+ return s;
+ }
+ UniqueCloseHandlePtr fileGuard(hFile, CloseHandleFunc);
+
+ uint64_t fileSize = 0;
+ s = GetFileSize(fname, &fileSize);
+ if (!s.ok()) {
+ return s;
+ }
+ // Will not map empty files
+ if (fileSize == 0) {
+ return Status::NotSupported("NewMemoryMappedFileBuffer can not map zero length files: " + fname);
+ }
+
+ // size_t is 32-bit with 32-bit builds
+ if (fileSize > std::numeric_limits<size_t>::max()) {
+ return Status::NotSupported(
+ "The specified file size does not fit into 32-bit memory addressing: " + fname);
+ }
+
+ HANDLE hMap = CreateFileMappingA(hFile, NULL, PAGE_READWRITE,
+ 0, // Whole file at its present length
+ 0,
+ NULL); // Mapping name
+
+ if (!hMap) {
+ auto lastError = GetLastError();
+ return IOErrorFromWindowsError(
+ "Failed to create file mapping for NewMemoryMappedFileBuffer: " + fname,
+ lastError);
+ }
+ UniqueCloseHandlePtr mapGuard(hMap, CloseHandleFunc);
+
+ void* base = MapViewOfFileEx(hMap, FILE_MAP_WRITE,
+ 0, // High DWORD of access start
+ 0, // Low DWORD
+ fileSize,
+ NULL); // Let the OS choose the mapping
+
+ if (!base) {
+ auto lastError = GetLastError();
+ return IOErrorFromWindowsError(
+ "Failed to MapViewOfFile for NewMemoryMappedFileBuffer: " + fname,
+ lastError);
+ }
+
+ result->reset(new WinMemoryMappedBuffer(hFile, hMap,
+ base, static_cast<size_t>(fileSize)));
+
+ mapGuard.release();
+ fileGuard.release();
+
+ return s;
+}
+
Status WinEnvIO::NewDirectory(const std::string& name,
std::unique_ptr<Directory>* result) {
Status s;
EnvOptions WinEnvIO::OptimizeForLogWrite(const EnvOptions& env_options,
const DBOptions& db_options) const {
- EnvOptions optimized = env_options;
+ EnvOptions optimized(env_options);
+ // These two the same as default optimizations
optimized.bytes_per_sync = db_options.wal_bytes_per_sync;
- optimized.use_mmap_writes = false;
- // This is because we flush only whole pages on unbuffered io and
- // the last records are not guaranteed to be flushed.
- optimized.use_direct_writes = false;
- // TODO(icanadi) it's faster if fallocate_with_keep_size is false, but it
- // breaks TransactionLogIteratorStallAtLastRecord unit test. Fix the unit
- // test and make this false
- optimized.fallocate_with_keep_size = true;
optimized.writable_file_max_buffer_size =
db_options.writable_file_max_buffer_size;
+
+ // This adversely affects %999 on windows
+ optimized.use_mmap_writes = false;
+ // Direct writes will produce a huge perf impact on
+ // Windows. Pre-allocate space for WAL.
+ optimized.use_direct_writes = false;
return optimized;
}
EnvOptions WinEnvIO::OptimizeForManifestWrite(
const EnvOptions& env_options) const {
- EnvOptions optimized = env_options;
+ EnvOptions optimized(env_options);
optimized.use_mmap_writes = false;
- optimized.use_direct_writes = false;
- optimized.fallocate_with_keep_size = true;
+ optimized.use_direct_reads = false;
+ return optimized;
+}
+
+EnvOptions WinEnvIO::OptimizeForManifestRead(
+ const EnvOptions& env_options) const {
+ EnvOptions optimized(env_options);
+ optimized.use_mmap_writes = false;
+ optimized.use_direct_reads = false;
return optimized;
}
return winenv_io_.DeleteFile(fname);
}
+Status WinEnv::Truncate(const std::string& fname, size_t size) {
+ return winenv_io_.Truncate(fname, size);
+}
+
Status WinEnv::GetCurrentTime(int64_t* unix_time) {
return winenv_io_.GetCurrentTime(unix_time);
}
}
Status WinEnv::NewRandomRWFile(const std::string & fname,
- unique_ptr<RandomRWFile>* result, const EnvOptions & options) {
+ std::unique_ptr<RandomRWFile>* result, const EnvOptions & options) {
return winenv_io_.NewRandomRWFile(fname, result, options);
}
+Status WinEnv::NewMemoryMappedFileBuffer(const std::string& fname,
+ std::unique_ptr<MemoryMappedFileBuffer>* result) {
+ return winenv_io_.NewMemoryMappedFileBuffer(fname, result);
+}
+
Status WinEnv::NewDirectory(const std::string& name,
std::unique_ptr<Directory>* result) {
return winenv_io_.NewDirectory(name, result);
return winenv_threads_.IncBackgroundThreadsIfNeeded(num, pri);
}
+EnvOptions WinEnv::OptimizeForManifestRead(
+ const EnvOptions& env_options) const {
+ return winenv_io_.OptimizeForManifestRead(env_options);
+}
+
EnvOptions WinEnv::OptimizeForLogWrite(const EnvOptions& env_options,
const DBOptions& db_options) const {
return winenv_io_.OptimizeForLogWrite(env_options, db_options);
virtual Status DeleteFile(const std::string& fname);
+ Status Truncate(const std::string& fname, size_t size);
+
virtual Status GetCurrentTime(int64_t* unix_time);
virtual Status NewSequentialFile(const std::string& fname,
unique_ptr<RandomRWFile>* result,
const EnvOptions& options);
+ virtual Status NewMemoryMappedFileBuffer(
+ const std::string& fname,
+ std::unique_ptr<MemoryMappedFileBuffer>* result);
+
virtual Status NewDirectory(const std::string& name,
std::unique_ptr<Directory>* result);
virtual EnvOptions OptimizeForManifestWrite(
const EnvOptions& env_options) const;
+ virtual EnvOptions OptimizeForManifestRead(
+ const EnvOptions& env_options) const;
+
size_t GetPageSize() const { return page_size_; }
size_t GetAllocationGranularity() const { return allocation_granularity_; }
Status DeleteFile(const std::string& fname) override;
+ Status Truncate(const std::string& fname, size_t size) override;
+
Status GetCurrentTime(int64_t* unix_time) override;
Status NewSequentialFile(const std::string& fname,
// The returned file will only be accessed by one thread at a time.
Status NewRandomRWFile(const std::string& fname,
- unique_ptr<RandomRWFile>* result,
+ std::unique_ptr<RandomRWFile>* result,
const EnvOptions& options) override;
+ Status NewMemoryMappedFileBuffer(
+ const std::string& fname,
+ std::unique_ptr<MemoryMappedFileBuffer>* result) override;
+
Status NewDirectory(const std::string& name,
std::unique_ptr<Directory>* result) override;
void IncBackgroundThreadsIfNeeded(int num, Env::Priority pri) override;
+ EnvOptions OptimizeForManifestRead(
+ const EnvOptions& env_options) const override;
+
EnvOptions OptimizeForLogWrite(const EnvOptions& env_options,
const DBOptions& db_options) const override;
EnvOptions OptimizeForManifestWrite(
const EnvOptions& env_options) const override;
+
private:
WinEnvIO winenv_io_;