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 2015/04/19 19:45:16 UTC
[2/8] trafficserver git commit: before seek change.
before seek change.
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/ee708499
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/ee708499
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/ee708499
Branch: refs/heads/ts-974-multi-range-read
Commit: ee7084990274939458314e35157a23abb13f3edc
Parents: 50f37f3
Author: Alan M. Carroll <so...@yahoo-inc.com>
Authored: Wed Nov 26 09:04:13 2014 -0600
Committer: Alan M. Carroll <so...@yahoo-inc.com>
Committed: Sat Dec 6 11:56:03 2014 -0600
----------------------------------------------------------------------
iocore/cache/CacheHttp.cc | 39 ++++++++++++++---
iocore/cache/CacheRead.cc | 22 ++++++----
iocore/cache/I_CacheDefs.h | 87 ++++++++++++++++++++++++++++++++++---
iocore/cache/P_CacheInternal.h | 27 ++++++++++++
lib/ts/InkErrno.h | 1 +
5 files changed, 155 insertions(+), 21 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/ee708499/iocore/cache/CacheHttp.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheHttp.cc b/iocore/cache/CacheHttp.cc
index e58e42e..024f5ca 100644
--- a/iocore/cache/CacheHttp.cc
+++ b/iocore/cache/CacheHttp.cc
@@ -329,20 +329,47 @@ RangeSpec::parse(char const* v, int len)
RangeSpec&
RangeSpec::add(uint64_t low, uint64_t high)
{
- if (EMPTY == _state || INVALID == _state) {
+ if (MULTI == _state) {
+ _ranges.push_back(Range(low, high));
+ } else if (SINGLE == _state) {
+ _ranges.push_back(_single);
+ _ranges.push_back(Range(low,high));
+ _state = MULTI;
+ } else {
_single._min = low;
_single._max = high;
_state = SINGLE;
- } else {
- _ranges.push_back(Range(low, high));
}
return *this;
}
-size_t
-RangeSpec::count() const
+bool
+RangeSpec::finalize(uint64_t len)
{
- return (EMPTY == _state || INVALID == _state) ? 0 : 1 + (_ranges.size());
+ if (INVALID == _state || EMPTY == _state) {
+ // nothing but simplifying later logic.
+ } else if (0 == len) {
+ /* Must special case zero length content
+ - suffix ranges are OK but other ranges are not.
+ - SM must return a 200 (not 206 or 416) for a valid range on zero length content.
+ (this is what Apache HTTPD does and seems the least bad thing)
+ - Therefore we don't bother actually adjusting the ranges as values don't matter.
+ */
+ if (!_single.isSuffix()) _state = INVALID;
+ if (MULTI == _state) {
+ for ( RangeBox::iterator spot = _ranges.begin(), limit = _ranges.end() ; spot != limit && MULTI == _state ; ++spot ) {
+ if (!spot->isSuffix()) _state = INVALID;
+ }
+ }
+ } else { // len > 0
+ if (!_single.finalize(len)) _state = INVALID;
+ if (MULTI == _state) {
+ for ( RangeBox::iterator spot = _ranges.begin(), limit = _ranges.end() ; spot != limit && MULTI == _state; ++spot ) {
+ if (!spot->finalize(len)) _state = INVALID;
+ }
+ }
+ }
+ return INVALID != _state;
}
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/ee708499/iocore/cache/CacheRead.cc
----------------------------------------------------------------------
diff --git a/iocore/cache/CacheRead.cc b/iocore/cache/CacheRead.cc
index 944cb37..c2caab7 100644
--- a/iocore/cache/CacheRead.cc
+++ b/iocore/cache/CacheRead.cc
@@ -106,18 +106,11 @@ Cache::open_read(Continuation * cont, CacheKey * key, CacheHTTPHdr * request,
OpenDirEntry *od = NULL;
CacheVC *c = NULL;
- MIMEField* range_field = request->field_find(MIME_FIELD_RANGE, MIME_LEN_RANGE);
- if (range_field) {
- RangeSpec rs;
- char const* value;
- int len;
- value = range_field->value_get(&len);
- rs.parse(value, len);
- }
-
{
CACHE_TRY_LOCK(lock, vol->mutex, mutex->thread_holding);
if (!lock.is_locked() || (od = vol->open_read(key)) || dir_probe(key, vol, &result, &last_collision)) {
+ MIMEField* range_field = request->field_find(MIME_FIELD_RANGE, MIME_LEN_RANGE);
+
c = new_CacheVC(cont);
c->first_key = c->key = c->earliest_key = *key;
c->vol = vol;
@@ -128,6 +121,12 @@ Cache::open_read(Continuation * cont, CacheKey * key, CacheHTTPHdr * request,
c->frag_type = CACHE_FRAG_TYPE_HTTP;
c->params = params;
c->od = od;
+ if (range_field) {
+ char const* value;
+ int len;
+ value = range_field->value_get(&len);
+ c->req_rs.parse(value, len);
+ }
}
if (!lock.is_locked()) {
SET_CONTINUATION_HANDLER(c, &CacheVC::openReadStartHead);
@@ -1157,6 +1156,11 @@ CacheVC::openReadStartHead(int event, Event * e)
doc_len = doc->total_len;
}
+ if (!req_rs.finalize(doc_len)) {
+ err = ECACHE_BAD_REQUEST_RANGE;
+ goto Ldone;
+ }
+
if (is_debug_tag_set("cache_read")) { // amc debug
char xt[33],yt[33];
Debug("cache_read", "CacheReadStartHead - read %s target %s - %s %d of %" PRId64" bytes, %d fragments",
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/ee708499/iocore/cache/I_CacheDefs.h
----------------------------------------------------------------------
diff --git a/iocore/cache/I_CacheDefs.h b/iocore/cache/I_CacheDefs.h
index 2c5caa4..df430f4 100644
--- a/iocore/cache/I_CacheDefs.h
+++ b/iocore/cache/I_CacheDefs.h
@@ -154,15 +154,22 @@ struct RangeSpec {
/// Construct as the range ( @a low .. @a high )
Range(uint64_t low, uint64_t high) : _min(low), _max(high) {}
- bool isValid() const { return _min <= _max || (0 == _max && 0 < _min); }
+ /// Test if this range is a trailing (terminal) range.
+ bool isSuffix() const;
+ /// Test if this range is a valid range.
+ bool isValid() const;
+ /// Adjust the range values based on content size @a len.
+ bool finalize(uint64_t len);
+ /// Force the range to an invalid state.
+ Range& invalidate();
};
/// Current state of the overall specification.
/// @internal We can distinguish between @c SINGLE and @c MULTI by looking at the
/// size of @a _ranges but we need this to mark @c EMPTY vs. not.
enum State {
- INVALID, ///< Range parsing failed.
EMPTY, ///< No range.
+ INVALID, ///< Range parsing failed.
SINGLE, ///< Single range.
MULTI, ///< Multiple ranges.
} _state;
@@ -171,21 +178,89 @@ struct RangeSpec {
/// By separating this out we can avoid allocation in the case of a single
/// range value, which is by far the most common ( > 99% in my experience).
Range _single;
- /// Storage for range values past the first one.
- std::vector<Range> _ranges;
+ /// Storage for range values.
+ typedef std::vector<Range> RangeBox;
+ /// The first range is copied here if there is more than one (to simplify).
+ RangeBox _ranges;
- RangeSpec() : _state(EMPTY)
- {}
+ /// Default constructor - invalid range
+ RangeSpec();
/** Parse a range field and update @a this with the results.
@return @c true if @a v was a valid range specifier, @c false otherwise.
*/
bool parse(char const* v, int len);
+ /** Validate and convert for a specific content @a length.
+
+ @return @c true if the range is satisfiable per the HTTP spec, @c false otherwise.
+ Note a range spec with no ranges is always satisfiable.
+ */
+ bool finalize(uint64_t length);
+
+ /** Number of distinct ranges.
+ @return Number of ranges.
+ */
size_t count() const;
+ /// If this is a valid, single range specification.
+ bool isSingle() const;
+
protected:
self& add(uint64_t low, uint64_t high);
};
+inline
+RangeSpec::RangeSpec() : _state(EMPTY)
+{
+}
+
+inline bool
+RangeSpec::isSingle() const
+{
+ return SINGLE == _state;
+}
+
+inline size_t
+RangeSpec::count() const
+{
+ return SINGLE == _state ? 1 : _ranges.size();
+}
+
+inline RangeSpec::Range&
+RangeSpec::Range::invalidate()
+{
+ _min = UINT64_MAX;
+ _max = 1;
+ return *this;
+}
+
+inline bool
+RangeSpec::Range::isSuffix() const
+{
+ return 0 == _max && _min > 0;
+}
+
+inline bool
+RangeSpec::Range::isValid() const
+{
+ return _min <= _max || this->isSuffix();
+}
+
+inline bool
+RangeSpec::Range::finalize(uint64_t len)
+{
+ ink_assert(len > 0);
+ bool zret = true; // is this range satisfiable for @a len?
+ if (this->isSuffix()) {
+ _max = len - 1;
+ _min = _min > len ? 0 : len - _min;
+ } else if (_min < len) {
+ _max = MIN(_max,len);
+ } else {
+ this->invalidate();
+ zret = false;
+ }
+ return zret;
+}
#endif // __CACHE_DEFS_H__
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/ee708499/iocore/cache/P_CacheInternal.h
----------------------------------------------------------------------
diff --git a/iocore/cache/P_CacheInternal.h b/iocore/cache/P_CacheInternal.h
index 57c5b0b..5a0b8fc 100644
--- a/iocore/cache/P_CacheInternal.h
+++ b/iocore/cache/P_CacheInternal.h
@@ -232,6 +232,25 @@ extern int cache_config_mutex_retry_delay;
#if TS_USE_INTERIM_CACHE == 1
extern int good_interim_disks;
#endif
+
+/** Range operation tracking.
+
+ This holds a range specification and tracks where in the range the current
+ cache operation is.
+*/
+class CacheRange : public RangeSpec
+{
+ public:
+ typedef CacheRange self; ///< Self reference type.
+
+ /// Default constructor
+ CacheRange() : _offset(0), _idx(-1) { }
+
+ protected:
+ uint64_t _offset; ///< Current offset into the range.
+ int _idx; ///< Current range index. (< 0 -> not in a range)
+};
+
// CacheVC
struct CacheVC: public CacheVConnection
{
@@ -462,6 +481,12 @@ struct CacheVC: public CacheVConnection
int header_to_write_len;
void *header_to_write;
short writer_lock_retry;
+ /* Range specs for range based operations.
+ @a req_rng is the range spec in the request from the User Agent.
+ @a rsp_rng is the range spec sent to the origin server.
+ */
+ CacheRange req_rs;
+ CacheRange rsp_rs;
#if TS_USE_INTERIM_CACHE == 1
InterimCacheVol *interim_vol;
MigrateToInterimCache *mts;
@@ -628,6 +653,8 @@ free_CacheVC(CacheVC *cont)
cont->alternate_index = CACHE_ALT_INDEX_DEFAULT;
if (cont->scan_vol_map)
ats_free(cont->scan_vol_map);
+ cont->req_rs.~CacheRange();
+ cont->rsp_rs.~CacheRange();
memset((char *) &cont->vio, 0, cont->size_to_init);
#ifdef CACHE_STAT_PAGES
ink_assert(!cont->stat_link.next && !cont->stat_link.prev);
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/ee708499/lib/ts/InkErrno.h
----------------------------------------------------------------------
diff --git a/lib/ts/InkErrno.h b/lib/ts/InkErrno.h
index 7f8676e..bb9bfb1 100644
--- a/lib/ts/InkErrno.h
+++ b/lib/ts/InkErrno.h
@@ -66,6 +66,7 @@
#define ECACHE_NOT_READY (CACHE_ERRNO+7)
#define ECACHE_ALT_MISS (CACHE_ERRNO+8)
#define ECACHE_BAD_READ_REQUEST (CACHE_ERRNO+9)
+#define ECACHE_BAD_REQUEST_RANGE (CACHE_ERRNO+10)
#define EHTTP_ERROR (HTTP_ERRNO+0)