/* * Copyright 2007, Hugo Santos. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: * Hugo Santos, hugosantos@gmail.com */ #ifndef _SLAB_HASH_STRATEGY_H_ #define _SLAB_HASH_STRATEGY_H_ #include #include // for TypedCache #include #include struct BaseHashCacheStrategy { struct Link : cache_object_link, HashTableLink { cache_slab *slab; void *buffer; }; struct HashTableDefinition { typedef BaseHashCacheStrategy ParentType; typedef void * KeyType; typedef Link ValueType; HashTableDefinition(BaseHashCacheStrategy *_parent) : parent(_parent) {} size_t HashKey(void *key) const { return (((uint8_t *)key) - ((uint8_t *)0)) >> parent->fLowerBoundary; } size_t Hash(Link *value) const { return HashKey(value->buffer); } bool Compare(void *key, Link *value) const { return value->buffer == key; } HashTableLink *GetLink(Link *value) const { return value; } BaseHashCacheStrategy *parent; }; // for g++ 2.95 friend class HashTableDefinition; typedef OpenHashTable HashTable; static inline int __Fls0(size_t value) { if (value == 0) return -1; int bit; for (bit = 0; value != 1; bit++) value >>= 1; return bit; } BaseHashCacheStrategy(base_cache *parent) : fHashTable(this), fLowerBoundary(__Fls0(parent->object_size)) {} void *Object(cache_object_link *link) const { return ((Link *)link)->buffer; } CacheObjectInfo ObjectInformation(void *object) const { Link *link = _Linkage(object); return CacheObjectInfo(link->slab, link); } protected: Link *_Linkage(void *object) const { Link *link = fHashTable.Lookup(object); if (link == NULL) panic("slab: missing buffer link from hash table."); return link; } static cache_object_link *_Linkage(void *_this, void *object) { return ((BaseHashCacheStrategy *)_this)->_Linkage(object); } HashTable fHashTable; const size_t fLowerBoundary; }; template struct HashCacheStrategy : BaseCacheStrategy, BaseHashCacheStrategy { typedef typename BaseCacheStrategy::BaseSlab BaseSlab; typedef typename BaseCacheStrategy::Slab Slab; typedef HashCacheStrategy Strategy; HashCacheStrategy(base_cache *parent) : BaseCacheStrategy(parent), BaseHashCacheStrategy(parent), fSlabCache("slab cache", 0), fLinkCache("link cache", 0) {} static size_t RequiredSpace(size_t objectSize) { return objectSize; } BaseSlab *NewSlab(uint32_t flags) { size_t byteCount = _SlabSize(); Slab *slab = fSlabCache.Alloc(flags); if (slab == NULL) return NULL; void *pages; if (Backend::AllocatePages(Parent(), &slab->id, &pages, byteCount, flags) < B_OK) { fSlabCache.Free(slab); return NULL; } // it's very important that we cast this to BaseHashCacheStrategy // so we get the proper instance offset through void * cache_slab *result = BaseCacheStrategy::_ConstructSlab(slab, pages, _SlabSize(), (BaseHashCacheStrategy *)this, _Linkage, _PrepareObject, _UnprepareObject); if (result == NULL) { Backend::FreePages(Parent(), slab->id); fSlabCache.Free(slab); } return result; } void ReturnSlab(BaseSlab *slab) { _ClearSlab(slab->pages, _SlabSize()); BaseCacheStrategy::_DestructSlab(slab); fSlabCache.Free((Slab *)slab); } private: size_t _SlabSize() const { return BaseCacheStrategy::SlabSize(0); } base_cache *Parent() const { return BaseCacheStrategy::Parent(); } static status_t _PrepareObject(void *_self, cache_slab *slab, void *object) { BaseHashCacheStrategy *base = (BaseHashCacheStrategy *)_self; Strategy *self = (Strategy *)base; Link *link = self->fLinkCache.Alloc(CACHE_DONT_SLEEP); if (link == NULL) return B_NO_MEMORY; link->slab = slab; link->buffer = object; self->fHashTable.Insert(link); return B_OK; } static void _UnprepareObject(void *_self, cache_slab *slab, void *object) { BaseHashCacheStrategy *base = (BaseHashCacheStrategy *)_self; ((Strategy *)base)->_UnprepareObject(object); } void _UnprepareObject(void *object) { Link *link = _Linkage(object); fHashTable.Remove(link); fLinkCache.Free(link); } void _ClearSlab(void *pages, size_t size) { uint8_t *data = (uint8_t *)pages; uint8_t *end = data + size; for (uint8_t *it = data; it < end; it += Parent()->object_size) _UnprepareObject(it); } TypedCache fSlabCache; TypedCache fLinkCache; }; #endif