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:
parent
35df9fef55
commit
103d0293a9
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user