summaryrefslogtreecommitdiff
path: root/src/database/env_esp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/database/env_esp.cpp')
-rw-r--r--src/database/env_esp.cpp497
1 files changed, 0 insertions, 497 deletions
diff --git a/src/database/env_esp.cpp b/src/database/env_esp.cpp
deleted file mode 100644
index f7a5637a..00000000
--- a/src/database/env_esp.cpp
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * Copyright 2023 jacqueline <me@jacqueline.id.au>
- *
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-#include "env_esp.hpp"
-
-#include <atomic>
-#include <cerrno>
-#include <cstddef>
-#include <cstdint>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <functional>
-#include <limits>
-#include <memory>
-#include <mutex>
-#include <queue>
-#include <set>
-#include <string>
-#include <thread>
-#include <type_traits>
-#include <utility>
-
-#include "esp_heap_caps.h"
-#include "esp_log.h"
-#include "ff.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/portmacro.h"
-#include "freertos/projdefs.h"
-#include "freertos/queue.h"
-#include "freertos/task.h"
-#include "leveldb/env.h"
-#include "leveldb/slice.h"
-#include "leveldb/status.h"
-
-#include "spi.hpp"
-#include "tasks.hpp"
-
-namespace leveldb {
-
-tasks::WorkerPool *sBackgroundThread = nullptr;
-
-std::string ErrToStr(FRESULT err) {
- switch (err) {
- case FR_OK:
- return "FR_OK";
- case FR_DISK_ERR:
- return "FR_DISK_ERR";
- case FR_INT_ERR:
- return "FR_INT_ERR";
- case FR_NOT_READY:
- return "FR_NOT_READY";
- case FR_NO_FILE:
- return "FR_NO_FILE";
- case FR_NO_PATH:
- return "FR_NO_PATH";
- case FR_INVALID_NAME:
- return "FR_INVALID_NAME";
- case FR_DENIED:
- return "FR_DENIED";
- case FR_EXIST:
- return "FR_EXIST";
- case FR_INVALID_OBJECT:
- return "FR_INVALID_OBJECT";
- case FR_WRITE_PROTECTED:
- return "FR_WRITE_PROTECTED";
- case FR_INVALID_DRIVE:
- return "FR_INVALID_DRIVE";
- case FR_NOT_ENABLED:
- return "FR_NOT_ENABLED";
- case FR_NO_FILESYSTEM:
- return "FR_NO_FILESYSTEM";
- case FR_MKFS_ABORTED:
- return "FR_MKFS_ABORTED";
- case FR_TIMEOUT:
- return "FR_TIMEOUT";
- case FR_LOCKED:
- return "FR_LOCKED";
- case FR_NOT_ENOUGH_CORE:
- return "FR_NOT_ENOUGH_CORE";
- case FR_TOO_MANY_OPEN_FILES:
- return "FR_TOO_MANY_OPEN_FILES";
- case FR_INVALID_PARAMETER:
- return "FR_INVALID_PARAMETER";
- default:
- return "UNKNOWN";
- }
-}
-
-Status EspError(const std::string& context, FRESULT err) {
- if (err == FR_NO_FILE) {
- return Status::NotFound(context, ErrToStr(err));
- } else {
- return Status::IOError(context, ErrToStr(err));
- }
-}
-
-class EspSequentialFile final : public SequentialFile {
- public:
- EspSequentialFile(const std::string& filename, FIL file)
- : file_(file), filename_(filename) {}
- ~EspSequentialFile() override {
- auto lock = drivers::acquire_spi();
- f_close(&file_);
- }
-
- Status Read(size_t n, Slice* result, char* scratch) override {
- auto lock = drivers::acquire_spi();
- UINT read_size = 0;
- FRESULT res = f_read(&file_, scratch, n, &read_size);
- if (res != FR_OK) { // Read error.
- return EspError(filename_, res);
- }
- *result = Slice(scratch, read_size);
- return Status::OK();
- }
-
- Status Skip(uint64_t n) override {
- auto lock = drivers::acquire_spi();
- DWORD current_pos = f_tell(&file_);
- FRESULT res = f_lseek(&file_, current_pos + n);
- if (res != FR_OK) {
- return EspError(filename_, res);
- }
- return Status::OK();
- }
-
- private:
- FIL file_;
- const std::string filename_;
-};
-
-// Implements random read access in a file using pread().
-//
-// Instances of this class are thread-safe, as required by the RandomAccessFile
-// API. Instances are immutable and Read() only calls thread-safe library
-// functions.
-class EspRandomAccessFile final : public RandomAccessFile {
- public:
- // The new instance takes ownership of |fd|. |fd_limiter| must outlive this
- // instance, and will be used to determine if .
- explicit EspRandomAccessFile(const std::string& filename)
- : filename_(std::move(filename)) {}
-
- ~EspRandomAccessFile() override {}
-
- Status Read(uint64_t offset,
- size_t n,
- Slice* result,
- char* scratch) const override {
- auto lock = drivers::acquire_spi();
- FIL file;
- FRESULT res = f_open(&file, filename_.c_str(), FA_READ);
- if (res != FR_OK) {
- return EspError(filename_, res);
- }
-
- res = f_lseek(&file, offset);
- if (res != FR_OK) {
- return EspError(filename_, res);
- }
-
- Status status;
- UINT read_size = 0;
- res = f_read(&file, scratch, n, &read_size);
- if (res != FR_OK || read_size == 0) {
- return EspError(filename_, res);
- }
- *result = Slice(scratch, read_size);
-
- f_close(&file);
-
- return status;
- }
-
- private:
- const std::string filename_;
-};
-
-// TODO(jacqueline): LevelDB expects writes to this class to be buffered in
-// memory. FatFs already does in-memory buffering, but we should think about
-// whether to layer more on top.
-class EspWritableFile final : public WritableFile {
- public:
- EspWritableFile(std::string filename, FIL file)
- : filename_(std::move(filename)), file_(file), is_open_(true) {}
-
- ~EspWritableFile() override {
- if (is_open_) {
- // Ignoring any potential errors
- Close();
- }
- }
-
- Status Append(const Slice& data) override {
- if (!is_open_) {
- return EspError(filename_, FR_NOT_ENABLED);
- }
-
- auto lock = drivers::acquire_spi();
- size_t write_size = data.size();
- const char* write_data = data.data();
-
- UINT bytes_written = 0;
- FRESULT res = f_write(&file_, write_data, write_size, &bytes_written);
- if (res != FR_OK) {
- return EspError(filename_, res);
- }
-
- return Status::OK();
- }
-
- Status Close() override {
- auto lock = drivers::acquire_spi();
- is_open_ = false;
- FRESULT res = f_close(&file_);
- if (res != FR_OK) {
- return EspError(filename_, res);
- }
- return Status::OK();
- }
-
- Status Flush() override { return Sync(); }
-
- Status Sync() override {
- if (!is_open_) {
- return EspError(filename_, FR_NOT_ENABLED);
- }
- auto lock = drivers::acquire_spi();
- FRESULT res = f_sync(&file_);
- if (res != FR_OK) {
- return EspError(filename_, res);
- }
- return Status::OK();
- }
-
- private:
- const std::string filename_;
- FIL file_;
- bool is_open_;
-};
-
-class EspFileLock : public FileLock {
- public:
- explicit EspFileLock(const std::string& filename) : filename_(filename) {}
- const std::string& filename() { return filename_; }
-
- private:
- const std::string filename_;
-};
-
-class EspLogger final : public Logger {
- public:
- explicit EspLogger(FIL file) : file_(file) {}
- ~EspLogger() override { f_close(&file_); }
-
- void Logv(const char* format, std::va_list ap) override {
- /*
- std::va_list args_copy;
- va_copy(args_copy, ap);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
- std::size_t bytes_needed = snprintf(NULL, 0, format, args_copy);
- char* output = reinterpret_cast<char*>(
- heap_caps_calloc(bytes_needed, 1, MALLOC_CAP_SPIRAM));
- snprintf(output, bytes_needed, format, args_copy);
-#pragma GCC diagnostic pop
- va_end(args_copy);
- ESP_LOGI("LEVELDB", "%s", output);
- // f_puts(output, &file_);
- free(reinterpret_cast<void*>(output));
- */
- }
-
- private:
- FIL file_;
-};
-
-EspEnv::~EspEnv() {
- ESP_LOGE("LEVELDB", "EspEnv singleton destroyed. Unsupported behavior!");
-}
-
-Status EspEnv::NewSequentialFile(const std::string& filename,
- SequentialFile** result) {
- auto lock = drivers::acquire_spi();
- FIL file;
- FRESULT res = f_open(&file, filename.c_str(), FA_READ);
- if (res != FR_OK) {
- *result = nullptr;
- return EspError(filename, res);
- }
-
- *result = new EspSequentialFile(filename, file);
- return Status::OK();
-}
-
-Status EspEnv::NewRandomAccessFile(const std::string& filename,
- RandomAccessFile** result) {
- auto lock = drivers::acquire_spi();
- // EspRandomAccessFile doesn't try to open the file until it's needed, so
- // we need to first ensure the file exists to handle the NotFound case
- // correctly.
- FILINFO info;
- FRESULT res = f_stat(filename.c_str(), &info);
- if (res != FR_OK) {
- *result = nullptr;
- return EspError(filename, res);
- }
-
- *result = new EspRandomAccessFile(filename);
- return Status::OK();
-}
-
-Status EspEnv::NewWritableFile(const std::string& filename,
- WritableFile** result) {
- auto lock = drivers::acquire_spi();
- FIL file;
- FRESULT res = f_open(&file, filename.c_str(), FA_WRITE | FA_CREATE_ALWAYS);
- if (res != FR_OK) {
- *result = nullptr;
- return EspError(filename, res);
- }
-
- *result = new EspWritableFile(filename, file);
- return Status::OK();
-}
-
-Status EspEnv::NewAppendableFile(const std::string& filename,
- WritableFile** result) {
- auto lock = drivers::acquire_spi();
- FIL file;
- FRESULT res = f_open(&file, filename.c_str(), FA_WRITE | FA_OPEN_APPEND);
- if (res != FR_OK) {
- *result = nullptr;
- return EspError(filename, res);
- }
-
- *result = new EspWritableFile(filename, file);
- return Status::OK();
-}
-
-bool EspEnv::FileExists(const std::string& filename) {
- auto lock = drivers::acquire_spi();
- FILINFO info;
- return f_stat(filename.c_str(), &info) == FR_OK;
-}
-
-Status EspEnv::GetChildren(const std::string& directory_path,
- std::vector<std::string>* result) {
- result->clear();
-
- auto lock = drivers::acquire_spi();
- FF_DIR dir;
- FRESULT res = f_opendir(&dir, directory_path.c_str());
- if (res != FR_OK) {
- return EspError(directory_path, res);
- }
-
- FILINFO info;
- for (;;) {
- res = f_readdir(&dir, &info);
- if (res != FR_OK) {
- return EspError(directory_path, res);
- }
- if (info.fname[0] == 0) {
- break;
- }
- result->emplace_back(info.fname);
- }
-
- res = f_closedir(&dir);
- if (res != FR_OK) {
- return EspError(directory_path, res);
- }
-
- return Status::OK();
-}
-
-Status EspEnv::RemoveFile(const std::string& filename) {
- auto lock = drivers::acquire_spi();
- FRESULT res = f_unlink(filename.c_str());
- if (res != FR_OK) {
- return EspError(filename, res);
- }
- return Status::OK();
-}
-
-Status EspEnv::CreateDir(const std::string& dirname) {
- auto lock = drivers::acquire_spi();
- FRESULT res = f_mkdir(dirname.c_str());
- if (res != FR_OK) {
- return EspError(dirname, res);
- }
- return Status::OK();
-}
-
-Status EspEnv::RemoveDir(const std::string& dirname) {
- return RemoveFile(dirname);
-}
-
-Status EspEnv::GetFileSize(const std::string& filename, uint64_t* size) {
- auto lock = drivers::acquire_spi();
- FILINFO info;
- FRESULT res = f_stat(filename.c_str(), &info);
- if (res != FR_OK) {
- *size = 0;
- return EspError(filename, res);
- }
- *size = info.fsize;
- return Status::OK();
-}
-
-Status EspEnv::RenameFile(const std::string& from, const std::string& to) {
- // Match the POSIX behaviour of replacing any existing file.
- if (FileExists(to)) {
- Status s = RemoveFile(to);
- if (!s.ok()) {
- return s;
- }
- }
- auto lock = drivers::acquire_spi();
- FRESULT res = f_rename(from.c_str(), to.c_str());
- if (res != FR_OK) {
- return EspError(from, res);
- }
- return Status::OK();
-}
-
-Status EspEnv::LockFile(const std::string& filename, FileLock** lock) {
- *lock = nullptr;
-
- if (!locks_.Insert(filename)) {
- return Status::IOError("lock " + filename, "already held by process");
- }
-
- *lock = new EspFileLock(filename);
- return Status::OK();
-}
-
-Status EspEnv::UnlockFile(FileLock* lock) {
- EspFileLock* posix_file_lock = static_cast<EspFileLock*>(lock);
- locks_.Remove(posix_file_lock->filename());
- delete posix_file_lock;
- return Status::OK();
-}
-
-void EspEnv::StartThread(void (*thread_main)(void* thread_main_arg),
- void* thread_main_arg) {
- std::thread new_thread(thread_main, thread_main_arg);
- new_thread.detach();
-}
-
-Status EspEnv::GetTestDirectory(std::string* result) {
- CreateDir("/tmp");
- *result = "/tmp";
- return Status::OK();
-}
-
-Status EspEnv::NewLogger(const std::string& filename, Logger** result) {
- auto lock = drivers::acquire_spi();
- FIL file;
- FRESULT res = f_open(&file, filename.c_str(), FA_WRITE | FA_OPEN_APPEND);
- if (res != FR_OK) {
- *result = nullptr;
- return EspError(filename, res);
- }
-
- *result = new EspLogger(file);
- return Status::OK();
-}
-
-uint64_t EspEnv::NowMicros() {
- struct timeval tv_now;
- gettimeofday(&tv_now, NULL);
- return (int64_t)tv_now.tv_sec * 1000000L + (int64_t)tv_now.tv_usec;
-}
-
-void EspEnv::SleepForMicroseconds(int micros) {
- vTaskDelay(pdMS_TO_TICKS(micros / 1000));
-}
-
-EspEnv::EspEnv() {}
-
-void EspEnv::Schedule(
- void (*background_work_function)(void* background_work_arg),
- void* background_work_arg) {
- auto worker = sBackgroundThread;
- if (worker) {
- worker->Dispatch<void>(
- [=]() { std::invoke(background_work_function, background_work_arg); });
- }
-}
-
-} // namespace leveldb