git-svn-id: https://profuse.googlecode.com/svn/branches/v2@139 aa027e90-d47c-11dd-86d7-074df07e0730

This commit is contained in:
ksherlock 2009-12-11 00:59:53 +00:00
parent f469d4e4d4
commit 922494caa6
8 changed files with 204 additions and 48 deletions

View File

@ -1,9 +1,15 @@
#include "BlockCache.h"
#include "BlockDevice.h"
#include "auto.h"
#include <algorithm> #include <algorithm>
#include <cerrno>
#include <sys/types.h>
#include <sys/mman.h>
#include "BlockDevice.h"
#include "BlockCache.h"
#include "Exception.h"
#include "auto.h"
/* /*
@ -15,15 +21,64 @@
using namespace ProFUSE; using namespace ProFUSE;
typedef std::vector<BlockDescriptor>::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<BlockCache::BlockDescriptor>::iterator BDIter;
BlockCache::BlockCache(BlockDevice *device, unsigned size)
{ {
_device = device; _device = device;
_ts = 0; _ts = 0;
_blocks.reserve(CacheSize); _cacheSize = std::max(16u, size);
_blocks.reserve(_cacheSize);
} }
BlockCache::~BlockCache() 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 mints = -1;
unsigned freeCount = 0; unsigned freeCount = 0;
@ -57,6 +125,7 @@ void *BlockCache::acquire(unsigned block)
{ {
++iter->count; ++iter->count;
iter->ts = _ts; iter->ts = _ts;
return iter->data; 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->block = block;
oldest->count = 1; oldest->count = 1;
oldest->ts = _ts; oldest->ts = _ts;
oldest->dirty = false;
_device->read(block, oldest->data); _device->read(block, oldest->data);
return oldest->data; return oldest->data;
@ -84,7 +156,7 @@ void *BlockCache::acquire(unsigned block)
auto_array<uint8_t> buffer(new uint8_t[512]); auto_array<uint8_t> 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()); _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) for (BDIter iter = _blocks.begin(); iter != _blocks.end(); ++iter)
{ {
if (iter->block == block) if (iter->block == block)
{ {
iter->dirty = dirty || iter->dirty;
if (!--iter->count) 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. // trim back if too many entries.
if (_blocks.size() > _cacheSize)
if (_blocks.size() > CacheSize)
{ {
delete[] iter->data; delete[] iter->data;
_blocks.erase(iter); _blocks.erase(iter);

View File

@ -8,30 +8,66 @@ namespace ProFUSE {
class BlockDevice; class BlockDevice;
struct BlockDescriptor {
unsigned block;
unsigned count; class AbstractBlockCache {
unsigned ts; public:
uint8_t *data; 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 : public AbstractBlockCache {
class BlockCache { public:
BlockCache(BlockDevice *device); BlockCache(BlockDevice *device, unsigned size = 16);
~BlockCache(); ~BlockCache();
void write(); virtual void write();
void *acquire(unsigned block);
void release(unsigned block);
virtual void *load(unsigned block);
virtual void unload(unsigned block, bool dirty);
private: private:
struct BlockDescriptor {
unsigned block;
unsigned count;
unsigned ts;
bool dirty;
uint8_t *data;
};
std::vector<BlockDescriptor> _blocks; std::vector<BlockDescriptor> _blocks;
BlockDevice *_device; BlockDevice *_device;
unsigned _ts; 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 #endif

View File

@ -1,4 +1,5 @@
#include "BlockDevice.h" #include "BlockDevice.h"
#include "BlockCache.h"
#include "Exception.h" #include "Exception.h"
#include "MappedFile.h" #include "MappedFile.h"
@ -12,10 +13,12 @@
using namespace ProFUSE; using namespace ProFUSE;
#pragma mark -
#pragma mark BlockDevice
BlockDevice::~BlockDevice() BlockDevice::~BlockDevice()
{ {
delete _cache;
} }
void BlockDevice::zeroBlock(unsigned block) void BlockDevice::zeroBlock(unsigned block)
@ -26,7 +29,23 @@ void BlockDevice::zeroBlock(unsigned block)
write(block, bp); write(block, bp);
} }
AbstractBlockCache *BlockDevice::blockCache()
{
if (!_cache)
{
_cache = createBlockCache();
}
return _cache;
}
AbstractBlockCache *BlockDevice::createBlockCache()
{
return new BlockCache(this);
}
#pragma mark -
#pragma mark DiskImage #pragma mark DiskImage
DiskImage::DiskImage(const char *name, bool readOnly) : 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) : ProDOSOrderDiskImage::ProDOSOrderDiskImage(const char *name, bool readOnly) :
DiskImage(name, readOnly) DiskImage(name, readOnly)
{ {

View File

@ -9,6 +9,7 @@
namespace ProFUSE { namespace ProFUSE {
class MappedFile; class MappedFile;
class AbstractBlockCache;
class BlockDevice { class BlockDevice {
public: public:
@ -23,6 +24,14 @@ public:
virtual unsigned blocks() = 0; virtual unsigned blocks() = 0;
void zeroBlock(unsigned block); void zeroBlock(unsigned block);
AbstractBlockCache *blockCache();
protected:
virtual AbstractBlockCache *createBlockCache();
private:
AbstractBlockCache *_cache;
}; };
@ -41,7 +50,9 @@ public:
protected: protected:
DiskImage(MappedFile * = NULL); virtual AbstractBlockCache *createBlockCache();
DiskImage(MappedFile * = 0);
DiskImage(const char *name, bool readOnly); DiskImage(const char *name, bool readOnly);
MappedFile *file() { return _file; } MappedFile *file() { return _file; }

View File

@ -1,8 +1,8 @@
#ifndef __EXCEPTION_H__ #ifndef __EXCEPTION_H__
#define __EXCEPTION_H__ #define __EXCEPTION_H__
#include <exception>
#include <string> #include <string>
#include <exception>
namespace ProFUSE { namespace ProFUSE {

View File

@ -1,5 +1,6 @@
#include "MappedFile.h" #include "MappedFile.h"
#include "Exception.h" #include "Exception.h"
#include <cerrno> #include <cerrno>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
@ -238,3 +239,4 @@ void MappedFile::reset()
} }

View File

@ -8,7 +8,6 @@
namespace ProFUSE { namespace ProFUSE {
class MappedFile { class MappedFile {
public: public:
@ -44,10 +43,12 @@ public:
bool readOnly() const { return _readOnly; } bool readOnly() const { return _readOnly; }
size_t fileSize() const { return _size; } size_t fileSize() const { return _size; }
void *fileData() const { return _map; } void *fileData() const { return _map; }
void *imageData() const { return _offset + (uint8_t *)_map; }
private: private:
MappedFile& operator=(const MappedFile& other); MappedFile& operator=(const MappedFile& other);
void init(int fd, bool readOnly); void init(int fd, bool readOnly);

View File

@ -3,8 +3,9 @@
#include "../Endian.h" #include "../Endian.h"
#include "../BlockDevice.h" #include "../BlockDevice.h"
#include <algorithm>
#include <cstring> #include <cstring>
#include <memory.h> #include <memory>
using namespace LittleEndian; using namespace LittleEndian;
using namespace Pascal; using namespace Pascal;
@ -156,6 +157,9 @@ FileEntry::FileEntry(void *vp) :
std::memcpy(_fileName, 0x07 + (uint8_t *)vp, _fileNameLength); std::memcpy(_fileName, 0x07 + (uint8_t *)vp, _fileNameLength);
_lastByte = Read16(vp, 0x16); _lastByte = Read16(vp, 0x16);
_modification = DateRec(Read16(vp, 0x18)); _modification = DateRec(Read16(vp, 0x18));
_fileSize = 0;
_pageLength = NULL;
} }
FileEntry::~FileEntry() FileEntry::~FileEntry()
@ -180,6 +184,11 @@ unsigned FileEntry::fileSize()
int FileEntry::read(uint8_t *buffer, unsigned size, unsigned offset) 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()) switch(fileKind())
{ {
case kTextFile: case kTextFile:
@ -199,7 +208,7 @@ unsigned FileEntry::dataFileSize()
unsigned FileEntry::textFileSize() unsigned FileEntry::textFileSize()
{ {
if (!_pageLength()) textInit(); if (!_pageLength) textInit();
return _fileSize; return _fileSize;
} }
@ -213,14 +222,9 @@ int FileEntry::dataRead(uint8_t *buffer, unsigned size, unsigned offset)
{ {
uint8_t tmp[512]; uint8_t tmp[512];
unsigned fileSize = fileSize();
unsigned count = 0; unsigned count = 0;
unsigned block = 0; unsigned block = 0;
if (offset >= fileSize) return 0;
if (offset + size > fileSize) size = fileSize - offset;
block = _startBlock + (offset / 512); block = _startBlock + (offset / 512);
// returned value (count) is equal to size at this point. // 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 page = 0;
unsigned to = 0; unsigned to = 0;
@ -285,9 +289,8 @@ int TextFile::read(uint8_t *buffer, unsigned size, unsigned offset)
auto_array<uint8_t> tmp; auto_array<uint8_t> tmp;
unsigned tmpSize = 0; unsigned tmpSize = 0;
if (offset >= _fileSize) return 0; if (!_pageLength) textInit();
if (offset + size > _fileSize) size = _fileSize - offset;
// find the first page. // find the first page.
for (page = 1; page < l; ++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]; uint8_t buffer[1024];
unsigned size = 0; unsigned size = 0;
@ -371,7 +374,7 @@ unsigned TextFile::decodePage(unsigned block, uint8_t *out)
return size; return size;
} }
unsigned TextFile::readPage(unsigned block, uint8_t *in) unsigned FileEntry::textReadPage(unsigned block, uint8_t *in)
{ {
// reads up to 2 blocks. // reads up to 2 blocks.
// assumes block within _startBlock ... _endBlock - 1 // 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. // calculate the file size and page offsets.