This is an automated email from the ASF dual-hosted git repository.
jvanderzee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 2b66ed0d29 Extract `PreservationTable` from `StripeSM` (#11628)
2b66ed0d29 is described below
commit 2b66ed0d29a2747cc6f90e01f1748d7f15eb0cc7
Author: JosiahWI <[email protected]>
AuthorDate: Fri Aug 2 16:29:12 2024 -0500
Extract `PreservationTable` from `StripeSM` (#11628)
* Extract `PreservationTable` from `StripeSM`
This extracts `PreservationTable` as a superclass. The new class represents
the responsibility of tracking documents that need to be preserved to avoid
being overwritten, such as pinned documents. Docstrings are added to better
document how this process works. The `StripeSM::evac_range` method is left
with that class because it is not part of the evacuation data structure
despite the name. It should be refactored and renamed in a future PR.
* Update documentation
---
.../cache-architecture/architecture.en.rst | 2 +-
.../cache-architecture/data-structures.en.rst | 14 +-
src/iocore/cache/CMakeLists.txt | 1 +
src/iocore/cache/CacheDir.cc | 1 +
src/iocore/cache/CacheEvacuateDocVC.cc | 1 +
src/iocore/cache/P_CacheDir.h | 1 +
src/iocore/cache/P_CacheVol.h | 122 ++------------
src/iocore/cache/PreservationTable.cc | 161 +++++++++++++++++++
src/iocore/cache/PreservationTable.h | 176 +++++++++++++++++++++
src/iocore/cache/Stripe.h | 10 --
src/iocore/cache/StripeSM.cc | 129 +--------------
11 files changed, 365 insertions(+), 253 deletions(-)
diff --git a/doc/developer-guide/cache-architecture/architecture.en.rst
b/doc/developer-guide/cache-architecture/architecture.en.rst
index db2eab0e8e..d7cc29c92f 100644
--- a/doc/developer-guide/cache-architecture/architecture.en.rst
+++ b/doc/developer-guide/cache-architecture/architecture.en.rst
@@ -978,7 +978,7 @@ stripe data structures (attached to the
:cpp:class:`StripeSM` instance).
Evacuation data structures are defined by dividing up the volume content into
a disjoint and contiguous set of regions of ``EVACUATION_BUCKET_SIZE`` bytes.
-The :cpp:member:`StripeSM::evacuate` member is an array with an element for
each
+The :cpp:member:`PreservationTable::evacuate` member is an array with an
element for each
evacuation region. Each element is a doubly linked list of
:cpp:class:`EvacuationBlock`
instances. Each instance contains a :cpp:class:`Dir` that specifies the
fragment
to evacuate. It is assumed that an evacuation block is placed in the evacuation
diff --git a/doc/developer-guide/cache-architecture/data-structures.en.rst
b/doc/developer-guide/cache-architecture/data-structures.en.rst
index d8ce281fbf..2f113ec8cf 100644
--- a/doc/developer-guide/cache-architecture/data-structures.en.rst
+++ b/doc/developer-guide/cache-architecture/data-structures.en.rst
@@ -166,17 +166,21 @@ Data Structures
Schedule the aggregation buffer to be written to disk.
- .. member:: DLL<EvacuationBlock> evacuate
-
- Array of :class:`EvacuationBlock` buckets. This is sized so there
- is one bucket for every evacuation span.
-
.. member:: int evac_range(off_t low, off_t high, int evac_phase)
Start an evacuation if there is any :class:`EvacuationBlock` in the
range
from :arg:`low` to :arg:`high`. Return ``0`` if no evacuation was
started,
non-zero otherwise.
+.. class:: PreservationTable
+
+ Defined in :ts:git:`src/iocore/cache/PreservationTable.h`.
+
+ .. member:: DLL<EvacuationBlock> evacuate
+
+ Array of :class:`EvacuationBlock` buckets. This is sized so there
+ is one bucket for every evacuation span.
+
.. class:: Doc
Defined in :ts:git:`iocore/cache/P_CacheVol.h`.
diff --git a/src/iocore/cache/CMakeLists.txt b/src/iocore/cache/CMakeLists.txt
index 6460b91e39..9bf5e554b3 100644
--- a/src/iocore/cache/CMakeLists.txt
+++ b/src/iocore/cache/CMakeLists.txt
@@ -30,6 +30,7 @@ add_library(
CacheVol.cc
CacheWrite.cc
HttpTransactCache.cc
+ PreservationTable.cc
RamCacheCLFUS.cc
RamCacheLRU.cc
Store.cc
diff --git a/src/iocore/cache/CacheDir.cc b/src/iocore/cache/CacheDir.cc
index a68e8767d8..e32e239dab 100644
--- a/src/iocore/cache/CacheDir.cc
+++ b/src/iocore/cache/CacheDir.cc
@@ -24,6 +24,7 @@
#include "P_Cache.h"
#include "P_CacheDir.h"
#include "P_CacheDoc.h"
+#include "PreservationTable.h"
#include "Stripe.h"
#include "tscore/hugepages.h"
diff --git a/src/iocore/cache/CacheEvacuateDocVC.cc
b/src/iocore/cache/CacheEvacuateDocVC.cc
index 99d7319072..5cfe610b3f 100644
--- a/src/iocore/cache/CacheEvacuateDocVC.cc
+++ b/src/iocore/cache/CacheEvacuateDocVC.cc
@@ -33,6 +33,7 @@
#include "P_CacheInternal.h"
#include "P_CacheVol.h"
#include "CacheEvacuateDocVC.h"
+#include "PreservationTable.h"
// tscore
#include "tscore/Diags.h"
diff --git a/src/iocore/cache/P_CacheDir.h b/src/iocore/cache/P_CacheDir.h
index ffa91eaf0a..0e5d78f0e7 100644
--- a/src/iocore/cache/P_CacheDir.h
+++ b/src/iocore/cache/P_CacheDir.h
@@ -31,6 +31,7 @@
#include "iocore/eventsystem/Continuation.h"
// aio
+#include "../aio/P_AIO.h"
#include "iocore/aio/AIO.h"
class Stripe;
diff --git a/src/iocore/cache/P_CacheVol.h b/src/iocore/cache/P_CacheVol.h
index 2098eafa99..7f61e595cd 100644
--- a/src/iocore/cache/P_CacheVol.h
+++ b/src/iocore/cache/P_CacheVol.h
@@ -28,6 +28,7 @@
#include "P_CacheStats.h"
#include "P_RamCache.h"
#include "AggregateWriteBuffer.h"
+#include "PreservationTable.h"
#include "Stripe.h"
#include "iocore/eventsystem/EThread.h"
@@ -40,29 +41,21 @@
#define STRIPE_MAGIC 0xF1D0F00D
#define START_BLOCKS 16 // 8k, STORE_BLOCK_SIZE
#define START_POS ((off_t)START_BLOCKS * CACHE_BLOCK_SIZE)
-#define EVACUATION_SIZE (2 * AGG_SIZE) // 8MB
#define STRIPE_BLOCK_SIZE (1024 * 1024 * 128) // 128MB
#define MIN_STRIPE_SIZE STRIPE_BLOCK_SIZE
#define MAX_STRIPE_SIZE ((off_t)512 * 1024 * 1024 * 1024 * 1024)
// 512TB
#define MAX_FRAG_SIZE (AGG_SIZE - sizeof(Doc))
// true max
#define LEAVE_FREE DEFAULT_MAX_BUFFER_SIZE
-#define PIN_SCAN_EVERY 16 // scan every 1/16 of disk
#define STRIPE_HASH_TABLE_SIZE 32707
#define STRIPE_HASH_EMPTY 0xFFFF
#define STRIPE_HASH_ALLOC_SIZE (8 * 1024 * 1024) // one chance per this
unit
#define LOOKASIDE_SIZE 256
-#define EVACUATION_BUCKET_SIZE (2 * EVACUATION_SIZE) // 16MB
#define AIO_NOT_IN_PROGRESS -1
#define AIO_AGG_WRITE_IN_PROGRESS -2
#define AUTO_SIZE_RAM_CACHE -1 // 1-1 with
directory size
#define DEFAULT_TARGET_FRAGMENT_SIZE (1048576 - sizeof(Doc)) // 1MB
#define STORE_BLOCKS_PER_STRIPE (STRIPE_BLOCK_SIZE / STORE_BLOCK_SIZE)
-#define dir_offset_evac_bucket(_o) (_o / (EVACUATION_BUCKET_SIZE /
CACHE_BLOCK_SIZE))
-#define dir_evac_bucket(_e) dir_offset_evac_bucket(dir_offset(_e))
-#define offset_evac_bucket(_d, _o) \
- dir_offset_evac_bucket((_d->offset_to_vol_offset(_o)
-
// Documents
struct Cache;
@@ -73,34 +66,7 @@ struct DiskStripe;
struct CacheVol;
class CacheEvacuateDocVC;
-// Key and Earliest key for each fragment that needs to be evacuated
-struct EvacuationKey {
- SLink<EvacuationKey> link;
- CryptoHash key;
- CryptoHash earliest_key;
-};
-
-struct EvacuationBlock {
- union {
- unsigned int init;
- struct {
- unsigned int done : 1; // has been evacuated
- unsigned int pinned : 1; // check pinning timeout
- unsigned int evacuate_head : 1; // check pinning timeout
- unsigned int unused : 29;
- } f;
- };
-
- int readers;
- Dir dir;
- Dir new_dir;
- // we need to have a list of evacuationkeys because of collision.
- EvacuationKey evac_frags;
- CacheEvacuateDocVC *earliest_evacuator;
- LINK(EvacuationBlock, link);
-};
-
-class StripeSM : public Continuation, public Stripe
+class StripeSM : public Continuation, public Stripe, public PreservationTable
{
public:
CryptoHash hash_id;
@@ -115,11 +81,10 @@ public:
Event *trigger = nullptr;
- OpenDir open_dir;
- RamCache *ram_cache = nullptr;
- DLL<EvacuationBlock> *evacuate = nullptr;
- DLL<EvacuationBlock> lookaside[LOOKASIDE_SIZE];
- CacheEvacuateDocVC *doc_evacuator = nullptr;
+ OpenDir open_dir;
+ RamCache *ram_cache = nullptr;
+ DLL<EvacuationBlock> lookaside[LOOKASIDE_SIZE];
+ CacheEvacuateDocVC *doc_evacuator = nullptr;
StripeInitInfo *init_info = nullptr;
@@ -197,31 +162,6 @@ public:
int evacuateDocReadDone(int event, Event *e);
int evac_range(off_t start, off_t end, int evac_phase);
- /**
- *
- * The caller must hold the mutex.
- */
- void periodic_scan();
- /**
- *
- * The caller must hold the mutex.
- */
- void scan_for_pinned_documents();
- /**
- *
- * The caller must hold the mutex.
- */
- void evacuate_cleanup_blocks(int i);
- /**
- *
- * The caller must hold the mutex.
- */
- void evacuate_cleanup();
- /**
- *
- * The caller must hold the mutex.
- */
- EvacuationBlock *force_evacuate_head(Dir const *dir, int pinned);
int within_hit_evacuate_window(Dir const *dir) const;
@@ -294,32 +234,13 @@ struct CacheVol {
// Global Data
-extern StripeSM **gstripes;
-extern std::atomic<int> gnstripes;
-extern ClassAllocator<OpenDirEntry> openDirEntryAllocator;
-extern ClassAllocator<EvacuationBlock> evacuationBlockAllocator;
-extern ClassAllocator<EvacuationKey> evacuationKeyAllocator;
-extern unsigned short *vol_hash_table;
-
-// inline Functions
+extern StripeSM **gstripes;
+extern std::atomic<int> gnstripes;
+extern ClassAllocator<OpenDirEntry> openDirEntryAllocator;
+extern unsigned short *vol_hash_table;
// inline Functions
-inline EvacuationBlock *
-evacuation_block_exists(Dir const *dir, StripeSM *stripe)
-{
- auto bucket = dir_evac_bucket(dir);
- if (stripe->evac_bucket_valid(bucket)) {
- EvacuationBlock *b = stripe->evacuate[bucket].head;
- for (; b; b = b->link.next) {
- if (dir_offset(&b->dir) == dir_offset(dir)) {
- return b;
- }
- }
- }
- return nullptr;
-}
-
inline void
StripeSM::cancel_trigger()
{
@@ -329,29 +250,6 @@ StripeSM::cancel_trigger()
}
}
-inline EvacuationBlock *
-new_EvacuationBlock()
-{
- EvacuationBlock *b = THREAD_ALLOC(evacuationBlockAllocator,
this_ethread());
- b->init = 0;
- b->readers = 0;
- b->earliest_evacuator = nullptr;
- b->evac_frags.link.next = nullptr;
- return b;
-}
-
-inline void
-free_EvacuationBlock(EvacuationBlock *b)
-{
- EvacuationKey *e = b->evac_frags.link.next;
- while (e) {
- EvacuationKey *n = e->link.next;
- evacuationKeyAllocator.free(e);
- e = n;
- }
- THREAD_FREE(b, evacuationBlockAllocator, this_ethread());
-}
-
inline OpenDirEntry *
StripeSM::open_read(const CryptoHash *key) const
{
diff --git a/src/iocore/cache/PreservationTable.cc
b/src/iocore/cache/PreservationTable.cc
new file mode 100644
index 0000000000..73741b4cfc
--- /dev/null
+++ b/src/iocore/cache/PreservationTable.cc
@@ -0,0 +1,161 @@
+/** @file
+
+ Preservation of documents that would be overwritten by the write head.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "P_CacheDir.h"
+#include "P_CacheInternal.h"
+#include "PreservationTable.h"
+
+#include "AggregateWriteBuffer.h"
+#include "Stripe.h"
+
+#include "tsutil/DbgCtl.h"
+
+#include <cinttypes>
+
+namespace
+{
+
+DbgCtl dbg_ctl_cache_evac{"cache_evac"};
+
+} // namespace
+
+void
+PreservationTable::force_evacuate_head(Dir const *evac_dir, int pinned)
+{
+ auto bucket = dir_evac_bucket(evac_dir);
+ if (!evac_bucket_valid(bucket)) {
+ DDbg(dbg_ctl_cache_evac, "dir_evac_bucket out of bounds, skipping
evacuate: %" PRId64 "(%d), %d, %d", bucket, evacuate_size,
+ (int)dir_offset(evac_dir), (int)dir_phase(evac_dir));
+ return;
+ }
+
+ // build an evacuation block for the object
+ EvacuationBlock *b = evacuation_block_exists(evac_dir, this);
+ // if we have already started evacuating this document, its too late
+ // to evacuate the head...bad luck
+ if (b && b->f.done) {
+ return;
+ }
+
+ if (!b) {
+ b = new_EvacuationBlock();
+ b->dir = *evac_dir;
+ DDbg(dbg_ctl_cache_evac, "force: %d, %d", (int)dir_offset(evac_dir),
(int)dir_phase(evac_dir));
+ evacuate[bucket].push(b);
+ }
+ b->f.pinned = pinned;
+ b->f.evacuate_head = 1;
+ b->evac_frags.key.clear(); // ensure that the block gets evacuated no matter
what
+ b->readers = 0; // ensure that the block does not disappear
+}
+
+void
+PreservationTable::periodic_scan(Stripe *stripe)
+{
+ cleanup(stripe);
+ scan_for_pinned_documents(stripe);
+ if (stripe->header->write_pos == stripe->start) {
+ stripe->scan_pos = stripe->start;
+ }
+ stripe->scan_pos += stripe->len / PIN_SCAN_EVERY;
+}
+
+void
+PreservationTable::scan_for_pinned_documents(Stripe const *stripe)
+{
+ if (cache_config_permit_pinning) {
+ // we can't evacuate anything between header->write_pos and
+ // header->write_pos + AGG_SIZE.
+ int ps = stripe->offset_to_vol_offset(stripe->header->write_pos +
AGG_SIZE);
+ int pe = stripe->offset_to_vol_offset(stripe->header->write_pos + 2 *
EVACUATION_SIZE + (stripe->len / PIN_SCAN_EVERY));
+ int vol_end_offset = stripe->offset_to_vol_offset(stripe->len +
stripe->skip);
+ int before_end_of_vol = pe < vol_end_offset;
+ DDbg(dbg_ctl_cache_evac, "scan %d %d", ps, pe);
+ for (int i = 0; i < stripe->direntries(); i++) {
+ // is it a valid pinned object?
+ if (!dir_is_empty(&stripe->dir[i]) && dir_pinned(&stripe->dir[i]) &&
dir_head(&stripe->dir[i])) {
+ // select objects only within this PIN_SCAN region
+ int o = dir_offset(&stripe->dir[i]);
+ if (dir_phase(&stripe->dir[i]) == stripe->header->phase) {
+ if (before_end_of_vol || o >= (pe - vol_end_offset)) {
+ continue;
+ }
+ } else {
+ if (o < ps || o >= pe) {
+ continue;
+ }
+ }
+ force_evacuate_head(&stripe->dir[i], 1);
+ }
+ }
+ }
+}
+
+void
+PreservationTable::cleanup(Stripe const *stripe)
+{
+ int64_t eo = ((stripe->header->write_pos - stripe->start) /
CACHE_BLOCK_SIZE) + 1;
+ int64_t e = dir_offset_evac_bucket(eo);
+ int64_t sx = e - (evacuate_size / PIN_SCAN_EVERY) - 1;
+ int64_t s = sx;
+ int i;
+
+ if (e > evacuate_size) {
+ e = evacuate_size;
+ }
+ if (sx < 0) {
+ s = 0;
+ }
+ for (i = s; i < e; i++) {
+ remove_finished_blocks(stripe, i);
+ }
+
+ // if we have wrapped, handle the end bit
+ if (sx <= 0) {
+ s = evacuate_size + sx - 2;
+ if (s < 0) {
+ s = 0;
+ }
+ for (i = s; i < evacuate_size; i++) {
+ remove_finished_blocks(stripe, i);
+ }
+ }
+}
+
+inline void
+PreservationTable::remove_finished_blocks(Stripe const *stripe, int bucket)
+{
+ EvacuationBlock *b = evac_bucket_valid(bucket) ? evacuate[bucket].head :
nullptr;
+ while (b) {
+ if (b->f.done && ((stripe->header->phase != dir_phase(&b->dir) &&
stripe->header->write_pos > stripe->vol_offset(&b->dir)) ||
+ (stripe->header->phase == dir_phase(&b->dir) &&
stripe->header->write_pos <= stripe->vol_offset(&b->dir)))) {
+ EvacuationBlock *x = b;
+ DDbg(dbg_ctl_cache_evac, "evacuate cleanup free %X offset %d",
(int)b->evac_frags.key.slice32(0), (int)dir_offset(&b->dir));
+ b = b->link.next;
+ evacuate[bucket].remove(x);
+ free_EvacuationBlock(x);
+ continue;
+ }
+ b = b->link.next;
+ }
+}
diff --git a/src/iocore/cache/PreservationTable.h
b/src/iocore/cache/PreservationTable.h
new file mode 100644
index 0000000000..944a330080
--- /dev/null
+++ b/src/iocore/cache/PreservationTable.h
@@ -0,0 +1,176 @@
+/** @file
+
+ Preservation of documents that would be overwritten by the write head.
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#pragma once
+
+#include "AggregateWriteBuffer.h"
+#include "P_CacheDir.h"
+#include "Stripe.h"
+
+#include "iocore/eventsystem/EThread.h"
+#include "iocore/eventsystem/ProxyAllocator.h"
+
+#include "tscore/Allocator.h"
+#include "tscore/CryptoHash.h"
+#include "tscore/ink_platform.h"
+#include "tscore/List.h"
+
+#define EVACUATION_BUCKET_SIZE (2 * EVACUATION_SIZE) // 16MB
+#define EVACUATION_SIZE (2 * AGG_SIZE) // 8MB
+#define PIN_SCAN_EVERY 16 // scan every 1/16 of disk
+
+#define dir_offset_evac_bucket(_o) (_o / (EVACUATION_BUCKET_SIZE /
CACHE_BLOCK_SIZE))
+#define dir_evac_bucket(_e) dir_offset_evac_bucket(dir_offset(_e))
+#define offset_evac_bucket(_d, _o) \
+ dir_offset_evac_bucket((_d->offset_to_vol_offset(_o)
+
+class CacheEvacuateDocVC;
+
+// Key and Earliest key for each fragment that needs to be evacuated
+struct EvacuationKey {
+ SLink<EvacuationKey> link;
+ CryptoHash key;
+ CryptoHash earliest_key;
+};
+
+struct EvacuationBlock {
+ union {
+ unsigned int init;
+ struct {
+ unsigned int done : 1; // has been evacuated
+ unsigned int pinned : 1; // check pinning timeout
+ unsigned int evacuate_head : 1; // check pinning timeout
+ unsigned int unused : 29;
+ } f;
+ };
+
+ int readers;
+ Dir dir;
+ Dir new_dir;
+ // we need to have a list of evacuationkeys because of collision.
+ EvacuationKey evac_frags;
+ CacheEvacuateDocVC *earliest_evacuator;
+ LINK(EvacuationBlock, link);
+};
+
+/**
+ * Represents the collection of documents that must be rewritten to the cache
+ * to avoid being overwritten. The documents themselves are not owned by this
+ * table, but are referenced by it via a cache directory entry. If any
+ * directory entry stored in this table is invalidated, this table is also
+ * invalidated. Once a document has been rewritten, mark its block as done
+ * and it will be removed on the next call to periodic_scan.
+ *
+ * This class is not safe for concurrent access. It should be protected
+ * by a lock.
+ *
+ * @see Stripe
+ */
+class PreservationTable
+{
+public:
+ /**
+ * The table of preserved documents.
+ *
+ * This is implemented as a hash table using separate chaining.
+ */
+ DLL<EvacuationBlock> *evacuate{nullptr};
+
+ /**
+ * Check whether the hash table may be indexed with the given offset.
+ *
+ * @param bucket An index into the hash table.
+ * @return Returns true if the index is valid, false otherwise.
+ */
+ bool evac_bucket_valid(off_t bucket) const;
+
+ /**
+ * Force the preservation of the given document.
+ *
+ * @param dir The directory entry for the document to preserve.
+ * @param pinned Whether the document is pinned (0 or 1).
+ */
+ void force_evacuate_head(Dir const *evac_dir, int pinned);
+
+protected:
+ int evacuate_size{};
+
+ /**
+ * Remove completed documents from the table and add pinned documents.
+ *
+ * @param Stripe The stripe to scan for pinned documents to preserve.
+ */
+ void periodic_scan(Stripe *stripe);
+
+private:
+ void cleanup(Stripe const *stripe);
+ void remove_finished_blocks(Stripe const *stripe, int bucket);
+ void scan_for_pinned_documents(Stripe const *stripe);
+};
+
+inline bool
+PreservationTable::evac_bucket_valid(off_t bucket) const
+{
+ return (bucket >= 0 && bucket < evacuate_size);
+}
+
+extern ClassAllocator<EvacuationBlock> evacuationBlockAllocator;
+extern ClassAllocator<EvacuationKey> evacuationKeyAllocator;
+
+inline EvacuationBlock *
+evacuation_block_exists(Dir const *dir, PreservationTable *stripe)
+{
+ auto bucket = dir_evac_bucket(dir);
+ if (stripe->evac_bucket_valid(bucket)) {
+ EvacuationBlock *b = stripe->evacuate[bucket].head;
+ for (; b; b = b->link.next) {
+ if (dir_offset(&b->dir) == dir_offset(dir)) {
+ return b;
+ }
+ }
+ }
+ return nullptr;
+}
+
+inline EvacuationBlock *
+new_EvacuationBlock()
+{
+ EvacuationBlock *b = THREAD_ALLOC(evacuationBlockAllocator,
this_ethread());
+ b->init = 0;
+ b->readers = 0;
+ b->earliest_evacuator = nullptr;
+ b->evac_frags.link.next = nullptr;
+ return b;
+}
+
+inline void
+free_EvacuationBlock(EvacuationBlock *b)
+{
+ EvacuationKey *e = b->evac_frags.link.next;
+ while (e) {
+ EvacuationKey *n = e->link.next;
+ evacuationKeyAllocator.free(e);
+ e = n;
+ }
+ THREAD_FREE(b, evacuationBlockAllocator, this_ethread());
+}
diff --git a/src/iocore/cache/Stripe.h b/src/iocore/cache/Stripe.h
index f9ce59aec3..807c8bb001 100644
--- a/src/iocore/cache/Stripe.h
+++ b/src/iocore/cache/Stripe.h
@@ -84,8 +84,6 @@ public:
off_t len{};
off_t data_blocks{};
- int evacuate_size{};
-
CacheDisk *disk{};
uint32_t sector_size{};
@@ -93,8 +91,6 @@ public:
int dir_check();
- bool evac_bucket_valid(off_t bucket) const;
-
uint32_t round_to_approx_size(uint32_t l) const;
// inline functions
@@ -152,12 +148,6 @@ private:
void _init_data_internal();
};
-inline bool
-Stripe::evac_bucket_valid(off_t bucket) const
-{
- return (bucket >= 0 && bucket < evacuate_size);
-}
-
inline uint32_t
Stripe::round_to_approx_size(uint32_t l) const
{
diff --git a/src/iocore/cache/StripeSM.cc b/src/iocore/cache/StripeSM.cc
index 2e1fc0769b..2101229f8c 100644
--- a/src/iocore/cache/StripeSM.cc
+++ b/src/iocore/cache/StripeSM.cc
@@ -29,6 +29,7 @@
#include "P_CacheDir.h"
#include "CacheEvacuateDocVC.h"
+#include "PreservationTable.h"
#include "Stripe.h"
#include "iocore/cache/CacheDefs.h"
@@ -663,133 +664,11 @@ StripeSM::handle_recover_write_dir(int /* event
ATS_UNUSED */, void * /* data AT
set_io_not_in_progress();
scan_pos = header->write_pos;
ink_assert(this->mutex->thread_holding = this_ethread());
- periodic_scan();
+ periodic_scan(this);
SET_HANDLER(&StripeSM::dir_init_done);
return dir_init_done(EVENT_IMMEDIATE, nullptr);
}
-void
-StripeSM::periodic_scan()
-{
- evacuate_cleanup();
- scan_for_pinned_documents();
- if (header->write_pos == start) {
- scan_pos = start;
- }
- scan_pos += len / PIN_SCAN_EVERY;
-}
-
-void
-StripeSM::evacuate_cleanup()
-{
- int64_t eo = ((header->write_pos - start) / CACHE_BLOCK_SIZE) + 1;
- int64_t e = dir_offset_evac_bucket(eo);
- int64_t sx = e - (evacuate_size / PIN_SCAN_EVERY) - 1;
- int64_t s = sx;
- int i;
-
- if (e > evacuate_size) {
- e = evacuate_size;
- }
- if (sx < 0) {
- s = 0;
- }
- for (i = s; i < e; i++) {
- evacuate_cleanup_blocks(i);
- }
-
- // if we have wrapped, handle the end bit
- if (sx <= 0) {
- s = evacuate_size + sx - 2;
- if (s < 0) {
- s = 0;
- }
- for (i = s; i < evacuate_size; i++) {
- evacuate_cleanup_blocks(i);
- }
- }
-}
-
-inline void
-StripeSM::evacuate_cleanup_blocks(int i)
-{
- EvacuationBlock *b = evac_bucket_valid(i) ? evacuate[i].head : nullptr;
- while (b) {
- if (b->f.done && ((header->phase != dir_phase(&b->dir) &&
header->write_pos > this->vol_offset(&b->dir)) ||
- (header->phase == dir_phase(&b->dir) &&
header->write_pos <= this->vol_offset(&b->dir)))) {
- EvacuationBlock *x = b;
- DDbg(dbg_ctl_cache_evac, "evacuate cleanup free %X offset %d",
(int)b->evac_frags.key.slice32(0), (int)dir_offset(&b->dir));
- b = b->link.next;
- evacuate[i].remove(x);
- free_EvacuationBlock(x);
- continue;
- }
- b = b->link.next;
- }
-}
-
-void
-StripeSM::scan_for_pinned_documents()
-{
- if (cache_config_permit_pinning) {
- // we can't evacuate anything between header->write_pos and
- // header->write_pos + AGG_SIZE.
- int ps = this->offset_to_vol_offset(header->write_pos +
AGG_SIZE);
- int pe = this->offset_to_vol_offset(header->write_pos + 2 *
EVACUATION_SIZE + (len / PIN_SCAN_EVERY));
- int vol_end_offset = this->offset_to_vol_offset(len + skip);
- int before_end_of_vol = pe < vol_end_offset;
- DDbg(dbg_ctl_cache_evac, "scan %d %d", ps, pe);
- for (int i = 0; i < this->direntries(); i++) {
- // is it a valid pinned object?
- if (!dir_is_empty(&dir[i]) && dir_pinned(&dir[i]) && dir_head(&dir[i])) {
- // select objects only within this PIN_SCAN region
- int o = dir_offset(&dir[i]);
- if (dir_phase(&dir[i]) == header->phase) {
- if (before_end_of_vol || o >= (pe - vol_end_offset)) {
- continue;
- }
- } else {
- if (o < ps || o >= pe) {
- continue;
- }
- }
- force_evacuate_head(&dir[i], 1);
- }
- }
- }
-}
-
-EvacuationBlock *
-StripeSM::force_evacuate_head(Dir const *evac_dir, int pinned)
-{
- auto bucket = dir_evac_bucket(evac_dir);
- if (!evac_bucket_valid(bucket)) {
- DDbg(dbg_ctl_cache_evac, "dir_evac_bucket out of bounds, skipping
evacuate: %" PRId64 "(%d), %d, %d", bucket, evacuate_size,
- (int)dir_offset(evac_dir), (int)dir_phase(evac_dir));
- return nullptr;
- }
-
- // build an evacuation block for the object
- EvacuationBlock *b = evacuation_block_exists(evac_dir, this);
- // if we have already started evacuating this document, its too late
- // to evacuate the head...bad luck
- if (b && b->f.done) {
- return b;
- }
-
- if (!b) {
- b = new_EvacuationBlock();
- b->dir = *evac_dir;
- DDbg(dbg_ctl_cache_evac, "force: %d, %d", (int)dir_offset(evac_dir),
(int)dir_phase(evac_dir));
- evacuate[bucket].push(b);
- }
- b->f.pinned = pinned;
- b->f.evacuate_head = 1;
- b->evac_frags.key.clear(); // ensure that the block gets evacuated no matter
what
- b->readers = 0; // ensure that the block does not disappear
- return b;
-}
-
CacheEvacuateDocVC *
new_DocEvacuator(int nbytes, StripeSM *stripe)
{
@@ -905,7 +784,7 @@ StripeSM::aggWriteDone(int event, Event *e)
ink_assert(header->write_pos == header->agg_pos);
if (header->write_pos + EVACUATION_SIZE > scan_pos) {
ink_assert(this->mutex->thread_holding == this_ethread());
- periodic_scan();
+ periodic_scan(this);
}
this->_write_buffer.reset_buffer_pos();
header->write_serial++;
@@ -1262,7 +1141,7 @@ StripeSM::agg_wrap()
Note("Cache volume %d on disk '%s' wraps around",
stripe->cache_vol->vol_number, stripe->hash_text.get());
}
ink_assert(this->mutex->thread_holding = this_ethread());
- periodic_scan();
+ periodic_scan(this);
}
int