diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-03-08 11:35:54 +1100 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-03-08 11:35:54 +1100 |
| commit | 4887f3789817f87bf1272af0b52684e3364270c2 (patch) | |
| tree | 945eb707ab4a0f6f0a6632dbb732dcc2ee2b39a8 /src/database/include/env_esp.hpp | |
| parent | d01f1bee1082840fdf50aa7ddd36dbcbff286d7e (diff) | |
| download | tangara-fw-4887f3789817f87bf1272af0b52684e3364270c2.tar.gz | |
add leveldb
Diffstat (limited to 'src/database/include/env_esp.hpp')
| -rw-r--r-- | src/database/include/env_esp.hpp | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/src/database/include/env_esp.hpp b/src/database/include/env_esp.hpp new file mode 100644 index 00000000..c9b3fbc8 --- /dev/null +++ b/src/database/include/env_esp.hpp @@ -0,0 +1,152 @@ +#pragma once + +#include <mutex> +#include <set> + +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" +#include "leveldb/env.h" +#include "leveldb/status.h" + +namespace leveldb { + +// Tracks the files locked by EspEnv::LockFile(). +// +// We maintain a separate set instead of relying on fcntl(F_SETLK) because +// fcntl(F_SETLK) does not provide any protection against multiple uses from the +// same process. +// +// Instances are thread-safe because all member data is guarded by a mutex. +class InMemoryLockTable { + public: + bool Insert(const std::string& fname) { + mu_.lock(); + bool succeeded = locked_files_.insert(fname).second; + mu_.unlock(); + return succeeded; + } + void Remove(const std::string& fname) { + mu_.lock(); + locked_files_.erase(fname); + mu_.unlock(); + } + + private: + std::mutex mu_; + std::set<std::string> locked_files_; +}; + +class EspEnv : public leveldb::Env { + public: + EspEnv(); + ~EspEnv() override; + + Status NewSequentialFile(const std::string& filename, + SequentialFile** result) override; + + Status NewRandomAccessFile(const std::string& filename, + RandomAccessFile** result) override; + + Status NewWritableFile(const std::string& filename, + WritableFile** result) override; + + Status NewAppendableFile(const std::string& filename, + WritableFile** result) override; + + bool FileExists(const std::string& filename) override; + + Status GetChildren(const std::string& directory_path, + std::vector<std::string>* result) override; + + Status RemoveFile(const std::string& filename) override; + + Status CreateDir(const std::string& dirname) override; + + Status RemoveDir(const std::string& dirname) override; + + Status GetFileSize(const std::string& filename, uint64_t* size) override; + + Status RenameFile(const std::string& from, const std::string& to) override; + + Status LockFile(const std::string& filename, FileLock** lock) override; + + Status UnlockFile(FileLock* lock) override; + + void Schedule(void (*background_work_function)(void* background_work_arg), + void* background_work_arg) override; + + void StartThread(void (*thread_main)(void* thread_main_arg), + void* thread_main_arg) override; + + Status GetTestDirectory(std::string* result) override; + + Status NewLogger(const std::string& filename, Logger** result) override; + + uint64_t NowMicros() override; + + void SleepForMicroseconds(int micros) override; + + void BackgroundThreadMain(); + + private: + // Stores the work item data in a Schedule() call. + // + // Instances are constructed on the thread calling Schedule() and used on the + // background thread. + // + // This structure is thread-safe beacuse it is immutable. + struct BackgroundWorkItem { + explicit BackgroundWorkItem(void (*f)(void*), void* a) + : function(f), arg(a) {} + + void (*const function)(void*); + void* const arg; + }; + + std::mutex background_work_mutex_; + bool started_background_thread_; + + QueueHandle_t background_work_queue_; + + InMemoryLockTable locks_; // Thread-safe. +}; + +} // namespace leveldb + +namespace database { + +// Wraps an Env instance whose destructor is never created. +// +// Intended usage: +// using PlatformSingletonEnv = SingletonEnv<PlatformEnv>; +// void ConfigurePosixEnv(int param) { +// PlatformSingletonEnv::AssertEnvNotInitialized(); +// // set global configuration flags. +// } +// Env* Env::Default() { +// static PlatformSingletonEnv default_env; +// return default_env.env(); +// } +template <typename EnvType> +class SingletonEnv { + public: + SingletonEnv() { + static_assert(sizeof(env_storage_) >= sizeof(EnvType), + "env_storage_ will not fit the Env"); + static_assert(alignof(decltype(env_storage_)) >= alignof(EnvType), + "env_storage_ does not meet the Env's alignment needs"); + new (&env_storage_) EnvType(); + } + ~SingletonEnv() = default; + + SingletonEnv(const SingletonEnv&) = delete; + SingletonEnv& operator=(const SingletonEnv&) = delete; + + leveldb::Env* env() { return reinterpret_cast<leveldb::Env*>(&env_storage_); } + + private: + typename std::aligned_storage<sizeof(EnvType), alignof(EnvType)>::type + env_storage_; +}; + +} // namespace database |
