Switch corruption_test to use InMemEnv.
This change switches corruption_test, which previously used direct file I/O to corrupt table files for open databases, to use InMemEnv. Using an Env eliminates some platform dependencies thus simplifying the tests. Also removed EnvWindowsTestHelper::RelaxFilePermissions(). This was only added because the Windows Env opens files for exclusive access. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=239305329
This commit is contained in:
parent
ce399ac28a
commit
ea49b27d06
@ -4,12 +4,8 @@
|
|||||||
|
|
||||||
#include "leveldb/db.h"
|
#include "leveldb/db.h"
|
||||||
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include "leveldb/cache.h"
|
#include "leveldb/cache.h"
|
||||||
#include "leveldb/env.h"
|
|
||||||
#include "leveldb/table.h"
|
#include "leveldb/table.h"
|
||||||
#include "leveldb/write_batch.h"
|
#include "leveldb/write_batch.h"
|
||||||
#include "db/db_impl.h"
|
#include "db/db_impl.h"
|
||||||
@ -20,10 +16,6 @@
|
|||||||
#include "util/testharness.h"
|
#include "util/testharness.h"
|
||||||
#include "util/testutil.h"
|
#include "util/testutil.h"
|
||||||
|
|
||||||
#if defined(LEVELDB_PLATFORM_WINDOWS)
|
|
||||||
#include "util/env_windows_test_helper.h"
|
|
||||||
#endif // defined(LEVELDB_PLATFORM_WINDOWS)
|
|
||||||
|
|
||||||
namespace leveldb {
|
namespace leveldb {
|
||||||
|
|
||||||
static const int kValueSize = 1000;
|
static const int kValueSize = 1000;
|
||||||
@ -36,22 +28,11 @@ class CorruptionTest {
|
|||||||
Options options_;
|
Options options_;
|
||||||
DB* db_;
|
DB* db_;
|
||||||
|
|
||||||
#if defined(LEVELDB_PLATFORM_WINDOWS)
|
|
||||||
static void SetFileLimits(int mmap_limit) {
|
|
||||||
EnvWindowsTestHelper::SetReadOnlyMMapLimit(mmap_limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(cmumford): Modify corruption_test to use MemEnv and remove.
|
|
||||||
static void RelaxFilePermissions() {
|
|
||||||
EnvWindowsTestHelper::RelaxFilePermissions();
|
|
||||||
}
|
|
||||||
#endif // defined(LEVELDB_PLATFORM_WINDOWS)
|
|
||||||
|
|
||||||
CorruptionTest() {
|
CorruptionTest() {
|
||||||
tiny_cache_ = NewLRUCache(100);
|
tiny_cache_ = NewLRUCache(100);
|
||||||
options_.env = &env_;
|
options_.env = &env_;
|
||||||
options_.block_cache = tiny_cache_;
|
options_.block_cache = tiny_cache_;
|
||||||
dbname_ = test::TmpDir() + "/corruption_test";
|
dbname_ = "/memenv/corruption_test";
|
||||||
DestroyDB(dbname_, options_);
|
DestroyDB(dbname_, options_);
|
||||||
|
|
||||||
db_ = nullptr;
|
db_ = nullptr;
|
||||||
@ -62,7 +43,6 @@ class CorruptionTest {
|
|||||||
|
|
||||||
~CorruptionTest() {
|
~CorruptionTest() {
|
||||||
delete db_;
|
delete db_;
|
||||||
DestroyDB(dbname_, Options());
|
|
||||||
delete tiny_cache_;
|
delete tiny_cache_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +121,7 @@ class CorruptionTest {
|
|||||||
void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
|
void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
|
||||||
// Pick file to corrupt
|
// Pick file to corrupt
|
||||||
std::vector<std::string> filenames;
|
std::vector<std::string> filenames;
|
||||||
ASSERT_OK(env_.GetChildren(dbname_, &filenames));
|
ASSERT_OK(env_.target()->GetChildren(dbname_, &filenames));
|
||||||
uint64_t number;
|
uint64_t number;
|
||||||
FileType type;
|
FileType type;
|
||||||
std::string fname;
|
std::string fname;
|
||||||
@ -156,35 +136,32 @@ class CorruptionTest {
|
|||||||
}
|
}
|
||||||
ASSERT_TRUE(!fname.empty()) << filetype;
|
ASSERT_TRUE(!fname.empty()) << filetype;
|
||||||
|
|
||||||
struct stat sbuf;
|
uint64_t file_size;
|
||||||
if (stat(fname.c_str(), &sbuf) != 0) {
|
ASSERT_OK(env_.target()->GetFileSize(fname, &file_size));
|
||||||
const char* msg = strerror(errno);
|
|
||||||
ASSERT_TRUE(false) << fname << ": " << msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
// Relative to end of file; make it absolute
|
// Relative to end of file; make it absolute
|
||||||
if (-offset > sbuf.st_size) {
|
if (-offset > file_size) {
|
||||||
offset = 0;
|
offset = 0;
|
||||||
} else {
|
} else {
|
||||||
offset = sbuf.st_size + offset;
|
offset = file_size + offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (offset > sbuf.st_size) {
|
if (offset > file_size) {
|
||||||
offset = sbuf.st_size;
|
offset = file_size;
|
||||||
}
|
}
|
||||||
if (offset + bytes_to_corrupt > sbuf.st_size) {
|
if (offset + bytes_to_corrupt > file_size) {
|
||||||
bytes_to_corrupt = sbuf.st_size - offset;
|
bytes_to_corrupt = file_size - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do it
|
// Do it
|
||||||
std::string contents;
|
std::string contents;
|
||||||
Status s = ReadFileToString(Env::Default(), fname, &contents);
|
Status s = ReadFileToString(env_.target(), fname, &contents);
|
||||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||||
for (int i = 0; i < bytes_to_corrupt; i++) {
|
for (int i = 0; i < bytes_to_corrupt; i++) {
|
||||||
contents[i + offset] ^= 0x80;
|
contents[i + offset] ^= 0x80;
|
||||||
}
|
}
|
||||||
s = WriteStringToFile(Env::Default(), contents, fname);
|
s = WriteStringToFile(env_.target(), contents, fname);
|
||||||
ASSERT_TRUE(s.ok()) << s.ToString();
|
ASSERT_TRUE(s.ok()) << s.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,16 +362,5 @@ TEST(CorruptionTest, UnrelatedKeys) {
|
|||||||
} // namespace leveldb
|
} // namespace leveldb
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
#if defined(LEVELDB_PLATFORM_WINDOWS)
|
|
||||||
// When Windows maps the contents of a file into memory, even if read/write,
|
|
||||||
// subsequent attempts to open that file for write access will fail. Forcing
|
|
||||||
// all RandomAccessFile instances to use base file I/O (e.g. ReadFile)
|
|
||||||
// allows these tests to open files in order to corrupt their contents.
|
|
||||||
leveldb::CorruptionTest::SetFileLimits(0);
|
|
||||||
|
|
||||||
// Allow this test to write to (and corrupt) files which are normally
|
|
||||||
// open for exclusive read access.
|
|
||||||
leveldb::CorruptionTest::RelaxFilePermissions();
|
|
||||||
#endif // defined(LEVELDB_PLATFORM_WINDOWS)
|
|
||||||
return leveldb::test::RunAllTests();
|
return leveldb::test::RunAllTests();
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,6 @@ constexpr int kDefaultMmapLimit = sizeof(void*) >= 8 ? 1000 : 0;
|
|||||||
// Modified by EnvWindowsTestHelper::SetReadOnlyMMapLimit().
|
// Modified by EnvWindowsTestHelper::SetReadOnlyMMapLimit().
|
||||||
int g_mmap_limit = kDefaultMmapLimit;
|
int g_mmap_limit = kDefaultMmapLimit;
|
||||||
|
|
||||||
// Relax some file access permissions for testing.
|
|
||||||
bool g_relax_permissions = false;
|
|
||||||
|
|
||||||
std::string GetWindowsErrorMessage(DWORD error_code) {
|
std::string GetWindowsErrorMessage(DWORD error_code) {
|
||||||
std::string message;
|
std::string message;
|
||||||
char* error_text = nullptr;
|
char* error_text = nullptr;
|
||||||
@ -366,10 +363,6 @@ class WindowsEnv : public Env {
|
|||||||
*result = nullptr;
|
*result = nullptr;
|
||||||
DWORD desired_access = GENERIC_READ;
|
DWORD desired_access = GENERIC_READ;
|
||||||
DWORD share_mode = FILE_SHARE_READ;
|
DWORD share_mode = FILE_SHARE_READ;
|
||||||
if (g_relax_permissions) {
|
|
||||||
desired_access |= GENERIC_WRITE;
|
|
||||||
share_mode |= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
|
||||||
}
|
|
||||||
ScopedHandle handle =
|
ScopedHandle handle =
|
||||||
::CreateFileA(fname.c_str(), desired_access, share_mode, nullptr,
|
::CreateFileA(fname.c_str(), desired_access, share_mode, nullptr,
|
||||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
@ -385,10 +378,6 @@ class WindowsEnv : public Env {
|
|||||||
*result = nullptr;
|
*result = nullptr;
|
||||||
DWORD desired_access = GENERIC_READ;
|
DWORD desired_access = GENERIC_READ;
|
||||||
DWORD share_mode = FILE_SHARE_READ;
|
DWORD share_mode = FILE_SHARE_READ;
|
||||||
if (g_relax_permissions) {
|
|
||||||
// desired_access |= GENERIC_WRITE;
|
|
||||||
share_mode |= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
|
||||||
}
|
|
||||||
DWORD file_flags = FILE_ATTRIBUTE_READONLY;
|
DWORD file_flags = FILE_ATTRIBUTE_READONLY;
|
||||||
|
|
||||||
ScopedHandle handle =
|
ScopedHandle handle =
|
||||||
@ -433,10 +422,6 @@ class WindowsEnv : public Env {
|
|||||||
WritableFile** result) override {
|
WritableFile** result) override {
|
||||||
DWORD desired_access = GENERIC_WRITE;
|
DWORD desired_access = GENERIC_WRITE;
|
||||||
DWORD share_mode = 0;
|
DWORD share_mode = 0;
|
||||||
if (g_relax_permissions) {
|
|
||||||
desired_access |= GENERIC_READ;
|
|
||||||
share_mode |= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScopedHandle handle =
|
ScopedHandle handle =
|
||||||
::CreateFileA(fname.c_str(), desired_access, share_mode, nullptr,
|
::CreateFileA(fname.c_str(), desired_access, share_mode, nullptr,
|
||||||
@ -721,11 +706,6 @@ void EnvWindowsTestHelper::SetReadOnlyMMapLimit(int limit) {
|
|||||||
g_mmap_limit = limit;
|
g_mmap_limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EnvWindowsTestHelper::RelaxFilePermissions() {
|
|
||||||
assert(default_env == nullptr);
|
|
||||||
g_relax_permissions = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
Env* Env::Default() {
|
Env* Env::Default() {
|
||||||
std::call_once(once, InitDefaultEnv);
|
std::call_once(once, InitDefaultEnv);
|
||||||
return default_env;
|
return default_env;
|
||||||
|
@ -18,11 +18,6 @@ class EnvWindowsTestHelper {
|
|||||||
// Set the maximum number of read-only files that will be mapped via mmap.
|
// Set the maximum number of read-only files that will be mapped via mmap.
|
||||||
// Must be called before creating an Env.
|
// Must be called before creating an Env.
|
||||||
static void SetReadOnlyMMapLimit(int limit);
|
static void SetReadOnlyMMapLimit(int limit);
|
||||||
|
|
||||||
// Relax file permissions for tests. This results in most files being opened
|
|
||||||
// with read-write permissions. This is helpful for corruption tests that
|
|
||||||
// need to corrupt the database files for open databases.
|
|
||||||
static void RelaxFilePermissions();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace leveldb
|
} // namespace leveldb
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_
|
#ifndef STORAGE_LEVELDB_UTIL_TESTUTIL_H_
|
||||||
#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_
|
#define STORAGE_LEVELDB_UTIL_TESTUTIL_H_
|
||||||
|
|
||||||
|
#include "helpers/memenv/memenv.h"
|
||||||
#include "leveldb/env.h"
|
#include "leveldb/env.h"
|
||||||
#include "leveldb/slice.h"
|
#include "leveldb/slice.h"
|
||||||
#include "util/random.h"
|
#include "util/random.h"
|
||||||
@ -32,9 +33,12 @@ class ErrorEnv : public EnvWrapper {
|
|||||||
bool writable_file_error_;
|
bool writable_file_error_;
|
||||||
int num_writable_file_errors_;
|
int num_writable_file_errors_;
|
||||||
|
|
||||||
ErrorEnv() : EnvWrapper(Env::Default()),
|
ErrorEnv() : EnvWrapper(NewMemEnv(Env::Default())),
|
||||||
writable_file_error_(false),
|
writable_file_error_(false),
|
||||||
num_writable_file_errors_(0) { }
|
num_writable_file_errors_(0) { }
|
||||||
|
~ErrorEnv() override {
|
||||||
|
delete target();
|
||||||
|
}
|
||||||
|
|
||||||
virtual Status NewWritableFile(const std::string& fname,
|
virtual Status NewWritableFile(const std::string& fname,
|
||||||
WritableFile** result) {
|
WritableFile** result) {
|
||||||
|
Loading…
Reference in New Issue
Block a user