You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by bc...@apache.org on 2018/09/14 22:03:49 UTC
[trafficserver] branch master updated: Removes the deprecated
plugin coallapsed_connection
This is an automated email from the ASF dual-hosted git repository.
bcall 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 01fafdf Removes the deprecated plugin coallapsed_connection
01fafdf is described below
commit 01fafdf4eb6cbe75dc350b9e9981942a46008915
Author: Randall Meyer <rr...@apple.com>
AuthorDate: Fri Sep 14 10:05:59 2018 -0700
Removes the deprecated plugin coallapsed_connection
use collapsed_forwarding instead
This was deprecated in 7.x
---
CMakeLists.txt | 4 -
plugins/Makefile.am | 1 -
.../experimental/collapsed_connection/Makefile.inc | 21 -
.../collapsed_connection/MurmurHash3.cc | 327 ------
.../collapsed_connection/MurmurHash3.h | 20 -
.../collapsed_connection/P_collapsed_connection.h | 113 --
plugins/experimental/collapsed_connection/README | 75 --
.../collapsed_connection/collapsed_connection.cc | 1154 --------------------
.../collapsed_connection/default.config | 5 -
.../experimental/collapsed_connection/state.dot | 40 -
10 files changed, 1760 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index be2be56..cbd3c6d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -521,10 +521,6 @@ add_executable(ats
plugins/experimental/buffer_upload/buffer_upload.cc
plugins/experimental/cache_key_genid/cache_key_genid.c
plugins/experimental/cache_range_requests/cache_range_requests.cc
- plugins/experimental/collapsed_connection/collapsed_connection.cc
- plugins/experimental/collapsed_connection/MurmurHash3.cc
- plugins/experimental/collapsed_connection/MurmurHash3.h
- plugins/experimental/collapsed_connection/P_collapsed_connection.h
plugins/experimental/collapsed_forwarding/collapsed_forwarding.cc
plugins/experimental/custom_redirect/custom_redirect.cc
plugins/experimental/geoip_acl/acl.cc
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 8fa846e..a93bad0 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -58,7 +58,6 @@ include experimental/balancer/Makefile.inc
include experimental/buffer_upload/Makefile.inc
include experimental/cache_range_requests/Makefile.inc
include experimental/certifier/Makefile.inc
-include experimental/collapsed_connection/Makefile.inc
include experimental/collapsed_forwarding/Makefile.inc
include experimental/custom_redirect/Makefile.inc
include experimental/fq_pacing/Makefile.inc
diff --git a/plugins/experimental/collapsed_connection/Makefile.inc b/plugins/experimental/collapsed_connection/Makefile.inc
deleted file mode 100644
index 15a0e51..0000000
--- a/plugins/experimental/collapsed_connection/Makefile.inc
+++ /dev/null
@@ -1,21 +0,0 @@
-# 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.
-
-pkglib_LTLIBRARIES += experimental/collapsed_connection/collapsed_connection.la
-
-experimental_collapsed_connection_collapsed_connection_la_SOURCES = \
- experimental/collapsed_connection/collapsed_connection.cc \
- experimental/collapsed_connection/MurmurHash3.cc
diff --git a/plugins/experimental/collapsed_connection/MurmurHash3.cc b/plugins/experimental/collapsed_connection/MurmurHash3.cc
deleted file mode 100644
index 0db045b..0000000
--- a/plugins/experimental/collapsed_connection/MurmurHash3.cc
+++ /dev/null
@@ -1,327 +0,0 @@
-//-----------------------------------------------------------------------------
-// MurmurHash3 was written by Austin Appleby, and is placed in the public
-// domain. The author hereby disclaims copyright to this source code.
-
-// Note - The x86 and x64 versions do _not_ produce the same results, as the
-// algorithms are optimized for their respective platforms. You can still
-// compile and run any of them on any platform, but your performance with the
-// non-native version will be less than optimal.
-
-#include "MurmurHash3.h"
-
-//-----------------------------------------------------------------------------
-#define FORCE_INLINE inline __attribute__((always_inline))
-
-inline uint32_t
-rotl32(uint32_t x, int8_t r)
-{
- return (x << r) | (x >> (32 - r));
-}
-
-inline uint64_t
-rotl64(uint64_t x, int8_t r)
-{
- return (x << r) | (x >> (64 - r));
-}
-
-#define ROTL32(x, y) rotl32(x, y)
-#define ROTL64(x, y) rotl64(x, y)
-
-#define BIG_CONSTANT(x) (x##LLU)
-
-//-----------------------------------------------------------------------------
-// Block read - if your platform needs to do endian-swapping or can only
-// handle aligned reads, do the conversion here
-
-FORCE_INLINE uint32_t
-getblock32(const uint32_t *p, int i)
-{
- return p[i];
-}
-
-FORCE_INLINE uint64_t
-getblock64(const uint64_t *p, int i)
-{
- return p[i];
-}
-
-//-----------------------------------------------------------------------------
-// Finalization mix - force all bits of a hash block to avalanche
-
-FORCE_INLINE uint32_t
-fmix32(uint32_t h)
-{
- h ^= h >> 16;
- h *= 0x85ebca6b;
- h ^= h >> 13;
- h *= 0xc2b2ae35;
- h ^= h >> 16;
-
- return h;
-}
-
-//----------
-
-FORCE_INLINE uint64_t
-fmix64(uint64_t k)
-{
- k ^= k >> 33;
- k *= BIG_CONSTANT(0xff51afd7ed558ccd);
- k ^= k >> 33;
- k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
- k ^= k >> 33;
-
- return k;
-}
-
-//-----------------------------------------------------------------------------
-
-void
-MurmurHash3_x86_32(const void *key, int len, uint32_t seed, void *out)
-{
- const uint8_t *data = (const uint8_t *)key;
- const int nblocks = len / 4;
-
- uint32_t h1 = seed;
-
- const uint32_t c1 = 0xcc9e2d51;
- const uint32_t c2 = 0x1b873593;
-
- //----------
- // body
-
- const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4);
-
- for (int i = -nblocks; i; i++) {
- uint32_t k1 = getblock32(blocks, i);
-
- k1 *= c1;
- k1 = ROTL32(k1, 15);
- k1 *= c2;
-
- h1 ^= k1;
- h1 = ROTL32(h1, 13);
- h1 = h1 * 5 + 0xe6546b64;
- }
-
- //----------
- // tail
-
- const uint8_t *tail = (const uint8_t *)(data + nblocks * 4);
-
- uint32_t k1 = 0;
-
- switch (len & 3) {
- case 3:
- k1 ^= tail[2] << 16;
- // fallthrough
-
- case 2:
- k1 ^= tail[1] << 8;
- // fallthrough
-
- case 1:
- k1 ^= tail[0];
- k1 *= c1;
- k1 = ROTL32(k1, 15);
- k1 *= c2;
- h1 ^= k1;
- };
-
- //----------
- // finalization
-
- h1 ^= len;
-
- h1 = fmix32(h1);
-
- *(uint32_t *)out = h1;
-}
-
-//-----------------------------------------------------------------------------
-
-void
-MurmurHash3_x86_128(const void *key, const int len, uint32_t seed, void *out)
-{
- const uint8_t *data = (const uint8_t *)key;
- const int nblocks = len / 16;
-
- uint32_t h1 = seed;
- uint32_t h2 = seed;
- uint32_t h3 = seed;
- uint32_t h4 = seed;
-
- const uint32_t c1 = 0x239b961b;
- const uint32_t c2 = 0xab0e9789;
- const uint32_t c3 = 0x38b34ae5;
- const uint32_t c4 = 0xa1e38b93;
-
- //----------
- // body
-
- const uint32_t *blocks = (const uint32_t *)(data + nblocks * 16);
-
- for (int i = -nblocks; i; i++) {
- uint32_t k1 = getblock32(blocks, i * 4 + 0);
- uint32_t k2 = getblock32(blocks, i * 4 + 1);
- uint32_t k3 = getblock32(blocks, i * 4 + 2);
- uint32_t k4 = getblock32(blocks, i * 4 + 3);
-
- k1 *= c1;
- k1 = ROTL32(k1, 15);
- k1 *= c2;
- h1 ^= k1;
-
- h1 = ROTL32(h1, 19);
- h1 += h2;
- h1 = h1 * 5 + 0x561ccd1b;
-
- k2 *= c2;
- k2 = ROTL32(k2, 16);
- k2 *= c3;
- h2 ^= k2;
-
- h2 = ROTL32(h2, 17);
- h2 += h3;
- h2 = h2 * 5 + 0x0bcaa747;
-
- k3 *= c3;
- k3 = ROTL32(k3, 17);
- k3 *= c4;
- h3 ^= k3;
-
- h3 = ROTL32(h3, 15);
- h3 += h4;
- h3 = h3 * 5 + 0x96cd1c35;
-
- k4 *= c4;
- k4 = ROTL32(k4, 18);
- k4 *= c1;
- h4 ^= k4;
-
- h4 = ROTL32(h4, 13);
- h4 += h1;
- h4 = h4 * 5 + 0x32ac3b17;
- }
-
- //----------
- // tail
-
- const uint8_t *tail = (const uint8_t *)(data + nblocks * 16);
-
- uint32_t k1 = 0;
- uint32_t k2 = 0;
- uint32_t k3 = 0;
- uint32_t k4 = 0;
-
- switch (len & 15) {
- case 15:
- k4 ^= tail[14] << 16;
- // fallthrough
-
- case 14:
- k4 ^= tail[13] << 8;
- // fallthrough
-
- case 13:
- k4 ^= tail[12] << 0;
- k4 *= c4;
- k4 = ROTL32(k4, 18);
- k4 *= c1;
- h4 ^= k4;
- // fallthrough
-
- case 12:
- k3 ^= tail[11] << 24;
- // fallthrough
-
- case 11:
- k3 ^= tail[10] << 16;
- // fallthrough
-
- case 10:
- k3 ^= tail[9] << 8;
- // fallthrough
-
- case 9:
- k3 ^= tail[8] << 0;
- k3 *= c3;
- k3 = ROTL32(k3, 17);
- k3 *= c4;
- h3 ^= k3;
- // fallthrough
-
- case 8:
- k2 ^= tail[7] << 24;
- // fallthrough
-
- case 7:
- k2 ^= tail[6] << 16;
- // fallthrough
-
- case 6:
- k2 ^= tail[5] << 8;
- // fallthrough
-
- case 5:
- k2 ^= tail[4] << 0;
- k2 *= c2;
- k2 = ROTL32(k2, 16);
- k2 *= c3;
- h2 ^= k2;
- // fallthrough
-
- case 4:
- k1 ^= tail[3] << 24;
- // fallthrough
-
- case 3:
- k1 ^= tail[2] << 16;
- // fallthrough
-
- case 2:
- k1 ^= tail[1] << 8;
- // fallthrough
-
- case 1:
- k1 ^= tail[0] << 0;
- k1 *= c1;
- k1 = ROTL32(k1, 15);
- k1 *= c2;
- h1 ^= k1;
- };
-
- //----------
- // finalization
-
- h1 ^= len;
- h2 ^= len;
- h3 ^= len;
- h4 ^= len;
-
- h1 += h2;
- h1 += h3;
- h1 += h4;
- h2 += h1;
- h3 += h1;
- h4 += h1;
-
- h1 = fmix32(h1);
- h2 = fmix32(h2);
- h3 = fmix32(h3);
- h4 = fmix32(h4);
-
- h1 += h2;
- h1 += h3;
- h1 += h4;
- h2 += h1;
- h3 += h1;
- h4 += h1;
-
- ((uint32_t *)out)[0] = h1;
- ((uint32_t *)out)[1] = h2;
- ((uint32_t *)out)[2] = h3;
- ((uint32_t *)out)[3] = h4;
-}
-
-//-----------------------------------------------------------------------------
diff --git a/plugins/experimental/collapsed_connection/MurmurHash3.h b/plugins/experimental/collapsed_connection/MurmurHash3.h
deleted file mode 100644
index 3d74173..0000000
--- a/plugins/experimental/collapsed_connection/MurmurHash3.h
+++ /dev/null
@@ -1,20 +0,0 @@
-//-----------------------------------------------------------------------------
-// MurmurHash3 was written by Austin Appleby, and is placed in the public
-// domain. The author hereby disclaims copyright to this source code.
-
-#ifndef _MURMURHASH3_H_
-#define _MURMURHASH3_H_
-
-//-----------------------------------------------------------------------------
-#include <cstdint>
-
-//-----------------------------------------------------------------------------
-
-void MurmurHash3_x86_32(const void *key, int len, uint32_t seed, void *out);
-
-void MurmurHash3_x86_128(const void *key, int len, uint32_t seed, void *out);
-
-//-----------------------------------------------------------------------------
-
-#endif // _MURMURHASH3_H_
-//-----------------------------------------------------------------------------
diff --git a/plugins/experimental/collapsed_connection/P_collapsed_connection.h b/plugins/experimental/collapsed_connection/P_collapsed_connection.h
deleted file mode 100644
index 44dffbf..0000000
--- a/plugins/experimental/collapsed_connection/P_collapsed_connection.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/** @file
-
- Implements Collapsed connection
-
- @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 <cstdint>
-#include <map>
-#include <list>
-#include <utility>
-
-#pragma once
-
-#define PLUGIN_NAME "collapsed_connection"
-#define PLUGIN_VENDOR "Apache Software Foundation"
-#define PLUGIN_SUPPORT "dev@trafficserver.apache.org"
-
-#define DEFAULT_INSERT_LOCK_RETRY_TIME 10
-#define DEFAULT_MAX_LOCK_RETRY_TIMEOUT 2000
-#define DEFAULT_KEEP_PASS_RECORD_TIME 5000
-
-typedef enum {
- CcEnabled,
- CcRequiredHeader,
- CcInsertLockRetryTime,
- CcMaxLockRetryTimeout,
- CcKeepPassRecordTime,
-} CcConfigKey;
-
-typedef enum {
- CC_NONE,
- CC_LOCKED,
- CC_INSERT,
- CC_PASS,
- CC_PASSED,
- CC_REMOVE,
- CC_DONE,
-} CcTxnState;
-
-struct PassRecord {
- int64_t timeout;
- uint32_t hash_key;
-};
-
-typedef std::map<uint32_t, int8_t> UintMap;
-typedef std::list<PassRecord> UsecList;
-
-typedef struct {
- bool enabled;
- TSMgmtString required_header;
- int required_header_len;
- TSMgmtInt insert_lock_retry_time;
- TSMgmtInt max_lock_retry_timeout;
- TSMgmtInt keep_pass_record_time;
-} CcPluginConfig;
-
-typedef struct {
- UintMap *active_hash_map;
- TSMutex mutex;
- uint64_t seq_id;
- int txn_slot;
- CcPluginConfig *global_config;
- UsecList *keep_pass_list;
- TSHRTime last_gc_time;
- bool read_while_writer;
- int tol_global_hook_reqs;
- int tol_remap_hook_reqs;
- int tol_collapsed_reqs;
- int tol_non_cacheable_reqs;
- int tol_got_passed_reqs;
- int cur_hash_entries;
- int cur_keep_pass_entries;
- int max_hash_entries;
- int max_keep_pass_entries;
-} CcPluginData;
-
-typedef struct {
- uint64_t seq_id;
- TSHttpTxn txnp;
- TSCont contp;
- CcPluginConfig *config;
- uint32_t hash_key;
- CcTxnState cc_state;
- TSHRTime wait_time;
-} CcTxnData;
-
-typedef struct {
- TSEvent event;
- CcTxnData *txn_data;
-} TryLockData;
-
-// hash seed for MurmurHash3_x86_32, must be a prime number
-const unsigned int c_hashSeed = 27240313;
-
-static CcPluginData *getCcPlugin();
-static int collapsedConnectionMainHandler(TSCont contp, TSEvent event, void *edata);
diff --git a/plugins/experimental/collapsed_connection/README b/plugins/experimental/collapsed_connection/README
deleted file mode 100644
index b82b2a2..0000000
--- a/plugins/experimental/collapsed_connection/README
+++ /dev/null
@@ -1,75 +0,0 @@
-NOTE: This plugin is deprecated as of ATS v7.x. Instead, look at the new
-``collapsed_forwardin'' plugin instead!
-
-
-ATS (Apache Traffic Server) Collapsed Connection Handling Plugin
-------------------------------------------------------------------------------
-
-This plugin collapses connections with identical CacheUrl/EffectiveUrl.
-
-If an entry was created for a given CacheUrl/EffectiveUrl in our global hashTable,
-successive GET requests with identical CacheUrl/EffectiveUrl will be blocked in
-POST_REMAP hook until the hash entry was removed. (POST_REMAP hook is the last
-hook before 'cache lookup')
-
-For requests going into 'cache lookup' stage,
- if CacheLookupStatus is HIT_FRESH,
- hash entry will be removed at earliest possible time.
-
-For requests going into 'read server response header' stage,
- if response is not 200 OK,
- hash entry will be removed at earliest possible time.
- if response is public cacheable, (by checking 'Expires' header and 'Cache-Control' header with 'public' & 'max-age=...' values),
- if proxy.config.cache.enable_read_while_writer is enabled,
- hash entry will be removed at earliest possible time.
- else
- hash entry will be removed in TXN_CLOSE hook.
- if response is not public cacheable,
- we will update hash entry with a special value to let successive requests pass collapsed check,
- this special hash entry will be removed in TXN_CLOSE hook if value of keep_pass_record_time is 0,
- else it will be added into a list with timeout and removed by later collapsed requests.
-
-To view full state diagram, please view state.png
-
-
-CONFIGURATION
-
-To have trafficserver use this plugin, add a line for 'collapsed_connection.so' in the 'plugin.config' file.
-The plugin can be configured with only 1 argument, which is location of its configuration file.
-
-Example plugin.config:
- collapsed_connection.so conf/collapsed_connection/check_X_CC_header.config
-
-This plugin can be added in remap.config as well.
-Thus, it can have different configurations or only be enabled/disabled for specific remap rules.
-If the only argument for this plugin is "0" or "1", it means just "disable" or "enable" this plugin with default config value.
-
-Example remap.config:
- map http://no-collapse1.www.example.com/ http://www.example.com/ @plugin=connection_collapsing.so @pparam=0
- map http://no-collapse2.www.example.com/ http://www.example.com/ @plugin=connection_collapsing.so @pparam=conf/collapsed_connection/disable.config
-
-Its configuration file can have 5 configurable options:
- CONFIG proxy.config.http.collapsed_connection.enabled INT 1
- CONFIG proxy.config.http.collapsed_connection.required_header STRING NULL
- CONFIG proxy.config.http.collapsed_connection.insert_lock_retry_time INT 10
- CONFIG proxy.config.http.collapsed_connection.max_lock_retry_timeout INT 2000
- CONFIG proxy.config.http.collapsed_connection.keep_pass_record_time INT 5000
-
-Meaning of these configurable options:
- enabled
- enable collapsing or not, useful in remap rules if we want to disable/enable specific remap rules.
- required_header
- only collapse requests with 'required_header' http header present.
- insert_lock_retry_time
- if hash entry was locked, retry to get lock after insert_lock_retry_time millisecond.
- max_lock_retry_timeout
- if request was unable to get lock more than max_lock_retry_timeout millisecond, it will be unblocked anyway.
- keep_pass_record_time
- if response is not public cacheable,
- the pass sentinel will be kept in hash table for at least keep_pass_record_time millisecond before be removed.
-
-
-3rd party open source code
-----------------------------------------------------------------------------------
-MurmurHash3 by Austin Appleby, https://code.google.com/p/smhasher/wiki/MurmurHash3
- * Calculate hash key for CacheUrl
diff --git a/plugins/experimental/collapsed_connection/collapsed_connection.cc b/plugins/experimental/collapsed_connection/collapsed_connection.cc
deleted file mode 100644
index 7ddd913..0000000
--- a/plugins/experimental/collapsed_connection/collapsed_connection.cc
+++ /dev/null
@@ -1,1154 +0,0 @@
-/** @file
-
- Implements Collapsed connection
-
- @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 <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <cctype>
-
-#include <ts/ts.h>
-#include <ts/remap.h>
-#include <ts/experimental.h>
-#include "MurmurHash3.h"
-#include <cinttypes>
-
-#include "P_collapsed_connection.h"
-
-/**
- * Helper function for the config parser
- * copied from plugins/conf_remap/conf_remap.cc
- *
- * @param const char *str config data type
- *
- * @return TSRecordDataType config data type
- */
-inline TSRecordDataType
-str_to_datatype(const char *str)
-{
- TSRecordDataType type = TS_RECORDDATATYPE_NULL;
-
- if (!str || !*str) {
- return TS_RECORDDATATYPE_NULL;
- }
-
- if (!strcmp(str, "INT")) {
- type = TS_RECORDDATATYPE_INT;
- } else if (!strcmp(str, "STRING")) {
- type = TS_RECORDDATATYPE_STRING;
- }
-
- return type;
-}
-
-/**
- * Find collapsed_connection transaction config option
- * modified from InkAPI.cc:TSHttpTxnConfigFind
- *
- * @param const char *name name of config options
- * @param int length length of *name
- * @param CcConfigKey *conf config key
- * @param TSRecordDataType *type config option data type
- *
- * @return CcTxnState hashEntry added, should be ignore and pass, or fail
- */
-static TSReturnCode
-CcHttpTxnConfigFind(const char *name, int length, CcConfigKey *conf, TSRecordDataType *type)
-{
- *type = TS_RECORDDATATYPE_NULL;
-
- if (length == -1) {
- length = strlen(name);
- }
-
- switch (length) {
- case 46:
- if (!strncmp(name, "proxy.config.http.collapsed_connection.enabled", length)) {
- *conf = CcEnabled;
- *type = TS_RECORDDATATYPE_INT;
- }
- break;
- case 54:
- if (!strncmp(name, "proxy.config.http.collapsed_connection.required_header", length)) {
- *conf = CcRequiredHeader;
- *type = TS_RECORDDATATYPE_STRING;
- }
- break;
- case 60:
- if (!strncmp(name, "proxy.config.http.collapsed_connection.keep_pass_record_time", length)) {
- *conf = CcKeepPassRecordTime;
- *type = TS_RECORDDATATYPE_INT;
- }
- break;
- case 61:
- if (!strncmp(name, "proxy.config.http.collapsed_connection.insert_lock_retry_time", length)) {
- *conf = CcInsertLockRetryTime;
- *type = TS_RECORDDATATYPE_INT;
- } else if (!strncmp(name, "proxy.config.http.collapsed_connection.max_lock_retry_timeout", length)) {
- *conf = CcMaxLockRetryTimeout;
- *type = TS_RECORDDATATYPE_INT;
- }
- break;
- default:
- break;
- }
-
- return ((*type != TS_RECORDDATATYPE_NULL) ? TS_SUCCESS : TS_ERROR);
-}
-
-/**
- * Initial collapsed_connection plugin with config file
- * modified from plugins/conf_remap/conf_remap.cc, RemapConfigs::parse_file
- *
- * @param const char *fn filename of config file
- *
- * @return CcPluginConfig *config object
- */
-static CcPluginConfig *
-initConfig(const char *fn)
-{
- CcPluginData *plugin_data = getCcPlugin();
- CcPluginConfig *config = static_cast<CcPluginConfig *>(TSmalloc(sizeof(CcPluginConfig)));
-
- // Default config
- if (nullptr == plugin_data || nullptr == plugin_data->global_config) {
- config->enabled = true;
- config->required_header = nullptr;
- config->insert_lock_retry_time = DEFAULT_INSERT_LOCK_RETRY_TIME;
- config->max_lock_retry_timeout = DEFAULT_MAX_LOCK_RETRY_TIMEOUT;
- config->keep_pass_record_time = DEFAULT_KEEP_PASS_RECORD_TIME;
- } else {
- // Inherit from global config
- CcPluginConfig *global_config = plugin_data->global_config;
-
- config->enabled = global_config->enabled;
- config->required_header = TSstrdup(global_config->required_header);
- config->insert_lock_retry_time = global_config->insert_lock_retry_time;
- config->max_lock_retry_timeout = global_config->max_lock_retry_timeout;
- config->keep_pass_record_time = global_config->keep_pass_record_time;
- }
-
- if (nullptr != fn) {
- if (1 == strlen(fn)) {
- if (0 == strcmp("0", fn)) {
- config->enabled = false;
- } else if (0 == strcmp("1", fn)) {
- config->enabled = true;
- } else {
- TSError("[collapsed_connection] Parameter '%s' ignored", fn);
- }
- } else {
- int line_num = 0;
- TSFile file;
- char buf[8192];
- CcConfigKey name;
- TSRecordDataType type, expected_type;
-
- if (nullptr == (file = TSfopen(fn, "r"))) {
- TSError("[collapsed_connection] Could not open config file %s", fn);
- } else {
- while (nullptr != TSfgets(file, buf, sizeof(buf))) {
- char *ln, *tok;
- char *s = buf;
-
- ++line_num; // First line is #1 ...
- while (isspace(*s)) {
- ++s;
- }
- tok = strtok_r(s, " \t", &ln);
-
- // check for blank lines and comments
- if ((!tok) || (tok && ('#' == *tok))) {
- continue;
- }
-
- if (strncmp(tok, "CONFIG", 6)) {
- TSError("[collapsed_connection] File %s, line %d: non-CONFIG line encountered", fn, line_num);
- continue;
- }
- // Find the configuration name
- tok = strtok_r(nullptr, " \t", &ln);
- if (CcHttpTxnConfigFind(tok, -1, &name, &expected_type) != TS_SUCCESS) {
- TSError("[collapsed_connection] File %s, line %d: no records.config name given", fn, line_num);
- continue;
- }
- // Find the type (INT or STRING only)
- tok = strtok_r(nullptr, " \t", &ln);
- if (TS_RECORDDATATYPE_NULL == (type = str_to_datatype(tok))) {
- TSError("[collapsed_connection] File %s, line %d: only INT and STRING types supported", fn, line_num);
- continue;
- }
-
- if (type != expected_type) {
- TSError("[collapsed_connection] File %s, line %d: mismatch between provide data type, and expected type", fn, line_num);
- continue;
- }
- // Find the value (which depends on the type above)
- if (ln) {
- while (isspace(*ln)) {
- ++ln;
- }
- if ('\0' == *ln) {
- tok = nullptr;
- } else {
- tok = ln;
- while (*ln != '\0') {
- ++ln;
- }
- --ln;
- while (isspace(*ln) && (ln > tok)) {
- --ln;
- }
- ++ln;
- *ln = '\0';
- }
- } else {
- tok = nullptr;
- }
- if (!tok) {
- TSError("[collapsed_connection] File %s, line %d: the configuration must provide a value", fn, line_num);
- continue;
- }
- // Now store the new config
- switch (name) {
- case CcRequiredHeader:
- if (nullptr != config->required_header) {
- TSfree(config->required_header);
- }
- if (4 == strlen(tok) && 0 == strcmp(tok, "NULL")) {
- config->required_header = nullptr;
- } else {
- config->required_header = TSstrdup(tok);
- }
- break;
- case CcEnabled:
- config->enabled = strtoll(tok, nullptr, 10);
- break;
- case CcInsertLockRetryTime:
- config->insert_lock_retry_time = strtoll(tok, nullptr, 10);
- break;
- case CcMaxLockRetryTimeout:
- config->max_lock_retry_timeout = strtoll(tok, nullptr, 10);
- break;
- case CcKeepPassRecordTime:
- config->keep_pass_record_time = strtoll(tok, nullptr, 10);
- break;
- default:
- break;
- }
- }
-
- TSfclose(file);
- }
- }
- }
- if (config->required_header) {
- config->required_header_len = strlen(config->required_header);
- } else {
- config->required_header_len = 0;
- }
-
- TSDebug(PLUGIN_NAME, "enabled = %d", static_cast<int>(config->enabled));
- TSDebug(PLUGIN_NAME, "required_header = %s", config->required_header);
- TSDebug(PLUGIN_NAME, "insert_lock_retry_time = %d", static_cast<int>(config->insert_lock_retry_time));
- TSDebug(PLUGIN_NAME, "max_lock_retry_timeout = %d", static_cast<int>(config->max_lock_retry_timeout));
- TSDebug(PLUGIN_NAME, "keep_pass_record_time = %d", static_cast<int>(config->keep_pass_record_time));
-
- return config;
-}
-
-/**
- * Update and get current size in map
- * it's ok to use static variable here because already protected by plugin_data->mutex
- *
- * @param UintMap *map Hash Map
- *
- * @return int64_t current Hash Map size
- */
-static int64_t
-getCurrentHashEntries(UintMap *map)
-{
- static int64_t cur = 0;
- static int64_t max = 0;
- int64_t size = map->size();
- int64_t diff = size - cur;
-
- cur = size;
- if (diff != 0) {
- CcPluginData *plugin_data = getCcPlugin();
-
- TSStatIntSet(plugin_data->cur_hash_entries, cur);
- if (cur > max) {
- TSStatIntSet(plugin_data->max_hash_entries, cur);
- max = cur;
- }
- }
-
- return cur;
-}
-
-/**
- * Update and get current size in list
- * it's ok to use static variable here because already protected by plugin_data->mutex
- *
- * @param UsecList *list List
- *
- * @return int64_t current List size
- */
-static int64_t
-getCurrentKeepPassEntries(UsecList *list)
-{
- CcPluginData *plugin_data = getCcPlugin();
- static int64_t cur = 0;
- static int64_t max = 0;
- int64_t size = list->size();
- int64_t diff = size - cur;
-
- cur = size;
- if (diff != 0) {
- TSStatIntSet(plugin_data->cur_keep_pass_entries, cur);
- if (cur > max) {
- TSStatIntSet(plugin_data->max_keep_pass_entries, cur);
- max = cur;
- }
- }
-
- return cur;
-}
-
-/**
- * Add Or Check keep pass records from list
- *
- * @param uint32_t hash_key new hash_key to add
- * @param int64_t timeout timeout of this record
- *
- * @return TSReturnCode success or not
- */
-static TSReturnCode
-addOrCheckKeepPassRecords(uint32_t hash_key, int64_t timeout)
-{
- CcPluginData *plugin_data = getCcPlugin();
- UintMap *active_hash_map = plugin_data->active_hash_map;
- UsecList *keep_pass_list = plugin_data->keep_pass_list;
- std::list<PassRecord>::iterator it;
- PassRecord passRecord;
- bool added = true;
- TSHRTime cur_ms = TShrtime() / TS_HRTIME_MSECOND; // TS-2200, ats_dev-4.1+
-
- // Only gc per 0.1ms
- if (0 == hash_key && timeout == 0) {
- if (cur_ms - plugin_data->last_gc_time < 100) {
- return TS_SUCCESS;
- }
- }
-
- passRecord.timeout = cur_ms + timeout;
- passRecord.hash_key = hash_key;
-
- if (hash_key > 0) {
- bool push_back = false;
-
- if (keep_pass_list->empty()) {
- push_back = true;
- } else {
- PassRecord &lastRecord = *--(keep_pass_list->end());
-
- if (lastRecord.timeout <= passRecord.timeout) {
- push_back = true;
- }
- }
-
- if (push_back) {
- keep_pass_list->push_back(passRecord);
- getCurrentKeepPassEntries(keep_pass_list);
- TSDebug(PLUGIN_NAME, "push_back pass entry with timeout = %" PRId64 ", hash_key = %" PRIu32, passRecord.timeout,
- passRecord.hash_key);
- } else {
- added = false;
- }
- }
-
- for (it = keep_pass_list->begin(); it != keep_pass_list->end(); ++it) {
- PassRecord &thisRecord = *it;
-
- if (thisRecord.timeout <= cur_ms) {
- UintMap::iterator pos = active_hash_map->find(thisRecord.hash_key);
- if (pos != active_hash_map->end()) {
- active_hash_map->erase(pos);
- getCurrentHashEntries(active_hash_map);
- }
- keep_pass_list->erase(it++);
- getCurrentKeepPassEntries(keep_pass_list);
- TSDebug(PLUGIN_NAME, "remove pass entry with timeout = %" PRId64 ", hash_key = %" PRIu32, thisRecord.timeout,
- thisRecord.hash_key);
- } else if (false == added) {
- if (thisRecord.timeout >= passRecord.timeout) {
- keep_pass_list->insert(it, passRecord);
- getCurrentKeepPassEntries(keep_pass_list);
- TSDebug(PLUGIN_NAME, "insert pass entry with timeout = %" PRId64 ", hash_key = %" PRIu32, passRecord.timeout,
- passRecord.hash_key);
- break;
- }
- } else {
- break;
- }
- }
- plugin_data->last_gc_time = cur_ms;
-
- return TS_SUCCESS;
-}
-
-/**
- * Insert new hashEntry into hashTable
- *
- * @param CcTxnData *txn_data transaction data
- *
- * @return CcTxnState hashEntry added, should be ignore and pass, or fail
- */
-static CcTxnState
-insertNewHashEntry(CcTxnData *txn_data)
-{
- CcPluginData *plugin_data = getCcPlugin();
- CcTxnState ret = CC_NONE;
- UintMap *active_hash_map = plugin_data->active_hash_map;
-
- if (0 == txn_data->hash_key) {
- return ret;
- }
-
- if (TS_SUCCESS == TSMutexLockTry(plugin_data->mutex)) {
- std::pair<std::map<uint32_t, int8_t>::iterator, bool> map_ret;
- int64_t size = 0;
- addOrCheckKeepPassRecords(0, 0);
- map_ret = active_hash_map->insert(std::make_pair(txn_data->hash_key, CC_INSERT));
- size = getCurrentHashEntries(active_hash_map);
- TSMutexUnlock(plugin_data->mutex);
- if (false != map_ret.second) {
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] hash_key inserted, active_hash_map.size = %" PRId64, txn_data->seq_id, size);
- ret = CC_INSERT;
- } else if (CC_PASS == map_ret.first->second) {
- TSDebug(PLUGIN_NAME, "hash value = %d, previous request mark it non-cacheable", map_ret.first->second);
- ret = CC_PASS;
- } else {
- TSDebug(PLUGIN_NAME, "hash value = %d, hash_key already exists, wait next schedule", map_ret.first->second);
- ret = CC_LOCKED;
- }
- } else {
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] Unable to get mutex", txn_data->seq_id);
- }
-
- if (CC_INSERT != ret && CC_PASS != ret) {
- TSHRTime cur_ms = TShrtime() / TS_HRTIME_MSECOND; // TS-2200, ats_dev-4.1+
-
- if (0 == txn_data->wait_time) {
- txn_data->wait_time = cur_ms;
- } else if (cur_ms - txn_data->wait_time > txn_data->config->max_lock_retry_timeout) {
- txn_data->wait_time = cur_ms - txn_data->wait_time;
- // Pass cache lock
- ret = CC_PASS;
- TSDebug(PLUGIN_NAME, "timeout (%" PRId64 " > %d), pass plugin", txn_data->wait_time,
- static_cast<int32_t>(txn_data->config->max_lock_retry_timeout));
- }
- } else if (0 != txn_data->wait_time) {
- txn_data->wait_time = TShrtime() / 1000000 - txn_data->wait_time;
- TSDebug(PLUGIN_NAME, "waited for %" PRId64 " ms", txn_data->wait_time);
- }
-
- return ret;
-}
-
-/**
- * Update or remove hashEntry from hashTable
- *
- * @param CcTxnData *txn_data transaction data
- *
- * @return TSReturnCode Success or failure
- */
-static TSReturnCode
-updateOrRemoveHashEntry(CcTxnData *txn_data)
-{
- TSReturnCode ret = TS_ERROR;
- CcPluginData *plugin_data = getCcPlugin();
- UintMap *active_hash_map = plugin_data->active_hash_map;
-
- if (0 == txn_data->hash_key || CC_PASSED == txn_data->cc_state) {
- return TS_SUCCESS;
- }
-
- if (CC_PASS != txn_data->cc_state && CC_REMOVE != txn_data->cc_state) {
- return ret;
- }
-
- if (TS_SUCCESS == TSMutexLockTry(plugin_data->mutex)) {
- UintMap::iterator pos = active_hash_map->find(txn_data->hash_key);
- int64_t size = 0;
- if (pos != active_hash_map->end()) {
- active_hash_map->erase(pos);
- }
- if (CC_PASS == txn_data->cc_state) {
- active_hash_map->insert(std::make_pair(txn_data->hash_key, CC_PASS));
- addOrCheckKeepPassRecords(txn_data->hash_key, txn_data->config->keep_pass_record_time);
- size = getCurrentHashEntries(active_hash_map);
- TSMutexUnlock(plugin_data->mutex);
-
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] hashEntry updated, active_hash_map.size = %" PRId64, txn_data->seq_id, size);
- txn_data->cc_state = CC_PASSED;
- } else {
- addOrCheckKeepPassRecords(0, 0);
- size = getCurrentHashEntries(active_hash_map);
- TSMutexUnlock(plugin_data->mutex);
-
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] hashEntry removed, active_hash_map.size = %" PRId64, txn_data->seq_id, size);
- txn_data->cc_state = CC_DONE;
- }
- ret = TS_SUCCESS;
- } else {
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] Unable to get mutex", txn_data->seq_id);
- }
-
- return ret;
-}
-
-/**
- * Get hash_key from CacheUrl
- *
- * @param TSHttpTxn txnp Transaction ptr
- * @param TSMBuffer bufp TS memory buffer
- * @param TSMLoc hdr_loc TS memory loc
- *
- * @return uint32_t hash_key
- */
-static uint32_t
-getCacheUrlHashKey(TSHttpTxn txnp, TSMBuffer bufp, TSMLoc /* hdr_loc ATS_UNUSED */)
-{
- TSMLoc url_loc = TS_NULL_MLOC;
- int url_len;
- char *url = nullptr;
- uint32_t hash_key = 0;
-
- if (TS_SUCCESS != TSUrlCreate(bufp, &url_loc)) {
- TSDebug(PLUGIN_NAME, "unable to create url");
- return 0;
- }
-
- if (TS_SUCCESS == TSHttpTxnCacheLookupUrlGet(txnp, bufp, url_loc)) {
- url = TSUrlStringGet(bufp, url_loc, &url_len);
- } else {
- TSDebug(PLUGIN_NAME, "use EffectiveUrl as CacheLookupUrl instead");
- url = TSHttpTxnEffectiveUrlStringGet(txnp, &url_len);
- }
-
- MurmurHash3_x86_32(url, url_len, c_hashSeed, &hash_key);
- TSDebug(PLUGIN_NAME, "CacheLookupUrl = %s, hash_key = %u", url, hash_key);
- TSfree(url);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, url_loc);
-
- return hash_key;
-}
-
-/**
- * Is response public cacheable or not
- * try to find Expires and Cache-Control: public, max-age=... headers from server response
- *
- * @param TSMBuffer bufp TS memory buffer
- * @param TSMLoc hdr_loc TS memory loc
- *
- * @return bool
- */
-static bool
-isResponseCacheable(TSMBuffer bufp, TSMLoc hdr_loc)
-{
- bool cacheable = false;
- bool found_public = false;
- bool found_maxage = false;
- bool found_expire = false;
- TSMLoc field_loc = TS_NULL_MLOC;
-
- if (nullptr != (field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_EXPIRES, TS_MIME_LEN_EXPIRES))) {
- found_expire = true;
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
- }
-
- if (nullptr != (field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, TS_MIME_FIELD_CACHE_CONTROL, TS_MIME_LEN_CACHE_CONTROL))) {
- int field_cnt = TSMimeHdrFieldValuesCount(bufp, hdr_loc, field_loc);
-
- for (int i = 0; i < field_cnt; i++) {
- int len = 0;
- const char *val = TSMimeHdrFieldValueStringGet(bufp, hdr_loc, field_loc, i, &len);
- if (0 == i) {
- TSDebug(PLUGIN_NAME, "Cache-Control: %s", val);
- }
- if (len == TS_HTTP_LEN_PUBLIC && 0 == strncasecmp(val, TS_HTTP_VALUE_PUBLIC, TS_HTTP_LEN_PUBLIC)) {
- found_public = true;
- }
- if (len > TS_HTTP_LEN_MAX_AGE && 0 == strncasecmp(val, TS_HTTP_VALUE_MAX_AGE, TS_HTTP_LEN_MAX_AGE)) {
- found_maxage = true;
- }
- }
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
- }
-
- if (found_public && (found_expire || found_maxage)) {
- TSDebug(PLUGIN_NAME, "Response is public cacheable");
- cacheable = true;
- } else {
- TSDebug(PLUGIN_NAME, "Response is non-cacheable");
- }
-
- return cacheable;
-}
-
-/**
- * Retry CacheUrl lock event handler
- *
- * @param TSCont contp Continuation ptr
- * @param TSEvent event TS event
- * @param void *edata event Data
- *
- * @return int
- */
-static int
-retryCacheUrlLock(TSCont contp, TSEvent /* event ATS_UNUSED */, void * /* edata ATS_UNUSED */)
-{
- TryLockData *data = reinterpret_cast<TryLockData *>(TSContDataGet(contp));
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] event = %d retry", data->txn_data->seq_id, data->event);
- collapsedConnectionMainHandler(nullptr, data->event, data->txn_data->txnp);
- TSfree(data);
- TSContDataSet(contp, nullptr);
- TSContDestroy(contp);
-
- return 0;
-}
-
-/**
- * Add TS Cont Schedule to retry mutex lock/update
- *
- * @param CcTxnData *txn_data transaction data
- * @param TSEvent event TS Event
- * @param TSHRTime timeout schedule timeout
- *
- * @return void
- */
-static void
-addMutexRetry(CcTxnData *txn_data, TSEvent event, TSHRTime timeout)
-{
- TSCont contp = TSContCreate(retryCacheUrlLock, TSMutexCreate());
- TryLockData *data = static_cast<TryLockData *>(TSmalloc(sizeof(TryLockData)));
-
- data->event = event;
- data->txn_data = txn_data;
- TSContDataSet(contp, data);
- TSContSchedule(contp, timeout, TS_THREAD_POOL_DEFAULT);
-}
-
-/**
- * Try to get Collapsed Connection transaction data
- * if is first entry hook, allocate it
- * else try to get it back from TxnArg
- *
- * @param TSHttpTxn txnp Transaction ptr
- * @param bool create Should create new CcTxnData if NULL
- * @param bool remap Calling from remap
- *
- * @return *CcTxnData
- */
-static CcTxnData *
-getCcTxnData(TSHttpTxn txnp, bool create, bool remap)
-{
- CcPluginData *plugin_data = getCcPlugin();
- CcTxnData *txn_data = nullptr;
-
- txn_data = reinterpret_cast<CcTxnData *>(TSHttpTxnArgGet(txnp, plugin_data->txn_slot));
- if (nullptr == txn_data && true == create) {
- txn_data = static_cast<CcTxnData *>(TSmalloc(sizeof(CcTxnData)));
- txn_data->config = plugin_data->global_config;
- txn_data->seq_id = plugin_data->seq_id++;
- txn_data->txnp = txnp;
- txn_data->contp = nullptr;
- txn_data->hash_key = 0;
- txn_data->cc_state = CC_NONE;
- txn_data->wait_time = 0;
- TSHttpTxnArgSet(txnp, plugin_data->txn_slot, txn_data);
- if (remap) {
- TSStatIntIncrement(plugin_data->tol_remap_hook_reqs, 1);
- } else {
- TSStatIntIncrement(plugin_data->tol_global_hook_reqs, 1);
- }
- TSDebug(PLUGIN_NAME, "txn_data created, active_hash_map.size = %zu", plugin_data->active_hash_map->size());
- }
-
- return txn_data;
-}
-
-/**
- * Free Collapsed Connection transaction data
- *
- * @param CcTxnData *txn_data transaction data
- *
- * @return void
- */
-static void
-freeCcTxnData(CcTxnData *txn_data)
-{
- CcPluginData *plugin_data = getCcPlugin();
-
- if (txn_data->contp) {
- TSContDataSet(txn_data->contp, nullptr);
- TSContDestroy(txn_data->contp);
- }
- if (txn_data->txnp) {
- TSHttpTxnArgSet(txn_data->txnp, plugin_data->txn_slot, nullptr);
- TSHttpTxnReenable(txn_data->txnp, TS_EVENT_HTTP_CONTINUE);
- }
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] txn_data released", txn_data->seq_id);
- TSfree(txn_data);
-}
-
-/**
- * Lookup CacheUrl in hashTable and lock it in hashTable for collapsed connection
- *
- * @param CcTxnData *txn_data transaction data
- * @param TSEvent event TS event
- *
- * @return TSReturnCode
- */
-static TSReturnCode
-lookupAndTryLockCacheUrl(CcTxnData *txn_data, TSEvent event)
-{
- CcTxnState ret;
- CcPluginData *plugin_data = getCcPlugin();
-
- if (0 == txn_data->hash_key) {
- // New request, check is GET method and gen hash_key
- TSMBuffer bufp = (TSMBuffer) nullptr;
- TSMLoc hdr_loc = TS_NULL_MLOC;
- int method_len;
- const char *method = nullptr;
-
- if (TS_SUCCESS != TSHttpTxnClientReqGet(txn_data->txnp, &bufp, &hdr_loc)) {
- TSDebug(PLUGIN_NAME, "unable to get client request");
- freeCcTxnData(txn_data);
- return TS_ERROR;
- }
-
- if (txn_data->config->required_header_len > 0) {
- TSMLoc field_loc =
- TSMimeHdrFieldFind(bufp, hdr_loc, txn_data->config->required_header, txn_data->config->required_header_len);
- if (!field_loc) {
- TSDebug(PLUGIN_NAME, "%s header not found, ignore it", txn_data->config->required_header);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- freeCcTxnData(txn_data);
- return TS_SUCCESS;
- }
- TSHandleMLocRelease(bufp, hdr_loc, field_loc);
- }
-
- method = TSHttpHdrMethodGet(bufp, hdr_loc, &method_len);
- if (TS_HTTP_LEN_GET != method_len || 0 != memcmp(method, TS_HTTP_METHOD_GET, TS_HTTP_LEN_GET)) {
- TSDebug(PLUGIN_NAME, "method is not GET, ignore it");
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- freeCcTxnData(txn_data);
- return TS_SUCCESS;
- }
-
- txn_data->hash_key = getCacheUrlHashKey(txn_data->txnp, bufp, hdr_loc);
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
- if (0 == txn_data->hash_key) {
- freeCcTxnData(txn_data);
- return TS_ERROR;
- }
- TSStatIntIncrement(plugin_data->tol_collapsed_reqs, 1);
- }
-
- /*
- * CC_NONE: unable to get mutex, try next time
- * CC_PASS: previous request mark it non-cacheable, pass, do NOT collapse
- * CC_LOCKED: hash entry found, wait for release
- * CC_INSERT: hash entry added, must remove it after receiving response
- */
- ret = insertNewHashEntry(txn_data);
- if (CC_NONE == ret || CC_LOCKED == ret) {
- addMutexRetry(txn_data, event, txn_data->config->insert_lock_retry_time);
- } else if (CC_PASS == ret) {
- TSStatIntIncrement(plugin_data->tol_got_passed_reqs, 1);
- freeCcTxnData(txn_data);
- } else if (CC_INSERT == ret) {
- if (!txn_data->contp) {
- // txn contp is already created from remap, but only global contp for global hook
- txn_data->contp = TSContCreate(collapsedConnectionMainHandler, nullptr);
- }
- txn_data->cc_state = ret;
- TSHttpTxnHookAdd(txn_data->txnp, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, txn_data->contp);
- TSHttpTxnHookAdd(txn_data->txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, txn_data->contp);
- TSHttpTxnHookAdd(txn_data->txnp, TS_HTTP_TXN_CLOSE_HOOK, txn_data->contp);
- TSHttpTxnReenable(txn_data->txnp, TS_EVENT_HTTP_CONTINUE);
- } else {
- TSAssert(!"Unexpected return code");
- }
-
- return TS_SUCCESS;
-}
-
-/**
- * Test origin server response is STATUS_OK & Cacheable or not
- * if ! STATUS_OK, try to remove it from hashTable
- * if ! cacheable, try to mark it uncacheable in hashTable to let further request pass
- * if read_while_writer, try to remove it from hashTable
- *
- * @param CcTxnData *txn_data transaction data
- *
- * @return TSReturnCode
- */
-static TSReturnCode
-testResponseCacheable(CcTxnData *txn_data)
-{
- TSMBuffer bufp = (TSMBuffer) nullptr;
- TSMLoc hdr_loc = TS_NULL_MLOC;
- TSHttpStatus resp_status;
-
- if (0 == txn_data->hash_key) {
- return TS_ERROR;
- }
-
- if (TS_SUCCESS != TSHttpTxnServerRespGet(txn_data->txnp, &bufp, &hdr_loc)) {
- TSDebug(PLUGIN_NAME, "unable to get server response");
- return TS_ERROR;
- }
- resp_status = TSHttpHdrStatusGet(bufp, hdr_loc);
-
- if (TS_HTTP_STATUS_OK != resp_status) {
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] response status is not 200 OK, ignore it", txn_data->seq_id);
- txn_data->cc_state = CC_REMOVE;
- } else {
- CcPluginData *plugin_data = getCcPlugin();
- if (!isResponseCacheable(bufp, hdr_loc)) {
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] response is not public cacheable, let all requests pass", txn_data->seq_id);
-
- txn_data->cc_state = CC_PASS;
- TSStatIntIncrement(plugin_data->tol_non_cacheable_reqs, 1);
- } else if (plugin_data->read_while_writer) {
- txn_data->cc_state = CC_REMOVE;
- }
- }
- TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc);
-
- if (CC_PASS == txn_data->cc_state || CC_REMOVE == txn_data->cc_state) {
- if (TS_SUCCESS != updateOrRemoveHashEntry(txn_data)) {
- // It's ok to unable to update/remove it here, can update it at next stage
- TSHttpTxnHookAdd(txn_data->txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, txn_data->contp);
- }
- }
-
- return TS_SUCCESS;
-}
-
-/**
- * Test cache lookup result is hit_fresh or not
- * if hit_fresh, try to remove it from hashTable
- *
- * @param CcTxnData *txn_data transaction data
- *
- * @return TSReturnCode
- */
-static TSReturnCode
-testCacheLookupResult(CcTxnData *txn_data)
-{
- int status = 0;
-
- if (TS_SUCCESS != TSHttpTxnCacheLookupStatusGet(txn_data->txnp, &status)) {
- TSDebug(PLUGIN_NAME, "unable to get cache lookup result");
- return TS_ERROR;
- }
-
- if (TS_CACHE_LOOKUP_HIT_FRESH == status || TS_CACHE_LOOKUP_SKIPPED == status) {
- if (TS_CACHE_LOOKUP_HIT_FRESH == status) {
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] cache lookup hit fresh", txn_data->seq_id);
- } else if (TS_CACHE_LOOKUP_SKIPPED == status) {
- // client request is not lookupable(no-cache) or in proxy mode only
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "] cache lookup skipped", txn_data->seq_id);
- }
- txn_data->cc_state = CC_REMOVE;
- // whether success or not, we'll remove it at TXN_CLOSE stage anyway
- updateOrRemoveHashEntry(txn_data);
- }
-
- return TS_SUCCESS;
-}
-
-/**
- * CollapsedConnection event handler
- *
- * @param TSCont contp Continuation ptr
- * @param TSEvent event TS event
- * @param void *edata TS Http transaction
- *
- * @return int
- */
-static int
-collapsedConnectionMainHandler(TSCont /* contp ATS_UNUSED */, TSEvent event, void *edata)
-{
- TSHttpTxn txnp = reinterpret_cast<TSHttpTxn>(edata);
- CcTxnData *txn_data = getCcTxnData(txnp, TS_EVENT_HTTP_POST_REMAP == event, false);
-
- if (nullptr != txn_data) {
- TSDebug(PLUGIN_NAME, "[%" PRIu64 "], event = %d, txn_data-> hash_key = %u, cc_state = %d", txn_data->seq_id, event,
- txn_data->hash_key, txn_data->cc_state);
-
- switch (event) {
- case TS_EVENT_HTTP_POST_REMAP:
- // hook in global but disabled in remap
- if (0 == txn_data->config->enabled) {
- freeCcTxnData(txn_data);
- return TS_SUCCESS;
- }
- lookupAndTryLockCacheUrl(txn_data, event);
- break;
- case TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE:
- testCacheLookupResult(txn_data);
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- break;
- case TS_EVENT_HTTP_READ_RESPONSE_HDR:
- testResponseCacheable(txn_data);
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- break;
- case TS_EVENT_HTTP_SEND_RESPONSE_HDR:
- // whether success or not, we'll remove it at TXN_CLOSE stage anyway
- updateOrRemoveHashEntry(txn_data);
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- break;
- case TS_EVENT_HTTP_TXN_CLOSE:
- if (CC_DONE == txn_data->cc_state) {
- freeCcTxnData(txn_data);
- txn_data = nullptr;
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- } else if (CC_PASS == txn_data->cc_state || CC_PASSED == txn_data->cc_state) {
- // keep pass sentinel for config->keep_pass_record_time
- if (txn_data->config->keep_pass_record_time > 0) {
- if (CC_PASS == txn_data->cc_state && TS_SUCCESS != updateOrRemoveHashEntry(txn_data)) {
- addMutexRetry(txn_data, event, 0);
- } else {
- freeCcTxnData(txn_data);
- txn_data = nullptr;
- }
- } else {
- txn_data->cc_state = CC_REMOVE;
- }
- }
- if (txn_data && (CC_INSERT == txn_data->cc_state || CC_REMOVE == txn_data->cc_state)) {
- txn_data->cc_state = CC_REMOVE;
- if (TS_SUCCESS == updateOrRemoveHashEntry(txn_data)) {
- freeCcTxnData(txn_data);
- } else {
- // We're at the last stage, must remove hashEntry anyway
- addMutexRetry(txn_data, event, 0);
- }
- }
- break;
- default:
- TSAssert(!"Unexpected event");
- break;
- }
- } else {
- TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
- }
-
- return 0;
-}
-
-/**
- * Try to get Collapsed Connection plugin data
- * if is first entry hook, allocate it
- *
- * @return *CcPluginData
- */
-static CcPluginData *
-getCcPlugin()
-{
- static CcPluginData *data = nullptr;
-
- if (nullptr == data) {
- TSMgmtInt read_while_writer = 0;
- data = static_cast<CcPluginData *>(TSmalloc(sizeof(CcPluginData)));
- data->mutex = TSMutexCreate();
- data->active_hash_map = new UintMap();
- data->keep_pass_list = new UsecList();
- data->seq_id = 0;
- data->global_config = nullptr;
- TSHttpTxnArgIndexReserve(PLUGIN_NAME, "reserve txn_data slot", &(data->txn_slot));
-
- if (TS_SUCCESS == TSMgmtIntGet("proxy.config.cache.enable_read_while_writer", &read_while_writer) && read_while_writer > 0) {
- data->read_while_writer = true;
- }
-
- data->tol_global_hook_reqs =
- TSStatCreate("collapsed_connection.total.global.reqs", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
- data->tol_remap_hook_reqs =
- TSStatCreate("collapsed_connection.total.remap.reqs", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
- data->tol_collapsed_reqs =
- TSStatCreate("collapsed_connection.total.collapsed.reqs", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
- data->tol_non_cacheable_reqs =
- TSStatCreate("collapsed_connection.total.noncacheable.reqs", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
- data->tol_got_passed_reqs =
- TSStatCreate("collapsed_connection.total.got_passed.reqs", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
- data->cur_hash_entries =
- TSStatCreate("collapsed_connection.current.hash.entries", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
- data->cur_keep_pass_entries = TSStatCreate("collapsed_connection.current.keep_pass.entries", TS_RECORDDATATYPE_INT,
- TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
- data->max_hash_entries =
- TSStatCreate("collapsed_connection.max.hash.entries", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
- data->max_keep_pass_entries =
- TSStatCreate("collapsed_connection.max.keep_pass.entries", TS_RECORDDATATYPE_INT, TS_STAT_NON_PERSISTENT, TS_STAT_SYNC_SUM);
- }
-
- return data;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Initialize the TSRemapAPI plugin.
-//
-TSReturnCode
-TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size)
-{
- if (!api_info) {
- strncpy(errbuf, "[TSRemapInit] - Invalid TSRemapInterface argument", errbuf_size - 1);
- return TS_ERROR;
- }
-
- if (api_info->size < sizeof(TSRemapInterface)) {
- strncpy(errbuf, "[TSRemapInit] - Incorrect size of TSRemapInterface structure", errbuf_size - 1);
- return TS_ERROR;
- }
-
- if (api_info->tsremap_version < TSREMAP_VERSION) {
- snprintf(errbuf, errbuf_size, "[TSRemapInit] - Incorrect API version %ld.%ld", api_info->tsremap_version >> 16,
- (api_info->tsremap_version & 0xffff));
- return TS_ERROR;
- }
-
- CcPluginData *plugin_data = getCcPlugin();
-
- TSDebug(PLUGIN_NAME, "Remap plugin is succesfully initialized, txn_slot = %d", plugin_data->txn_slot);
- return TS_SUCCESS;
-}
-
-TSReturnCode
-TSRemapNewInstance(int argc, char *argv[], void **ih, char *, int)
-{
- if (argc > 2) {
- *ih = static_cast<CcPluginConfig *>(initConfig(argv[2]));
- } else {
- *ih = static_cast<CcPluginConfig *>(initConfig(nullptr));
- }
-
- return TS_SUCCESS;
-}
-
-void
-TSRemapDeleteInstance(void *ih)
-{
- CcPluginConfig *config = static_cast<CcPluginConfig *>(ih);
-
- if (nullptr != config->required_header) {
- TSfree(config->required_header);
- }
-
- TSfree(config);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// This is the main "entry" point for the plugin, called for every request.
-//
-TSRemapStatus
-TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo * /* rri ATS_UNUSED */)
-{
- TSHttpTxn txnp = static_cast<TSHttpTxn>(rh);
- CcPluginData *plugin_data = getCcPlugin();
- CcTxnData *txn_data = getCcTxnData(txnp, true, true);
-
- txn_data->config = reinterpret_cast<CcPluginConfig *>(ih);
-
- if (!plugin_data->global_config || !plugin_data->global_config->enabled) {
- if (txn_data->config->enabled) {
- TSCont contp = TSContCreate(collapsedConnectionMainHandler, nullptr);
- TSHttpTxnHookAdd(txnp, TS_HTTP_POST_REMAP_HOOK, contp);
-
- txn_data->contp = contp;
- TSHttpTxnArgSet(txnp, plugin_data->txn_slot, txn_data);
- } else {
- // global & remap were both disabled
- txn_data->txnp = nullptr;
- freeCcTxnData(txn_data);
- }
- } else {
- // if globally enabled, set txn_data for remap config
- TSHttpTxnArgSet(txnp, plugin_data->txn_slot, txn_data);
- }
-
- return TSREMAP_NO_REMAP;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Initialize the TSAPI plugin for the global hooks we support.
-//
-void
-TSPluginInit(int argc, const char *argv[])
-{
- TSPluginRegistrationInfo info;
- TSMgmtInt http_cache = 0;
- TSCont contp = nullptr;
-
- info.plugin_name = const_cast<char *>(PLUGIN_NAME);
- info.vendor_name = const_cast<char *>(PLUGIN_VENDOR);
- info.support_email = const_cast<char *>(PLUGIN_SUPPORT);
-
- TSError("[collapsed_connection] This plugin is deprecated as of ATS v7.1, use collapsed_forwarding instead!");
-
- if (TS_SUCCESS != TSPluginRegister(&info)) {
- TSError("[collapsed_connection] Plugin registration failed");
- return;
- }
-
- if (TS_SUCCESS != TSMgmtIntGet("proxy.config.http.cache.http", &http_cache) || 0 == http_cache) {
- TSError("[collapsed_connection] Http cache is disabled, plugin would not work");
- return;
- }
-
- if (!(contp = TSContCreate(collapsedConnectionMainHandler, nullptr))) {
- TSError("[collapsed_connection] Could not create continuation");
- return;
- }
-
- CcPluginData *plugin_data = getCcPlugin();
- if (argc > 1) {
- plugin_data->global_config = initConfig(argv[1]);
- } else {
- plugin_data->global_config = initConfig(nullptr);
- }
-
- if (plugin_data->global_config->enabled) {
- // Last API hook before cache lookup
- TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, contp);
- TSDebug(PLUGIN_NAME, "TS_HTTP_POST_REMAP_HOOK added, txn_slot = %d", plugin_data->txn_slot);
- } else {
- TSDebug(PLUGIN_NAME, "plugin generally disabled");
- }
-}
diff --git a/plugins/experimental/collapsed_connection/default.config b/plugins/experimental/collapsed_connection/default.config
deleted file mode 100644
index ce37b71..0000000
--- a/plugins/experimental/collapsed_connection/default.config
+++ /dev/null
@@ -1,5 +0,0 @@
-CONFIG proxy.config.http.collapsed_connection.enabled INT 1
-CONFIG proxy.config.http.collapsed_connection.required_header STRING NULL
-CONFIG proxy.config.http.collapsed_connection.insert_lock_retry_time INT 10
-CONFIG proxy.config.http.collapsed_connection.max_lock_retry_timeout INT 2000
-CONFIG proxy.config.http.collapsed_connection.keep_pass_record_time INT 5000
diff --git a/plugins/experimental/collapsed_connection/state.dot b/plugins/experimental/collapsed_connection/state.dot
deleted file mode 100644
index 5ce368e..0000000
--- a/plugins/experimental/collapsed_connection/state.dot
+++ /dev/null
@@ -1,40 +0,0 @@
-digraph collapsed_connection {
- accept -> TS_HTTP_POST_REMAP_HOOK;
- TS_HTTP_POST_REMAP_HOOK -> "check request method (and header)";
-
- "check request method (and header)" -> "get CacheUrl hash_key using MurmurHash3" [label = "GET request (required_header present)"];
- "check request method (and header)" -> "pass request" [label = "others"];
- "get CacheUrl hash_key using MurmurHash3" -> "check hash_key from hashTable";
- "check hash_key from hashTable" -> "lock URL in hashTable" [label = "not found"];
- "check hash_key from hashTable" -> "pass request" [label = "found, but marked pass"];
- "check hash_key from hashTable" -> "check hash_key from hashTable" [label = "locked or unable to get mutex, wait insert_lock_retry_time"];
- "lock URL in hashTable" -> TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK;
- TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK -> "remove URL from hashTable(1)" [label = "hit_fresh or skipped"];
- TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK -> "request origin server" [label = "miss or stale"];
- "request origin server" -> TS_HTTP_READ_RESPONSE_HDR_HOOK;
- TS_HTTP_READ_RESPONSE_HDR_HOOK -> "remove URL from hashTable(1)" [label = "not 200/OK response"];
- TS_HTTP_READ_RESPONSE_HDR_HOOK -> "check read_while_writer config";
- "check read_while_writer config" -> "remove URL from hashTable(1)" [label = "enabled"];
- "check read_while_writer config" -> TS_HTTP_TXN_CLOSE_HOOK [label = "disabled"];
- TS_HTTP_READ_RESPONSE_HDR_HOOK -> "mark pass in hashTable" [label = "non-cacheable"];
- "remove URL from hashTable(1)" -> TS_HTTP_TXN_CLOSE_HOOK;
- "mark pass in hashTable" -> TS_HTTP_TXN_CLOSE_HOOK;
- "pass request" -> TS_HTTP_TXN_CLOSE_HOOK;
- TS_HTTP_TXN_CLOSE_HOOK -> "remove URL from hashTable(2)";
- TS_HTTP_TXN_CLOSE_HOOK -> "check keep_pass_record_time" [label = "non-cacheable"];
- "check keep_pass_record_time" -> "add into KeepPassList" [label = "> 0"];
- "check keep_pass_record_time" -> "remove URL from hashTable(2)" [label = "= 0"];
- "add into KeepPassList" -> "transaction close";
- "remove URL from hashTable(2)" -> "transaction close";
- "transaction close" -> accept;
-
- TS_HTTP_POST_REMAP_HOOK [shape = box];
- TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK[shape = box];
- TS_HTTP_READ_RESPONSE_HDR_HOOK [shape = box];
- TS_HTTP_TXN_CLOSE_HOOK [shape = box];
-
- "check request method (and header)" [shape = diamond];
- "check hash_key from hashTable" [shape = diamond];
- "check read_while_writer config" [shape = diamond];
- "check keep_pass_record_time" [shape = diamond];
-}