mirror of
https://github.com/ksherlock/profuse.git
synced 2024-06-15 19:29:32 +00:00
git-svn-id: https://profuse.googlecode.com/svn/branches/v2@197 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
parent
58ffa151e3
commit
fbc49a398e
177
BlockCache.cpp
Normal file
177
BlockCache.cpp
Normal 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
81
BlockCache.h
Normal 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
|
Loading…
Reference in New Issue
Block a user