Moved this file to ../cache/block_cache.cpp.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8824 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2004-09-03 15:40:10 +00:00
parent 35df9fef55
commit 103d0293a9

View File

@ -1,348 +0,0 @@
/*
** Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include <KernelExport.h>
#include <cache.h>
#include <khash.h>
#include <lock.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
/* Note, this is just a dump and simple cache implementation targeted to be
* compatible with the one found in BeOS.
* This won't be the cache we end up using in R1, seriously :-)
*/
struct cache_entry {
cache_entry *next; // next in hash
off_t block_number;
void *data;
int32 ref_count;
int32 lock;
bool is_dirty;
};
struct cache {
hash_table *hash;
mutex lock;
off_t max_blocks;
size_t block_size;
};
static const int32 kNumCaches = 16;
struct cache sCaches[kNumCaches];
// we can cache the first 16 fds (I said we were dumb, right?)
class MutexLocker {
public:
MutexLocker(int fd)
: fMutex(NULL)
{
if (fd < 0 || fd >= kNumCaches)
return;
fMutex = &sCaches[fd].lock;
mutex_lock(fMutex);
}
~MutexLocker()
{
if (fMutex != NULL)
mutex_unlock(fMutex);
}
status_t InitCheck()
{
return fMutex != NULL ? B_OK : B_ERROR;
}
private:
mutex *fMutex;
};
static int
cache_entry_compare(void *_cacheEntry, const void *_block)
{
cache_entry *cacheEntry = (cache_entry *)_cacheEntry;
const off_t *block = (const off_t *)_block;
return cacheEntry->block_number - *block;
}
static uint32
cache_entry_hash(void *_cacheEntry, const void *_block, uint32 range)
{
cache_entry *cacheEntry = (cache_entry *)_cacheEntry;
const off_t *block = (const off_t *)_block;
if (cacheEntry != NULL)
return cacheEntry->block_number % range;
return *block % range;
}
static status_t
write_cache_entry(int fd, cache_entry *entry)
{
ssize_t blockSize = sCaches[fd].block_size;
return write_pos(fd, entry->block_number * blockSize,
entry->data, blockSize) < blockSize ? B_ERROR : B_OK;
}
void
put_cache_entry(int fd, cache_entry *entry)
{
if (entry == NULL)
return;
if (--entry->ref_count > 0)
return;
// write out entry if necessary
if (entry->is_dirty
&& write_cache_entry(fd, entry) != B_OK)
panic("could not write back entry\n");
hash_remove(sCaches[fd].hash, entry);
free(entry->data);
free(entry);
}
cache_entry *
new_cache_entry(int fd, off_t blockNumber, size_t blockSize)
{
cache_entry *entry = (cache_entry *)malloc(sizeof(cache_entry));
if (entry == NULL)
return NULL;
entry->data = malloc(blockSize);
if (entry->data == NULL) {
free(entry);
return NULL;
}
sCaches[fd].block_size = blockSize;
// store block size (once would be sufficient, though)
entry->block_number = blockNumber;
entry->ref_count = 1;
entry->lock = 0;
entry->is_dirty = false;
hash_insert(sCaches[fd].hash, entry);
return entry;
}
cache_entry *
lookup_cache_entry(int fd, off_t blockNumber)
{
cache_entry *entry = (cache_entry *)hash_lookup(sCaches[fd].hash, &blockNumber);
if (entry == NULL)
return NULL;
entry->ref_count++;
return entry;
}
// #pragma mark -
// public BeOS compatible interface
extern "C" void
force_cache_flush(int dev, int prefer_log_blocks)
{
}
extern "C" int
flush_blocks(int dev, off_t bnum, int nblocks)
{
return 0;
}
extern "C" int
flush_device(int dev, int warn_locked)
{
return 0;
}
extern "C" int
init_cache_for_device(int fd, off_t max_blocks)
{
if (fd < 0 || fd >= kNumCaches)
return B_ERROR;
if (sCaches[fd].hash != NULL)
return B_BUSY;
sCaches[fd].hash = hash_init(32, 0, &cache_entry_compare, &cache_entry_hash);
return mutex_init(&sCaches[fd].lock, "block cache");
}
extern "C" int
remove_cached_device_blocks(int fd, int allowWrite)
{
if (fd < 0 || fd >= kNumCaches || sCaches[fd].hash == NULL)
return B_ERROR;
if (allowWrite) {
hash_iterator iterator;
hash_open(sCaches[fd].hash, &iterator);
cache_entry *entry;
while ((entry = (cache_entry *)hash_next(sCaches[fd].hash, &iterator)) != NULL) {
// write out entry if necessary
if (entry->is_dirty
&& write_cache_entry(fd, entry) != B_OK)
panic("write failed!\n");
}
hash_close(sCaches[fd].hash, &iterator, false);
}
hash_uninit(sCaches[fd].hash);
mutex_destroy(&sCaches[fd].lock);
return 0;
}
extern "C" void *
get_block(int fd, off_t blockNumber, int blockSize)
{
MutexLocker locker(fd);
if (locker.InitCheck() != B_OK)
return NULL;
cache_entry *entry = lookup_cache_entry(fd, blockNumber);
if (entry == NULL) {
// read entry into cache
entry = new_cache_entry(fd, blockNumber, blockSize);
if (entry == NULL)
return NULL;
if (read_pos(fd, blockNumber * blockSize, entry->data, blockSize) < blockSize) {
free(entry->data);
free(entry);
return NULL;
}
}
entry->lock++;
return entry->data;
}
extern "C" void *
get_empty_block(int fd, off_t blockNumber, int blockSize)
{
MutexLocker locker(fd);
if (locker.InitCheck() != B_OK)
return NULL;
cache_entry *entry = lookup_cache_entry(fd, blockNumber);
if (entry == NULL) {
// create new cache entry
entry = new_cache_entry(fd, blockNumber, blockSize);
if (entry == NULL)
return NULL;
}
memset(entry->data, 0, blockSize);
entry->lock++;
return entry->data;
}
extern "C" int
release_block(int fd, off_t blockNumber)
{
MutexLocker locker(fd);
if (locker.InitCheck() != B_OK)
return B_ERROR;
cache_entry *entry = lookup_cache_entry(fd, blockNumber);
if (entry == NULL)
panic("release_block() called on block %Ld that was not cached\n", blockNumber);
entry->lock--;
put_cache_entry(fd, entry);
return 0;
}
extern "C" int
mark_blocks_dirty(int fd, off_t blockNumber, int numBlocks)
{
return -1;
}
extern "C" int
cached_read(int fd, off_t blockNumber, void *data, off_t numBlocks, int blockSize)
{
MutexLocker locker(fd);
if (locker.InitCheck() != B_OK)
return B_ERROR;
ssize_t bytes = numBlocks * blockSize;
if (read_pos(fd, blockNumber * blockSize, data, bytes) < bytes)
return -1;
// check if there are any cached blocks in that range shadowing the device contents
for (off_t blockOffset = 0; blockOffset < numBlocks; blockOffset++) {
cache_entry *entry = lookup_cache_entry(fd, blockNumber + blockOffset);
if (entry != NULL) {
if (entry->is_dirty)
memcpy((void *)((addr_t)data + blockOffset * blockSize), entry->data, blockSize);
put_cache_entry(fd, entry);
}
}
return 0;
}
extern "C" int
cached_write(int fd, off_t blockNumber, const void *data, off_t numBlocks, int blockSize)
{
return -1;
}
extern "C" int
cached_write_locked(int fd, off_t blockNumber, const void *data, off_t numBlocks, int blockSize)
{
return -1;
}
extern "C" int
set_blocks_info(int fd, off_t *blocks, int numBlocks,
void (*func)(off_t bnum, size_t nblocks, void *arg),
void *arg)
{
return -1;
}