From 922494caa69d7a8d7270b4dc1c22d8563240761f Mon Sep 17 00:00:00 2001 From: ksherlock Date: Fri, 11 Dec 2009 00:59:53 +0000 Subject: [PATCH] git-svn-id: https://profuse.googlecode.com/svn/branches/v2@139 aa027e90-d47c-11dd-86d7-074df07e0730 --- BlockCache.cpp | 105 +++++++++++++++++++++++++++++++++++++++++------- BlockCache.h | 62 ++++++++++++++++++++++------ BlockDevice.cpp | 30 +++++++++++++- BlockDevice.h | 13 +++++- Exception.h | 2 +- MappedFile.cpp | 2 + MappedFile.h | 5 ++- pascal/File.cpp | 33 ++++++++------- 8 files changed, 204 insertions(+), 48 deletions(-) diff --git a/BlockCache.cpp b/BlockCache.cpp index b0d4c74..f2a955a 100644 --- a/BlockCache.cpp +++ b/BlockCache.cpp @@ -1,9 +1,15 @@ -#include "BlockCache.h" -#include "BlockDevice.h" -#include "auto.h" #include +#include +#include +#include + + +#include "BlockDevice.h" +#include "BlockCache.h" +#include "Exception.h" +#include "auto.h" /* @@ -15,15 +21,64 @@ using namespace ProFUSE; -typedef std::vector::iterator BDIter; +#pragma mark - +#pragma mark AbstractBlockCache -const unsigned CacheSize = 16; +AbstractBlockCache::~AbstractBlockCache() +{ +} -BlockCache::BlockCache(BlockDevice *device) +#pragma mark - +#pragma mark MappedBlockCache + +MappedBlockCache::MappedBlockCache(void *data, unsigned blocks) +{ + _blocks = blocks; + _data = (uint8_t *)_data; +} + +void MappedBlockCache::write() +{ + // TODO... +} + +void *MappedBlockCache::load(unsigned block) +{ +#undef __METHOD__ +#define __METHOD__ "MappedBlockCache::load" + + if (block >= _blocks) + throw Exception(__METHOD__ ": Invalid block."); + + + return _data + block * 512; +} +void MappedBlockCache::unload(unsigned block, bool dirty) +{ +#undef __METHOD__ +#define __METHOD__ "MappedBlockCache::unload" + + if (!dirty) return; + if (::msync(_data + block * 512, 512, MS_ASYNC) < 0) + { + throw POSIXException(__METHOD__ ": msync failed.", errno); + } +} + + +#pragma mark - +#pragma mark BlockCache + +typedef std::vector::iterator BDIter; + + + +BlockCache::BlockCache(BlockDevice *device, unsigned size) { _device = device; _ts = 0; - _blocks.reserve(CacheSize); + _cacheSize = std::max(16u, size); + _blocks.reserve(_cacheSize); } BlockCache::~BlockCache() @@ -34,8 +89,21 @@ BlockCache::~BlockCache() } } +void BlockCache::write() +{ + for (BDIter iter = _blocks.begin(); iter != _blocks.end(); ++iter) + { + if (iter->dirty) + { + _device->write(iter->block, iter->data); + iter->dirty = false; + } + } +} -void *BlockCache::acquire(unsigned block) + + +void *BlockCache::load(unsigned block) { unsigned mints = -1; unsigned freeCount = 0; @@ -57,6 +125,7 @@ void *BlockCache::acquire(unsigned block) { ++iter->count; iter->ts = _ts; + return iter->data; } @@ -72,11 +141,14 @@ void *BlockCache::acquire(unsigned block) } - if (freeCount && (_blocks.size() >= CacheSize)) + if (freeCount && (_blocks.size() >= _cacheSize)) { + // re-use old buffer. + oldest->block = block; oldest->count = 1; oldest->ts = _ts; + oldest->dirty = false; _device->read(block, oldest->data); return oldest->data; @@ -84,7 +156,7 @@ void *BlockCache::acquire(unsigned block) auto_array buffer(new uint8_t[512]); - BlockDescriptor bd = { block, 1, _ts, buffer.get() }; + BlockDescriptor bd = { block, 1, _ts, false, buffer.get() }; _device->read(block, buffer.get()); @@ -95,20 +167,23 @@ void *BlockCache::acquire(unsigned block) } -void BlockCache::release(unsigned block) +void BlockCache::unload(unsigned block, bool dirty) { for (BDIter iter = _blocks.begin(); iter != _blocks.end(); ++iter) { if (iter->block == block) { + iter->dirty = dirty || iter->dirty; if (!--iter->count) { - _device->write(block, iter->data); - + if (iter->dirty) + { + _device->write(block, iter->data); + iter->dirty = false; + } // trim back if too many entries. - - if (_blocks.size() > CacheSize) + if (_blocks.size() > _cacheSize) { delete[] iter->data; _blocks.erase(iter); diff --git a/BlockCache.h b/BlockCache.h index 4e65719..4126c4f 100644 --- a/BlockCache.h +++ b/BlockCache.h @@ -8,30 +8,66 @@ namespace ProFUSE { class BlockDevice; -struct BlockDescriptor { - unsigned block; - unsigned count; - unsigned ts; - uint8_t *data; + + +class AbstractBlockCache { +public: + virtual ~AbstractBlockCache(); + + virtual void write() = 0; + + virtual void *load(unsigned block); + virtual void unload(unsigned block, bool dirty); + + void unload(unsigned block) { unload(block, false); } }; - -class BlockCache { - BlockCache(BlockDevice *device); +class BlockCache : public AbstractBlockCache { +public: + BlockCache(BlockDevice *device, unsigned size = 16); ~BlockCache(); - void write(); - - void *acquire(unsigned block); - void release(unsigned block); + virtual void write(); + virtual void *load(unsigned block); + virtual void unload(unsigned block, bool dirty); + + private: + + struct BlockDescriptor { + unsigned block; + unsigned count; + unsigned ts; + bool dirty; + uint8_t *data; + }; + + + std::vector _blocks; BlockDevice *_device; unsigned _ts; + unsigned _cacheSize; + }; -} +class MappedBlockCache : public AbstractBlockCache { + public: + + MappedBlockCache(void *data, unsigned blocks); + + virtual void write(); + + virtual void *load(unsigned block); + virtual void unload(unsigned block, bool dirty); + + private: + unsigned _blocks; + uint8_t * _data; +}; + +} // namespace #endif \ No newline at end of file diff --git a/BlockDevice.cpp b/BlockDevice.cpp index 3463965..d58c39d 100644 --- a/BlockDevice.cpp +++ b/BlockDevice.cpp @@ -1,4 +1,5 @@ #include "BlockDevice.h" +#include "BlockCache.h" #include "Exception.h" #include "MappedFile.h" @@ -12,10 +13,12 @@ using namespace ProFUSE; - +#pragma mark - +#pragma mark BlockDevice BlockDevice::~BlockDevice() { + delete _cache; } void BlockDevice::zeroBlock(unsigned block) @@ -26,7 +29,23 @@ void BlockDevice::zeroBlock(unsigned block) write(block, bp); } +AbstractBlockCache *BlockDevice::blockCache() +{ + if (!_cache) + { + _cache = createBlockCache(); + } + return _cache; +} +AbstractBlockCache *BlockDevice::createBlockCache() +{ + return new BlockCache(this); +} + + + +#pragma mark - #pragma mark DiskImage DiskImage::DiskImage(const char *name, bool readOnly) : @@ -100,6 +119,15 @@ void DiskImage::sync() +AbstractBlockCache *DiskImage::createBlockCache() +{ + if (_file->encoding() == MappedFile::ProDOSOrder) + return new MappedBlockCache(_file->imageData(), _file->blocks()); + + return BlockDevice::createBlockCache(); +} + + ProDOSOrderDiskImage::ProDOSOrderDiskImage(const char *name, bool readOnly) : DiskImage(name, readOnly) { diff --git a/BlockDevice.h b/BlockDevice.h index 8b8d23e..9712f4c 100644 --- a/BlockDevice.h +++ b/BlockDevice.h @@ -9,6 +9,7 @@ namespace ProFUSE { class MappedFile; +class AbstractBlockCache; class BlockDevice { public: @@ -23,6 +24,14 @@ public: virtual unsigned blocks() = 0; void zeroBlock(unsigned block); + + AbstractBlockCache *blockCache(); + +protected: + virtual AbstractBlockCache *createBlockCache(); + +private: + AbstractBlockCache *_cache; }; @@ -41,7 +50,9 @@ public: protected: - DiskImage(MappedFile * = NULL); + virtual AbstractBlockCache *createBlockCache(); + + DiskImage(MappedFile * = 0); DiskImage(const char *name, bool readOnly); MappedFile *file() { return _file; } diff --git a/Exception.h b/Exception.h index cd23c37..a163ec9 100644 --- a/Exception.h +++ b/Exception.h @@ -1,8 +1,8 @@ #ifndef __EXCEPTION_H__ #define __EXCEPTION_H__ -#include #include +#include namespace ProFUSE { diff --git a/MappedFile.cpp b/MappedFile.cpp index 7b078b3..00042d3 100644 --- a/MappedFile.cpp +++ b/MappedFile.cpp @@ -1,5 +1,6 @@ #include "MappedFile.h" #include "Exception.h" + #include #include #include @@ -238,3 +239,4 @@ void MappedFile::reset() } + diff --git a/MappedFile.h b/MappedFile.h index c174391..ce2c768 100644 --- a/MappedFile.h +++ b/MappedFile.h @@ -8,7 +8,6 @@ namespace ProFUSE { - class MappedFile { public: @@ -44,10 +43,12 @@ public: bool readOnly() const { return _readOnly; } size_t fileSize() const { return _size; } void *fileData() const { return _map; } - + void *imageData() const { return _offset + (uint8_t *)_map; } private: + + MappedFile& operator=(const MappedFile& other); void init(int fd, bool readOnly); diff --git a/pascal/File.cpp b/pascal/File.cpp index 7e99fb2..2278aa1 100644 --- a/pascal/File.cpp +++ b/pascal/File.cpp @@ -3,8 +3,9 @@ #include "../Endian.h" #include "../BlockDevice.h" +#include #include -#include +#include using namespace LittleEndian; using namespace Pascal; @@ -156,6 +157,9 @@ FileEntry::FileEntry(void *vp) : std::memcpy(_fileName, 0x07 + (uint8_t *)vp, _fileNameLength); _lastByte = Read16(vp, 0x16); _modification = DateRec(Read16(vp, 0x18)); + + _fileSize = 0; + _pageLength = NULL; } FileEntry::~FileEntry() @@ -180,6 +184,11 @@ unsigned FileEntry::fileSize() int FileEntry::read(uint8_t *buffer, unsigned size, unsigned offset) { + unsigned fsize = fileSize(); + + if (offset + size > fsize) size = fsize - offset; + if (offset >= fsize) return 0; + switch(fileKind()) { case kTextFile: @@ -199,7 +208,7 @@ unsigned FileEntry::dataFileSize() unsigned FileEntry::textFileSize() { - if (!_pageLength()) textInit(); + if (!_pageLength) textInit(); return _fileSize; } @@ -213,14 +222,9 @@ int FileEntry::dataRead(uint8_t *buffer, unsigned size, unsigned offset) { uint8_t tmp[512]; - unsigned fileSize = fileSize(); unsigned count = 0; unsigned block = 0; - - if (offset >= fileSize) return 0; - - if (offset + size > fileSize) size = fileSize - offset; - + block = _startBlock + (offset / 512); // returned value (count) is equal to size at this point. @@ -274,7 +278,7 @@ int FileEntry::dataRead(uint8_t *buffer, unsigned size, unsigned offset) -int TextFile::read(uint8_t *buffer, unsigned size, unsigned offset) +int FileEntry::textRead(uint8_t *buffer, unsigned size, unsigned offset) { unsigned page = 0; unsigned to = 0; @@ -285,9 +289,8 @@ int TextFile::read(uint8_t *buffer, unsigned size, unsigned offset) auto_array tmp; unsigned tmpSize = 0; - if (offset >= _fileSize) return 0; - if (offset + size > _fileSize) size = _fileSize - offset; - + if (!_pageLength) textInit(); + // find the first page. for (page = 1; page < l; ++page) @@ -341,7 +344,7 @@ int TextFile::read(uint8_t *buffer, unsigned size, unsigned offset) -unsigned TextFile::decodePage(unsigned block, uint8_t *out) +unsigned FileEntry::textDecodePage(unsigned block, uint8_t *out) { uint8_t buffer[1024]; unsigned size = 0; @@ -371,7 +374,7 @@ unsigned TextFile::decodePage(unsigned block, uint8_t *out) return size; } -unsigned TextFile::readPage(unsigned block, uint8_t *in) +unsigned FileEntry::textReadPage(unsigned block, uint8_t *in) { // reads up to 2 blocks. // assumes block within _startBlock ... _endBlock - 1 @@ -394,7 +397,7 @@ unsigned TextFile::readPage(unsigned block, uint8_t *in) -void TextFile::init() +void FileEntry::textInit() { // calculate the file size and page offsets.