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)