From b50050358ccdef26be308e2403467de3f4b0c2a6 Mon Sep 17 00:00:00 2001 From: Scott Lamb Date: Sat, 12 Nov 2016 11:57:44 -0800 Subject: [PATCH] read-only operation, database locking These are meant to ease safe side-by-side testing with the upcoming Rust implementation. --- src/filesystem.cc | 5 +++++ src/filesystem.h | 3 +++ src/moonfire-nvr-main.cc | 32 +++++++++++++++++++++++++++----- src/testutil.h | 1 + 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/filesystem.cc b/src/filesystem.cc index 3a39fac..f901912 100644 --- a/src/filesystem.cc +++ b/src/filesystem.cc @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,10 @@ class RealFile : public File { return 0; } + int Lock(int operation) final { + return (flock(fd_, operation) < 0) ? errno : 0; + } + int Open(const char *path, int flags, int *fd) final { return Open(path, flags, 0, fd); } diff --git a/src/filesystem.h b/src/filesystem.h index 32ab47c..824bd06 100644 --- a/src/filesystem.h +++ b/src/filesystem.h @@ -67,6 +67,9 @@ class File { // Already closed is considered a success. virtual int Close() = 0; + // flock(), returning 0 on success or errno>0 on failure. + virtual int Lock(int operation) = 0; + // openat(), returning 0 on success or errno>0 on failure. virtual int Open(const char *path, int flags, int *fd) = 0; virtual int Open(const char *path, int flags, std::unique_ptr *f) = 0; diff --git a/src/moonfire-nvr-main.cc b/src/moonfire-nvr-main.cc index 4f0d9c2..c21696a 100644 --- a/src/moonfire-nvr-main.cc +++ b/src/moonfire-nvr-main.cc @@ -59,6 +59,7 @@ using moonfire_nvr::StrCat; DEFINE_int32(http_port, 0, ""); DEFINE_string(db_dir, "", ""); DEFINE_string(sample_file_dir, "", ""); +DEFINE_bool(read_only, false, ""); namespace { @@ -152,10 +153,28 @@ int main(int argc, char** argv) { env.sample_file_dir = sample_file_dir.release(); + std::unique_ptr db_dir; + std::string db_dirname = FLAGS_db_dir; + ret = moonfire_nvr::GetRealFilesystem()->Open( + db_dirname.c_str(), O_DIRECTORY | O_RDONLY, &db_dir); + if (ret != 0) { + LOG(ERROR) << "Unable to open --db_dir=" << db_dirname << ": " + << strerror(ret) << "; exiting."; + exit(1); + } + bool read_only = FLAGS_read_only; + ret = db_dir->Lock((read_only ? LOCK_SH : LOCK_EX) | LOCK_NB); + if (ret != 0) { + LOG(ERROR) << "Unable to lock --db_dir=" << db_dirname << ": " + << strerror(ret) << "; exiting."; + exit(1); + } moonfire_nvr::Database db; std::string error_msg; std::string db_path = StrCat(FLAGS_db_dir, "/db"); - if (!db.Open(db_path.c_str(), SQLITE_OPEN_READWRITE, &error_msg)) { + if (!db.Open(db_path.c_str(), + read_only ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE, + &error_msg)) { LOG(ERROR) << error_msg << "; exiting."; exit(1); } @@ -171,10 +190,13 @@ int main(int argc, char** argv) { << ", running with version " << event_get_version(); base = CHECK_NOTNULL(event_base_new()); - std::unique_ptr nvr(new moonfire_nvr::Nvr(&env)); - if (!nvr->Init(&error_msg)) { - LOG(ERROR) << "Unable to initialize: " << error_msg << "; exiting."; - exit(1); + std::unique_ptr nvr; + if (!read_only) { + nvr.reset(new moonfire_nvr::Nvr(&env)); + if (!nvr->Init(&error_msg)) { + LOG(ERROR) << "Unable to initialize: " << error_msg << "; exiting."; + exit(1); + } } evhttp* http = CHECK_NOTNULL(evhttp_new(base)); diff --git a/src/testutil.h b/src/testutil.h index d9b936c..874fa14 100644 --- a/src/testutil.h +++ b/src/testutil.h @@ -137,6 +137,7 @@ class MockFile : public File { return ret; } + MOCK_METHOD1(Lock, int(int)); MOCK_METHOD3(Open, int(const char *, int, int *)); MOCK_METHOD4(Open, int(const char *, int, mode_t, int *)); MOCK_METHOD3(OpenRaw, int(const char *, int, File **));