]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Separate shared page limits for different purposes.
authorDmitry Kurochkin <dmitry.kurochkin@measurement-factory.com>
Mon, 27 Jun 2011 20:58:29 +0000 (00:58 +0400)
committerDmitry Kurochkin <dmitry.kurochkin@measurement-factory.com>
Mon, 27 Jun 2011 20:58:29 +0000 (00:58 +0400)
The patch implements separate level counters for shared pages
with different purpose (i.e. memory cache and IPC I/O).  A new
purpose parameter was added to Ipc::Mem::GetPage() function to
update the level and check the limits.  After the change, memory
cache and IPC I/O limits are separate and do not affect each
other, i.e. full memory cache does not eat all IPC I/O pages.

src/DiskIO/IpcIo/IpcIoFile.cc
src/MemStore.cc
src/fs/rock/RockSwapDir.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 a9a2bd497c5e8a65953425c0d9df98c007cb827d..757571d19e1e5f181614199e8cd5f89b8e1b90f6 100644 (file)
@@ -309,9 +309,9 @@ IpcIoFile::push(IpcIoPendingRequest *const pending)
             ipcIo.len = pending->readRequest->len;
         } else { // pending->writeRequest
             Must(pending->writeRequest->len <= Ipc::Mem::PageSize());
-            if (!Ipc::Mem::GetPage(ipcIo.page)) {
+            if (!Ipc::Mem::GetPage(Ipc::Mem::PageId::ioPage, ipcIo.page)) {
                 ipcIo.len = 0;
-                throw TexcHere("run out of shared memory pages");
+                throw TexcHere("run out of shared memory pages for IPC I/O");
             }
             ipcIo.command = IpcIo::cmdWrite;
             ipcIo.offset = pending->writeRequest->offset;
@@ -551,9 +551,9 @@ static int TheFile = -1; ///< db file descriptor
 static void
 diskerRead(IpcIoMsg &ipcIo)
 {
-    if (!Ipc::Mem::GetPage(ipcIo.page)) {
+    if (!Ipc::Mem::GetPage(Ipc::Mem::PageId::ioPage, ipcIo.page)) {
         ipcIo.len = 0;
-        debugs(47,5, HERE << "run out of shared memory pages");
+        debugs(47,5, HERE << "run out of shared memory pages for IPC I/O");
         return;
     }
 
index a59e4a0b25f4112ea20ffef4948b6b2c243a03e4..e7621689d44aa93b65d4f09fc111790d48efc94c 100644 (file)
@@ -290,8 +290,7 @@ bool
 MemStore::copyToShm(StoreEntry &e, MemStoreMap::Extras &extras)
 {
     Ipc::Mem::PageId page;
-    if (Ipc::Mem::CachePageLevel() > Ipc::Mem::CachePageLimit() ||
-        !Ipc::Mem::GetPage(page)) {
+    if (!Ipc::Mem::GetPage(Ipc::Mem::PageId::cachePage, page)) {
         debugs(20, 5, HERE << "No mem-cache page for " << e);
         return false; // GetPage is responsible for any cleanup on failures
     }
index 9e74a296fecc03c7f88b878904ec464b9528832a..f95f864b47d837eeaca92b0598c85ced62361f59 100644 (file)
@@ -354,8 +354,10 @@ Rock::SwapDir::canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load)
     if (!map)
         return false;
 
-    if (Ipc::Mem::IoPageLevel() > Ipc::Mem::IoPageLimit()) {
-        debugs(47, 5, HERE << "too few shared pages for IPC IO left");
+    // Do not start I/O transaction is there are less than 10% free pages left.
+    // TODO: reserve page instead
+    if (Ipc::Mem::PageLevel(Ipc::Mem::PageId::ioPage) >= 0.9 * Ipc::Mem::PageLimit(Ipc::Mem::PageId::ioPage)) {
+        debugs(47, 5, HERE << "too few shared pages for IPC I/O left");
         return false;
     }
 
@@ -445,8 +447,10 @@ Rock::SwapDir::openStoreIO(StoreEntry &e, StoreIOState::STFNCB *cbFile, StoreIOS
         return NULL;
     }
 
-    if (Ipc::Mem::IoPageLevel() > Ipc::Mem::IoPageLimit()) {
-        debugs(47, 5, HERE << "too few shared pages for IPC IO left");
+    // Do not start I/O transaction is there are less than 10% free pages left.
+    // TODO: reserve page instead
+    if (Ipc::Mem::PageLevel(Ipc::Mem::PageId::ioPage) >= 0.9 * Ipc::Mem::PageLimit(Ipc::Mem::PageId::ioPage)) {
+        debugs(47, 5, HERE << "too few shared pages for IPC I/O left");
         return NULL;
     }
 
index b8edf95b9e0e3868f42852f5e6fea3f5b054a988..b2f69df911052d780141a5b916eaafd1c702c600 100644 (file)
@@ -17,13 +17,16 @@ namespace Mem {
 /// Shared memory page identifier, address, or handler
 class PageId {
 public:
-    PageId(): pool(0), number(0) {}
+    PageId(): pool(0), number(0), purpose(maxPurpose) {}
 
     operator bool() const { return pool && number; }
 
     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
+
+    enum Purpose { cachePage, ioPage, maxPurpose };
+    Purpose purpose; ///< page purpose
 };
 
 /// writes page address (e.g., "sh_page5.3"), for debugging
index 843b28f1aea1334887af23a6fec63ec20a151d1e..36b5231775bbf1c7f8e887fbcb8bbbfb0ef759d2 100644 (file)
@@ -23,11 +23,43 @@ Ipc::Mem::PagePool::Init(const char *const id, const unsigned int capacity, cons
 }
 
 Ipc::Mem::PagePool::PagePool(const char *const id):
-    pageIndex(shm_old(PageStack)(id))
+    pageIndex(shm_old(PageStack)(id)),
+    theLevels(reinterpret_cast<AtomicWord *>(
+              reinterpret_cast<char *>(pageIndex.getRaw()) +
+              pageIndex->stackSize())),
+    theBuf(reinterpret_cast<char *>(theLevels + PageId::maxPurpose))
 {
-    const size_t pagesDataOffset =
-        pageIndex->sharedMemorySize() - capacity() * pageSize();
-    theBuf = reinterpret_cast<char *>(pageIndex.getRaw()) + pagesDataOffset;
+}
+
+size_t
+Ipc::Mem::PagePool::level(const int purpose) const
+{
+    Must(0 <= purpose && purpose < PageId::maxPurpose);
+    return theLevels[purpose];
+}
+
+bool
+Ipc::Mem::PagePool::get(const PageId::Purpose purpose, PageId &page)
+{
+    Must(0 <= purpose && purpose < PageId::maxPurpose);
+    if (pageIndex->pop(page)) {
+        page.purpose = purpose;
+        ++theLevels[purpose];
+        return true;
+    }
+    return false;
+}
+
+void
+Ipc::Mem::PagePool::put(PageId &page)
+{
+    if (!page)
+        return;
+
+    Must(0 <= page.purpose && page.purpose < PageId::maxPurpose);
+    --theLevels[page.purpose];
+    page.purpose = PageId::maxPurpose;
+    return pageIndex->push(page);
 }
 
 char *
index f2b0ef827b0ef4f8ecf6e80672f54e3affacc324..44a59740ad8201fbd2bee88687d5eb59f91cc08b 100644 (file)
@@ -6,6 +6,7 @@
 #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/Pointer.h"
 
@@ -28,17 +29,23 @@ public:
     size_t pageSize() const { return pageIndex->pageSize(); }
     /// lower bound for the number of free pages
     unsigned int size() const { return pageIndex->size(); }
+    /// approximate number of shared memory pages used now
+    size_t level() const { return capacity() - size(); }
+    /// approximate number of shared memory pages used now for given purpose
+    size_t level(const int purpose) const;
 
     /// sets page ID and returns true unless no free pages are found
-    bool get(PageId &page) { return pageIndex->pop(page); }
+    bool get(const PageId::Purpose purpose, PageId &page);
     /// makes identified page available as a free page to future get() callers
-    void put(PageId &page) { return pageIndex->push(page); }
+    void put(PageId &page);
     /// converts page handler into a temporary writeable shared memory pointer
     char *pagePointer(const PageId &page);
 
 private:
     Ipc::Mem::Pointer<PageStack> pageIndex; ///< free pages index
-    char *theBuf; ///< pages storage
+    /// number of shared memory pages used now for each purpose
+    AtomicWord *const theLevels;
+    char *const theBuf; ///< pages storage
 };
 
 } // namespace Mem
index 6061e3fbca04697befa40a3380a301a16a4cc5d5..07789d55adfba947d6c52d886490d35c94874a71 100644 (file)
@@ -113,5 +113,19 @@ Ipc::Mem::PageStack::sharedMemorySize() const
 size_t
 Ipc::Mem::PageStack::SharedMemorySize(const uint32_t, const unsigned int capacity, const size_t pageSize)
 {
-    return sizeof(PageStack) + capacity * (sizeof(Item) + pageSize);
+    const size_t levelsSize = PageId::maxPurpose * sizeof(AtomicWord);
+    const size_t pagesDataSize = capacity * pageSize;
+    return StackSize(capacity) + pagesDataSize + levelsSize;
+}
+
+size_t
+Ipc::Mem::PageStack::StackSize(const unsigned int capacity)
+{
+    return sizeof(PageStack) + capacity * sizeof(Item);
+}
+
+size_t
+Ipc::Mem::PageStack::stackSize() const
+{
+    return StackSize(theCapacity);
 }
index 8c571702c909af3d891595c72169d8ac5d8f32e2..d64cbd723d2e0ec75c43d3e2e13e3e0c5be2a1d5 100644 (file)
@@ -39,6 +39,11 @@ public:
     static size_t SharedMemorySize(const uint32_t aPoolId, const unsigned int capacity, const size_t pageSize);
     size_t sharedMemorySize() const;
 
+    /// shared memory size required only by PageStack, excluding
+    /// shared counters and page data
+    static size_t StackSize(const unsigned int capacity);
+    size_t stackSize() const;
+
 private:
     /// stack index and size type (may temporary go negative)
     typedef int Offset;
index 312c186e34fe44e2e8e98dbc5dd260cc205fe17c..cdd13af5181a763a4b3170d55e5f91842b13835a 100644 (file)
@@ -27,9 +27,10 @@ Ipc::Mem::PageSize() {
 }
 
 bool
-Ipc::Mem::GetPage(PageId &page)
+Ipc::Mem::GetPage(const PageId::Purpose purpose, PageId &page)
 {
-    return ThePagePool ? ThePagePool->get(page) : false;
+    return ThePagePool && PagesAvailable(purpose) > 0 ?
+        ThePagePool->get(purpose, page) : false;
 }
 
 void
@@ -49,44 +50,41 @@ Ipc::Mem::PagePointer(const PageId &page)
 size_t
 Ipc::Mem::PageLimit()
 {
-    return ThePagePool ? ThePagePool->capacity() : 0;
+    size_t limit = 0;
+    for (int i = 0; i < PageId::maxPurpose; ++i)
+        limit += PageLimit(i);
+    return limit;
 }
 
 size_t
-Ipc::Mem::CachePageLimit()
+Ipc::Mem::PageLimit(const int purpose)
 {
-    // TODO: adjust cache_mem description to say that in SMP mode,
-    // in-transit objects are not allocated using cache_mem. Eventually,
-    // they should not use cache_mem even if shared memory is not used:
-    // in-transit objects have nothing to do with caching.
-    return Config.memMaxSize > 0 ? Config.memMaxSize / PageSize() : 0;
-}
-
-size_t
-Ipc::Mem::IoPageLimit()
-{
-    // XXX: this should be independent from memory cache pages
-    return CachePageLimit();
+    switch (purpose) {
+    case PageId::cachePage:
+        // TODO: adjust cache_mem description to say that in SMP mode,
+        // in-transit objects are not allocated using cache_mem. Eventually,
+        // they should not use cache_mem even if shared memory is not used:
+        // in-transit objects have nothing to do with caching.
+        return Config.memMaxSize > 0 ? Config.memMaxSize / PageSize() : 0;
+    case PageId::ioPage:
+        // XXX: this should be independent from memory cache pages
+        return PageLimit(PageId::cachePage) * 0.5;
+    default:
+        Must(false);
+    }
+    return 0;
 }
 
 size_t
 Ipc::Mem::PageLevel()
 {
-    return ThePagePool ? ThePagePool->capacity() - ThePagePool->size() : 0;
-}
-
-size_t
-Ipc::Mem::CachePageLevel()
-{
-    // TODO: make a separate counter for shared memory pages for memory cache
-    return PageLevel();
+    return ThePagePool ? ThePagePool->level() : 0;
 }
 
 size_t
-Ipc::Mem::IoPageLevel()
+Ipc::Mem::PageLevel(const int purpose)
 {
-    // TODO: make a separate counter for shared memory pages for IPC I/O
-    return PageLevel();
+    return ThePagePool ? ThePagePool->level(purpose) : 0;
 }
 
 /// initializes shared memory pages
@@ -115,7 +113,7 @@ void SharedMemPagesRr::run(const RunnerRegistry &)
     if (Config.memMaxSize <= 0)
         return;
 
-    if (Ipc::Mem::CachePageLimit() <= 0) {
+    if (Ipc::Mem::PageLimit() <= 0) {
         if (IamMasterProcess()) {
             debugs(54, DBG_IMPORTANT, "WARNING: mem-cache size is too small ("
                    << (Config.memMaxSize / 1024.0) << " KB), should be >= " <<
@@ -126,9 +124,7 @@ void SharedMemPagesRr::run(const RunnerRegistry &)
 
     if (IamMasterProcess()) {
         Must(!owner);
-        // reserve 10% for IPC I/O
-        const size_t capacity = Ipc::Mem::CachePageLimit() * 1.1;
-        owner = Ipc::Mem::PagePool::Init(PagePoolId, capacity, Ipc::Mem::PageSize());
+        owner = Ipc::Mem::PagePool::Init(PagePoolId, Ipc::Mem::PageLimit(), Ipc::Mem::PageSize());
     }
 
     Must(!ThePagePool);
index a8e06f0b8bd052623c11f8a433ff72c3b8ab42b8..e447c51f20fca30c0cfa9a33ab400afc592cdb84 100644 (file)
@@ -6,16 +6,16 @@
 #ifndef SQUID_IPC_MEM_PAGES_H
 #define SQUID_IPC_MEM_PAGES_H
 
+#include "ipc/mem/Page.h"
+
 namespace Ipc {
 
 namespace Mem {
 
-class PageId;
-
 /* Single page manipulation */
 
 /// sets page ID and returns true unless no free pages are found
-bool GetPage(PageId &page);
+bool GetPage(const PageId::Purpose purpose, PageId &page);
 
 /// makes identified page available as a free page to future GetPage() callers
 void PutPage(PageId &page);
@@ -29,32 +29,22 @@ char *PagePointer(const PageId &page);
 /// the total number of shared memory pages that can be in use at any time
 size_t PageLimit();
 
-/// the total number of shared memory pages for memory cache that can be in
-/// use at any time
-size_t CachePageLimit();
-
-/// the total number of shared memory pages for IPC I/O that can be in
-/// use at any time
-size_t IoPageLimit();
+/// the total number of shared memory pages that can be in use at any
+/// time for given purpose
+size_t PageLimit(const int purpose);
 
 /// approximate total number of shared memory pages used now
 size_t PageLevel();
 
-/// approximate total number of shared memory pages for memory cache used now
-size_t CachePageLevel();
-
-/// approximate total number of shared memory pages for IPC I/O used now
-size_t IoPageLevel();
+/// approximate total number of shared memory pages used now for given purpose
+size_t PageLevel(const int purpose);
 
 /// approximate total number of shared memory pages we can allocate now
 inline size_t PagesAvailable() { return PageLimit() - PageLevel(); }
 
-/// approximate total number of shared memory pages for memory cache we can
-/// allocate now
-inline size_t CachePagesAvailable() { return CachePageLimit() - CachePageLevel(); }
-
-/// approximate total number of shared memory pages for IPC I/O we can allocate now
-inline size_t IoPagesAvailable() { return IoPageLimit() - IoPageLevel(); }
+/// approximate total number of shared memory pages we can allocate
+/// now for given purpose
+inline size_t PagesAvailable(const int purpose) { return PageLimit(purpose) - PageLevel(purpose); }
 
 /// returns page size in bytes; all pages are assumed to be the same size
 size_t PageSize();