From d5b04e50f8eca76ce5e6690dc8873861fa978de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 13 May 2005 18:18:28 +0000 Subject: [PATCH] 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 --- headers/private/kernel/block_cache.h | 22 ++++ src/system/kernel/cache/BlockAllocator.cpp | 117 +++++++++++++++++++++ src/system/kernel/cache/BlockAllocator.h | 43 ++++++++ src/system/kernel/cache/Jamfile | 1 + src/system/kernel/cache/block_cache.cpp | 61 +++++++---- src/system/kernel/fs/vfs.cpp | 4 + 6 files changed, 226 insertions(+), 22 deletions(-) create mode 100644 headers/private/kernel/block_cache.h create mode 100644 src/system/kernel/cache/BlockAllocator.cpp create mode 100644 src/system/kernel/cache/BlockAllocator.h diff --git a/headers/private/kernel/block_cache.h b/headers/private/kernel/block_cache.h new file mode 100644 index 0000000000..321a549087 --- /dev/null +++ b/headers/private/kernel/block_cache.h @@ -0,0 +1,22 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_BLOCK_CACHE_H +#define _KERNEL_BLOCK_CACHE_H + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +extern status_t block_cache_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _KRENEL_BLOCK_CACHE_H */ diff --git a/src/system/kernel/cache/BlockAllocator.cpp b/src/system/kernel/cache/BlockAllocator.cpp new file mode 100644 index 0000000000..ca6154fa8a --- /dev/null +++ b/src/system/kernel/cache/BlockAllocator.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "BlockAllocator.h" + +#include +#include + + +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; + // static initializers do not work in the kernel, + // so we have to do it here, manually + return B_OK; +} + diff --git a/src/system/kernel/cache/BlockAllocator.h b/src/system/kernel/cache/BlockAllocator.h new file mode 100644 index 0000000000..1d202364ac --- /dev/null +++ b/src/system/kernel/cache/BlockAllocator.h @@ -0,0 +1,43 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef BLOCK_ALLOCATOR_H +#define BLOCK_ALLOCATOR_H + + +#include +#include + + +class BlockAllocator : public DoublyLinkedListLinkImpl { + 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 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 */ diff --git a/src/system/kernel/cache/Jamfile b/src/system/kernel/cache/Jamfile index 62803ddf2d..7517df41c8 100644 --- a/src/system/kernel/cache/Jamfile +++ b/src/system/kernel/cache/Jamfile @@ -1,6 +1,7 @@ SubDir OBOS_TOP src system kernel cache ; KernelMergeObject kernel_cache.o : + BlockAllocator.cpp block_cache.cpp file_cache.cpp vnode_store.cpp diff --git a/src/system/kernel/cache/block_cache.cpp b/src/system/kernel/cache/block_cache.cpp index 70e7e08a3d..bcec5fafae 100644 --- a/src/system/kernel/cache/block_cache.cpp +++ b/src/system/kernel/cache/block_cache.cpp @@ -4,10 +4,12 @@ */ +#include "BlockAllocator.h" + #include #include -#include +#include #include #include #include @@ -41,6 +43,7 @@ struct cache_transaction; struct cached_block; typedef DoublyLinkedListLink block_link; + struct cached_block { cached_block *next; // next in hash cached_block *transaction_next; @@ -66,6 +69,7 @@ struct block_cache { size_t block_size; int32 next_transaction_id; hash_table *transaction_hash; + BlockAllocator *allocator; }; typedef DoublyLinkedListdata); - free(block->original); + cache->allocator->Put(block->data); + cache->allocator->Put(block->original); #ifdef DEBUG_CHANGED - free(block->compare); + cache->allocator->Put(block->compare); #endif + free(block); } @@ -220,7 +224,7 @@ new_cached_block(block_cache *cache, off_t blockNumber, bool cleared = false) return NULL; if (!cleared) { - block->data = malloc(cache->block_size); + block->data = cache->allocator->Get(); if (block->data == NULL) { free(block); return NULL; @@ -297,7 +301,7 @@ put_cached_block(block_cache *cache, cached_block *block) write_cached_block(cache, block); panic("block_cache: supposed to be clean block was changed!\n"); - free(block->compare); + cache->allocator->Put(block->compare); block->compare = NULL; } #endif @@ -332,7 +336,7 @@ get_cached_block(block_cache *cache, off_t blockNumber, bool cleared = false) if (!allocated && block->data == NULL && !cleared) { // there is no block yet, but we need one - block->data = malloc(cache->block_size); + block->data = cache->allocator->Get(); if (block->data == NULL) return NULL; @@ -343,7 +347,7 @@ get_cached_block(block_cache *cache, off_t blockNumber, bool cleared = false) int32 blockSize = cache->block_size; if (read_pos(cache->fd, blockNumber * blockSize, block->data, blockSize) < blockSize) { - free_cached_block(block); + free_cached_block(cache, block); 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 (transactionID == -1) { if (cleared && block->data == NULL) { - block->data = malloc(cache->block_size); + block->data = cache->allocator->Get(); if (block->data == NULL) { put_cached_block(cache, block); 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) { // 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) { put_cached_block(cache, block); 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) { // 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) { put_cached_block(cache, block); return NULL; @@ -479,8 +483,14 @@ write_cached_block(block_cache *cache, cached_block *block, bool deleteTransacti } -// #pragma mark - -// Transactions +extern "C" status_t +block_cache_init(void) +{ + return init_block_allocator(); +} + + +// #pragma mark - public transaction extern "C" int32 @@ -567,7 +577,7 @@ cache_end_transaction(void *_cache, int32 id, transaction_notification_hook hook } if (block->original != NULL) { - free(block->original); + cache->allocator->Put(block->original); 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 @@ -666,7 +676,7 @@ block_cache_delete(void *_cache, bool allowWrites) uint32 cookie = 0; cached_block *block; 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) @@ -679,6 +689,7 @@ block_cache_delete(void *_cache, bool allowWrites) hash_uninit(cache->hash); hash_uninit(cache->transaction_hash); + BlockAllocator::PutAllocator(cache->allocator); benaphore_destroy(&cache->lock); delete cache; @@ -700,9 +711,13 @@ block_cache_create(int fd, off_t numBlocks, size_t blockSize) if (cache->transaction_hash == NULL) goto err2; - if (benaphore_init(&cache->lock, "block cache") < B_OK) + cache->allocator = BlockAllocator::GetAllocator(blockSize); + if (cache->allocator == NULL) goto err3; + if (benaphore_init(&cache->lock, "block cache") < B_OK) + goto err4; + cache->fd = fd; cache->max_blocks = numBlocks; cache->block_size = blockSize; @@ -710,6 +725,8 @@ block_cache_create(int fd, off_t numBlocks, size_t blockSize) return cache; +err4: + BlockAllocator::PutAllocator(cache->allocator); err3: hash_uninit(cache->transaction_hash); err2: @@ -801,7 +818,7 @@ block_cache_get_etc(void *_cache, off_t blockNumber, off_t base, off_t length) #ifdef DEBUG_CHANGED if (block->compare == NULL) - block->compare = malloc(cache->block_size); + block->compare = cache->allocator->Get(); if (block->compare != NULL) memcpy(block->compare, block->data, cache->block_size); #endif diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 7959e54e65..d122cb50de 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -2841,6 +2842,9 @@ vfs_init(kernel_args *args) if (mutex_init(&sVnodeMutex, "vfs_vnode_lock") < 0) panic("vfs_init: error allocating vnode lock\n"); + if (block_cache_init() != B_OK) + return B_ERROR; + return file_cache_init(); }