From: Eduard Bagdasaryan Date: Tue, 19 May 2020 17:01:40 +0000 (+0000) Subject: Reduced startup time with large rock cache_dirs (#634) X-Git-Tag: SQUID_5_0_3~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=562ffa4283f9a019c4469c965d2b998c51a6be5f;p=thirdparty%2Fsquid.git Reduced startup time with large rock cache_dirs (#634) ... addressing an old TODO. Before scanning the disks to find the actual entries, the old rock cache_dir initialization code had to populate its index as if all disk slots were available and then remove all the added entries. Those two wasteful operations took ~1.5 seconds for a 200GB disk before the PageStack ABA bug was fixed in a586085. With the tree-based fix, that time increased to ~15 seconds. The delay is completely gone now, reducing the total index initialization time (for a 200GB disk) down to a second. --- diff --git a/src/MemStore.cc b/src/MemStore.cc index 5b38b9cdaa..7c77002fda 100644 --- a/src/MemStore.cc +++ b/src/MemStore.cc @@ -1008,10 +1008,14 @@ MemStoreRr::create() const int64_t entryLimit = MemStore::EntryLimit(); assert(entryLimit > 0); + + Ipc::Mem::PageStack::Config spaceConfig; + spaceConfig.poolId = Ipc::Mem::PageStack::IdForMemStoreSpace(), + spaceConfig.pageSize = 0; // the pages are stored in Ipc::Mem::Pages + spaceConfig.capacity = entryLimit; + spaceConfig.createFull = true; // all pages are initially available Must(!spaceOwner); - spaceOwner = shm_new(Ipc::Mem::PageStack)(SpaceLabel, - Ipc::Mem::PageStack::IdForMemStoreSpace(), - entryLimit, 0); + spaceOwner = shm_new(Ipc::Mem::PageStack)(SpaceLabel, spaceConfig); Must(!mapOwner); mapOwner = MemStoreMap::Init(MapLabel, entryLimit); Must(!extrasOwner); diff --git a/src/fs/rock/RockSwapDir.cc b/src/fs/rock/RockSwapDir.cc index ac324aac5f..d39efc0439 100644 --- a/src/fs/rock/RockSwapDir.cc +++ b/src/fs/rock/RockSwapDir.cc @@ -1136,19 +1136,14 @@ void Rock::SwapDirRr::create() mapOwners.push_back(mapOwner); // TODO: somehow remove pool id and counters from PageStack? + Ipc::Mem::PageStack::Config config; + config.poolId = Ipc::Mem::PageStack::IdForSwapDirSpace(i); + config.pageSize = 0; // this is an index of slots on _disk_ + config.capacity = capacity; + config.createFull = false; // Rebuild finds and pushes free slots Ipc::Mem::Owner *const freeSlotsOwner = - shm_new(Ipc::Mem::PageStack)(sd->freeSlotsPath(), - Ipc::Mem::PageStack::IdForSwapDirSpace(i), - capacity, - 0); + shm_new(Ipc::Mem::PageStack)(sd->freeSlotsPath(), config); freeSlotsOwners.push_back(freeSlotsOwner); - - // TODO: add method to initialize PageStack with no free pages - while (true) { - Ipc::Mem::PageId pageId; - if (!freeSlotsOwner->object()->pop(pageId)) - break; - } } } } diff --git a/src/ipc/mem/PagePool.cc b/src/ipc/mem/PagePool.cc index 8e81098a3a..2664e71b91 100644 --- a/src/ipc/mem/PagePool.cc +++ b/src/ipc/mem/PagePool.cc @@ -18,7 +18,12 @@ Ipc::Mem::PagePool::Owner * Ipc::Mem::PagePool::Init(const char *const shmId, const Ipc::Mem::PoolId stackId, const unsigned int capacity, const size_t pageSize) { - return shm_new(PageStack)(shmId, stackId, capacity, pageSize); + PageStack::Config config; + config.poolId = stackId; + config.pageSize = pageSize; // the pages are stored in Ipc::Mem::Pages + config.capacity = capacity; + config.createFull = true; // all pages are initially available + return shm_new(PageStack)(shmId, config); } Ipc::Mem::PagePool::PagePool(const char *const id): diff --git a/src/ipc/mem/PageStack.cc b/src/ipc/mem/PageStack.cc index a2557f7002..d0ea201a20 100644 --- a/src/ipc/mem/PageStack.cc +++ b/src/ipc/mem/PageStack.cc @@ -156,8 +156,6 @@ Ipc::Mem::IdSet::IdSet(const size_type capacity): // atomic wrappers in nodes_ must be zero-size. Check the best we can. Once. static_assert(sizeof(StoredNode) == sizeof(Node), "atomic locks use no storage"); assert(StoredNode().is_lock_free()); - - makeFullBeforeSharing(); } void @@ -428,12 +426,15 @@ Ipc::Mem::IdSet::MemorySize(const size_type capacity) /* Ipc::Mem::PageStack */ -Ipc::Mem::PageStack::PageStack(const PoolId aPoolId, const PageCount aCapacity, const size_t aPageSize): - thePoolId(aPoolId), capacity_(aCapacity), thePageSize(aPageSize), +Ipc::Mem::PageStack::PageStack(const Config &config): + config_(config), size_(0), - ids_(capacity_) + ids_(config_.capacity) { - size_ = capacity_; + if (config.createFull) { + ids_.makeFullBeforeSharing(); + size_ = config_.capacity; + } } bool @@ -441,7 +442,7 @@ Ipc::Mem::PageStack::pop(PageId &page) { assert(!page); - if (!capacity_) + if (!config_.capacity) return false; IdSet::size_type pageIndex = 0; @@ -450,10 +451,10 @@ Ipc::Mem::PageStack::pop(PageId &page) // must decrement after removing the page to avoid underflow const auto newSize = --size_; - assert(newSize < capacity_); + assert(newSize < config_.capacity); page.number = pageIndex + 1; - page.pool = thePoolId; + page.pool = config_.poolId; debugs(54, 8, page << " size: " << newSize); assert(pageIdIsValid(page)); return true; @@ -468,7 +469,7 @@ Ipc::Mem::PageStack::push(PageId &page) // must increment before inserting the page to avoid underflow in pop() const auto newSize = ++size_; - assert(newSize <= capacity_); + assert(newSize <= config_.capacity); const auto pageIndex = page.number - 1; ids_.push(pageIndex); @@ -480,22 +481,22 @@ Ipc::Mem::PageStack::push(PageId &page) bool Ipc::Mem::PageStack::pageIdIsValid(const PageId &page) const { - return page.pool == thePoolId && + return page.pool == config_.poolId && 0 < page.number && page.number <= capacity(); } size_t Ipc::Mem::PageStack::sharedMemorySize() const { - return SharedMemorySize(thePoolId, capacity_, thePageSize); + return SharedMemorySize(config_); } size_t -Ipc::Mem::PageStack::SharedMemorySize(const PoolId, const PageCount capacity, const size_t pageSize) +Ipc::Mem::PageStack::SharedMemorySize(const Config &cfg) { const auto levelsSize = PageId::maxPurpose * sizeof(Levels_t); - const size_t pagesDataSize = capacity * pageSize; - return StackSize(capacity) + LevelsPaddingSize(capacity) + levelsSize + pagesDataSize; + const size_t pagesDataSize = cfg.capacity * cfg.pageSize; + return StackSize(cfg.capacity) + pagesDataSize + levelsSize; } size_t @@ -510,7 +511,7 @@ Ipc::Mem::PageStack::StackSize(const PageCount capacity) size_t Ipc::Mem::PageStack::stackSize() const { - return StackSize(capacity_); + return StackSize(config_.capacity); } size_t diff --git a/src/ipc/mem/PageStack.h b/src/ipc/mem/PageStack.h index 46a3822e06..d3b44f7466 100644 --- a/src/ipc/mem/PageStack.h +++ b/src/ipc/mem/PageStack.h @@ -116,10 +116,24 @@ public: /// the number of (free and/or used) pages in a stack typedef unsigned int PageCount; - PageStack(const PoolId aPoolId, const PageCount aCapacity, const size_t aPageSize); + // XXX: poolId, pageSize look misplaced due to messy separation of PagePool + // (which should support multiple Segments but does not) and PageStack + // (which should not calculate the Segment size but does) duties. + /// PageStack construction and SharedMemorySize calculation parameters + class Config { + public: + uint32_t poolId = 0; ///< pool ID + size_t pageSize = 0; ///< page size, used to calculate shared memory size + PageCount capacity = 0; ///< the maximum number of pages + + /// whether a newly created PageStack should be prefilled with PageIds + bool createFull = false; + }; - PageCount capacity() const { return capacity_; } - size_t pageSize() const { return thePageSize; } + explicit PageStack(const Config &); + + PageCount capacity() const { return config_.capacity; } + size_t pageSize() const { return config_.pageSize; } /// an approximate number of free pages PageCount size() const { return size_.load(); } @@ -131,7 +145,7 @@ public: bool pageIdIsValid(const PageId &page) const; /// total shared memory size required to share - static size_t SharedMemorySize(const PoolId aPoolId, const PageCount capacity, const size_t pageSize); + static size_t SharedMemorySize(const Config &); size_t sharedMemorySize() const; /// shared memory size required only by PageStack, excluding @@ -141,7 +155,7 @@ public: /// \returns the number of padding bytes to align PagePool::theLevels array static size_t LevelsPaddingSize(const PageCount capacity); - size_t levelsPaddingSize() const { return LevelsPaddingSize(capacity_); } + size_t levelsPaddingSize() const { return LevelsPaddingSize(config_.capacity); } /** * The following functions return PageStack IDs for the corresponding @@ -157,12 +171,7 @@ public: static PoolId IdForSwapDirSpace(const int dirIdx) { return 900 + dirIdx + 1; } private: - // XXX: theFoo members look misplaced due to messy separation of PagePool - // (which should support multiple Segments but does not) and PageStack - // (which should not calculate the Segment size but does) duties. - const PoolId thePoolId; ///< pool ID - const PageCount capacity_; ///< the maximum number of pages - const size_t thePageSize; ///< page size, used to calculate shared memory size + const Config config_; /// a lower bound for the number of free pages (for debugging purposes) std::atomic size_;