First step into a new block allocation strategy for the block_cache
(right now, it's still malloc/free, just encapsulated in an allocator class). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@12662 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef _KERNEL_BLOCK_CACHE_H
|
||||||
|
#define _KERNEL_BLOCK_CACHE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern status_t block_cache_init(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _KRENEL_BLOCK_CACHE_H */
|
||||||
+117
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "BlockAllocator.h"
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <util/AutoLock.h>
|
||||||
|
|
||||||
|
|
||||||
|
BlockAllocator::AllocatorList BlockAllocator::sList;
|
||||||
|
mutex BlockAllocator::sMutex;
|
||||||
|
|
||||||
|
|
||||||
|
BlockAllocator::BlockAllocator(size_t size)
|
||||||
|
:
|
||||||
|
fSize(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BlockAllocator::~BlockAllocator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
BlockAllocator::Get()
|
||||||
|
{
|
||||||
|
return malloc(fSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BlockAllocator::Put(void *block)
|
||||||
|
{
|
||||||
|
free(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
BlockAllocator::Acquire()
|
||||||
|
{
|
||||||
|
fRefCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
BlockAllocator::Release()
|
||||||
|
{
|
||||||
|
return --fRefCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - static
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
BlockAllocator *
|
||||||
|
BlockAllocator::GetAllocator(size_t size)
|
||||||
|
{
|
||||||
|
MutexLocker locker(&sMutex);
|
||||||
|
|
||||||
|
// search for allocator in list
|
||||||
|
|
||||||
|
AllocatorList::Iterator iterator = sList.GetIterator();
|
||||||
|
while (iterator.HasNext()) {
|
||||||
|
BlockAllocator *allocator = iterator.Next();
|
||||||
|
|
||||||
|
if (allocator->Size() == size) {
|
||||||
|
allocator->Acquire();
|
||||||
|
return allocator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// it's not yet there, create new one
|
||||||
|
|
||||||
|
BlockAllocator *allocator = new BlockAllocator(size);
|
||||||
|
if (allocator == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sList.Add(allocator);
|
||||||
|
return allocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// static
|
||||||
|
void
|
||||||
|
BlockAllocator::PutAllocator(BlockAllocator *allocator)
|
||||||
|
{
|
||||||
|
MutexLocker locker(&sMutex);
|
||||||
|
|
||||||
|
if (!allocator->Release()) {
|
||||||
|
sList.Remove(allocator);
|
||||||
|
delete allocator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" status_t
|
||||||
|
init_block_allocator(void)
|
||||||
|
{
|
||||||
|
status_t status = mutex_init(&BlockAllocator::sMutex, "block allocator");
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
new(&BlockAllocator::sList) DoublyLinkedList<BlockAllocator>;
|
||||||
|
// static initializers do not work in the kernel,
|
||||||
|
// so we have to do it here, manually
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef BLOCK_ALLOCATOR_H
|
||||||
|
#define BLOCK_ALLOCATOR_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
#include <lock.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BlockAllocator : public DoublyLinkedListLinkImpl<BlockAllocator> {
|
||||||
|
public:
|
||||||
|
void *Get();
|
||||||
|
void Put(void *block);
|
||||||
|
|
||||||
|
static BlockAllocator *GetAllocator(size_t size);
|
||||||
|
static void PutAllocator(BlockAllocator *allocator);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BlockAllocator(size_t size);
|
||||||
|
~BlockAllocator();
|
||||||
|
|
||||||
|
size_t Size() const { return fSize; }
|
||||||
|
|
||||||
|
void Acquire();
|
||||||
|
int32 Release();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef DoublyLinkedList<BlockAllocator> AllocatorList;
|
||||||
|
|
||||||
|
size_t fSize;
|
||||||
|
int32 fRefCount;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static AllocatorList sList;
|
||||||
|
static mutex sMutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" status_t init_block_allocator(void);
|
||||||
|
|
||||||
|
#endif /* BLOCK_ALLOCATOR_H */
|
||||||
Vendored
+1
@@ -1,6 +1,7 @@
|
|||||||
SubDir OBOS_TOP src system kernel cache ;
|
SubDir OBOS_TOP src system kernel cache ;
|
||||||
|
|
||||||
KernelMergeObject kernel_cache.o :
|
KernelMergeObject kernel_cache.o :
|
||||||
|
BlockAllocator.cpp
|
||||||
block_cache.cpp
|
block_cache.cpp
|
||||||
file_cache.cpp
|
file_cache.cpp
|
||||||
vnode_store.cpp
|
vnode_store.cpp
|
||||||
|
|||||||
+39
-22
@@ -4,10 +4,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "BlockAllocator.h"
|
||||||
|
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <fs_cache.h>
|
#include <fs_cache.h>
|
||||||
|
|
||||||
#include <cache.h>
|
#include <block_cache.h>
|
||||||
#include <lock.h>
|
#include <lock.h>
|
||||||
#include <util/kernel_cpp.h>
|
#include <util/kernel_cpp.h>
|
||||||
#include <util/DoublyLinkedList.h>
|
#include <util/DoublyLinkedList.h>
|
||||||
@@ -41,6 +43,7 @@ struct cache_transaction;
|
|||||||
struct cached_block;
|
struct cached_block;
|
||||||
typedef DoublyLinkedListLink<cached_block> block_link;
|
typedef DoublyLinkedListLink<cached_block> block_link;
|
||||||
|
|
||||||
|
|
||||||
struct cached_block {
|
struct cached_block {
|
||||||
cached_block *next; // next in hash
|
cached_block *next; // next in hash
|
||||||
cached_block *transaction_next;
|
cached_block *transaction_next;
|
||||||
@@ -66,6 +69,7 @@ struct block_cache {
|
|||||||
size_t block_size;
|
size_t block_size;
|
||||||
int32 next_transaction_id;
|
int32 next_transaction_id;
|
||||||
hash_table *transaction_hash;
|
hash_table *transaction_hash;
|
||||||
|
BlockAllocator *allocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef DoublyLinkedList<cached_block,
|
typedef DoublyLinkedList<cached_block,
|
||||||
@@ -132,7 +136,7 @@ class BenaphoreLocker {
|
|||||||
static status_t write_cached_block(block_cache *cache, cached_block *block, bool deleteTransaction = true);
|
static status_t write_cached_block(block_cache *cache, cached_block *block, bool deleteTransaction = true);
|
||||||
|
|
||||||
|
|
||||||
// private transaction functions
|
// #pragma mark - private transaction
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -173,8 +177,7 @@ lookup_transaction(block_cache *cache, int32 id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark - private block_cache
|
||||||
// private cached block functions
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -201,13 +204,14 @@ cached_block_hash(void *_cacheEntry, const void *_block, uint32 range)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
free_cached_block(cached_block *block)
|
free_cached_block(block_cache *cache, cached_block *block)
|
||||||
{
|
{
|
||||||
free(block->data);
|
cache->allocator->Put(block->data);
|
||||||
free(block->original);
|
cache->allocator->Put(block->original);
|
||||||
#ifdef DEBUG_CHANGED
|
#ifdef DEBUG_CHANGED
|
||||||
free(block->compare);
|
cache->allocator->Put(block->compare);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
free(block);
|
free(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +224,7 @@ new_cached_block(block_cache *cache, off_t blockNumber, bool cleared = false)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!cleared) {
|
if (!cleared) {
|
||||||
block->data = malloc(cache->block_size);
|
block->data = cache->allocator->Get();
|
||||||
if (block->data == NULL) {
|
if (block->data == NULL) {
|
||||||
free(block);
|
free(block);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -297,7 +301,7 @@ put_cached_block(block_cache *cache, cached_block *block)
|
|||||||
write_cached_block(cache, block);
|
write_cached_block(cache, block);
|
||||||
panic("block_cache: supposed to be clean block was changed!\n");
|
panic("block_cache: supposed to be clean block was changed!\n");
|
||||||
|
|
||||||
free(block->compare);
|
cache->allocator->Put(block->compare);
|
||||||
block->compare = NULL;
|
block->compare = NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -332,7 +336,7 @@ get_cached_block(block_cache *cache, off_t blockNumber, bool cleared = false)
|
|||||||
|
|
||||||
if (!allocated && block->data == NULL && !cleared) {
|
if (!allocated && block->data == NULL && !cleared) {
|
||||||
// there is no block yet, but we need one
|
// there is no block yet, but we need one
|
||||||
block->data = malloc(cache->block_size);
|
block->data = cache->allocator->Get();
|
||||||
if (block->data == NULL)
|
if (block->data == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -343,7 +347,7 @@ get_cached_block(block_cache *cache, off_t blockNumber, bool cleared = false)
|
|||||||
int32 blockSize = cache->block_size;
|
int32 blockSize = cache->block_size;
|
||||||
|
|
||||||
if (read_pos(cache->fd, blockNumber * blockSize, block->data, blockSize) < blockSize) {
|
if (read_pos(cache->fd, blockNumber * blockSize, block->data, blockSize) < blockSize) {
|
||||||
free_cached_block(block);
|
free_cached_block(cache, block);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -368,7 +372,7 @@ get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base, off
|
|||||||
// if there is no transaction support, we just return the current block
|
// if there is no transaction support, we just return the current block
|
||||||
if (transactionID == -1) {
|
if (transactionID == -1) {
|
||||||
if (cleared && block->data == NULL) {
|
if (cleared && block->data == NULL) {
|
||||||
block->data = malloc(cache->block_size);
|
block->data = cache->allocator->Get();
|
||||||
if (block->data == NULL) {
|
if (block->data == NULL) {
|
||||||
put_cached_block(cache, block);
|
put_cached_block(cache, block);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -414,7 +418,7 @@ get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base, off
|
|||||||
|
|
||||||
if (block->data != NULL && block->original == NULL) {
|
if (block->data != NULL && block->original == NULL) {
|
||||||
// we already have data, so we need to save it
|
// we already have data, so we need to save it
|
||||||
block->original = malloc(cache->block_size);
|
block->original = cache->allocator->Get();
|
||||||
if (block->original == NULL) {
|
if (block->original == NULL) {
|
||||||
put_cached_block(cache, block);
|
put_cached_block(cache, block);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -425,7 +429,7 @@ get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base, off
|
|||||||
|
|
||||||
if (block->data == NULL && cleared) {
|
if (block->data == NULL && cleared) {
|
||||||
// there is no data yet, we need a clean new block
|
// there is no data yet, we need a clean new block
|
||||||
block->data = malloc(cache->block_size);
|
block->data = cache->allocator->Get();
|
||||||
if (block->data == NULL) {
|
if (block->data == NULL) {
|
||||||
put_cached_block(cache, block);
|
put_cached_block(cache, block);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -479,8 +483,14 @@ write_cached_block(block_cache *cache, cached_block *block, bool deleteTransacti
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
extern "C" status_t
|
||||||
// Transactions
|
block_cache_init(void)
|
||||||
|
{
|
||||||
|
return init_block_allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - public transaction
|
||||||
|
|
||||||
|
|
||||||
extern "C" int32
|
extern "C" int32
|
||||||
@@ -567,7 +577,7 @@ cache_end_transaction(void *_cache, int32 id, transaction_notification_hook hook
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (block->original != NULL) {
|
if (block->original != NULL) {
|
||||||
free(block->original);
|
cache->allocator->Put(block->original);
|
||||||
block->original = NULL;
|
block->original = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,7 +659,7 @@ cache_next_block_in_transaction(void *_cache, int32 id, uint32 *_cookie, off_t *
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark - public block cache
|
||||||
// public interface
|
// public interface
|
||||||
|
|
||||||
|
|
||||||
@@ -666,7 +676,7 @@ 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) {
|
||||||
free_cached_block(block);
|
free_cached_block(cache, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
// free all transactions (they will all be aborted)
|
// free all transactions (they will all be aborted)
|
||||||
@@ -679,6 +689,7 @@ block_cache_delete(void *_cache, bool allowWrites)
|
|||||||
|
|
||||||
hash_uninit(cache->hash);
|
hash_uninit(cache->hash);
|
||||||
hash_uninit(cache->transaction_hash);
|
hash_uninit(cache->transaction_hash);
|
||||||
|
BlockAllocator::PutAllocator(cache->allocator);
|
||||||
benaphore_destroy(&cache->lock);
|
benaphore_destroy(&cache->lock);
|
||||||
|
|
||||||
delete cache;
|
delete cache;
|
||||||
@@ -700,9 +711,13 @@ block_cache_create(int fd, off_t numBlocks, size_t blockSize)
|
|||||||
if (cache->transaction_hash == NULL)
|
if (cache->transaction_hash == NULL)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
if (benaphore_init(&cache->lock, "block cache") < B_OK)
|
cache->allocator = BlockAllocator::GetAllocator(blockSize);
|
||||||
|
if (cache->allocator == NULL)
|
||||||
goto err3;
|
goto err3;
|
||||||
|
|
||||||
|
if (benaphore_init(&cache->lock, "block cache") < B_OK)
|
||||||
|
goto err4;
|
||||||
|
|
||||||
cache->fd = fd;
|
cache->fd = fd;
|
||||||
cache->max_blocks = numBlocks;
|
cache->max_blocks = numBlocks;
|
||||||
cache->block_size = blockSize;
|
cache->block_size = blockSize;
|
||||||
@@ -710,6 +725,8 @@ block_cache_create(int fd, off_t numBlocks, size_t blockSize)
|
|||||||
|
|
||||||
return cache;
|
return cache;
|
||||||
|
|
||||||
|
err4:
|
||||||
|
BlockAllocator::PutAllocator(cache->allocator);
|
||||||
err3:
|
err3:
|
||||||
hash_uninit(cache->transaction_hash);
|
hash_uninit(cache->transaction_hash);
|
||||||
err2:
|
err2:
|
||||||
@@ -801,7 +818,7 @@ block_cache_get_etc(void *_cache, off_t blockNumber, off_t base, off_t length)
|
|||||||
|
|
||||||
#ifdef DEBUG_CHANGED
|
#ifdef DEBUG_CHANGED
|
||||||
if (block->compare == NULL)
|
if (block->compare == NULL)
|
||||||
block->compare = malloc(cache->block_size);
|
block->compare = cache->allocator->Get();
|
||||||
if (block->compare != NULL)
|
if (block->compare != NULL)
|
||||||
memcpy(block->compare, block->data, cache->block_size);
|
memcpy(block->compare, block->data, cache->block_size);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
#include <vm_cache.h>
|
#include <vm_cache.h>
|
||||||
#include <file_cache.h>
|
#include <file_cache.h>
|
||||||
|
#include <block_cache.h>
|
||||||
#include <khash.h>
|
#include <khash.h>
|
||||||
#include <lock.h>
|
#include <lock.h>
|
||||||
#include <fd.h>
|
#include <fd.h>
|
||||||
@@ -2841,6 +2842,9 @@ vfs_init(kernel_args *args)
|
|||||||
if (mutex_init(&sVnodeMutex, "vfs_vnode_lock") < 0)
|
if (mutex_init(&sVnodeMutex, "vfs_vnode_lock") < 0)
|
||||||
panic("vfs_init: error allocating vnode lock\n");
|
panic("vfs_init: error allocating vnode lock\n");
|
||||||
|
|
||||||
|
if (block_cache_init() != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
return file_cache_init();
|
return file_cache_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user