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

This commit is contained in:
ksherlock 2010-03-01 00:14:12 +00:00
parent 58ffa151e3
commit fbc49a398e
2 changed files with 258 additions and 0 deletions

177
BlockCache.cpp Normal file
View File

@ -0,0 +1,177 @@
#include "BlockCache.h"
struct FileBlockCache::Entry {
FileBlockCache::Entry *next;
unsigned block;
unsigned count;
bool dirty;
uint8_t buffer[512];
};
FileBlockCache::FileBlockCache(Device *device)
{
_device = device;
// allocate initial buffer.
for (unsigned i = 0; i < 10; ++i)
{
Entry *e = new Entry;
std::memset(e, 0, sizeof(Entry));
_pages.push_back(e);
_unused.push_back(e);
}
}
FileBlockCache::~FileBlockCache()
{
std::vector<Entry *>::iterator iter;
// todo -- check if dirty.
// deallocate everything that was allocated.
for (iter = _pages.begin(); iter != _pages.end(); ++iter)
{
Entrty *e = *iter;
if (e->dirty) sync(e);
delete e;
}
}
uint8_t *FileBlockCache::acquire(unsigned block)
{
Entry *e = findEntry(block);
if (e)
{
if (++e->count == 1)
_unused.remove(e);
return e->buffer;
}
if (_unused.empty())
{
e = new Entry;
_pages.push_back(e);
}
else
{
e = _unused.pop_front();
removeEntry(e);
}
std::memset(e, 0, sizeof(Entry));
unsigned hash = hashFunction(block);
e->block = block;
e->count = 1;
e->dirty = 0;
_device->read(block, e->buffer);
_e->next = _hashMap[hash];
_hashMap[hash] = e;
return e->buffer;
}
void FileBlockCache::release(unsigned block, bool dirty)
{
Entry *e = findEntry(block);
// throw error?
if (!e) return;
if (dirty) e->dirty = true;
if (e->count == 0) return;
if (--e->count == 0)
{
_unused.push_back(e);
}
// sync if dirty??
}
void FileBlockCache::markDirty(unsigned block)
{
Entry *e = findEntry(e);
if (e && e->count) e->dirty = true;
}
Entry *FileBlockCache::findEntry(unsigned block)
{
unsigned hash = hashFunction(block);
Entry *e;
e = _hashMap[hash];
while (e && e->block != block)
{
e = e->next;
}
return e;
}
void FileBlockCache::removeEntry(Entry *e)
{
unsigned hash;
Entry *curr;
Entry *prev;
if (!e) return;
hash = hashFunction(e->block);
curr = _hashMap[hash];
if (curr == e)
{
_hashMap[hash] = e->next;
return;
}
for (;;)
{
prev = curr;
curr = curr->next;
if (!curr) break;
if (e == curr)
{
prev->next = e->next;
return;
}
}
}
unsigned FileBlockCache::hashFunction(unsigned block)
{
return block % HashEntries;
}
void FileBlockCache::sync(Entry *e)
{
if (!e) return;
if (!e->dirty) return;
_device->write(e->block, e->buffer);
e->dirty = false;
}
void FileBlockCache::sync()
{
std::vector<Entry *>::iterator iter;
for (iter = _pages.begin(); iter != _pages.end(); ++iter)
{
Entry *e = *iter;
if (e && e->dirty) sync(e);
}
}

81
BlockCache.h Normal file
View File

@ -0,0 +1,81 @@
#ifndef __BLOCK_CACHE_H__
#define __BLOCK_CACHE__
#include <stdint.h>
#include <vector>
#include <list>
//#include <ext/hash_map>
//typedef std::__gnu_cxx::hash_map hash_map;
namespace ProFUSE {
class BlockCache {
public:
virtual ~BlockCache();
virtual uint8_t *acquire(unsigned block) = 0;
virtual void release(unsigned block, bool dirty = false) = 0;
virtual void markDirty(unsigned block) = 0;
virtual void sync() = 0;
};
class FileBlockCache : public BlockCache {
FileBlockCache(Device *);
virtual ~FileBlockCache();
virtual uint8_t *acquire(unsigned block);
virtual void release(unsigned block, bool dirty = false);
virtual void markDirty(unsigned block);
virtual void sync();
private:
struct Entry;
enum { HashEntries = 23 };
unsigned hashFunction(unsigned);
void removeEntry(Entry *);
Entry *findEntry(unsigned block);
void sync(Entry *);
std::vector<Entry *> _pages;
std::list<Entry *> _unused;
Entry *_hashMap[HashEntries];
Device *_device;
};
class MappedBlockCache : public BlockCache
{
public:
MappedBlockCache(Device *);
virtual ~MappedBlockCache();
virtual uint8_t *acquire(unsigned block);
virtual void release(unsigned block, bool dirty = false);
virtual void markDirty(unsigned block);
virtual void sync();
private:
Device *_device;
};
}
#endif