From 9fc279ef643a093c2cbe4c5b5f57944f30fed833 Mon Sep 17 00:00:00 2001 From: ksherlock Date: Tue, 8 Dec 2009 00:01:24 +0000 Subject: [PATCH] git-svn-id: https://profuse.googlecode.com/svn/branches/v2@127 aa027e90-d47c-11dd-86d7-074df07e0730 --- BlockCache.cpp | 120 ++++++++++++++++++++++++++++++++++++++++++++ BlockCache.h | 37 ++++++++++++++ VolumeDirectory.cpp | 1 + 3 files changed, 158 insertions(+) create mode 100644 BlockCache.cpp create mode 100644 BlockCache.h diff --git a/BlockCache.cpp b/BlockCache.cpp new file mode 100644 index 0000000..b0d4c74 --- /dev/null +++ b/BlockCache.cpp @@ -0,0 +1,120 @@ +#include "BlockCache.h" +#include "BlockDevice.h" +#include "auto.h" + +#include + + + +/* + * Note -- everything is assumed to be single-threaded. + * + */ + + + +using namespace ProFUSE; + +typedef std::vector::iterator BDIter; + +const unsigned CacheSize = 16; + +BlockCache::BlockCache(BlockDevice *device) +{ + _device = device; + _ts = 0; + _blocks.reserve(CacheSize); +} + +BlockCache::~BlockCache() +{ + for (BDIter iter = _blocks.begin(); iter != _blocks.end(); ++iter) + { + if (iter->data) delete[] iter->data; + } +} + + +void *BlockCache::acquire(unsigned block) +{ + unsigned mints = -1; + unsigned freeCount = 0; + + BDIter oldest; + + + ++_ts; + + /* + * keep a pointer to the oldest free entry (according to ts). + * and re-use if >= 16 entries. + */ + + + for (BDIter iter = _blocks.begin(); iter != _blocks.end(); ++iter) + { + if (iter->block == block) + { + ++iter->count; + iter->ts = _ts; + return iter->data; + } + + if (iter->count == 0) + { + ++freeCount; + if (iter->ts < mints) + { + mints = iter->ts; + oldest = iter; + } + } + } + + + if (freeCount && (_blocks.size() >= CacheSize)) + { + oldest->block = block; + oldest->count = 1; + oldest->ts = _ts; + + _device->read(block, oldest->data); + return oldest->data; + } + + + auto_array buffer(new uint8_t[512]); + BlockDescriptor bd = { block, 1, _ts, buffer.get() }; + + _device->read(block, buffer.get()); + + _blocks.push_back(bd); + + + return buffer.release(); +} + + +void BlockCache::release(unsigned block) +{ + + for (BDIter iter = _blocks.begin(); iter != _blocks.end(); ++iter) + { + if (iter->block == block) + { + if (!--iter->count) + { + _device->write(block, iter->data); + + // trim back if too many entries. + + if (_blocks.size() > CacheSize) + { + delete[] iter->data; + _blocks.erase(iter); + } + } + return; + } + } +} \ No newline at end of file diff --git a/BlockCache.h b/BlockCache.h new file mode 100644 index 0000000..4e65719 --- /dev/null +++ b/BlockCache.h @@ -0,0 +1,37 @@ +#ifndef __BLOCKCACHE_H__ +#define __BLOCKCACHE_H__ + +#include +#include + +namespace ProFUSE { + +class BlockDevice; + +struct BlockDescriptor { + unsigned block; + unsigned count; + unsigned ts; + uint8_t *data; +}; + + + +class BlockCache { + BlockCache(BlockDevice *device); + ~BlockCache(); + + void write(); + + void *acquire(unsigned block); + void release(unsigned block); + +private: + std::vector _blocks; + BlockDevice *_device; + unsigned _ts; +}; + +} + +#endif \ No newline at end of file diff --git a/VolumeDirectory.cpp b/VolumeDirectory.cpp index dd67bdb..fe1e94e 100644 --- a/VolumeDirectory.cpp +++ b/VolumeDirectory.cpp @@ -16,6 +16,7 @@ using namespace LittleEndian; #pragma mark VolumeDirectory + VolumeDirectory *VolumeDirectory::Create(const char *name, BlockDevice *device) { return new VolumeDirectory(name, device);