]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Shared Rock::DirMap version 2.
authorDmitry Kurochkin <dmitry.kurochkin@measurement-factory.com>
Sun, 30 Jan 2011 04:35:36 +0000 (07:35 +0300)
committerDmitry Kurochkin <dmitry.kurochkin@measurement-factory.com>
Sun, 30 Jan 2011 04:35:36 +0000 (07:35 +0300)
src/fs/rock/RockDirMap.cc
src/fs/rock/RockDirMap.h

index af7aee090bd81734c776a6bbcc5ad6d635c8c690..9e63cd22f4dfef8a142f659e51e4869bfff009c8 100644 (file)
@@ -25,6 +25,85 @@ Rock::DirMap::DirMap(const int id):
     shared = reinterpret_cast<Shared *>(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<const uint64_t *>(&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<const uint64_t *>(&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)
 {
 }
index 9efa6b79e29f96db1ee6c0d795b420e622572d3a..99c0992fd10ea0ebd3e060acb0b7595d2cb4eb74 100644 (file)
@@ -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<uint8_t> state; ///< slot state
+        AtomicWord readLevel; ///< read level
+        AtomicWordT<uint64_t> key[2]; ///< MD5 entry key
+        StoreEntryBasics seBasics; ///< basic store entry data
+    };
 
-    typedef AtomicWordT<uint8_t> 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
 };