Improve block cache

git-svn-id: https://profuse.googlecode.com/svn/branches/v2@199 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
ksherlock 2010-03-13 19:24:00 +00:00
parent a750f2ff5f
commit 2754cdd24a
2 changed files with 88 additions and 20 deletions

View File

@ -18,6 +18,34 @@
* *
*/ */
/*
* The primary purpose of the block cache is not as a cache
* (the OS probably does a decent job of that) but rather to
* simplify read/writes. Blocks will always be accessed by
* pointer, so any updates will be shared.
* For memory mapped prodos-order files, MappedBlockCache just
* returns a pointer to the memory.
* For dos-order, nibblized, or raw devices, ConcreteBlockCache
* uses an approach similar to minix (although the buffer pool will
* expand if needed).
*
* _buffers is a vector of all buffers and only exists to make
* freeing them easier.
* _hashTable is a simple hashtable of loaded blocks.
* _first and _last are a double-linked list of unused blocks, stored
* in lru order.
*
* The Entry struct contains the buffer, the block, a dirty flag, and an in-use
* count as well as pointer for the hashtable and lru list.
* When a block is loaded, it is stored in the _hashTable. It remains in the
* hash table when the in-use count goes to 0 (it will also be added to the
* end of the lru list).
*
* dirty buffers are only written to disk in 3 scenarios:
* a) sync() is called
* b) the cache is deleted
* c) a buffer is re-used from the lru list.
*/
using namespace Device; using namespace Device;
@ -40,6 +68,20 @@ BlockCache::~BlockCache()
delete _device; delete _device;
} }
void BlockCache::write(unsigned block, const void *bp)
{
void *address = acquire(block);
std::memcpy(address, bp, 512);
release(block, true);
}
void BlockCache::read(unsigned block, void *bp)
{
void *address = acquire(block);
std::memcpy(bp, address, 512);
release(block, false);
}
#pragma mark - #pragma mark -
#pragma mark MappedBlockCache #pragma mark MappedBlockCache
@ -157,6 +199,30 @@ ConcreteBlockCache::sync()
} }
void ConcreteBlockCache::write(unsigned block, const void *bp)
{
FileEntry *e = findEntry();
if (e)
{
e->dirty = true;
std::memcpy(e->buffer, bp, 512);
return;
}
// returns a new entry not in the hashtable or the linked list.
// we add it to both.
e = newEntry(block);
e->count = 0;
e->dirty = true;
std::memcpy(e->buffer, bp, 512);
addEntry(e);
setLast(e);
}
void ConcreteBlockCache::markDirty(unsigned block) void ConcreteBlockCache::markDirty(unsigned block)
{ {
Entry *e = findEntry(block); Entry *e = findEntry(block);
@ -188,16 +254,13 @@ void *ConcreteBlockCache::acquire(unsigned block)
incrementCount(e); incrementCount(e);
return e->buffer; return e->buffer;
} }
unsigned hash = hashFunction(block);
// returns a new entry, not in hash table, not in free list. // returns a new entry, not in hash table, not in free list.
e = newEntry(block); e = newEntry(block);
_device->read(block, e->buffer); _device->read(block, e->buffer);
e->nextHash = _hashTable[hash]; addEntry(e);
_hashTable[hash] = e;
return e->buffer; return e->buffer;
} }
@ -240,18 +303,20 @@ void removeEntry(unsigned block)
prev->nextHash = e->nextHash; prev->nextHash = e->nextHash;
e->nextHash = NULL; e->nextHash = NULL;
if (e->dirty)
{
_device->write(e->block, e->buffer);
e->dirty = false;
}
break; break;
} }
} }
} }
void ConcreteBlockCache::addEntry(Entry *e)
{
unsigned hash = hashFunction(e->block);
e->nextHash = _hashTable[hash];
_hashTable[hash] = e;
}
// increment the count and remove from the free list // increment the count and remove from the free list
// if necessary. // if necessary.
void ConcreteBlockCache::incrementCount(Entry *e) void ConcreteBlockCache::incrementCount(Entry *e)
@ -310,6 +375,12 @@ Entry *ConcreteBlockCache::newEntry(unsigned block)
_first->prev = NULL; _first->prev = NULL;
} }
if (e->dirty)
{
_device->write(e->block, e->buffer);
e->dirty = false;
}
removeEntry(e->block); removeEntry(e->block);
} }
else else

View File

@ -23,8 +23,8 @@ public:
virtual void sync() = 0; virtual void sync() = 0;
virtual void write(unsigned block, const void *vp) = 0; virtual void write(unsigned block, const void *bp);
virtual void read(unsigned block, void *bp);
virtual void *acquire(unsigned block) = 0; virtual void *acquire(unsigned block) = 0;
virtual void release(unsigned block, bool dirty) = 0; virtual void release(unsigned block, bool dirty) = 0;
@ -84,6 +84,7 @@ private:
Entry *findEntry(unsigned block); Entry *findEntry(unsigned block);
void removeEntry(unsigned block); void removeEntry(unsigned block);
void addEntry(Entry *);
Entry *newEntry(unsigned block); Entry *newEntry(unsigned block);
@ -102,16 +103,12 @@ class MappedBlockCache : public BlockCache {
virtual ~MappedBlockCache(); virtual ~MappedBlockCache();
virtual void sync() = 0; virtual void sync() = 0;
virtual void write(unsigned block, const void *vp) = 0; virtual void write(unsigned block, const void *vp);
virtual bool readOnly();
virtual unsigned blocks();
virtual void *acquire(unsigned block) = 0; virtual void *acquire(unsigned block);
virtual void release(unsigned block, bool dirty) = 0; virtual void release(unsigned block, bool dirty);
virtual void markDirty(unsigned block) = 0; virtual void markDirty(unsigned block);
private: private:
void *_data; void *_data;