From: Dmitry Kurochkin Date: Sun, 30 Jan 2011 04:35:36 +0000 (+0300) Subject: Shared Rock::DirMap version 2. X-Git-Tag: take01~21 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3333a25664f8a122b4a9c97905a96fc3eafbf329;p=thirdparty%2Fsquid.git Shared Rock::DirMap version 2. --- diff --git a/src/fs/rock/RockDirMap.cc b/src/fs/rock/RockDirMap.cc index af7aee090b..9e63cd22f4 100644 --- a/src/fs/rock/RockDirMap.cc +++ b/src/fs/rock/RockDirMap.cc @@ -25,6 +25,85 @@ Rock::DirMap::DirMap(const int id): shared = reinterpret_cast(shm.mem()); } +bool +Rock::DirMap::initialize(const cache_key *const key, const StoreEntryBasics &seBasics) +{ + Slot &s = slot(key); + if (s.state.swap_if(Slot::WaitingToBeInitialized, Slot::Initializing)) { + assert(!s.readLevel); + s.setKey(key); + s.seBasics = seBasics; + ++shared->count; + assert(s.state.swap_if(Slot::Initializing, Slot::Usable)); + return true; + } + return false; +} + +bool +Rock::DirMap::initialize(const int idx) +{ + return valid(idx) && + shared->slots[idx].state.swap_if(Slot::WaitingToBeInitialized, Slot::Empty); +} + +StoreEntryBasics * +Rock::DirMap::add(const cache_key *const key) +{ + Slot &s = slot(key); + if (s.state.swap_if(Slot::Empty, Slot::Writing)) { + assert(!s.readLevel); + s.setKey(key); + return &s.seBasics; + } + return 0; +} + +void +Rock::DirMap::added(const cache_key *const key) +{ + Slot &s = slot(key); + assert(s.checkKey(key)); + assert(s.state == Slot::Writing); + assert(!s.readLevel); + ++shared->count; + assert(s.state.swap_if(Slot::Writing, Slot::Usable)); +} + +bool +Rock::DirMap::free(const cache_key *const key) +{ + if (open(key)) { + slot(key).state.swap_if(Slot::Usable, Slot::WaitingToBeFreed); + close(key); + } + return false; +} + +const StoreEntryBasics * +Rock::DirMap::open(const cache_key *const key) +{ + Slot &s = slot(key); + if (s.checkKey(key) && s.state == Slot::Usable) { + ++s.readLevel; + if (s.checkKey(key) && s.state == Slot::Usable) + return &s.seBasics; + --s.readLevel; + freeIfNeeded(s); + } + return 0; +} + +void +Rock::DirMap::close(const cache_key *const key) +{ + Slot &s = slot(key); + assert(s.checkKey(key)); + assert(s.readLevel > 0); + --s.readLevel; + freeIfNeeded(s); +} + int Rock::DirMap::entryLimit() const { @@ -50,93 +129,57 @@ Rock::DirMap::valid(const int pos) const } int -Rock::DirMap::useNext() +Rock::DirMap::AbsoluteEntryLimit() { - assert(!full()); - const int next = findNext(); - assert(valid(next)); // because we were not full - use(next); - return next; + const int sfilenoMax = 0xFFFFFF; // Core sfileno maximum + return sfilenoMax; } int -Rock::DirMap::AbsoluteEntryLimit() +Rock::DirMap::slotIdx(const cache_key *const key) const { - const int sfilenoMax = 0xFFFFFF; // Core sfileno maximum - return sfilenoMax; + const uint64_t *const k = reinterpret_cast(&key); + // TODO: use a better hash function + return (k[0] + k[1]) % shared->limit; } -void -Rock::DirMap::use(const int pos) +Rock::DirMap::Slot & +Rock::DirMap::slot(const cache_key *const key) { - if (!has(pos)) { - assert(valid(pos)); - shared->slots[pos] = 1; - ++shared->count; - debugs(8, 6, HERE << pos); - } else { - debugs(8, 3, HERE << pos << " in vain"); - } + return shared->slots[slotIdx(key)]; } void -Rock::DirMap::clear(const int pos) +Rock::DirMap::freeIfNeeded(Slot &s) { - if (has(pos)) { - shared->slots[pos] = 0; + if (!s.readLevel && + s.state.swap_if(Slot::WaitingToBeFreed, Slot::Freeing)) { + memset(s.key, 0, sizeof(s.key)); + memset(&s.seBasics, 0, sizeof(s.seBasics)); --shared->count; - debugs(8, 6, HERE << pos); - } else { - debugs(8, 3, HERE << pos << " in vain"); - assert(valid(pos)); + s.state.swap_if(Slot::Freeing, Slot::Empty); } - if (shared->hintPast < 0) - shared->hintPast = pos; // remember cleared slot } -bool -Rock::DirMap::has(const int pos) const +int +Rock::DirMap::SharedSize(const int limit) { - if (!valid(pos)) // the only place where we are forgiving - return false; - - return shared->slots[pos]; + return sizeof(Shared) + limit * sizeof(Slot); } -/// low-level empty-slot search routine, uses and updates hints -int -Rock::DirMap::findNext() const -{ - // try the clear-based hint, if any - if (shared->hintPast >= 0) { - const int result = shared->hintPast; - shared->hintPast = -1; // assume used; or we could update it in set() - if (valid(result) && !has(result)) - return result; - } - - // adjust and try the scan-based hint - if (!valid(shared->hintNext)) - shared->hintNext = 0; - - for (int i = 0; i < shared->limit; ++i) { - if (!has(shared->hintNext)) - return shared->hintNext++; - - shared->hintNext = (shared->hintNext + 1) % shared->limit; - } - - // the map is full - return -1; +void +Rock::DirMap::Slot::setKey(const cache_key *const aKey) +{ + memcpy(key, &aKey, sizeof(key)); } -int -Rock::DirMap::SharedSize(const int limit) +bool +Rock::DirMap::Slot::checkKey(const cache_key *const aKey) const { - return sizeof(Shared) + limit * sizeof(Slot); + const uint64_t *const k = reinterpret_cast(&key); + return k[0] == key[0] && k[1] == key[1]; } -Rock::DirMap::Shared::Shared(const int aLimit): - hintPast(-1), hintNext(0), limit(aLimit), count(0) +Rock::DirMap::Shared::Shared(const int aLimit): limit(aLimit), count(0) { } diff --git a/src/fs/rock/RockDirMap.h b/src/fs/rock/RockDirMap.h index 9efa6b79e2..99c0992fd1 100644 --- a/src/fs/rock/RockDirMap.h +++ b/src/fs/rock/RockDirMap.h @@ -4,6 +4,19 @@ #include "ipc/AtomicWord.h" #include "ipc/SharedMemory.h" +class StoreEntryBasics { +public: + /* START OF ON-DISK STORE_META_STD TLV field */ + time_t timestamp; + time_t lastref; + time_t expires; + time_t lastmod; + uint64_t swap_file_sz; + u_short refcount; + u_short flags; + /* END OF ON-DISK STORE_META_STD */ +}; + namespace Rock { /// \ingroup Rock @@ -14,39 +27,68 @@ public: DirMap(const int id, const int limit); ///< create a new shared DirMap DirMap(const int id); ///< open an existing shared DirMap + /// initialize usable slot + bool initialize(const cache_key *const key, const StoreEntryBasics &seBasics); + /// initialize empty slot + bool initialize(const int idx); + + /// start adding a new entry + StoreEntryBasics *add(const cache_key *const key); + /// finish adding a new entry + void added(const cache_key *const key); + + /// mark slot as waiting to be freed, will be freed when no one uses it + bool free(const cache_key *const key); + + /// open slot for reading, increments read level + const StoreEntryBasics *open(const cache_key *const key); + /// close slot after reading, decrements read level + void close(const cache_key *const key); + bool full() const; ///< there are no empty slots left - bool has(int n) const; ///< whether slot n is occupied bool valid(int n) const; ///< whether n is a valid slot coordinate int entryCount() const; ///< number of used slots int entryLimit() const; ///< maximum number of slots that can be used - void use(int n); ///< mark slot n as used - void clear(int n); ///< mark slot n as unused - int useNext(); ///< finds and uses an empty slot, returning its coordinate - static int AbsoluteEntryLimit(); ///< maximum entryLimit() possible private: - int findNext() const; - - static int SharedSize(const int limit); - - SharedMemory shm; ///< shared memory segment + struct Slot { + enum { + WaitingToBeInitialized, + Initializing, + Empty, + Writing, + Usable, + WaitingToBeFreed, + Freeing + }; + + void setKey(const cache_key *const aKey); + bool checkKey(const cache_key *const aKey) const; + + AtomicWordT state; ///< slot state + AtomicWord readLevel; ///< read level + AtomicWordT key[2]; ///< MD5 entry key + StoreEntryBasics seBasics; ///< basic store entry data + }; - typedef AtomicWordT Slot; struct Shared { Shared(const int aLimit); - /// unreliable next empty slot suggestion #1 (clear based) - mutable AtomicWord hintPast; - ///< unreliable next empty slot suggestion #2 (scan based) - mutable AtomicWord hintNext; - - AtomicWord limit; ///< maximum number of map slots + const AtomicWord limit; ///< maximum number of map slots AtomicWord count; ///< current number of map slots Slot slots[]; ///< slots storage }; + + int slotIdx(const cache_key *const key) const; + Slot &slot(const cache_key *const key); + void freeIfNeeded(Slot &s); + + static int SharedSize(const int limit); + + SharedMemory shm; ///< shared memory segment Shared *shared; ///< pointer to shared memory };