You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by am...@apache.org on 2014/08/12 03:42:54 UTC
git commit: TS-3000: Add seed string for cache storage.
Repository: trafficserver
Updated Branches:
refs/heads/master 3710a276c -> 83248169b
TS-3000: Add seed string for cache storage.
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/83248169
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/83248169
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/83248169
Branch: refs/heads/master
Commit: 83248169bbdaab383583fbb0b25f0916b18594c4
Parents: 3710a27
Author: Alan M. Carroll <am...@network-geographics.com>
Authored: Mon Aug 11 19:06:53 2014 -0500
Committer: Alan M. Carroll <am...@network-geographics.com>
Committed: Mon Aug 11 20:42:17 2014 -0500
----------------------------------------------------------------------
.../configuration/storage.config.en.rst | 56 +++++--
iocore/cache/Cache.cc | 55 ++++---
iocore/cache/CacheDir.cc | 20 +--
iocore/cache/CachePagesInternal.cc | 2 +-
iocore/cache/CacheWrite.cc | 4 +-
iocore/cache/I_Store.h | 52 +++++--
iocore/cache/P_CacheDisk.h | 7 +-
iocore/cache/P_CacheVol.h | 2 +-
iocore/cache/Store.cc | 145 +++++++++----------
lib/ts/ink_memory.h | 6 +
10 files changed, 207 insertions(+), 142 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/doc/reference/configuration/storage.config.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/configuration/storage.config.en.rst b/doc/reference/configuration/storage.config.en.rst
index 9236344..af019b1 100644
--- a/doc/reference/configuration/storage.config.en.rst
+++ b/doc/reference/configuration/storage.config.en.rst
@@ -21,23 +21,31 @@ storage.config
.. configfile:: storage.config
-The :file:`storage.config` file (by default, located in
+The :file:`storage.config` file (by default, located in
``/opt/trafficserver/etc/trafficserver/``) lists all the files, directories, and/or
hard disk partitions that make up the Traffic Server cache. After you
-modify the :file:`storage.config` file, you must restart Traffic Server.
+modify the :file:`storage.config` file the new settings will not be effective until Traffic Server is restarted.
Format
======
-The format of the :file:`storage.config` file is::
+The format of the :file:`storage.config` file is a series of lines of the form
- pathname size volume=volume_number
+ *pathname* *size* [ ``volume=``\ *number* ] [ ``seed=``\ *string* ]
-where :arg:`pathname` is the name of a partition, directory or file, :arg:`size`
-is the size of the named partition, directory or file (in bytes), and
-:arg:`volume` is the volume number that is used in :file:`volume.config`
-and :file:`hosting.config`. You must specify a size for directories or
-files; size is optional for raw partitions. :arg:`volume` is optional.
+where :arg:`pathname` is the name of a partition, directory or file, :arg:`size` is the size of the named partition,
+directory or file (in bytes), and :arg:`volume` is the volume number used in the files :file:`volume.config` and
+:file:`hosting.config`. :arg:`seed` is used for seeding the :ref:`assignment-table`. You must specify a size for
+directories or files; size is optional for raw partitions. :arg:`volume` is optional and :arg:`seed` are optional.
+
+.. note::
+
+ The :arg:`volume` option is independent of the :arg:`seed` option and either can be used with or without the other,
+ and their ordering on the line is irrelevant.
+
+.. note::
+
+ If the :arg:`seed` option is used every use must have a unique value for :arg:`string`.
You can use any partition of any size. For best performance:
@@ -67,6 +75,22 @@ supported. They include
- ``G`` Gigabytes (1024^3 or 1,073,741,824 bytes)
- ``T`` Terabytes (1024^4 or 1,099,511,627,776 bytes)
+.. _assignment-table:
+
+Assignment Table
+----------------
+
+Each storage element defined in :file:`storage.config` is divided in to :term:`stripes`. The assignment table maps from
+an object URL to a specific stripe. The table is initialized based on a pseudo-random process which is seeded by hashing
+a string for each stripe. This string is composed of a seed string, an offset (the start of the stripe on the storage
+element) and the length of the stripe. By default the path for the storage is used as the seed string. This ensures that
+each stripe has a unique string for the assignment hash. This does make the assignment table very sensitive to the path
+for the storage elements and changing even one can have a cascading effect which will effectively clear most of the cache.
+This can be problem when drives fail and a system reboot causes the path names to change.
+
+The :arg:`seed` option can be used to create a fixed string that an administrator can use to keep the assignment table
+consistent even if a device has a changed path. This value of the option is used instead of the path as the seed string
+for the assignment table hash.
Examples
========
@@ -90,7 +114,7 @@ cache file with::
.. note::
When using on-filesystem cache disk storage, you can only have one such
directory specified. This will be address in a future version.
-
+
Solaris Example
---------------
@@ -124,6 +148,17 @@ In order to apply these settings, trigger a reload with :manpage:`udevadm(8)`:::
udevadm trigger --subsystem-match=block
+As an implementation note, modern Linux supports `alternative symlinked names for disk devices
+<https://wiki.archlinux.org/index.php/persistent_block_device_naming>`_ in the ``/dev/disk`` directory structure. As
+noted for the :ref:`assignment-table` the path used for the disk can effect the cache if it changes. This can be
+ameloriated in some cases by using one of the alternate paths in via ``/dev/disk``. Note that if the ``by-id`` style is
+used, replacing a failed drive will cause that path to change because the new drive will have a different physical ID.
+
+If this is not sufficient then the :arg:`seed` argument should be used to create a more permanent assignment table. An
+example would be::
+
+ /dev/sde seed=cache.disk.0
+ /dev/sdg seed=cache.disk.1
FreeBSD Example
---------------
@@ -143,4 +178,3 @@ following rules are stored in :manpage:`devfs.conf(5)`::
# Assign /dev/ada1 and /dev/ada2 to the tserver user
own ada[12] tserver:tserver
-
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/iocore/cache/Cache.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/Cache.cc b/iocore/cache/Cache.cc
index be3674f..3913b71 100644
--- a/iocore/cache/Cache.cc
+++ b/iocore/cache/Cache.cc
@@ -739,10 +739,14 @@ CacheProcessor::start_internal(int flags)
}
}
if (diskok) {
+ int sector_size = sd->hw_sector_size;
+
gdisks[gndisks] = new CacheDisk();
- gdisks[gndisks]->forced_volume_num = sd->vol_num;
+ gdisks[gndisks]->forced_volume_num = sd->forced_volume_num;
+ if (sd->hash_seed_string)
+ gdisks[gndisks]->hash_seed_string = ats_strdup(sd->hash_seed_string);
+
Debug("cache_hosting", "Disk: %d, blocks: %d", gndisks, blocks);
- int sector_size = sd->hw_sector_size;
if (sector_size < cache_config_force_sector_size)
sector_size = cache_config_force_sector_size;
@@ -1133,7 +1137,7 @@ int
Vol::db_check(bool /* fix ATS_UNUSED */ )
{
char tt[256];
- printf(" Data for [%s]\n", hash_text);
+ printf(" Data for [%s]\n", hash_text.get());
printf(" Length: %" PRIu64 "\n", (uint64_t)len);
printf(" Write Position: %" PRIu64 "\n", (uint64_t) (header->write_pos - skip));
printf(" Phase: %d\n", (int)!!header->phase);
@@ -1231,7 +1235,7 @@ vol_dir_clear(Vol *d)
vol_clear_init(d);
if (pwrite(d->fd, d->raw_dir, dir_len, d->skip) < 0) {
- Warning("unable to clear cache directory '%s'", d->hash_text);
+ Warning("unable to clear cache directory '%s'", d->hash_text.get());
return -1;
}
return 0;
@@ -1259,15 +1263,18 @@ Vol::clear_dir()
int
Vol::init(char *s, off_t blocks, off_t dir_skip, bool clear)
{
- dir_skip = ROUND_TO_STORE_BLOCK((dir_skip < START_POS ? START_POS : dir_skip));
- path = ats_strdup(s);
- const size_t hash_text_size = strlen(s) + 32;
- hash_text = (char *)ats_malloc(hash_text_size);
- ink_strlcpy(hash_text, s, hash_text_size);
- const size_t s_size = strlen(s);
- snprintf(hash_text + s_size, (hash_text_size - s_size), " %" PRIu64 ":%" PRIu64 "",
+ char* seed_str = disk->hash_seed_string ? disk->hash_seed_string : s;
+ const size_t hash_seed_size = strlen(seed_str);
+ const size_t hash_text_size = hash_seed_size + 32;
+
+ hash_text = static_cast<char *>(ats_malloc(hash_text_size));
+ ink_strlcpy(hash_text, seed_str, hash_text_size);
+ snprintf(hash_text + hash_seed_size, (hash_text_size - hash_seed_size), " %" PRIu64 ":%" PRIu64 "",
(uint64_t)dir_skip, (uint64_t)blocks);
MD5Context().hash_immediate(hash_id, hash_text, strlen(hash_text));
+
+ dir_skip = ROUND_TO_STORE_BLOCK((dir_skip < START_POS ? START_POS : dir_skip));
+ path = ats_strdup(s);
len = blocks * STORE_BLOCK_SIZE;
ink_assert(len <= MAX_VOL_SIZE);
skip = dir_skip;
@@ -1305,7 +1312,7 @@ Vol::init(char *s, off_t blocks, off_t dir_skip, bool clear)
#endif
if (clear) {
- Note("clearing cache directory '%s'", hash_text);
+ Note("clearing cache directory '%s'", hash_text.get());
return clear_dir();
}
@@ -1315,7 +1322,7 @@ Vol::init(char *s, off_t blocks, off_t dir_skip, bool clear)
// try A
off_t as = skip;
if (is_debug_tag_set("cache_init"))
- Note("reading directory '%s'", hash_text);
+ Note("reading directory '%s'", hash_text.get());
SET_HANDLER(&Vol::handle_header_read);
init_info->vol_aio[0].aiocb.aio_offset = as;
init_info->vol_aio[1].aiocb.aio_offset = as + footer_offset;
@@ -1349,7 +1356,7 @@ Vol::handle_dir_clear(int event, void *data)
if (event == AIO_EVENT_DONE) {
op = (AIOCallback *) data;
if ((size_t) op->aio_result != (size_t) op->aiocb.aio_nbytes) {
- Warning("unable to clear cache directory '%s'", hash_text);
+ Warning("unable to clear cache directory '%s'", hash_text.get());
fd = -1;
}
@@ -1385,8 +1392,8 @@ Vol::handle_dir_read(int event, void *data)
if (!(header->magic == VOL_MAGIC && footer->magic == VOL_MAGIC &&
CACHE_DB_MAJOR_VERSION_COMPATIBLE <= header->version.ink_major && header->version.ink_major <= CACHE_DB_MAJOR_VERSION
)) {
- Warning("bad footer in cache directory for '%s', clearing", hash_text);
- Note("clearing cache directory '%s'", hash_text);
+ Warning("bad footer in cache directory for '%s', clearing", hash_text.get());
+ Note("clearing cache directory '%s'", hash_text.get());
clear_dir();
return EVENT_DONE;
}
@@ -1482,7 +1489,7 @@ Vol::handle_recover_from_data(int event, void * /* data ATS_UNUSED */ )
io.aiocb.aio_nbytes = (skip + len) - recover_pos;
} else if (event == AIO_EVENT_DONE) {
if ((size_t) io.aiocb.aio_nbytes != (size_t) io.aio_result) {
- Warning("disk read error on recover '%s', clearing", hash_text);
+ Warning("disk read error on recover '%s', clearing", hash_text.get());
goto Lclear;
}
if (io.aiocb.aio_offset == header->last_write_pos) {
@@ -1499,7 +1506,7 @@ Vol::handle_recover_from_data(int event, void * /* data ATS_UNUSED */ )
while (done < to_check) {
Doc *doc = (Doc *) (s + done);
if (doc->magic != DOC_MAGIC || doc->write_serial > header->write_serial) {
- Warning("no valid directory found while recovering '%s', clearing", hash_text);
+ Warning("no valid directory found while recovering '%s', clearing", hash_text.get());
goto Lclear;
}
done += round_to_approx_size(doc->len);
@@ -1642,7 +1649,7 @@ Ldone:{
recover_pos += EVACUATION_SIZE; // safely cover the max write size
if (recover_pos < header->write_pos && (recover_pos + EVACUATION_SIZE >= header->write_pos)) {
Debug("cache_init", "Head Pos: %" PRIu64 ", Rec Pos: %" PRIu64 ", Wrapped:%d", header->write_pos, recover_pos, recover_wrapped);
- Warning("no valid directory found while recovering '%s', clearing", hash_text);
+ Warning("no valid directory found while recovering '%s', clearing", hash_text.get());
goto Lclear;
}
@@ -1749,7 +1756,7 @@ Vol::handle_header_read(int event, void *data)
(hf[0]->sync_serial >= hf[2]->sync_serial || hf[2]->sync_serial != hf[3]->sync_serial)) {
SET_HANDLER(&Vol::handle_dir_read);
if (is_debug_tag_set("cache_init"))
- Note("using directory A for '%s'", hash_text);
+ Note("using directory A for '%s'", hash_text.get());
io.aiocb.aio_offset = skip;
ink_assert(ink_aio_read(&io));
}
@@ -1758,11 +1765,11 @@ Vol::handle_header_read(int event, void *data)
SET_HANDLER(&Vol::handle_dir_read);
if (is_debug_tag_set("cache_init"))
- Note("using directory B for '%s'", hash_text);
+ Note("using directory B for '%s'", hash_text.get());
io.aiocb.aio_offset = skip + vol_dirlen(this);
ink_assert(ink_aio_read(&io));
} else {
- Note("no good directory, clearing '%s'", hash_text);
+ Note("no good directory, clearing '%s'", hash_text.get());
clear_dir();
delete init_info;
init_info = 0;
@@ -2467,7 +2474,7 @@ CacheVC::handleReadDone(int event, Event *e)
if (!io.ok()) {
Debug("cache_disk_error", "Read error on disk %s\n \
read range : [%" PRIu64 " - %" PRIu64 " bytes] [%" PRIu64 " - %" PRIu64 " blocks] \n",
- vol->hash_text, (uint64_t)io.aiocb.aio_offset, (uint64_t)io.aiocb.aio_offset + io.aiocb.aio_nbytes,
+ vol->hash_text.get(), (uint64_t)io.aiocb.aio_offset, (uint64_t)io.aiocb.aio_offset + io.aiocb.aio_nbytes,
(uint64_t)io.aiocb.aio_offset / 512, (uint64_t)(io.aiocb.aio_offset + io.aiocb.aio_nbytes) / 512);
}
goto Ldone;
@@ -2494,7 +2501,7 @@ CacheVC::handleReadDone(int event, Event *e)
doc = reinterpret_cast<Doc*>(buf->data()); // buf may be a new copy
} else {
Debug("cache_bc", "Upgrade of fragment failed - disk %s - doc id = %" PRIx64 ":%" PRIx64 "\n"
- , vol->hash_text, read_key->slice64(0), read_key->slice64(1));
+ , vol->hash_text.get(), read_key->slice64(0), read_key->slice64(1));
doc->magic = DOC_CORRUPT;
// Should really trash the directory entry for this, as it's never going to work in the future.
// Or does that happen later anyway?
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/iocore/cache/CacheDir.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheDir.cc b/iocore/cache/CacheDir.cc
index 18b3be6..bd81325 100644
--- a/iocore/cache/CacheDir.cc
+++ b/iocore/cache/CacheDir.cc
@@ -1015,13 +1015,13 @@ sync_cache_dir_on_shutdown(void)
Vol *d = gvol[i];
if (DISK_BAD(d->disk)) {
- Debug("cache_dir_sync", "Dir %s: ignoring -- bad disk", d->hash_text);
+ Debug("cache_dir_sync", "Dir %s: ignoring -- bad disk", d->hash_text.get());
continue;
}
size_t dirlen = vol_dirlen(d);
ink_assert(dirlen > 0); // make clang happy - if not > 0 the vol is seriously messed up
if (!d->header->dirty && !d->dir_sync_in_progress) {
- Debug("cache_dir_sync", "Dir %s: ignoring -- not dirty", d->hash_text);
+ Debug("cache_dir_sync", "Dir %s: ignoring -- not dirty", d->hash_text.get());
continue;
}
// recompute hit_evacuate_window
@@ -1032,7 +1032,7 @@ sync_cache_dir_on_shutdown(void)
// dont worry about the cachevc s in the agg queue
// directories have not been inserted for these writes
if (d->agg_buf_pos) {
- Debug("cache_dir_sync", "Dir %s: flushing agg buffer first", d->hash_text);
+ Debug("cache_dir_sync", "Dir %s: flushing agg buffer first", d->hash_text.get());
// set write limit
d->header->agg_pos = d->header->write_pos + d->agg_buf_pos;
@@ -1054,7 +1054,7 @@ sync_cache_dir_on_shutdown(void)
for (int i = 0; i < d->num_interim_vols; i++) {
InterimCacheVol *sv = &(d->interim_vols[i]);
if (sv->agg_buf_pos) {
- Debug("cache_dir_sync", "Dir %s: flushing agg buffer first to interim", d->hash_text);
+ Debug("cache_dir_sync", "Dir %s: flushing agg buffer first to interim", d->hash_text.get());
sv->header->agg_pos = sv->header->write_pos + sv->agg_buf_pos;
int r = pwrite(sv->fd, sv->agg_buffer, sv->agg_buf_pos, sv->header->write_pos);
@@ -1096,7 +1096,7 @@ sync_cache_dir_on_shutdown(void)
off_t start = d->skip + (B ? dirlen : 0);
B = pwrite(d->fd, buf, dirlen, start);
ink_assert(B == dirlen);
- Debug("cache_dir_sync", "done syncing dir for vol %s", d->hash_text);
+ Debug("cache_dir_sync", "done syncing dir for vol %s", d->hash_text.get());
}
Debug("cache_dir_sync", "sync done");
if (buf)
@@ -1131,7 +1131,7 @@ Lrestart:
if (event == AIO_EVENT_DONE) {
// AIO Thread
if (io.aio_result != (int64_t)io.aiocb.aio_nbytes) {
- Warning("vol write error during directory sync '%s'", gvol[vol]->hash_text);
+ Warning("vol write error during directory sync '%s'", gvol[vol]->hash_text.get());
event = EVENT_NONE;
goto Ldone;
}
@@ -1164,11 +1164,11 @@ Lrestart:
The dirty bit it set in dir_insert, dir_overwrite and dir_delete_entry
*/
if (!d->header->dirty) {
- Debug("cache_dir_sync", "Dir %s not dirty", d->hash_text);
+ Debug("cache_dir_sync", "Dir %s not dirty", d->hash_text.get());
goto Ldone;
}
if (d->is_io_in_progress() || d->agg_buf_pos) {
- Debug("cache_dir_sync", "Dir %s: waiting for agg buffer", d->hash_text);
+ Debug("cache_dir_sync", "Dir %s: waiting for agg buffer", d->hash_text.get());
d->dir_sync_waiting = 1;
if (!d->is_io_in_progress())
d->aggWrite(EVENT_IMMEDIATE, 0);
@@ -1182,7 +1182,7 @@ Lrestart:
#endif
return EVENT_CONT;
}
- Debug("cache_dir_sync", "pos: %" PRIu64 " Dir %s dirty...syncing to disk", d->header->write_pos, d->hash_text);
+ Debug("cache_dir_sync", "pos: %" PRIu64 " Dir %s dirty...syncing to disk", d->header->write_pos, d->hash_text.get());
d->header->dirty = 0;
if (buflen < dirlen) {
if (buf)
@@ -1276,7 +1276,7 @@ Vol::dir_check(bool /* fix ATS_UNUSED */) // TODO: we should eliminate this para
free += dir_freelist_length(this, s);
}
int total = buckets * segments * DIR_DEPTH;
- printf(" Directory for [%s]\n", hash_text);
+ printf(" Directory for [%s]\n", hash_text.get());
printf(" Bytes: %d\n", total * SIZEOF_DIR);
printf(" Segments: %" PRIu64 "\n", (uint64_t)segments);
printf(" Buckets: %" PRIu64 "\n", (uint64_t)buckets);
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/iocore/cache/CachePagesInternal.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CachePagesInternal.cc b/iocore/cache/CachePagesInternal.cc
index 6221191..3fd8e9a 100644
--- a/iocore/cache/CachePagesInternal.cc
+++ b/iocore/cache/CachePagesInternal.cc
@@ -283,7 +283,7 @@ ShowCacheInternal::showVolVolumes(int event, Event * e)
"<td>%u</td>" // sync serial
"<td>%u</td>" // write serial
"</tr>\n",
- p->hash_text,
+ p->hash_text.get(),
(uint64_t)((p->len - (p->start - p->skip)) / CACHE_BLOCK_SIZE),
(uint64_t)(p->buckets * DIR_DEPTH * p->segments),
(uint64_t)((p->header->write_pos - p->start) / CACHE_BLOCK_SIZE),
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/iocore/cache/CacheWrite.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheWrite.cc b/iocore/cache/CacheWrite.cc
index a40f825..4050c88 100644
--- a/iocore/cache/CacheWrite.cc
+++ b/iocore/cache/CacheWrite.cc
@@ -319,7 +319,7 @@ Vol::aggWriteDone(int event, Event *e)
header->write_pos += io.aiocb.aio_nbytes;
ink_assert(header->write_pos >= start);
DDebug("cache_agg", "Dir %s, Write: %" PRIu64 ", last Write: %" PRIu64 "\n",
- hash_text, header->write_pos, header->last_write_pos);
+ hash_text.get(), header->write_pos, header->last_write_pos);
ink_assert(header->write_pos == header->agg_pos);
if (header->write_pos + EVACUATION_SIZE > scan_pos)
periodic_scan();
@@ -330,7 +330,7 @@ Vol::aggWriteDone(int event, Event *e)
// for fragments is this aggregation buffer
Debug("cache_disk_error", "Write error on disk %s\n \
write range : [%" PRIu64 " - %" PRIu64 " bytes] [%" PRIu64 " - %" PRIu64 " blocks] \n",
- hash_text, (uint64_t)io.aiocb.aio_offset,
+ hash_text.get(), (uint64_t)io.aiocb.aio_offset,
(uint64_t)io.aiocb.aio_offset + io.aiocb.aio_nbytes,
(uint64_t)io.aiocb.aio_offset / CACHE_BLOCK_SIZE,
(uint64_t)(io.aiocb.aio_offset + io.aiocb.aio_nbytes) / CACHE_BLOCK_SIZE);
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/iocore/cache/I_Store.h
----------------------------------------------------------------------
diff --git a/iocore/cache/I_Store.h b/iocore/cache/I_Store.h
index ba55657..303f880 100644
--- a/iocore/cache/I_Store.h
+++ b/iocore/cache/I_Store.h
@@ -43,20 +43,23 @@
//
struct Span
{
- char *pathname;
int64_t blocks;
- int hw_sector_size;
- bool file_pathname; // the pathname is a file
- bool isRaw;
int64_t offset; // used only if (file == true)
+ int hw_sector_size;
int alignment;
int disk_id;
- int vol_num;
- LINK(Span, link);
-
+ int forced_volume_num; ///< Force span in to specific volume.
private:
bool is_mmapable_internal;
public:
+ bool file_pathname; // the pathname is a file
+ bool isRaw;
+ // v- used as a magic location for copy constructor.
+ // we memcpy everything before this member and do explicit assignment for the rest.
+ ats_scoped_str pathname;
+ ats_scoped_str hash_seed_string; ///< Used to seed the stripe assignment hash.
+ SLINK(Span, link);
+
bool is_mmapable() { return is_mmapable_internal; }
void set_mmapable(bool s) { is_mmapable_internal = s; }
int64_t size() { return blocks * STORE_BLOCK_SIZE; }
@@ -84,6 +87,7 @@ public:
int write(int fd);
int read(int fd);
+ /// Duplicate this span and all chained spans.
Span *dup();
int64_t end() { return offset + blocks; }
@@ -94,10 +98,33 @@ public:
int64_t * offset, // for file, start offset (unsupported)
char *buf, int buflen); // where to store the path
+ /// Set the hash seed string.
+ void hash_seed_string_set(char const* s);
+ /// Set the volume number.
+ void volume_number_set(int n);
+
Span()
- : pathname(NULL), blocks(0), hw_sector_size(DEFAULT_HW_SECTOR_SIZE), file_pathname(false),
- isRaw(true), offset(0), alignment(0), disk_id(0), is_mmapable_internal(false)
+ : blocks(0)
+ , offset(0)
+ , hw_sector_size(DEFAULT_HW_SECTOR_SIZE)
+ , alignment(0)
+ , disk_id(0)
+ , forced_volume_num(-1)
+ , is_mmapable_internal(false)
+ , file_pathname(false)
+ , isRaw(true)
{ }
+
+ /// Copy constructor.
+ /// @internal Prior to this implementation handling the char* pointers was done manual
+ /// at every call site. We also need this because we have ats_scoped_str members.
+ Span(Span const& that) {
+ memcpy(this, &that, reinterpret_cast<intptr_t>(&(static_cast<Span*>(0)->pathname)));
+ if (that.pathname) pathname = ats_strdup(that.pathname);
+ if (that.hash_seed_string) hash_seed_string = ats_strdup(that.hash_seed_string);
+ link.next = NULL;
+ }
+
~Span();
};
@@ -180,9 +207,10 @@ struct Store
//
const char *read_config(int fd = -1);
int write_config_data(int fd);
-private:
- char const * const vol_str;
- int getVolume(char* line);
+
+ /// Additional configuration key values.
+ static char const VOLUME_KEY[];
+ static char const HASH_SEED_KEY[];
};
extern Store theStore;
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/iocore/cache/P_CacheDisk.h
----------------------------------------------------------------------
diff --git a/iocore/cache/P_CacheDisk.h b/iocore/cache/P_CacheDisk.h
index c704bdc..76c11ef 100644
--- a/iocore/cache/P_CacheDisk.h
+++ b/iocore/cache/P_CacheDisk.h
@@ -103,14 +103,17 @@ struct CacheDisk: public Continuation
DiskVol *free_blocks;
int num_errors;
int cleared;
- int forced_volume_num; // assuming zero is not a valid volume number
+ // Extra configuration values
+ int forced_volume_num; ///< Volume number for this disk.
+ ats_scoped_str hash_seed_string; ///< Base string for hash seed.
+
CacheDisk()
: Continuation(new_ProxyMutex()), header(NULL),
path(NULL), header_len(0), len(0), start(0), skip(0),
num_usable_blocks(0), fd(-1), free_space(0), wasted_space(0),
disk_vols(NULL), free_blocks(NULL), num_errors(0), cleared(0),
- forced_volume_num(0)
+ forced_volume_num(-1)
{ }
~CacheDisk();
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/iocore/cache/P_CacheVol.h
----------------------------------------------------------------------
diff --git a/iocore/cache/P_CacheVol.h b/iocore/cache/P_CacheVol.h
index c14c200..d8748a3 100644
--- a/iocore/cache/P_CacheVol.h
+++ b/iocore/cache/P_CacheVol.h
@@ -414,7 +414,7 @@ void dir_clean_interimvol(InterimCacheVol *d);
struct Vol: public Continuation
{
char *path;
- char *hash_text;
+ ats_scoped_str hash_text;
CryptoHash hash_id;
int fd;
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/iocore/cache/Store.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/Store.cc b/iocore/cache/Store.cc
index f86c16b..be4ffc9 100644
--- a/iocore/cache/Store.cc
+++ b/iocore/cache/Store.cc
@@ -40,52 +40,18 @@
// Global
Store theStore;
-int
-Store::getVolume(char* line)
-{
- if (!line) {
- return 0;
- }
-
- int v = 0;
- char* str = strstr(line, vol_str);
- char* vol_start = str;
-
- if (!str) {
- return 0;
- }
-
- while (*str && !ParseRules::is_digit(*str))
- str++;
- v = ink_atoi(str);
-
- while (*str && ParseRules::is_digit(*str))
- str++;
- while(*str) {
- *vol_start = *str;
- vol_start++;
- str++;
- }
- *vol_start = 0;
- Debug("cache_init", "returning %d and '%s'", v, line);
-
- if (v < 0) {
- return 0;
- }
-
- return v;
-}
-
-
//
// Store
//
+
+char const Store::VOLUME_KEY[] = "volume";
+char const Store::HASH_SEED_KEY[] = "seed";
+
Ptr<ProxyMutex> tmp_p;
-Store::Store():n_disks(0), disk(NULL),
+Store::Store():n_disks(0), disk(NULL)
#if TS_USE_INTERIM_CACHE == 1
- n_interim_disks(0), interim_disk(NULL),
+ ,n_interim_disks(0), interim_disk(NULL)
#endif
- vol_str("volume=")
{
}
@@ -234,6 +200,18 @@ Span::path(char *filename, int64_t * aoffset, char *buf, int buflen)
}
void
+Span::hash_seed_string_set(char const* s)
+{
+ hash_seed_string = s ? ats_strdup(s) : NULL;
+}
+
+void
+Span::volume_number_set(int n)
+{
+ forced_volume_num = n;
+}
+
+void
Store::delete_all()
{
for (unsigned i = 0; i < n_disks; i++) {
@@ -252,7 +230,6 @@ Store::~Store()
Span::~Span()
{
- ats_free(pathname);
if (link.next)
delete link.next;
}
@@ -320,46 +297,57 @@ Store::read_config(int fd)
}
// For each line
- char line[256];
- while (ink_file_fd_readline(fd, sizeof(line) - 1, line) > 0) {
+ char line[1024];
+ int len;
+ while ((len = ink_file_fd_readline(fd, sizeof(line), line)) > 0) {
+ char const* path;
+ char const* seed = 0;
// update lines
- line[sizeof(line) - 1] = 0;
- ln++;
+ ++ln;
- // skip comments and blank lines
+ // Because the SimpleTokenizer is a bit too simple, we have to normalize whitespace.
+ for ( char *spot = line, *limit = line+len ; spot < limit ; ++spot )
+ if (ParseRules::is_space(*spot)) *spot = ' '; // force whitespace to literal space.
- if (*line == '#')
- continue;
- char *n = line;
- n += strspn(n, " \t\n");
- if (!*n)
- continue;
+ SimpleTokenizer tokens(line, ' ', SimpleTokenizer::OVERWRITE_INPUT_STRING);
- int volume_id = getVolume(n);
+ // skip comments and blank lines
+ path = tokens.getNext();
+ if (0 == path || '#' == path[0])
+ continue;
// parse
- Debug("cache_init", "Store::read_config: \"%s\"", n);
+ Debug("cache_init", "Store::read_config: \"%s\"", path);
- char *e = strpbrk(n, " \t\n");
- int len = e ? e - n : strlen(n);
- (void) len;
int64_t size = -1;
- while (e && *e && !ParseRules::is_digit(*e))
- e++;
- if (e && *e) {
- if ((size = ink_atoi64(e)) <= 0) {
- err = "error parsing size";
- goto Lfail;
+ int volume_num = -1;
+ char const* e;
+ while (0 != (e = tokens.getNext())) {
+ if (ParseRules::is_digit(*e)) {
+ if ((size = ink_atoi64(e)) <= 0) {
+ err = "error parsing size";
+ goto Lfail;
+ }
+ } else if (0 == strncasecmp(HASH_SEED_KEY, e, sizeof(HASH_SEED_KEY)-1)) {
+ e += sizeof(HASH_SEED_KEY) - 1;
+ if ('=' == *e) ++e;
+ if (*e && !ParseRules::is_space(*e))
+ seed = e;
+ } else if (0 == strncasecmp(VOLUME_KEY, e, sizeof(VOLUME_KEY)-1)) {
+ e += sizeof(VOLUME_KEY) - 1;
+ if ('=' == *e) ++e;
+ if (!*e || !ParseRules::is_digit(*e) || 0 >= (volume_num = ink_atoi(e))) {
+ err = "error parsing volume number";
+ goto Lfail;
+ }
}
}
- n[len] = 0;
- char *pp = Layout::get()->relative(n);
+ char *pp = Layout::get()->relative(path);
ns = new Span;
- ns->vol_num = volume_id;
- Debug("cache_init", "Store::read_config - ns = new Span; ns->init(\"%s\",%" PRId64 "), ns->vol_num=%d",
- pp, size, ns->vol_num);
+ Debug("cache_init", "Store::read_config - ns = new Span; ns->init(\"%s\",%" PRId64 "), forced volume=%d%s%s",
+ pp, size, volume_num, seed ? " seed=" : "", seed ? seed : "");
if ((err = ns->init(pp, size))) {
RecSignalWarning(REC_SIGNAL_SYSTEM_ERROR, "could not initialize storage \"%s\" [%s]", pp, err);
Debug("cache_init", "Store::read_config - could not initialize storage \"%s\" [%s]", pp, err);
@@ -370,6 +358,10 @@ Store::read_config(int fd)
ats_free(pp);
n_dsstore++;
+ // Set side values if present.
+ if (seed) ns->hash_seed_string_set(seed);
+ if (volume_num > 0) ns->volume_number_set(volume_num);
+
// new Span
{
Span *prev = cur;
@@ -454,7 +446,7 @@ Store::write_config_data(int fd)
for (unsigned i = 0; i < n_disks; i++)
for (Span * sd = disk[i]; sd; sd = sd->link.next) {
char buf[PATH_NAME_MAX + 64];
- snprintf(buf, sizeof(buf), "%s %" PRId64 "\n", sd->pathname, (int64_t) sd->blocks * (int64_t) STORE_BLOCK_SIZE);
+ snprintf(buf, sizeof(buf), "%s %" PRId64 "\n", sd->pathname.get(), (int64_t) sd->blocks * (int64_t) STORE_BLOCK_SIZE);
if (ink_file_fd_writestring(fd, buf) == -1)
return (-1);
}
@@ -574,7 +566,7 @@ Span::init(char *an, int64_t size)
offset = 1;
}
- Debug("cache_init", "Span::init - %s hw_sector_size = %d size = %" PRId64 ", blocks = %" PRId64 ", disk_id = %d, file_pathname = %d", pathname, hw_sector_size, size, blocks, disk_id, file_pathname);
+ Debug("cache_init", "Span::init - %s hw_sector_size = %d size = %" PRId64 ", blocks = %" PRId64 ", disk_id = %d, file_pathname = %d", pathname.get(), hw_sector_size, size, blocks, disk_id, file_pathname);
Lfail:
return err;
@@ -822,7 +814,7 @@ Span::init(char *filename, int64_t size)
if (!file_pathname)
if (size <= 0)
return "When using directories for cache storage, you must specify a size\n";
- Debug("cache_init", "Span::init - mapped file \"%s\", %" PRId64 "", pathname, size);
+ Debug("cache_init", "Span::init - mapped file \"%s\", %" PRId64 "", pathname.get(), size);
}
blocks = size / STORE_BLOCK_SIZE;
}
@@ -860,10 +852,7 @@ try_alloc(Store & target, Span * source, unsigned int start_blocks, bool one_onl
a = blocks;
Span *d = new Span(*source);
- d->pathname = ats_strdup(source->pathname);
d->blocks = a;
- d->file_pathname = source->file_pathname;
- d->offset = source->offset;
d->link.next = ds;
if (d->file_pathname)
@@ -935,7 +924,6 @@ Store::try_realloc(Store & s, Store & diff)
goto Lfound;
} else {
Span *x = new Span(*d);
- x->pathname = ats_strdup(x->pathname);
// d will be the first vol
d->blocks = sd->offset - d->offset;
d->link.next = x;
@@ -988,7 +976,7 @@ Span::write(int fd)
{
char buf[32];
- if (ink_file_fd_writestring(fd, (char *) (pathname ? pathname : ")")) == -1)
+ if (ink_file_fd_writestring(fd, (pathname ? pathname.get() : ")")) == -1)
return (-1);
if (ink_file_fd_writestring(fd, "\n") == -1)
return (-1);
@@ -1156,9 +1144,8 @@ Span *
Span::dup()
{
Span *ds = new Span(*this);
- ds->pathname = ats_strdup(pathname);
- if (ds->link.next)
- ds->link.next = ds->link.next->dup();
+ if (this->link.next)
+ ds->link.next = this->link.next->dup();
return ds;
}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/83248169/lib/ts/ink_memory.h
----------------------------------------------------------------------
diff --git a/lib/ts/ink_memory.h b/lib/ts/ink_memory.h
index 0b1ea5f..5859ed3 100644
--- a/lib/ts/ink_memory.h
+++ b/lib/ts/ink_memory.h
@@ -257,6 +257,12 @@ public:
operator value_type () const {
return _r;
}
+ /// Explicit conversion to resource type.
+ /// @note Syntactic sugar for @c static_cast<value_type>(instance). Required when passing to var arg function
+ /// as automatic conversion won't be done.
+ value_type get() const {
+ return _r;
+ }
/** Release resource from this container.
After this call, the resource will @b not cleaned up when this container is destructed.