Made FileStore a template to support arbitrary address space sizes.

This commit is contained in:
2016-06-06 19:53:57 -05:00
parent 02e25000e1
commit c822a7564a
7 changed files with 250 additions and 201 deletions
+3 -2
View File
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 2.8.8) cmake_minimum_required(VERSION 2.8.8)
project(Memphis) project(WombatFS)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules)
include(address_sanitizer) include(address_sanitizer)
@@ -24,4 +24,5 @@ include_directories("src")
add_subdirectory(src) add_subdirectory(src)
add_subdirectory(test) add_subdirectory(test)
add_test("MemFs" test/MemFsTest) add_test("Format" test/Format)
add_test("FsStore" test/FsStore)
+2 -2
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 2.8.8) cmake_minimum_required(VERSION 2.8.8)
add_library( add_library(
Memphis WFS
filestore.cpp filestore.cpp
_memops.cpp _memops.cpp
) )
@@ -11,5 +11,5 @@ install(
filestore.hpp filestore.hpp
_memops.hpp _memops.hpp
DESTINATION DESTINATION
include/Memphis include/WFS
) )
-151
View File
@@ -10,156 +10,5 @@
namespace wombat { namespace wombat {
namespace fs { namespace fs {
uint32_t FileStore::version = 0;
uint8_t *initFs(uint8_t *buffer, size_t size, bool hasDirectories) {
auto fs = (MemFsHeader*) buffer;
fs->version = FileStore::version;
return (uint8_t*) fs;
}
MemFsPtr FileStore::Record::size() {
return offsetof(FileStore::Record, m_id) + dataLen;
}
void FileStore::Record::setId(RecordId id) {
this->m_id = id;
}
void FileStore::Record::setData(uint8_t *data, int size) {
memcpy(this + m_data, data, size);
m_data = size;
}
// FileStore
FileStore::FileStore(uint8_t *begin, uint8_t *end, Error *error): m_version(*((uint32_t*) begin)), m_lastRec(*(MemFsPtr*) (begin + sizeof(m_version))) {
if (version != m_version) {
// version mismatch
if (error) {
*error = 1;
}
} else {
// ok
m_begin = begin;
m_end = end;
m_root = (Record*) (begin + sizeof(MemFsPtr));
if (error) {
*error = 0;
}
}
}
void FileStore::init() {
memset(m_begin, 0, m_end - m_begin);
m_version = version;
}
void FileStore::write(RecordId id, uint8_t *data, MemFsPtr dataLen) {
const MemFsPtr size = offsetof(FileStore::Record, m_id) + dataLen;
auto rec = (Record*) alloc(size);
rec->dataLen = dataLen;
insert(m_root, rec);
}
int FileStore::read(RecordId id, uint8_t *data, MemFsPtr *size) {
auto rec = getRecord(m_root, id);
int retval = 1;
if (rec) {
*size = rec->dataLen;
memcpy(data, ptr<uint8_t*>(rec->m_data), *size);
retval = 0;
}
return retval;
}
FileStore::Record *FileStore::getRecord(FileStore::Record *root, RecordId id) {
auto cmp = root->m_id > id;
MemFsPtr recPt;
if (cmp) {
recPt = root->left;
} else if (!cmp) {
recPt = root->right;
} else {
recPt = ptr(root);
}
if (recPt) {
return getRecord(ptr<Record*>(recPt), id);
} else {
return ptr<Record*>(recPt);
}
}
void *FileStore::alloc(MemFsPtr size) {
const auto iterator = this->iterator();
if ((iterator + size) > (uint64_t) m_end) {
compress();
if ((iterator + size) > (uint64_t) m_end) {
return nullptr;
}
}
ptr<Record*>(m_lastRec)->next = iterator;
auto rec = ptr<uint8_t*>(iterator);
memset(rec, 0, size);
ptr<Record*>(iterator)->prev = m_lastRec;
m_lastRec = iterator;
return rec;
}
void FileStore::compress() {
auto current = m_root;
while (current->next) {
auto prevEnd = current + current->size();
current = ptr<Record*>(current->next);
if (prevEnd != current) {
memcpy(prevEnd, current, current->size());
current = prevEnd;
}
}
}
bool FileStore::insert(Record *root, Record *insertValue, MemFsPtr *rootParentPtr) {
auto cmp = root->m_id > insertValue->m_id;
if (cmp) {
if (root->left) {
return insert(ptr<Record*>(root->left), insertValue, &root->left);
} else {
root->left = ((uint8_t*) insertValue) - m_begin;
return true;
}
} else if (!cmp) {
if (root->right) {
return insert(ptr<Record*>(root->right), insertValue, &root->right);
} else {
root->right = ((uint8_t*) insertValue) - m_begin;
return true;
}
} else {
auto ivAddr = ((uint8_t*) insertValue) - m_begin;
if (root->prev) {
ptr<Record*>(root->prev)->next = ivAddr;
}
if (root->next) {
ptr<Record*>(root->next)->prev = ivAddr;
}
if (rootParentPtr) {
*rootParentPtr = ivAddr;
}
return true;
}
return false;
}
MemFsPtr FileStore::iterator() {
return m_lastRec + ((Record*) m_begin + m_lastRec)->size();
}
MemFsPtr FileStore::ptr(void *ptr) {
return ((uint8_t*) ptr) - m_begin;
}
} }
} }
+213 -41
View File
@@ -8,42 +8,42 @@
#ifndef WOMBAT_FS_FILESTORE_HPP #ifndef WOMBAT_FS_FILESTORE_HPP
#define WOMBAT_FS_FILESTORE_HPP #define WOMBAT_FS_FILESTORE_HPP
#include "_memops.hpp"
#include "_types.hpp" #include "_types.hpp"
namespace wombat { namespace wombat {
namespace fs { namespace fs {
typedef uint32_t MemFsPtr; template<typename FsSize_t>
typedef uint32_t RecordId;
struct MemFsHeader {
uint32_t version;
MemFsPtr rootDir = -1;
};
class DirectoryHeader {
/**
* Count of the number of files listed in this directory.
*/
MemFsPtr files;
const char* operator[](int i);
};
class FileStore { class FileStore {
public: public:
static uint32_t version; struct FsHeader {
uint32_t version;
FsSize_t rootDir = -1;
};
struct Inode {
enum class Type: uint8_t {
FILE,
DIRECTORY
} type;
FsSize_t size;
};
typedef FsSize_t RecordId;
private: private:
struct Record { struct Record {
// the next Record in memory // the next Record in memory
MemFsPtr prev, next; FsSize_t prev, next;
MemFsPtr left, right; FsSize_t left, right;
MemFsPtr dataLen; FsSize_t dataLen;
// offsets from Record this // offsets from Record this
MemFsPtr m_id; FsSize_t m_id;
MemFsPtr m_data; FsSize_t m_data;
MemFsPtr size(); FsSize_t size();
void setId(RecordId); void setId(RecordId);
void setData(uint8_t *data, int size); void setData(uint8_t *data, int size);
}; };
@@ -51,7 +51,7 @@ class FileStore {
uint8_t *m_begin, *m_end; uint8_t *m_begin, *m_end;
uint32_t &m_version; uint32_t &m_version;
// the last Record in the FileStore's memory chunk // the last Record in the FileStore's memory chunk
MemFsPtr &m_lastRec; FsSize_t &m_lastRec;
Record *m_root; Record *m_root;
public: public:
@@ -75,7 +75,7 @@ class FileStore {
* @param data the contents of the file * @param data the contents of the file
* @param dataLen the number of bytes data points to * @param dataLen the number of bytes data points to
*/ */
void write(RecordId id, uint8_t *data, MemFsPtr dataLen); void write(RecordId id, uint8_t *data, FsSize_t dataLen);
/** /**
* Reads the "file" at the given id. You are responsible for freeing * Reads the "file" at the given id. You are responsible for freeing
@@ -85,7 +85,11 @@ class FileStore {
* @param size pointer to a value that will be assigned the size of data * @param size pointer to a value that will be assigned the size of data
* @return 0 if read is a success * @return 0 if read is a success
*/ */
int read(RecordId id, uint8_t *data, MemFsPtr *size); int read(RecordId id, uint8_t *data, FsSize_t *size);
static uint8_t version();
static uint8_t *format(uint8_t *buffer, size_t size, bool hasDirectories);
private: private:
/** /**
@@ -95,13 +99,13 @@ class FileStore {
* @param pathLen number of characters in pathLen * @param pathLen number of characters in pathLen
* @return the requested Record, if available * @return the requested Record, if available
*/ */
Record *getRecord(Record *root, RecordId id); Record *getRecord(FileStore::Record *root, RecordId id);
/** /**
* Gets an address for a new Record. * Gets an address for a new Record.
* @param size the size of the Record * @param size the size of the Record
*/ */
void *alloc(MemFsPtr size); void *alloc(FsSize_t size);
/** /**
* Compresses all of the records into a contiguous space, starting at m_root. * Compresses all of the records into a contiguous space, starting at m_root.
@@ -113,32 +117,200 @@ class FileStore {
* If the record already exists, it replaces the old on deletes it. * If the record already exists, it replaces the old on deletes it.
* @return true if the record was inserted * @return true if the record was inserted
*/ */
bool insert(Record *root, Record *insertValue, MemFsPtr *rootParentPtr = 0); bool insert(Record *root, Record *insertValue, FsSize_t *rootParentPtr = 0);
/** /**
* Gets the MemFsPtr associated with the next Record to be allocated. * Gets the FsSize_t associated with the next Record to be allocated.
* @retrun the MemFsPtr associated with the next Record to be allocated * @retrun the FsSize_t associated with the next Record to be allocated
*/ */
MemFsPtr iterator(); FsSize_t iterator();
/** /**
* Converts an actual pointer to a MemFsPtr. * Converts an actual pointer to a FsSize_t.
*/ */
MemFsPtr ptr(void *ptr); FsSize_t ptr(void *ptr);
/** /**
* Converts a MemFsPtr to an actual pointer. * Converts a FsSize_t to an actual pointer.
*/ */
template<typename T> template<typename T>
T ptr(MemFsPtr ptr); T ptr(FsSize_t ptr) {
return (T) m_begin + ptr;
};
}; };
template<typename T> template<typename FsSize_t>
T FileStore::ptr(MemFsPtr ptr) { FsSize_t FileStore<FsSize_t>::Record::size() {
return (T) m_begin + ptr; return offsetof(FileStore::Record, m_id) + dataLen;
} }
uint8_t *initFs(uint8_t *buffer, size_t size, bool hasDirectories); template<typename FsSize_t>
void FileStore<FsSize_t>::Record::setId(RecordId id) {
this->m_id = id;
}
template<typename FsSize_t>
void FileStore<FsSize_t>::Record::setData(uint8_t *data, int size) {
memcpy(this + m_data, data, size);
m_data = size;
}
// FileStore
template<typename FsSize_t>
FileStore<FsSize_t>::FileStore(uint8_t *begin, uint8_t *end, Error *error): m_version(*((uint32_t*) begin)), m_lastRec(*(FsSize_t*) (begin + sizeof(m_version))) {
if (version() != m_version) {
// version mismatch
if (error) {
*error = 1;
}
} else {
// ok
m_begin = begin;
m_end = end;
m_root = (Record*) (begin + sizeof(FsSize_t));
if (error) {
*error = 0;
}
}
}
template<typename FsSize_t>
void FileStore<FsSize_t>::init() {
memset(m_begin, 0, m_end - m_begin);
m_version = version;
}
template<typename FsSize_t>
void FileStore<FsSize_t>::write(RecordId id, uint8_t *data, FsSize_t dataLen) {
const FsSize_t size = offsetof(FileStore::Record, m_id) + dataLen;
auto rec = (Record*) alloc(size);
rec->dataLen = dataLen;
insert(m_root, rec);
}
template<typename FsSize_t>
int FileStore<FsSize_t>::read(RecordId id, uint8_t *data, FsSize_t *size) {
auto rec = getRecord(m_root, id);
int retval = 1;
if (rec) {
if (size) {
*size = rec->dataLen;
}
memcpy(data, ptr<uint8_t*>(rec->m_data), rec->dataLen);
retval = 0;
}
return retval;
}
template<typename FsSize_t>
typename FileStore<FsSize_t>::Record *FileStore<FsSize_t>::getRecord(FileStore::Record *root, RecordId id) {
auto cmp = root->m_id > id;
FsSize_t recPt;
if (cmp) {
recPt = root->left;
} else if (!cmp) {
recPt = root->right;
} else {
recPt = ptr(root);
}
if (recPt) {
return getRecord(ptr<Record*>(recPt), id);
} else {
return ptr<Record*>(recPt);
}
}
template<typename FsSize_t>
void *FileStore<FsSize_t>::alloc(FsSize_t size) {
const auto iterator = this->iterator();
if ((iterator + size) > (uint64_t) m_end) {
compress();
if ((iterator + size) > (uint64_t) m_end) {
return nullptr;
}
}
ptr<Record*>(m_lastRec)->next = iterator;
auto rec = ptr<uint8_t*>(iterator);
memset(rec, 0, size);
ptr<Record*>(iterator)->prev = m_lastRec;
m_lastRec = iterator;
return rec;
}
template<typename FsSize_t>
void FileStore<FsSize_t>::compress() {
auto current = m_root;
while (current->next) {
auto prevEnd = current + current->size();
current = ptr<Record*>(current->next);
if (prevEnd != current) {
memcpy(prevEnd, current, current->size());
current = prevEnd;
}
}
}
template<typename FsSize_t>
bool FileStore<FsSize_t>::insert(Record *root, Record *insertValue, FsSize_t *rootParentPtr) {
auto cmp = root->m_id > insertValue->m_id;
if (cmp) {
if (root->left) {
return insert(ptr<Record*>(root->left), insertValue, &root->left);
} else {
root->left = ((uint8_t*) insertValue) - m_begin;
return true;
}
} else if (!cmp) {
if (root->right) {
return insert(ptr<Record*>(root->right), insertValue, &root->right);
} else {
root->right = ((uint8_t*) insertValue) - m_begin;
return true;
}
} else {
auto ivAddr = ((uint8_t*) insertValue) - m_begin;
if (root->prev) {
ptr<Record*>(root->prev)->next = ivAddr;
}
if (root->next) {
ptr<Record*>(root->next)->prev = ivAddr;
}
if (rootParentPtr) {
*rootParentPtr = ivAddr;
}
return true;
}
return false;
}
template<typename FsSize_t>
FsSize_t FileStore<FsSize_t>::iterator() {
return m_lastRec + ((Record*) m_begin + m_lastRec)->size();
}
template<typename FsSize_t>
FsSize_t FileStore<FsSize_t>::ptr(void *ptr) {
return ((uint8_t*) ptr) - m_begin;
}
template<typename FsSize_t>
uint8_t FileStore<FsSize_t>::version() {
return 0;
};
template<typename FsSize_t>
uint8_t *FileStore<FsSize_t>::format(uint8_t *buffer, size_t size, bool hasDirectories) {
auto retval = (typename FileStore<FsSize_t>::FsHeader*) buffer;
retval->version = FileStore<FsSize_t>::version();
return (uint8_t*) retval;
}
typedef FileStore<uint16_t> FileStore16;
typedef FileStore<uint32_t> FileStore32;
typedef FileStore<uint64_t> FileStore64;
} }
} }
+9 -3
View File
@@ -1,8 +1,14 @@
cmake_minimum_required(VERSION 2.8.8) cmake_minimum_required(VERSION 2.8.8)
add_executable( add_executable(
MemFsTest Format
test.cpp format.cpp
) )
target_link_libraries(MemFsTest Memphis) add_executable(
FsStore
fsstore.cpp
)
target_link_libraries(Format WFS)
target_link_libraries(FsStore WFS)
+2 -2
View File
@@ -13,7 +13,7 @@ int main() {
const auto size = 1 << 16; const auto size = 1 << 16;
uint8_t volume[size]; uint8_t volume[size];
uint32_t err; uint32_t err;
initFs(volume, size, false); FileStore32::format(volume, size, false);
FileStore(volume, volume + size, &err); FileStore32(volume, volume + size, &err);
return err; return err;
} }
+21
View File
@@ -0,0 +1,21 @@
/*
* Copyright 2015 gtalent2@gmail.com
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <filestore.hpp>
using namespace wombat::fs;
int main() {
const auto size = 1 << 16;
uint8_t volume[size];
char out[6];
uint32_t err;
FileStore32 fs(volume, volume + size, &err);
fs.write(42, (uint8_t*) "Hello", 6);
err = fs.read(42, (uint8_t*) out, nullptr);
return err;
}