From 92c1c776cc5db4b7248fe008cb0ab449eac07c31 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sat, 21 Dec 2013 01:24:17 +0200 Subject: [PATCH] Refactor library filesystem code --- include/library/filesys.hpp | 179 ---------------------- include/library/filesystem.hpp | 222 ++++++++++++++++++++++++++++ src/core/inthread.cpp | 32 ++-- src/library/{filesys.cpp => filesystem.cpp} | 51 ++++++- src/util/fattest.cpp | 2 +- src/util/lsvsdump.cpp | 2 +- 6 files changed, 290 insertions(+), 198 deletions(-) delete mode 100644 include/library/filesys.hpp create mode 100644 include/library/filesystem.hpp rename src/library/{filesys.cpp => filesystem.cpp} (90%) diff --git a/include/library/filesys.hpp b/include/library/filesys.hpp deleted file mode 100644 index 8cd9bd19..00000000 --- a/include/library/filesys.hpp +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef _library__filesys__hpp__included -#define _library__filesys__hpp__included - -#include -#include -#include -#include -#include "threadtypes.hpp" - -#define CLUSTER_SIZE 8192 -#define CLUSTERS_PER_SUPER (CLUSTER_SIZE / 4) -#define SUPERCLUSTER_SIZE (static_cast(CLUSTER_SIZE) * CLUSTERS_PER_SUPER) -#define FILESYSTEM_SUPERBLOCK 1 -#define FILESYSTEM_ROOTDIR 2 - -class filesystem -{ -public: - //Create a new or open existing filesystem backed by specified file. - filesystem(const std::string& backingfile); - //Allocate a new file. - uint32_t allocate_cluster(); - //Delete specified file. - void free_cluster_chain(uint32_t cluster); - //Skip specfied amount of data. If skip goes to end of file, ptr will be left at CLUSTER_SIZE. - size_t skip_data(uint32_t& cluster, uint32_t& ptr, uint32_t length); - //Read specified amount of data. If read goes to end of file, ptr will be left at CLUSTER_SIZE. - //Returns the number of bytes read. - size_t read_data(uint32_t& cluster, uint32_t& ptr, void* data, uint32_t length); - //Write specified amount of data. real_cluster and real_ptr point to location data was written to. - //If write exactly fills the last cluster, ptr will be left at CLUSTER_SIZE. - void write_data(uint32_t& cluster, uint32_t& ptr, const void* data, uint32_t length, - uint32_t& real_cluster, uint32_t& real_ptr); -private: - filesystem(const filesystem&); - filesystem& operator=(const filesystem&); - void link_cluster(uint32_t cluster, uint32_t linkto); - struct supercluster - { - unsigned free_clusters; - uint32_t clusters[CLUSTERS_PER_SUPER]; - void load(std::fstream& s, uint32_t index); - void save(std::fstream& s, uint32_t index); - }; - uint32_t supercluster_count; - std::map superclusters; - std::fstream backing; -}; - -class filesystem_ref -{ -public: - filesystem_ref() - { - refcnt = NULL; - mutex = NULL; - fs = NULL; - } - filesystem_ref(const std::string& backingfile) - { - refcnt = NULL; - mutex = NULL; - try { - refcnt = new unsigned; - mutex = new mutex_class; - fs = new filesystem(backingfile); - } catch(...) { - delete refcnt; - delete mutex; - throw; - } - *refcnt = 1; - } - ~filesystem_ref() - { - mutex_class* mtodelete = NULL; - if(!mutex) - return; - { - umutex_class m(*mutex); - --*refcnt; - if(!*refcnt) { - delete fs; - delete refcnt; - mtodelete = mutex; - } - } - if(mtodelete) - delete mtodelete; - } - filesystem_ref(const filesystem_ref& r) - { - umutex_class m(*r.mutex); - ++*(r.refcnt); - refcnt = r.refcnt; - mutex = r.mutex; - fs = r.fs; - } - filesystem_ref& operator=(const filesystem_ref& r) - { - if(this == &r) - return *this; - //This is tricky, due to having to lock two objects. - size_t A = (size_t)this; - size_t B = (size_t)&r; - mutex_class* mtodelete = NULL; - if(!refcnt) { - //We just have to grab a ref and copy. - umutex_class m(*r.mutex); - ++*(r.refcnt); - refcnt = r.refcnt; - mutex = r.mutex; - fs = r.fs; - } else if(A < B) { - //Two-object case. - umutex_class m1(*mutex); - umutex_class m2(*r.mutex); - --*refcnt; - if(!*refcnt) { - delete fs; - delete refcnt; - mtodelete = mutex;; - } - ++*(r.refcnt); - refcnt = r.refcnt; - mutex = r.mutex; - fs = r.fs; - } else { - //Two-object case. - umutex_class m1(*r.mutex); - umutex_class m2(*mutex); - --*refcnt; - if(!*refcnt) { - delete fs; - delete refcnt; - mtodelete = mutex;; - } - ++*(r.refcnt); - refcnt = r.refcnt; - mutex = r.mutex; - fs = r.fs; - } - if(mtodelete) - delete mtodelete; - return *this; - } - uint32_t allocate_cluster() - { - umutex_class m(*mutex); - return fs->allocate_cluster(); - } - void free_cluster_chain(uint32_t cluster) - { - umutex_class m(*mutex); - fs->free_cluster_chain(cluster); - } - size_t skip_data(uint32_t& cluster, uint32_t& ptr, uint32_t length) - { - umutex_class m(*mutex); - return fs->skip_data(cluster, ptr, length); - } - size_t read_data(uint32_t& cluster, uint32_t& ptr, void* data, uint32_t length) - { - umutex_class m(*mutex); - return fs->read_data(cluster, ptr, data, length); - } - void write_data(uint32_t& cluster, uint32_t& ptr, const void* data, uint32_t length, - uint32_t& real_cluster, uint32_t& real_ptr) - { - umutex_class m(*mutex); - fs->write_data(cluster, ptr, data, length, real_cluster, real_ptr); - } -private: - filesystem* fs; - unsigned* refcnt; - mutex_class* mutex; -}; - -#endif diff --git a/include/library/filesystem.hpp b/include/library/filesystem.hpp new file mode 100644 index 00000000..32619dcb --- /dev/null +++ b/include/library/filesystem.hpp @@ -0,0 +1,222 @@ +#ifndef _library__filesystem__hpp__included +#define _library__filesystem__hpp__included + +#include +#include +#include +#include +#include "threadtypes.hpp" + +#define CLUSTER_SIZE 8192 +#define CLUSTERS_PER_SUPER (CLUSTER_SIZE / 4) +#define SUPERCLUSTER_SIZE (static_cast(CLUSTER_SIZE) * CLUSTERS_PER_SUPER) +#define FILESYSTEM_SUPERBLOCK 1 +#define FILESYSTEM_ROOTDIR 2 + +/** + * A filesystem. + */ +class filesystem +{ +public: +/** + * Create a new filesystem or open existing one, backed by specified file. + * + * Parameters backingfile: The backing file name. + */ + filesystem(const std::string& backingfile); +/** + * Allocate a new file. + * + * Returns: The initial cluster for the new file. + */ + uint32_t allocate_cluster(); +/** + * Delete a file. + * + * Parameter cluster: The initial cluster of file to delete. + */ + void free_cluster_chain(uint32_t cluster); +/** + * Read and discard specified amount of data. + * + * Parameter cluster: Cluster to start the read from. Updated to be cluster for following data. + * Parameter ptr: The offset in cluster. Updated to be offset for following data. + * Parameter length: The length to read. + * Returns: The actual amount read. Can only be smaller than length if EOF was seen first. + * + * Note: If this runs off the end of file, cluster will be left pointing to last cluster in file and ptr will be + * left at CLUSTER_SIZE. + */ + size_t skip_data(uint32_t& cluster, uint32_t& ptr, uint32_t length); +/** + * Read specified amount of data. + * + * Parameter cluster: Cluster to start the read from. Updated to be cluster for following data. + * Parameter ptr: The offset in cluster. Updated to be offset for following data. + * Parameter data: The buffer to store the read data to. + * Parameter length: The length to read. + * Returns: The actual amount read. Can only be smaller than length if EOF was seen first. + * + * Note: If this runs off the end of file, cluster will be left pointing to last cluster in file and ptr will be + * left at CLUSTER_SIZE. + */ + size_t read_data(uint32_t& cluster, uint32_t& ptr, void* data, uint32_t length); +/** + * Write specified amount of data. + * + * Parameter cluster: Cluster to start the write from. Update to be cluster for following data. + * Parameter ptr: The offset in cluster. Updated to be offset for following data. + * Parameter data: The buffer to read the data to write. + * Parameter length: The length to write. + * Parameter real_cluster: The real cluster the write started from is stored here. + * Parameter real_ptr: The real offset the write started from is stored here. + * + * Note: If the write exactly fills the last cluster, ptr will be left as CLUSTER_SIZE. + */ + void write_data(uint32_t& cluster, uint32_t& ptr, const void* data, uint32_t length, + uint32_t& real_cluster, uint32_t& real_ptr); +/** + * A reference-counted refernece to a filesystem. + */ + class ref + { + public: +/** + * Create a reference to NULL filesystem. + */ + ref() + { + refcnt = NULL; + mutex = NULL; + fs = NULL; + } +/** + * Create/Open a new filesystem and take reference to that. + * + * Parameters backingfile: The backing file. + */ + ref(const std::string& backingfile) + { + refcnt = NULL; + mutex = NULL; + try { + refcnt = new unsigned; + mutex = new mutex_class; + fs = new filesystem(backingfile); + } catch(...) { + delete refcnt; + delete mutex; + throw; + } + *refcnt = 1; + } +/** + * Destructor. + */ + ~ref() + { + mutex_class* mtodelete = NULL; + if(!mutex) + return; + { + umutex_class m(*mutex); + --*refcnt; + if(!*refcnt) { + delete fs; + delete refcnt; + mtodelete = mutex; + } + } + if(mtodelete) + delete mtodelete; + } +/** + * Copy constructor. + */ + ref(const ref& r) + { + umutex_class m(*r.mutex); + ++*(r.refcnt); + refcnt = r.refcnt; + mutex = r.mutex; + fs = r.fs; + } +/** + * Assignment operator. + */ + ref& operator=(const ref& r); +/** + * Call allocate_cluster() on underlying filesystem. + * + * Note: See filesystem::allocate_cluster() for description. + */ + uint32_t allocate_cluster() + { + umutex_class m(*mutex); + return fs->allocate_cluster(); + } +/** + * Call free_cluster_chain() on underlying filesystem. + * + * Note: See filesystem::free_cluster_chain() for description. + */ + void free_cluster_chain(uint32_t cluster) + { + umutex_class m(*mutex); + fs->free_cluster_chain(cluster); + } +/** + * Call skip_data() on underlying filesystem. + * + * Note: See filesystem::skip_data() for description. + */ + size_t skip_data(uint32_t& cluster, uint32_t& ptr, uint32_t length) + { + umutex_class m(*mutex); + return fs->skip_data(cluster, ptr, length); + } +/** + * Call read_data() on underlying filesystem. + * + * Note: See filesystem::read_data() for description. + */ + size_t read_data(uint32_t& cluster, uint32_t& ptr, void* data, uint32_t length) + { + umutex_class m(*mutex); + return fs->read_data(cluster, ptr, data, length); + } +/** + * Call write_data() on underlying filesystem. + * + * Note: See filesystem::write_data() for description. + */ + void write_data(uint32_t& cluster, uint32_t& ptr, const void* data, uint32_t length, + uint32_t& real_cluster, uint32_t& real_ptr) + { + umutex_class m(*mutex); + fs->write_data(cluster, ptr, data, length, real_cluster, real_ptr); + } + private: + filesystem* fs; + unsigned* refcnt; + mutex_class* mutex; + }; +private: + filesystem(const filesystem&); + filesystem& operator=(const filesystem&); + void link_cluster(uint32_t cluster, uint32_t linkto); + struct supercluster + { + unsigned free_clusters; + uint32_t clusters[CLUSTERS_PER_SUPER]; + void load(std::fstream& s, uint32_t index); + void save(std::fstream& s, uint32_t index); + }; + uint32_t supercluster_count; + std::map superclusters; + std::fstream backing; +}; + + +#endif diff --git a/src/core/inthread.cpp b/src/core/inthread.cpp index 0d190cda..5c03be56 100644 --- a/src/core/inthread.cpp +++ b/src/core/inthread.cpp @@ -1,6 +1,6 @@ #include #include -#include "library/filesys.hpp" +#include "library/filesystem.hpp" #include "library/minmax.hpp" #include "library/workthread.hpp" #include "library/serialization.hpp" @@ -192,12 +192,12 @@ namespace uint64_t offset() { return descriptor & 0xFFFFFFFFFFULL; } //Read the packet. //Can throw. - std::vector packet(filesystem_ref from_sys); + std::vector packet(filesystem::ref from_sys); private: uint64_t descriptor; }; - std::vector opus_packetinfo::packet(filesystem_ref from_sys) + std::vector opus_packetinfo::packet(filesystem::ref from_sys) { std::vector ret; uint64_t off = offset(); @@ -216,13 +216,13 @@ namespace struct opus_stream { //Create new empty stream with specified base time. - opus_stream(uint64_t base, filesystem_ref filesys); + opus_stream(uint64_t base, filesystem::ref filesys); //Read stream with specified base time and specified start clusters. //Can throw. - opus_stream(uint64_t base, filesystem_ref filesys, uint32_t ctrl_cluster, uint32_t data_cluster); + opus_stream(uint64_t base, filesystem::ref filesys, uint32_t ctrl_cluster, uint32_t data_cluster); //Import a stream with specified base time. //Can throw. - opus_stream(uint64_t base, filesystem_ref filesys, std::ifstream& data, + opus_stream(uint64_t base, filesystem::ref filesys, std::ifstream& data, external_stream_format extfmt); //Delete this stream (also puts a ref) void delete_stream() { deleting = true; put_ref(); } @@ -295,7 +295,7 @@ namespace opus_stream(const opus_stream&); opus_stream& operator=(const opus_stream&); void destroy(); - filesystem_ref fs; + filesystem::ref fs; std::vector packets; uint64_t total_len; uint64_t s_timebase; @@ -314,7 +314,7 @@ namespace bool deleting; }; - opus_stream::opus_stream(uint64_t base, filesystem_ref filesys) + opus_stream::opus_stream(uint64_t base, filesystem::ref filesys) : fs(filesys) { refcount = 1; @@ -333,7 +333,7 @@ namespace gain = 0; } - opus_stream::opus_stream(uint64_t base, filesystem_ref filesys, uint32_t _ctrl_cluster, + opus_stream::opus_stream(uint64_t base, filesystem::ref filesys, uint32_t _ctrl_cluster, uint32_t _data_cluster) : fs(filesys) { @@ -415,7 +415,7 @@ out_parsing: } } - opus_stream::opus_stream(uint64_t base, filesystem_ref filesys, std::ifstream& data, + opus_stream::opus_stream(uint64_t base, filesystem::ref filesys, std::ifstream& data, external_stream_format extfmt) : fs(filesys) { @@ -955,7 +955,7 @@ out: public: //Create a new collection. //Can throw. - stream_collection(filesystem_ref filesys); + stream_collection(filesystem::ref filesys); //Destroy a collection. All streams are destroyed but not deleted. ~stream_collection(); //Get list of streams active at given point. @@ -964,7 +964,7 @@ out: //Can throw. uint64_t add_stream(opus_stream& stream); //Get the filesystem this collection is for. - filesystem_ref get_filesystem() { return fs; } + filesystem::ref get_filesystem() { return fs; } //Unlock all streams in collection. void unlock_all(); //Get stream with given index (NULL if not found). @@ -991,7 +991,7 @@ out: //Can throw. void export_superstream(std::ofstream& out); private: - filesystem_ref fs; + filesystem::ref fs; uint64_t next_index; unsigned next_stream; mutex_class mutex; @@ -1002,7 +1002,7 @@ out: std::map streams; }; - stream_collection::stream_collection(filesystem_ref filesys) + stream_collection::stream_collection(filesystem::ref filesys) : fs(filesys) { next_stream = 0; @@ -1825,9 +1825,9 @@ void voicesub_export_superstream(const std::string& filename) void voicesub_load_collection(const std::string& filename) { umutex_class m2(current_collection_lock); - filesystem_ref newfs; + filesystem::ref newfs; stream_collection* newc; - newfs = filesystem_ref(filename); + newfs = filesystem::ref(filename); newc = new stream_collection(newfs); if(current_collection) delete current_collection; diff --git a/src/library/filesys.cpp b/src/library/filesystem.cpp similarity index 90% rename from src/library/filesys.cpp rename to src/library/filesystem.cpp index cb6663c4..09e4568b 100644 --- a/src/library/filesys.cpp +++ b/src/library/filesystem.cpp @@ -1,4 +1,4 @@ -#include "filesys.hpp" +#include "filesystem.hpp" #include "minmax.hpp" #include "serialization.hpp" #include @@ -283,3 +283,52 @@ void filesystem::supercluster::save(std::fstream& s, uint32_t index) if(!s) throw std::runtime_error("Can't write cluster table"); } + +filesystem::ref& filesystem::ref::operator=(const filesystem::ref& r) +{ + if(this == &r) + return *this; + //This is tricky, due to having to lock two objects. + size_t A = (size_t)this; + size_t B = (size_t)&r; + mutex_class* mtodelete = NULL; + if(!refcnt) { + //We just have to grab a ref and copy. + umutex_class m(*r.mutex); + ++*(r.refcnt); + refcnt = r.refcnt; + mutex = r.mutex; + fs = r.fs; + } else if(A < B) { + //Two-object case. + umutex_class m1(*mutex); + umutex_class m2(*r.mutex); + --*refcnt; + if(!*refcnt) { + delete fs; + delete refcnt; + mtodelete = mutex;; + } + ++*(r.refcnt); + refcnt = r.refcnt; + mutex = r.mutex; + fs = r.fs; + } else { + //Two-object case. + umutex_class m1(*r.mutex); + umutex_class m2(*mutex); + --*refcnt; + if(!*refcnt) { + delete fs; + delete refcnt; + mtodelete = mutex;; + } + ++*(r.refcnt); + refcnt = r.refcnt; + mutex = r.mutex; + fs = r.fs; + } + if(mtodelete) + delete mtodelete; + return *this; +} diff --git a/src/util/fattest.cpp b/src/util/fattest.cpp index 85daf331..da57051c 100644 --- a/src/util/fattest.cpp +++ b/src/util/fattest.cpp @@ -1,4 +1,4 @@ -#include "library/filesys.hpp" +#include "library/filesystem.hpp" #include #include #include diff --git a/src/util/lsvsdump.cpp b/src/util/lsvsdump.cpp index f1396f42..0de78dc8 100644 --- a/src/util/lsvsdump.cpp +++ b/src/util/lsvsdump.cpp @@ -1,4 +1,4 @@ -#include "library/filesys.hpp" +#include "library/filesystem.hpp" #include "library/serialization.hpp" #include "library/string.hpp" #include -- 2.11.4.GIT