mirror of
https://github.com/ksherlock/profuse.git
synced 2025-01-05 05:29:37 +00:00
git-svn-id: https://profuse.googlecode.com/svn/branches/v2@139 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
parent
f469d4e4d4
commit
922494caa6
105
BlockCache.cpp
105
BlockCache.cpp
@ -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);
|
||||||
|
60
BlockCache.h
60
BlockCache.h
@ -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();
|
||||||
|
|
||||||
|
virtual void *load(unsigned block);
|
||||||
|
virtual void unload(unsigned block, bool dirty);
|
||||||
|
|
||||||
void *acquire(unsigned block);
|
|
||||||
void release(unsigned block);
|
|
||||||
|
|
||||||
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
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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; }
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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,8 +289,7 @@ 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.
|
||||||
@ -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.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user