]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Initial shared memory pages implementation.
authorDmitry Kurochkin <dmitry.kurochkin@measurement-factory.com>
Wed, 6 Apr 2011 13:23:03 +0000 (17:23 +0400)
committerDmitry Kurochkin <dmitry.kurochkin@measurement-factory.com>
Wed, 6 Apr 2011 13:23:03 +0000 (17:23 +0400)
src/ipc/mem/Page.cc
src/ipc/mem/Page.h
src/ipc/mem/PagePool.cc
src/ipc/mem/PagePool.h
src/ipc/mem/PageStack.cc
src/ipc/mem/PageStack.h
src/ipc/mem/Pages.cc
src/ipc/mem/Pages.h

index 377b9bd53cbb507999a05f31590225c19f7094f7..e1fb96c88ca7c537d0f9bcfb3a18538a8c21d03f 100644 (file)
@@ -8,4 +8,12 @@
 #include "config.h"
 #include "ipc/mem/Page.h"
 
-// TODO: implement
+#if HAVE_IOSTREAM
+#include <iostream>
+#endif
+
+
+std::ostream &Ipc::Mem::operator <<(std::ostream &os, const PageId &page)
+{
+    return os << "sh_page" << page.pool << '.' << page.number;
+}
index cebce9f3eb72097b2736d8a8088433e14435d691..fabab730a78acbf71427410af3d05caca38434e0 100644 (file)
@@ -17,10 +17,10 @@ namespace Mem {
 /// Shared memory page identifier, address, or handler
 class PageId {
 public:
-    PageId(): segment(0), number(0) {}
+    PageId(): pool(0), number(0) {}
 
-    // uint32_t pool; ///< page pool ID within Squid; unused for now
-    uint32_t segment; ///< memory segment ID within the pool
+    uint32_t pool; ///< page pool ID within Squid
+    // uint32_t segment; ///< memory segment ID within the pool; unused for now
     uint32_t number; ///< page number within the segment
 };
 
index 5fb2288b1743eece4b5e3a173469e36b556cf1d0..f04da8db50cd704acec25e74a15b20fa2faa510e 100644 (file)
@@ -6,6 +6,78 @@
  */
 
 #include "config.h"
+#include "base/TextException.h"
+#include "ipc/mem/Page.h"
 #include "ipc/mem/PagePool.h"
 
-// TODO: implement
+
+static String
+PageIndexId(String id)
+{
+    id.append("-index");
+    return id;
+}
+
+
+// Ipc::Mem::PagePool
+
+Ipc::Mem::PagePool::PagePool(const String &id, const unsigned int capacity, const unsigned int pageSize):
+    pageIndex(PageIndexId(id), capacity),
+    shm(id.termedBuf())
+{
+    shm.create(pageSize * capacity + sizeof(Shared));
+    assert(shm.mem());
+    shared = new (shm.mem()) Shared(capacity, pageSize);
+}
+
+Ipc::Mem::PagePool::PagePool(const String &id):
+    pageIndex(PageIndexId(id)), shm(id.termedBuf())
+{
+    shm.open();
+    shared = reinterpret_cast<Shared *>(shm.mem());
+    assert(shared);
+}
+
+bool
+Ipc::Mem::PagePool::get(PageId &page)
+{
+    if (pageIndex.pop(page.number)) {
+        page.pool = shared->theId;
+        return true;
+    }
+    return false;
+}
+
+void
+Ipc::Mem::PagePool::put(PageId &page)
+{
+    Must(pageIdIsValid(page));
+    pageIndex.push(page.number);
+    page = PageId();
+}
+
+void *
+Ipc::Mem::PagePool::pagePointer(const PageId &page)
+{
+    Must(pageIdIsValid(page));
+    return shared->theBuf + shared->thePageSize * (page.number - 1);
+}
+
+bool
+Ipc::Mem::PagePool::pageIdIsValid(const PageId &page) const
+{
+    return page.pool == shared->theId &&
+        0 < page.number && page.number <= shared->theCapacity;
+}
+
+
+// Ipc::Mem::PagePool::Shared
+
+static unsigned int LastPagePoolId = 0;
+
+Ipc::Mem::PagePool::Shared::Shared(const unsigned int aCapacity, const unsigned int aPageSize):
+    theId(++LastPagePoolId), theCapacity(aCapacity), thePageSize(aPageSize)
+{
+    if (LastPagePoolId + 1 == 0)
+        ++LastPagePoolId; // skip zero pool id
+}
index 6bdf638a574b4ec26c4648fe218efae336c57d77..fdccf893577420b1f81c2d8cbb48d6ce68ab9e9d 100644 (file)
@@ -6,33 +6,51 @@
 #ifndef SQUID_IPC_MEM_PAGE_POOL_H
 #define SQUID_IPC_MEM_PAGE_POOL_H
 
-#include "ipc/mem/Page.h"
+#include "ipc/mem/PageStack.h"
 #include "ipc/mem/Segment.h"
 
 namespace Ipc {
 
 namespace Mem {
 
+class PageId;
+
 /// Atomic container of shared memory pages. Implemented using a collection of
-/// Segments, each with a PageStack index of free pages.
+/// Segments, each with a PageStack index of free pages. All pools must be
+/// created by a single process.
 class PagePool {
 public:
-    /// creates a new shared page pool that can hold up to capacity pages
-    PagePool(const String &id, const unsigned int capacity);
+    /// creates a new shared page pool that can hold up to capacity pages of pageSize size
+    PagePool(const String &id, const unsigned int capacity, const unsigned int pageSize);
     /// attaches to the identified shared page pool
     PagePool(const String &id);
 
+    unsigned int capacity() const { return shared->theCapacity; }
+    unsigned int pageSize() const { return shared->thePageSize; }
+
     /// sets page ID and returns true unless no free pages are found
     bool get(PageId &page);
     /// makes identified page available as a free page to future get() callers
-    void put(const PageId &page);
+    void put(PageId &page);
+    /// converts page handler into a temporary writeable shared memory pointer
+    void *pagePointer(const PageId &page);
 
 private:
-    Segment meta; ///< shared memory segment to store our metadata
-    /// TODO: Shared *shared; ///< our metadata, shared among all pool users
+    inline bool pageIdIsValid(const PageId &page) const;
+
+    struct Shared {
+        Shared(const unsigned int aCapacity, const unsigned int aPageSize);
+
+        const unsigned int theId; ///< pool id
+        const unsigned int theCapacity; ///< number of pages in the pool
+        const unsigned int thePageSize; ///< page size
+
+        char *theBuf[]; ///< pages storage
+    };
 
-    /// TODO: typedef collection<Segment*> Store; ///< storage for pages
-    /// TODO: Store store; ///< pages (with free page indexes)
+    PageStack pageIndex; ///< free pages index
+    Segment shm; ///< shared memory segment to store metadata (and pages)
+    Shared *shared; ///< our metadata and page storage, shared among all stack users
 };
 
 } // namespace Mem
index bd11aa70235f7a56f89538721d9769ecd9dcd012..a31d774f2bc634a7ac5c7c049aa4e3b0190a847a 100644 (file)
@@ -71,6 +71,7 @@ void
 Ipc::Mem::PageStack::push(const Value value)
 {
     Must(value != Writable);
+    Must(value <= shared->theCapacity);
     // find a Writable slot, starting with theFirstWritable and going right
     while (shared->theSize < shared->theCapacity) {
         const Offset idx = shared->theFirstWritable;
index ae3b9b0712f6629d59e28020abebfa2a3a3f2a22..d7a8bd7fe9eb6c49c98c0620ec5e4c4b15b684c1 100644 (file)
@@ -34,7 +34,7 @@ private:
     typedef unsigned int Offset; ///< stack index type
 
     struct Shared {
-        Shared(const unsigned int theCapacity);
+        Shared(const unsigned int aCapacity);
 
         // these help iterate the stack in search of a free spot or a page
         Offset next(const Offset idx) const { return (idx + 1) % theCapacity; }
index 83d4655f326df436b668ead6f80da1f0445a7c38..4b95a08d21a9579f50d3fd515d2522bc49b9743d 100644 (file)
@@ -6,7 +6,65 @@
  */
 
 #include "config.h"
+#include "base/TextException.h"
+#include "ipc/mem/PagePool.h"
 #include "ipc/mem/Pages.h"
+#include "structs.h"
+#include "SwapDir.h"
 
-// TODO: Implement using a single PagePool instance, for now.
+// Uses a single PagePool instance, for now.
 // Eventually, we may have pools dedicated to memory caching, disk I/O, etc.
+
+// TODO: make pool id more unique so it does not conflict with other Squids?
+static const String PagePoolId = "squid-page-pool";
+static Ipc::Mem::PagePool *ThePagePool = 0;
+
+// XXX: temporary function until we have a better page size handling
+static unsigned int
+calculatePageSize()
+{
+    unsigned int max_objsize = 0;
+    for (int i = 0; i < Config.cacheSwap.n_configured; ++i) {
+        const SwapDir *const sd = dynamic_cast<SwapDir *>(INDEXSD(i));
+        if (sd->max_objsize > max_objsize)
+            max_objsize = sd->max_objsize;
+    }
+    return max_objsize;
+}
+
+void
+Ipc::Mem::Init()
+{
+    Must(!ThePagePool);
+    // XXX: pool capacity and page size should be configurable/meaningful
+    ThePagePool = new PagePool(PagePoolId, 1024, calculatePageSize());
+}
+
+void
+Ipc::Mem::Attach()
+{
+    Must(!ThePagePool);
+    // TODO: make pool id more unique so it does not conflict with other Squid instances?
+    ThePagePool = new PagePool(PagePoolId);
+}
+
+bool
+Ipc::Mem::GetPage(PageId &page)
+{
+    Must(ThePagePool);
+    return ThePagePool->get(page);
+}
+
+void
+Ipc::Mem::PutPage(PageId &page)
+{
+    Must(ThePagePool);
+    ThePagePool->put(page);
+}
+
+void *
+Ipc::Mem::PagePointer(const PageId &page)
+{
+    Must(ThePagePool);
+    return ThePagePool->pagePointer(page);
+}
index f6c4a1e521d7b72edc87b04859781a754865ba6e..c18e14903c1f5c953d4db415d47d0480623b697a 100644 (file)
@@ -25,7 +25,7 @@ void Attach();
 bool GetPage(PageId &page);
 
 /// makes identified page available as a free page to future GetPage() callers
-void PutPage(const PageId &page);
+void PutPage(PageId &page);
 
 /// converts page handler into a temporary writeable shared memory pointer
 void *PagePointer(const PageId &page);