Incorporated hash and block cache changes of r20368 and r20374.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20375 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
de4145dbb6
commit
73a3220667
|
@ -105,7 +105,6 @@ transaction_hash(void *_transaction, const void *_id, uint32 range)
|
||||||
static void
|
static void
|
||||||
delete_transaction(block_cache *cache, cache_transaction *transaction)
|
delete_transaction(block_cache *cache, cache_transaction *transaction)
|
||||||
{
|
{
|
||||||
hash_remove(cache->transaction_hash, transaction);
|
|
||||||
if (cache->last_transaction == transaction)
|
if (cache->last_transaction == transaction)
|
||||||
cache->last_transaction = NULL;
|
cache->last_transaction = NULL;
|
||||||
|
|
||||||
|
@ -152,7 +151,8 @@ cached_block::Hash(void *_cacheEntry, const void *_block, uint32 range)
|
||||||
// #pragma mark - block_cache
|
// #pragma mark - block_cache
|
||||||
|
|
||||||
|
|
||||||
block_cache::block_cache(int _fd, off_t numBlocks, size_t blockSize, bool readOnly)
|
block_cache::block_cache(int _fd, off_t numBlocks, size_t blockSize,
|
||||||
|
bool readOnly)
|
||||||
:
|
:
|
||||||
hash(NULL),
|
hash(NULL),
|
||||||
fd(_fd),
|
fd(_fd),
|
||||||
|
@ -222,8 +222,10 @@ block_cache::FreeBlock(cached_block *block)
|
||||||
Free(block->current_data);
|
Free(block->current_data);
|
||||||
block->current_data = NULL;
|
block->current_data = NULL;
|
||||||
|
|
||||||
if (block->original_data != NULL || block->parent_data != NULL)
|
if (block->original_data != NULL || block->parent_data != NULL) {
|
||||||
panic("block_cache::FreeBlock(): %p, %p\n", block->original_data, block->parent_data);
|
panic("block_cache::FreeBlock(): %p, %p\n", block->original_data,
|
||||||
|
block->parent_data);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_CHANGED
|
#ifdef DEBUG_CHANGED
|
||||||
Free(block->compare);
|
Free(block->compare);
|
||||||
|
@ -233,6 +235,7 @@ block_cache::FreeBlock(cached_block *block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Allocates a new block for \a blockNumber, ready for use */
|
||||||
cached_block *
|
cached_block *
|
||||||
block_cache::NewBlock(off_t blockNumber)
|
block_cache::NewBlock(off_t blockNumber)
|
||||||
{
|
{
|
||||||
|
@ -268,7 +271,6 @@ block_cache::NewBlock(off_t blockNumber)
|
||||||
block->compare = NULL;
|
block->compare = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
hash_insert(hash, block);
|
|
||||||
allocated_block_count++;
|
allocated_block_count++;
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
|
@ -281,7 +283,8 @@ block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
|
||||||
TRACE(("block_cache: remove up to %ld unused blocks\n", count));
|
TRACE(("block_cache: remove up to %ld unused blocks\n", count));
|
||||||
|
|
||||||
cached_block *next = NULL;
|
cached_block *next = NULL;
|
||||||
for (cached_block *block = unused_blocks.First(); block != NULL; block = next) {
|
for (cached_block *block = unused_blocks.First(); block != NULL;
|
||||||
|
block = next) {
|
||||||
next = block->next;
|
next = block->next;
|
||||||
|
|
||||||
if (maxAccessed < block->accessed)
|
if (maxAccessed < block->accessed)
|
||||||
|
@ -306,14 +309,15 @@ block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark - private block functions
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
put_cached_block(block_cache *cache, cached_block *block)
|
put_cached_block(block_cache *cache, cached_block *block)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_CHANGED
|
#ifdef DEBUG_CHANGED
|
||||||
if (!block->is_dirty && block->compare != NULL && memcmp(block->current_data, block->compare, cache->block_size)) {
|
if (!block->is_dirty && block->compare != NULL
|
||||||
|
&& memcmp(block->current_data, block->compare, cache->block_size)) {
|
||||||
dprintf("new block:\n");
|
dprintf("new block:\n");
|
||||||
dump_block((const char *)block->current_data, 256, " ");
|
dump_block((const char *)block->current_data, 256, " ");
|
||||||
dprintf("unchanged block:\n");
|
dprintf("unchanged block:\n");
|
||||||
|
@ -344,8 +348,10 @@ put_cached_block(block_cache *cache, cached_block *block)
|
||||||
static void
|
static void
|
||||||
put_cached_block(block_cache *cache, off_t blockNumber)
|
put_cached_block(block_cache *cache, off_t blockNumber)
|
||||||
{
|
{
|
||||||
if (blockNumber < 0 || blockNumber >= cache->max_blocks)
|
if (blockNumber < 0 || blockNumber >= cache->max_blocks) {
|
||||||
panic("put_cached_block: invalid block number %lld (max %lld)", blockNumber, cache->max_blocks - 1);
|
panic("put_cached_block: invalid block number %lld (max %lld)",
|
||||||
|
blockNumber, cache->max_blocks - 1);
|
||||||
|
}
|
||||||
|
|
||||||
cached_block *block = (cached_block *)hash_lookup(cache->hash, &blockNumber);
|
cached_block *block = (cached_block *)hash_lookup(cache->hash, &blockNumber);
|
||||||
if (block != NULL)
|
if (block != NULL)
|
||||||
|
@ -353,14 +359,29 @@ put_cached_block(block_cache *cache, off_t blockNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static cached_block *
|
/*!
|
||||||
get_cached_block(block_cache *cache, off_t blockNumber, bool *allocated, bool readBlock = true)
|
Retrieves the block \a blockNumber from the hash table, if it's already
|
||||||
{
|
there, or reads it from the disk.
|
||||||
if (blockNumber < 0 || blockNumber >= cache->max_blocks)
|
|
||||||
panic("get_cached_block: invalid block number %lld (max %lld)", blockNumber, cache->max_blocks - 1);
|
|
||||||
|
|
||||||
cached_block *block = (cached_block *)hash_lookup(cache->hash, &blockNumber);
|
\param _allocated tells you wether or not a new block has been allocated
|
||||||
*allocated = false;
|
to satisfy your request.
|
||||||
|
\param readBlock if \c false, the block will not be read in case it was
|
||||||
|
not already in the cache. The block you retrieve may contain random
|
||||||
|
data.
|
||||||
|
*/
|
||||||
|
static cached_block *
|
||||||
|
get_cached_block(block_cache *cache, off_t blockNumber, bool *_allocated,
|
||||||
|
bool readBlock = true)
|
||||||
|
{
|
||||||
|
if (blockNumber < 0 || blockNumber >= cache->max_blocks) {
|
||||||
|
panic("get_cached_block: invalid block number %lld (max %lld)",
|
||||||
|
blockNumber, cache->max_blocks - 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_block *block = (cached_block *)hash_lookup(cache->hash,
|
||||||
|
&blockNumber);
|
||||||
|
*_allocated = false;
|
||||||
|
|
||||||
if (block == NULL) {
|
if (block == NULL) {
|
||||||
// read block into cache
|
// read block into cache
|
||||||
|
@ -368,8 +389,10 @@ get_cached_block(block_cache *cache, off_t blockNumber, bool *allocated, bool re
|
||||||
if (block == NULL)
|
if (block == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
*allocated = true;
|
hash_insert(cache->hash, block);
|
||||||
|
*_allocated = true;
|
||||||
} else {
|
} else {
|
||||||
|
// TODO: currently, the data is always mapped in
|
||||||
/*
|
/*
|
||||||
if (block->ref_count == 0 && block->current_data != NULL) {
|
if (block->ref_count == 0 && block->current_data != NULL) {
|
||||||
// see if the old block can be resurrected
|
// see if the old block can be resurrected
|
||||||
|
@ -382,15 +405,16 @@ get_cached_block(block_cache *cache, off_t blockNumber, bool *allocated, bool re
|
||||||
if (block->current_data == NULL)
|
if (block->current_data == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
*allocated = true;
|
*_allocated = true;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*allocated && readBlock) {
|
if (*_allocated && readBlock) {
|
||||||
int32 blockSize = cache->block_size;
|
int32 blockSize = cache->block_size;
|
||||||
|
|
||||||
if (read_pos(cache->fd, blockNumber * blockSize, block->current_data, blockSize) < blockSize) {
|
if (read_pos(cache->fd, blockNumber * blockSize, block->current_data,
|
||||||
|
blockSize) < blockSize) {
|
||||||
hash_remove(cache->hash, block);
|
hash_remove(cache->hash, block);
|
||||||
cache->FreeBlock(block);
|
cache->FreeBlock(block);
|
||||||
FATAL(("could not read block %Ld\n", blockNumber));
|
FATAL(("could not read block %Ld\n", blockNumber));
|
||||||
|
@ -411,24 +435,29 @@ get_cached_block(block_cache *cache, off_t blockNumber, bool *allocated, bool re
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns the writable block data for the requested blockNumber.
|
/*!
|
||||||
* If \a cleared is true, the block is not read from disk; an empty block
|
Returns the writable block data for the requested blockNumber.
|
||||||
* is returned.
|
If \a cleared is true, the block is not read from disk; an empty block
|
||||||
* This is the only method to insert a block into a transaction. It makes
|
is returned.
|
||||||
* sure that the previous block contents are preserved in that case.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
This is the only method to insert a block into a transaction. It makes
|
||||||
|
sure that the previous block contents are preserved in that case.
|
||||||
|
*/
|
||||||
static void *
|
static void *
|
||||||
get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base, off_t length,
|
get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base,
|
||||||
int32 transactionID, bool cleared)
|
off_t length, int32 transactionID, bool cleared)
|
||||||
{
|
{
|
||||||
TRACE(("get_writable_cached_block(blockNumber = %Ld, transaction = %ld)\n", blockNumber, transactionID));
|
TRACE(("get_writable_cached_block(blockNumber = %Ld, transaction = %ld)\n",
|
||||||
|
blockNumber, transactionID));
|
||||||
|
|
||||||
if (blockNumber < 0 || blockNumber >= cache->max_blocks)
|
if (blockNumber < 0 || blockNumber >= cache->max_blocks) {
|
||||||
panic("get_writable_cached_block: invalid block number %lld (max %lld)", blockNumber, cache->max_blocks - 1);
|
panic("get_writable_cached_block: invalid block number %lld (max %lld)",
|
||||||
|
blockNumber, cache->max_blocks - 1);
|
||||||
|
}
|
||||||
|
|
||||||
bool allocated;
|
bool allocated;
|
||||||
cached_block *block = get_cached_block(cache, blockNumber, &allocated, !cleared);
|
cached_block *block = get_cached_block(cache, blockNumber, &allocated,
|
||||||
|
!cleared);
|
||||||
if (block == NULL)
|
if (block == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -454,7 +483,8 @@ get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base, off
|
||||||
// get new transaction
|
// get new transaction
|
||||||
cache_transaction *transaction = lookup_transaction(cache, transactionID);
|
cache_transaction *transaction = lookup_transaction(cache, transactionID);
|
||||||
if (transaction == NULL) {
|
if (transaction == NULL) {
|
||||||
panic("get_writable_cached_block(): invalid transaction %ld!\n", transactionID);
|
panic("get_writable_cached_block(): invalid transaction %ld!\n",
|
||||||
|
transactionID);
|
||||||
put_cached_block(cache, block);
|
put_cached_block(cache, block);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -487,7 +517,7 @@ get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base, off
|
||||||
// remember any previous contents for the parent transaction
|
// remember any previous contents for the parent transaction
|
||||||
block->parent_data = cache->Allocate();
|
block->parent_data = cache->Allocate();
|
||||||
if (block->parent_data == NULL) {
|
if (block->parent_data == NULL) {
|
||||||
// ToDo: maybe we should just continue the current transaction in this case...
|
// TODO: maybe we should just continue the current transaction in this case...
|
||||||
FATAL(("could not allocate parent\n"));
|
FATAL(("could not allocate parent\n"));
|
||||||
put_cached_block(cache, block);
|
put_cached_block(cache, block);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -507,20 +537,24 @@ get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base, off
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
write_cached_block(block_cache *cache, cached_block *block, bool deleteTransaction)
|
write_cached_block(block_cache *cache, cached_block *block,
|
||||||
|
bool deleteTransaction)
|
||||||
{
|
{
|
||||||
cache_transaction *previous = block->previous_transaction;
|
cache_transaction *previous = block->previous_transaction;
|
||||||
int32 blockSize = cache->block_size;
|
int32 blockSize = cache->block_size;
|
||||||
|
|
||||||
void *data = previous && block->original_data ? block->original_data : block->current_data;
|
void *data = previous && block->original_data
|
||||||
|
? block->original_data : block->current_data;
|
||||||
// we first need to write back changes from previous transactions
|
// we first need to write back changes from previous transactions
|
||||||
|
|
||||||
TRACE(("write_cached_block(block %Ld)\n", block->block_number));
|
TRACE(("write_cached_block(block %Ld)\n", block->block_number));
|
||||||
|
|
||||||
ssize_t written = write_pos(cache->fd, block->block_number * blockSize, data, blockSize);
|
ssize_t written = write_pos(cache->fd, block->block_number * blockSize,
|
||||||
|
data, blockSize);
|
||||||
|
|
||||||
if (written < blockSize) {
|
if (written < blockSize) {
|
||||||
FATAL(("could not write back block %Ld (%s)\n", block->block_number, strerror(errno)));
|
FATAL(("could not write back block %Ld (%s)\n", block->block_number,
|
||||||
|
strerror(errno)));
|
||||||
return B_IO_ERROR;
|
return B_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,11 +569,15 @@ write_cached_block(block_cache *cache, cached_block *block, bool deleteTransacti
|
||||||
if (--previous->num_blocks == 0) {
|
if (--previous->num_blocks == 0) {
|
||||||
TRACE(("cache transaction %ld finished!\n", previous->id));
|
TRACE(("cache transaction %ld finished!\n", previous->id));
|
||||||
|
|
||||||
if (previous->notification_hook != NULL)
|
if (previous->notification_hook != NULL) {
|
||||||
previous->notification_hook(previous->id, previous->notification_data);
|
previous->notification_hook(previous->id,
|
||||||
|
previous->notification_data);
|
||||||
|
}
|
||||||
|
|
||||||
if (deleteTransaction)
|
if (deleteTransaction) {
|
||||||
|
hash_remove(cache->transaction_hash, previous);
|
||||||
delete_transaction(cache, previous);
|
delete_transaction(cache, previous);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,8 +601,10 @@ cache_start_transaction(void *_cache)
|
||||||
block_cache *cache = (block_cache *)_cache;
|
block_cache *cache = (block_cache *)_cache;
|
||||||
BenaphoreLocker locker(&cache->lock);
|
BenaphoreLocker locker(&cache->lock);
|
||||||
|
|
||||||
if (cache->last_transaction && cache->last_transaction->open)
|
if (cache->last_transaction && cache->last_transaction->open) {
|
||||||
panic("last transaction (%ld) still open!\n", cache->last_transaction->id);
|
panic("last transaction (%ld) still open!\n",
|
||||||
|
cache->last_transaction->id);
|
||||||
|
}
|
||||||
|
|
||||||
cache_transaction *transaction = new(nothrow) cache_transaction;
|
cache_transaction *transaction = new(nothrow) cache_transaction;
|
||||||
if (transaction == NULL)
|
if (transaction == NULL)
|
||||||
|
@ -592,17 +632,21 @@ cache_sync_transaction(void *_cache, int32 id)
|
||||||
hash_open(cache->transaction_hash, &iterator);
|
hash_open(cache->transaction_hash, &iterator);
|
||||||
|
|
||||||
cache_transaction *transaction;
|
cache_transaction *transaction;
|
||||||
while ((transaction = (cache_transaction *)hash_next(cache->transaction_hash, &iterator)) != NULL) {
|
while ((transaction = (cache_transaction *)hash_next(
|
||||||
// ToDo: fix hash interface to make this easier
|
cache->transaction_hash, &iterator)) != NULL) {
|
||||||
|
// close all earlier transactions which haven't been closed yet
|
||||||
|
|
||||||
if (transaction->id <= id && !transaction->open) {
|
if (transaction->id <= id && !transaction->open) {
|
||||||
|
// write back all of their remaining dirty blocks
|
||||||
while (transaction->num_blocks > 0) {
|
while (transaction->num_blocks > 0) {
|
||||||
status = write_cached_block(cache, transaction->blocks.Head(), false);
|
status = write_cached_block(cache, transaction->blocks.Head(),
|
||||||
|
false);
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash_remove_current(cache->transaction_hash, &iterator);
|
||||||
delete_transaction(cache, transaction);
|
delete_transaction(cache, transaction);
|
||||||
hash_rewind(cache->transaction_hash, &iterator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,7 +656,8 @@ cache_sync_transaction(void *_cache, int32 id)
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
cache_end_transaction(void *_cache, int32 id, transaction_notification_hook hook, void *data)
|
cache_end_transaction(void *_cache, int32 id,
|
||||||
|
transaction_notification_hook hook, void *data)
|
||||||
{
|
{
|
||||||
block_cache *cache = (block_cache *)_cache;
|
block_cache *cache = (block_cache *)_cache;
|
||||||
BenaphoreLocker locker(&cache->lock);
|
BenaphoreLocker locker(&cache->lock);
|
||||||
|
@ -700,16 +745,17 @@ cache_abort_transaction(void *_cache, int32 id)
|
||||||
block->transaction = NULL;
|
block->transaction = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash_remove(cache->transaction_hash, transaction);
|
||||||
delete_transaction(cache, transaction);
|
delete_transaction(cache, transaction);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Acknowledges the current parent transaction, and starts a new transaction
|
/*!
|
||||||
* from its sub transaction.
|
Acknowledges the current parent transaction, and starts a new transaction
|
||||||
* The new transaction also gets a new transaction ID.
|
from its sub transaction.
|
||||||
*/
|
The new transaction also gets a new transaction ID.
|
||||||
|
*/
|
||||||
int32
|
int32
|
||||||
cache_detach_sub_transaction(void *_cache, int32 id,
|
cache_detach_sub_transaction(void *_cache, int32 id,
|
||||||
transaction_notification_hook hook, void *data)
|
transaction_notification_hook hook, void *data)
|
||||||
|
@ -755,7 +801,8 @@ cache_detach_sub_transaction(void *_cache, int32 id,
|
||||||
cache->Free(block->original_data);
|
cache->Free(block->original_data);
|
||||||
block->original_data = NULL;
|
block->original_data = NULL;
|
||||||
}
|
}
|
||||||
if (block->parent_data != NULL && block->parent_data != block->current_data) {
|
if (block->parent_data != NULL
|
||||||
|
&& block->parent_data != block->current_data) {
|
||||||
// we need to move this block over to the new transaction
|
// we need to move this block over to the new transaction
|
||||||
block->original_data = block->parent_data;
|
block->original_data = block->parent_data;
|
||||||
if (last == NULL)
|
if (last == NULL)
|
||||||
|
@ -810,7 +857,8 @@ cache_abort_sub_transaction(void *_cache, int32 id)
|
||||||
if (block->original_data != NULL) {
|
if (block->original_data != NULL) {
|
||||||
// the parent transaction didn't change the block, but the sub
|
// the parent transaction didn't change the block, but the sub
|
||||||
// transaction did - we need to revert from the original data
|
// transaction did - we need to revert from the original data
|
||||||
memcpy(block->current_data, block->original_data, cache->block_size);
|
memcpy(block->current_data, block->original_data,
|
||||||
|
cache->block_size);
|
||||||
}
|
}
|
||||||
} else if (block->parent_data != block->current_data) {
|
} else if (block->parent_data != block->current_data) {
|
||||||
// the block has been changed and must be restored
|
// the block has been changed and must be restored
|
||||||
|
@ -871,8 +919,8 @@ cache_start_sub_transaction(void *_cache, int32 id)
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
cache_next_block_in_transaction(void *_cache, int32 id, uint32 *_cookie, off_t *_blockNumber,
|
cache_next_block_in_transaction(void *_cache, int32 id, uint32 *_cookie,
|
||||||
void **_data, void **_unchangedData)
|
off_t *_blockNumber, void **_data, void **_unchangedData)
|
||||||
{
|
{
|
||||||
cached_block *block = (cached_block *)*_cookie;
|
cached_block *block = (cached_block *)*_cookie;
|
||||||
block_cache *cache = (block_cache *)_cache;
|
block_cache *cache = (block_cache *)_cache;
|
||||||
|
@ -949,7 +997,8 @@ block_cache_delete(void *_cache, bool allowWrites)
|
||||||
|
|
||||||
uint32 cookie = 0;
|
uint32 cookie = 0;
|
||||||
cached_block *block;
|
cached_block *block;
|
||||||
while ((block = (cached_block *)hash_remove_first(cache->hash, &cookie)) != NULL) {
|
while ((block = (cached_block *)hash_remove_first(cache->hash,
|
||||||
|
&cookie)) != NULL) {
|
||||||
cache->FreeBlock(block);
|
cache->FreeBlock(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -957,7 +1006,8 @@ block_cache_delete(void *_cache, bool allowWrites)
|
||||||
|
|
||||||
cookie = 0;
|
cookie = 0;
|
||||||
cache_transaction *transaction;
|
cache_transaction *transaction;
|
||||||
while ((transaction = (cache_transaction *)hash_remove_first(cache->transaction_hash, &cookie)) != NULL) {
|
while ((transaction = (cache_transaction *)hash_remove_first(
|
||||||
|
cache->transaction_hash, &cookie)) != NULL) {
|
||||||
delete transaction;
|
delete transaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -968,7 +1018,8 @@ block_cache_delete(void *_cache, bool allowWrites)
|
||||||
void *
|
void *
|
||||||
block_cache_create(int fd, off_t numBlocks, size_t blockSize, bool readOnly)
|
block_cache_create(int fd, off_t numBlocks, size_t blockSize, bool readOnly)
|
||||||
{
|
{
|
||||||
block_cache *cache = new(nothrow) block_cache(fd, numBlocks, blockSize, readOnly);
|
block_cache *cache = new(nothrow) block_cache(fd, numBlocks, blockSize,
|
||||||
|
readOnly);
|
||||||
if (cache == NULL)
|
if (cache == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -1098,12 +1149,20 @@ block_cache_get(void *_cache, off_t blockNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Changes the internal status of a writable block to \a dirty. This can be
|
||||||
|
helpful in case you realize you don't need to change that block anymore
|
||||||
|
for whatever reason.
|
||||||
|
|
||||||
|
Note, you must only use this function on blocks that were acquired
|
||||||
|
writable!
|
||||||
|
*/
|
||||||
status_t
|
status_t
|
||||||
block_cache_set_dirty(void *_cache, off_t blockNumber, bool isDirty, int32 transaction)
|
block_cache_set_dirty(void *_cache, off_t blockNumber, bool dirty,
|
||||||
|
int32 transaction)
|
||||||
{
|
{
|
||||||
// not yet implemented
|
// TODO: not yet implemented
|
||||||
// Note, you must only use this function on blocks that were acquired writable!
|
if (dirty)
|
||||||
if (isDirty)
|
|
||||||
panic("block_cache_set_dirty(): not yet implemented that way!\n");
|
panic("block_cache_set_dirty(): not yet implemented that way!\n");
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
|
@ -11,7 +11,8 @@
|
||||||
|
|
||||||
#include <Debug.h>
|
#include <Debug.h>
|
||||||
#include <Errors.h>
|
#include <Errors.h>
|
||||||
#include <KernelExport.h>
|
|
||||||
|
#include "kernel_emu.h"
|
||||||
|
|
||||||
#undef TRACE
|
#undef TRACE
|
||||||
#define TRACE_HASH 0
|
#define TRACE_HASH 0
|
||||||
|
@ -21,13 +22,16 @@
|
||||||
# define TRACE(x) ;
|
# define TRACE(x) ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using UserlandFS::KernelEmu::dprintf;
|
||||||
|
using UserlandFS::KernelEmu::panic;
|
||||||
|
|
||||||
namespace UserlandFS {
|
namespace UserlandFS {
|
||||||
namespace HaikuKernelEmu {
|
namespace HaikuKernelEmu {
|
||||||
|
|
||||||
|
|
||||||
// ToDo: the hashtable is not expanded when necessary (no load factor, no nothing)
|
// TODO: the hashtable is not expanded when necessary (no load factor, nothing)
|
||||||
// Could try to use pools instead of malloc() for the elements - might be
|
// resizing should be optional, though, in case the hash is used at times
|
||||||
// faster than the current approach.
|
// that forbid resizing.
|
||||||
|
|
||||||
struct hash_table {
|
struct hash_table {
|
||||||
struct hash_element **table;
|
struct hash_element **table;
|
||||||
|
@ -130,7 +134,8 @@ hash_remove(struct hash_table *table, void *_element)
|
||||||
uint32 hash = table->hash_func(_element, NULL, table->table_size);
|
uint32 hash = table->hash_func(_element, NULL, table->table_size);
|
||||||
void *element, *lastElement = NULL;
|
void *element, *lastElement = NULL;
|
||||||
|
|
||||||
for (element = table->table[hash]; element != NULL; lastElement = element, element = NEXT(table, element)) {
|
for (element = table->table[hash]; element != NULL;
|
||||||
|
lastElement = element, element = NEXT(table, element)) {
|
||||||
if (element == _element) {
|
if (element == _element) {
|
||||||
if (lastElement != NULL) {
|
if (lastElement != NULL) {
|
||||||
// connect the previous entry with the next one
|
// connect the previous entry with the next one
|
||||||
|
@ -147,6 +152,40 @@ hash_remove(struct hash_table *table, void *_element)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
hash_remove_current(struct hash_table *table, struct hash_iterator *iterator)
|
||||||
|
{
|
||||||
|
uint32 index = iterator->bucket;
|
||||||
|
void *element;
|
||||||
|
|
||||||
|
if (iterator->current == NULL)
|
||||||
|
panic("hash_remove_current() called too early.");
|
||||||
|
|
||||||
|
for (element = table->table[index]; index < table->table_size; index++) {
|
||||||
|
void *lastElement = NULL;
|
||||||
|
|
||||||
|
while (element != NULL) {
|
||||||
|
if (element == iterator->current) {
|
||||||
|
iterator->current = lastElement;
|
||||||
|
|
||||||
|
if (lastElement != NULL) {
|
||||||
|
// connect the previous entry with the next one
|
||||||
|
PUT_IN_NEXT(table, lastElement, NEXT(table, element));
|
||||||
|
} else {
|
||||||
|
table->table[index] = (struct hash_element *)NEXT(table,
|
||||||
|
element);
|
||||||
|
}
|
||||||
|
|
||||||
|
table->num_elements--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = NEXT(table, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
hash_remove_first(struct hash_table *table, uint32 *_cookie)
|
hash_remove_first(struct hash_table *table, uint32 *_cookie)
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct hash_table *hash_init(uint32 table_size, int next_ptr_offset,
|
||||||
int hash_uninit(struct hash_table *table);
|
int hash_uninit(struct hash_table *table);
|
||||||
status_t hash_insert(struct hash_table *table, void *_element);
|
status_t hash_insert(struct hash_table *table, void *_element);
|
||||||
status_t hash_remove(struct hash_table *table, void *_element);
|
status_t hash_remove(struct hash_table *table, void *_element);
|
||||||
|
void hash_remove_current(struct hash_table *table, struct hash_iterator *iterator);
|
||||||
void *hash_remove_first(struct hash_table *table, uint32 *_cookie);
|
void *hash_remove_first(struct hash_table *table, uint32 *_cookie);
|
||||||
void *hash_find(struct hash_table *table, void *e);
|
void *hash_find(struct hash_table *table, void *e);
|
||||||
void *hash_lookup(struct hash_table *table, const void *key);
|
void *hash_lookup(struct hash_table *table, const void *key);
|
||||||
|
@ -32,17 +33,15 @@ void hash_close(struct hash_table *table, struct hash_iterator *i, bool free_ite
|
||||||
void *hash_next(struct hash_table *table, struct hash_iterator *i);
|
void *hash_next(struct hash_table *table, struct hash_iterator *i);
|
||||||
void hash_rewind(struct hash_table *table, struct hash_iterator *i);
|
void hash_rewind(struct hash_table *table, struct hash_iterator *i);
|
||||||
|
|
||||||
/* function ptrs must look like this:
|
/* function pointers must look like this:
|
||||||
*
|
*
|
||||||
* uint32 hash_func(void *e, const void *key, uint32 range);
|
* uint32 hash_func(void *e, const void *key, uint32 range);
|
||||||
* hash function should calculate hash on either e or key,
|
* hash function should calculate hash on either e or key,
|
||||||
* depending on which one is not NULL
|
* depending on which one is not NULL - they also need
|
||||||
|
* to make sure the returned value is within range.
|
||||||
* int compare_func(void *e, const void *key);
|
* int compare_func(void *e, const void *key);
|
||||||
* compare function should compare the element with
|
* compare function should compare the element with
|
||||||
* the key, returning 0 if equal, other if not
|
* the key, returning 0 if equal, other if not
|
||||||
* NOTE: compare func can be null, in which case the hash
|
|
||||||
* code will compare the key pointer with the target
|
|
||||||
* ToDo: check this!
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uint32 hash_hash_string(const char *str);
|
uint32 hash_hash_string(const char *str);
|
||||||
|
|
Loading…
Reference in New Issue