From ed0603fd1e01f34f581a5dcb47052ef27368b8e2 Mon Sep 17 00:00:00 2001 From: Vijay Mamidi Date: Mon, 1 Feb 2021 17:29:16 -0800 Subject: [PATCH 1/4] Experimental Cache fill plugin --- plugins/Makefile.am | 1 + plugins/experimental/cache_fill/Makefile.inc | 21 ++ .../cache_fill/background_fetch.cc | 299 ++++++++++++++++++ .../cache_fill/background_fetch.h | 181 +++++++++++ plugins/experimental/cache_fill/cache_fill.cc | 185 +++++++++++ 5 files changed, 687 insertions(+) create mode 100644 plugins/experimental/cache_fill/Makefile.inc create mode 100644 plugins/experimental/cache_fill/background_fetch.cc create mode 100644 plugins/experimental/cache_fill/background_fetch.h create mode 100644 plugins/experimental/cache_fill/cache_fill.cc diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 52ce5d8bfdc..b2ae67279ba 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -59,6 +59,7 @@ if BUILD_EXPERIMENTAL_PLUGINS include experimental/access_control/Makefile.inc include experimental/acme/Makefile.inc +include experimental/cache_fill/Makefile.inc include experimental/cert_reporting_tool/Makefile.inc include experimental/collapsed_forwarding/Makefile.inc include experimental/cookie_remap/Makefile.inc diff --git a/plugins/experimental/cache_fill/Makefile.inc b/plugins/experimental/cache_fill/Makefile.inc new file mode 100644 index 00000000000..14085977211 --- /dev/null +++ b/plugins/experimental/cache_fill/Makefile.inc @@ -0,0 +1,21 @@ +# 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/cache_fill/cache_fill.la +experimental_cache_fill_cache_fill_la_SOURCES = \ + experimental/cache_fill/cache_fill.cc \ + experimental/cache_fill/background_fetch.cc \ + experimental/cache_fill/background_fetch.h diff --git a/plugins/experimental/cache_fill/background_fetch.cc b/plugins/experimental/cache_fill/background_fetch.cc new file mode 100644 index 00000000000..99857e8fb34 --- /dev/null +++ b/plugins/experimental/cache_fill/background_fetch.cc @@ -0,0 +1,299 @@ +/** @file + + Plugin to perform background fetches of certain content that would + otherwise not be cached. For example, Range: requests / responses. + + @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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ts/ts.h" +#include "ts/remap.h" +#include "background_fetch.h" +typedef std::unordered_map OutstandingRequests; + +/////////////////////////////////////////////////////////////////////////// +// Set a header to a specific value. This will avoid going to through a +// remove / add sequence in case of an existing header. +// but clean. +static bool +set_header(TSMBuffer bufp, TSMLoc hdr_loc, const char *header, int len, const char *val, int val_len) +{ + if (!bufp || !hdr_loc || !header || len <= 0 || !val || val_len <= 0) { + return false; + } + + bool ret = false; + TSMLoc field_loc = TSMimeHdrFieldFind(bufp, hdr_loc, header, len); + + if (!field_loc) { + // No existing header, so create one + if (TS_SUCCESS == TSMimeHdrFieldCreateNamed(bufp, hdr_loc, header, len, &field_loc)) { + if (TS_SUCCESS == TSMimeHdrFieldValueStringSet(bufp, hdr_loc, field_loc, -1, val, val_len)) { + TSMimeHdrFieldAppend(bufp, hdr_loc, field_loc); + ret = true; + } + TSHandleMLocRelease(bufp, hdr_loc, field_loc); + } + } else { + TSMLoc tmp = nullptr; + bool first = true; + + while (field_loc) { + if (first) { + first = false; + if (TS_SUCCESS == TSMimeHdrFieldValueStringSet(bufp, hdr_loc, field_loc, -1, val, val_len)) { + ret = true; + } + } else { + TSMimeHdrFieldDestroy(bufp, hdr_loc, field_loc); + } + tmp = TSMimeHdrFieldNextDup(bufp, hdr_loc, field_loc); + TSHandleMLocRelease(bufp, hdr_loc, field_loc); + field_loc = tmp; + } + } + + return ret; +} + +/////////////////////////////////////////////////////////////////////////// +// Dump a header on stderr, useful together with TSDebug(). +static void +dump_headers(TSMBuffer bufp, TSMLoc hdr_loc) +{ + TSIOBuffer output_buffer; + TSIOBufferReader reader; + TSIOBufferBlock block; + int64_t block_avail; + + output_buffer = TSIOBufferCreate(); + reader = TSIOBufferReaderAlloc(output_buffer); + + /* This will print just MIMEFields and not the http request line */ + TSMimeHdrPrint(bufp, hdr_loc, output_buffer); + + /* We need to loop over all the buffer blocks, there can be more than 1 */ + block = TSIOBufferReaderStart(reader); + do { + const char *block_start = TSIOBufferBlockReadStart(block, reader, &block_avail); + if (block_avail > 0) { + TSDebug(PLUGIN_NAME, "Headers are:\n%.*s", static_cast(block_avail), block_start); + } + TSIOBufferReaderConsume(reader, block_avail); + block = TSIOBufferReaderStart(reader); + } while (block && block_avail != 0); + + /* Free up the TSIOBuffer that we used to print out the header */ + TSIOBufferReaderFree(reader); + TSIOBufferDestroy(output_buffer); +} + +bool +BgFetchData::initialize(TSMBuffer request, TSMLoc req_hdr, TSHttpTxn txnp) +{ + struct sockaddr const *ip = TSHttpTxnClientAddrGet(txnp); + bool ret = false; + + TSAssert(TS_NULL_MLOC == hdr_loc); + TSAssert(TS_NULL_MLOC == url_loc); + + if (ip) { + if (ip->sa_family == AF_INET) { + memcpy(&client_ip, ip, sizeof(sockaddr_in)); + } else if (ip->sa_family == AF_INET6) { + memcpy(&client_ip, ip, sizeof(sockaddr_in6)); + } else { + TSError("[%s] Unknown address family %d", PLUGIN_NAME, ip->sa_family); + } + } else { + TSError("[%s] Failed to get client host info", PLUGIN_NAME); + return false; + } + + hdr_loc = TSHttpHdrCreate(mbuf); + if (TS_SUCCESS == TSHttpHdrCopy(mbuf, hdr_loc, request, req_hdr)) { + TSMLoc p_url; + + // Now copy the pristine request URL into our MBuf + if (TS_SUCCESS == TSHttpTxnPristineUrlGet(txnp, &request, &p_url)) { + if (TS_SUCCESS == TSUrlClone(mbuf, request, p_url, &url_loc)) { + TSMLoc c_url = TS_NULL_MLOC; + int len; + char *url = nullptr; + + // Get the cache key URL (for now), since this has better lookup behavior when using + // e.g. the cachekey plugin. + if (TS_SUCCESS == TSUrlCreate(request, &c_url)) { + if (TS_SUCCESS == TSHttpTxnCacheLookupUrlGet(txnp, request, c_url)) { + url = TSUrlStringGet(request, c_url, &len); + TSHandleMLocRelease(request, TS_NULL_MLOC, c_url); + TSDebug(PLUGIN_NAME, "Cache URL is %.*s", len, url); + } + } + + if (url) { + _url.assign(url, len); // Save away the cache URL for later use when acquiring lock + TSfree(static_cast(url)); + + if (TS_SUCCESS == TSHttpHdrUrlSet(mbuf, hdr_loc, url_loc)) { + // Make sure we have the correct Host: header for this request. + const char *hostp = TSUrlHostGet(mbuf, url_loc, &len); + + if (set_header(mbuf, hdr_loc, TS_MIME_FIELD_HOST, TS_MIME_LEN_HOST, hostp, len)) { + TSDebug(PLUGIN_NAME, "Set header Host: %.*s", len, hostp); + } + ret = true; + } + } + } + TSHandleMLocRelease(request, TS_NULL_MLOC, p_url); + } + } + + return ret; +} + +static int cont_bg_fetch(TSCont contp, TSEvent event, void *edata); + +// Create, setup and schedule the background fetch continuation. +void +BgFetchData::schedule() +{ + TSAssert(nullptr == _cont); + + // Setup the continuation + _cont = TSContCreate(cont_bg_fetch, TSMutexCreate()); + TSContDataSet(_cont, static_cast(this)); + + // Initialize the VIO stuff (for the fetch) + req_io_buf = TSIOBufferCreate(); + req_io_buf_reader = TSIOBufferReaderAlloc(req_io_buf); + resp_io_buf = TSIOBufferCreate(); + resp_io_buf_reader = TSIOBufferReaderAlloc(resp_io_buf); + + // Schedule + TSContScheduleOnPool(_cont, 0, TS_THREAD_POOL_NET); +} + +////////////////////////////////////////////////////////////////////////////// +// Continuation to perform a background fill of a URL. This is pretty +// expensive (memory allocations etc.), we could eliminate maybe the +// std::string, but I think it's fine for now. +static int +cont_bg_fetch(TSCont contp, TSEvent event, void * /* edata ATS_UNUSED */) +{ + BgFetchData *data = static_cast(TSContDataGet(contp)); + int64_t avail; + + switch (event) { + case TS_EVENT_IMMEDIATE: + case TS_EVENT_TIMEOUT: + // Debug info for this particular bg fetch (put all debug in here please) + if (TSIsDebugTagSet(PLUGIN_NAME)) { + char buf[INET6_ADDRSTRLEN]; + const sockaddr *sockaddress = reinterpret_cast(&data->client_ip); + + switch (sockaddress->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &(((struct sockaddr_in *)sockaddress)->sin_addr), buf, INET_ADDRSTRLEN); + TSDebug(PLUGIN_NAME, "Client IPv4 = %s", buf); + break; + case AF_INET6: + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sockaddress)->sin6_addr), buf, INET6_ADDRSTRLEN); + TSDebug(PLUGIN_NAME, "Client IPv6 = %s", buf); + break; + default: + TSError("[%s] Unknown address family %d", PLUGIN_NAME, sockaddress->sa_family); + break; + } + TSDebug(PLUGIN_NAME, "Starting background fetch, replaying:"); + dump_headers(data->mbuf, data->hdr_loc); + } + + // Setup the NetVC for background fetch + TSAssert(nullptr == data->vc); + if ((data->vc = TSHttpConnectWithPluginId(reinterpret_cast(&data->client_ip), PLUGIN_NAME, 0)) != nullptr) { + TSHttpHdrPrint(data->mbuf, data->hdr_loc, data->req_io_buf); + // We never send a body with the request. ToDo: Do we ever need to support that ? + TSIOBufferWrite(data->req_io_buf, "\r\n", 2); + + data->r_vio = TSVConnRead(data->vc, contp, data->resp_io_buf, INT64_MAX); + data->w_vio = TSVConnWrite(data->vc, contp, data->req_io_buf_reader, TSIOBufferReaderAvail(data->req_io_buf_reader)); + } else { + delete data; + TSError("[%s] Failed to connect to internal process, major malfunction", PLUGIN_NAME); + } + break; + + case TS_EVENT_VCONN_WRITE_COMPLETE: + // TSVConnShutdown(data->vc, 0, 1); + // TSVIOReenable(data->w_vio); + TSDebug(PLUGIN_NAME, "Write Complete"); + break; + + case TS_EVENT_VCONN_READ_READY: + avail = TSIOBufferReaderAvail(data->resp_io_buf_reader); + data->addBytes(avail); + TSIOBufferReaderConsume(data->resp_io_buf_reader, avail); + TSVIONDoneSet(data->r_vio, TSVIONDoneGet(data->r_vio) + avail); + TSVIOReenable(data->r_vio); + break; + + case TS_EVENT_VCONN_READ_COMPLETE: + case TS_EVENT_VCONN_EOS: + case TS_EVENT_VCONN_INACTIVITY_TIMEOUT: + case TS_EVENT_ERROR: + if (event == TS_EVENT_VCONN_INACTIVITY_TIMEOUT) { + TSDebug(PLUGIN_NAME, "Encountered Inactivity Timeout"); + TSVConnAbort(data->vc, TS_VC_CLOSE_ABORT); + } else { + TSVConnClose(data->vc); + } + + TSDebug(PLUGIN_NAME, "Closing down background transaction, event= %s(%d)", TSHttpEventNameLookup(event), event); + avail = TSIOBufferReaderAvail(data->resp_io_buf_reader); + data->addBytes(avail); + TSIOBufferReaderConsume(data->resp_io_buf_reader, avail); + TSVIONDoneSet(data->r_vio, TSVIONDoneGet(data->r_vio) + avail); + + // Close, release and cleanup + data->vc = nullptr; + delete data; + break; + + default: + TSDebug(PLUGIN_NAME, "Unhandled event: %s (%d)", TSHttpEventNameLookup(event), event); + break; + } + + return 0; +} diff --git a/plugins/experimental/cache_fill/background_fetch.h b/plugins/experimental/cache_fill/background_fetch.h new file mode 100644 index 00000000000..1a70ec95e9b --- /dev/null +++ b/plugins/experimental/cache_fill/background_fetch.h @@ -0,0 +1,181 @@ +/** @file + + Plugin to perform background fetches of certain content that would + otherwise not be cached. For example, Range: requests / responses. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#pragma once +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ts/ts.h" +#include "ts/remap.h" + +typedef std::unordered_map OutstandingRequests; +const char PLUGIN_NAME[] = "cache_fill"; + +class BgFetchState +{ +public: + BgFetchState() = default; + BgFetchState(BgFetchState const &) = delete; + void operator=(BgFetchState const &) = delete; + + static BgFetchState & + getInstance() + { + static BgFetchState _instance; + return _instance; + } + + ~BgFetchState() { TSMutexDestroy(_lock); } + + bool + acquire(const std::string &url) + { + bool ret; + + TSMutexLock(_lock); + if (_urls.end() == _urls.find(url)) { + _urls[url] = true; + ret = true; + } else { + ret = false; + } + TSMutexUnlock(_lock); + + TSDebug(PLUGIN_NAME, "BgFetchState.acquire(): ret = %d, url = %s", ret, url.c_str()); + + return ret; + } + + bool + release(const std::string &url) + { + bool ret; + + TSMutexLock(_lock); + if (_urls.end() == _urls.find(url)) { + ret = false; + } else { + _urls.erase(url); + ret = true; + } + TSMutexUnlock(_lock); + + return ret; + } + +private: + OutstandingRequests _urls; + TSMutex _lock = TSMutexCreate(); +}; + +////////////////////////////////////////////////////////////////////////////// +// Hold and manage some state for the TXN background fetch continuation. +// This is necessary, because the TXN is likely to not be available +// during the time we fetch from origin. +struct BgFetchData { + BgFetchData() { memset(&client_ip, 0, sizeof(client_ip)); } + + ~BgFetchData() + { + TSHandleMLocRelease(mbuf, TS_NULL_MLOC, hdr_loc); + TSHandleMLocRelease(mbuf, TS_NULL_MLOC, url_loc); + + TSMBufferDestroy(mbuf); + + if (vc) { + TSError("[%s] Destroyed BgFetchDATA while VC was alive", PLUGIN_NAME); + TSVConnClose(vc); + vc = nullptr; + } + + // If we got schedule, also clean that up + if (_cont) { + releaseUrl(); + + TSContDestroy(_cont); + _cont = nullptr; + TSIOBufferReaderFree(req_io_buf_reader); + TSIOBufferDestroy(req_io_buf); + TSIOBufferReaderFree(resp_io_buf_reader); + TSIOBufferDestroy(resp_io_buf); + } + } + + bool + acquireUrl() const + { + return BgFetchState::getInstance().acquire(_url); + } + bool + releaseUrl() const + { + return BgFetchState::getInstance().release(_url); + } + + const char * + getUrl() const + { + return _url.c_str(); + } + + void + addBytes(int64_t b) + { + _bytes += b; + } + + bool initialize(TSMBuffer request, TSMLoc req_hdr, TSHttpTxn txnp); + void schedule(); + + TSMBuffer mbuf = TSMBufferCreate(); + TSMLoc hdr_loc = TS_NULL_MLOC; + TSMLoc url_loc = TS_NULL_MLOC; + + struct sockaddr_storage client_ip; + + // This is for the actual background fetch / NetVC + TSVConn vc = nullptr; + TSIOBuffer req_io_buf = nullptr; + TSIOBuffer resp_io_buf = nullptr; + TSIOBufferReader req_io_buf_reader = nullptr; + TSIOBufferReader resp_io_buf_reader = nullptr; + TSVIO r_vio = nullptr; + TSVIO w_vio = nullptr; + +private: + std::string _url; + int64_t _bytes = 0; + TSCont _cont = nullptr; +}; diff --git a/plugins/experimental/cache_fill/cache_fill.cc b/plugins/experimental/cache_fill/cache_fill.cc new file mode 100644 index 00000000000..0165e5f1fe5 --- /dev/null +++ b/plugins/experimental/cache_fill/cache_fill.cc @@ -0,0 +1,185 @@ +/** @file + + Plugin to perform background fetches of certain content that would + otherwise not be cached. For example, Range: requests / responses. + + @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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ts/ts.h" +#include "ts/remap.h" +#include "background_fetch.h" + +static const char * +getCacheLookupResultName(TSCacheLookupResult result) +{ + switch (result) { + case TS_CACHE_LOOKUP_MISS: + return "TS_CACHE_LOOKUP_MISS"; + break; + case TS_CACHE_LOOKUP_HIT_STALE: + return "TS_CACHE_LOOKUP_HIT_STALE"; + break; + case TS_CACHE_LOOKUP_HIT_FRESH: + return "TS_CACHE_LOOKUP_HIT_FRESH"; + break; + case TS_CACHE_LOOKUP_SKIPPED: + return "TS_CACHE_LOOKUP_SKIPPED"; + break; + default: + return "UNKNOWN_CACHE_LOOKUP_EVENT"; + break; + } + return "UNKNOWN_CACHE_LOOKUP_EVENT"; +} + +/////////////////////////////////////////////////////////////////////////// +// create background fetch request if possible +// +static bool +cont_check_cacheable(TSHttpTxn txnp) +{ + if (TSHttpTxnIsInternal(txnp)) + return false; + int lookupStatus; + TSHttpTxnCacheLookupStatusGet(txnp, &lookupStatus); + TSDebug(PLUGIN_NAME, "lookup status: %s", getCacheLookupResultName((TSCacheLookupResult)lookupStatus)); + bool ret = false; + if (TS_CACHE_LOOKUP_MISS == lookupStatus || TS_CACHE_LOOKUP_HIT_STALE == lookupStatus) { + bool const nostore = TSHttpTxnServerRespNoStoreGet(txnp); + + TSDebug(PLUGIN_NAME, "is nostore set %d", nostore); + if (!nostore) { + TSMBuffer request; + TSMLoc req_hdr; + if (TS_SUCCESS == TSHttpTxnClientReqGet(txnp, &request, &req_hdr)) { + BgFetchData *data = new BgFetchData(); + // Initialize the data structure (can fail) and acquire a privileged lock on the URL + if (data->initialize(request, req_hdr, txnp) && data->acquireUrl()) { + TSDebug(PLUGIN_NAME, "scheduling background fetch"); + data->schedule(); + ret = true; + } else { + delete data; + } + } + TSHandleMLocRelease(request, TS_NULL_MLOC, req_hdr); + } + } + return ret; +} + +////////////////////////////////////////////////////////////////////////////// +// Main "plugin", which is a global TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE hook. Before +// initiating a background fetch, this checks +// if a background fetch is allowed for this request +// +static int +cont_handle_cache(TSCont contp, TSEvent event, void *edata) +{ + TSHttpTxn txnp = static_cast(edata); + if (TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE == event) { + bool const requested = cont_check_cacheable(txnp); + if (requested) // Made a background fetch request, do not cache the response + { + TSDebug(PLUGIN_NAME, "setting no store"); + TSHttpTxnServerRespNoStoreSet(txnp, 1); + TSHttpTxnCacheLookupStatusSet(txnp, TS_CACHE_LOOKUP_MISS); + } + + } else { + TSError("[%s] Unknown event for this plugin %d", PLUGIN_NAME, event); + TSDebug(PLUGIN_NAME, "unknown event for this plugin %d", event); + } + + // Reenable and continue with the state machine. + TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); + return 0; +} + +/////////////////////////////////////////////////////////////////////////// +// Setup Remap mode +/////////////////////////////////////////////////////////////////////////////// +// Initialize the plugin. +// +TSReturnCode +TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size) +{ + TSDebug(PLUGIN_NAME, "cache fill remap init"); + if (!api_info) { + strncpy(errbuf, "[tsremap_init] - Invalid TSRemapInterface argument", 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; + } + + TSDebug(PLUGIN_NAME, "cache fill remap is successfully initialized"); + return TS_SUCCESS; +} + +/////////////////////////////////////////////////////////////////////////////// +// We don't have any specific "instances" here, at least not yet. +// +TSReturnCode +TSRemapNewInstance(int argc, char *argv[], void **ih, char * /* errbuf */, int /* errbuf_size */) +{ + TSCont cont = TSContCreate(cont_handle_cache, nullptr); + *ih = cont; + return TS_SUCCESS; +} + +void +TSRemapDeleteInstance(void *ih) +{ + TSCont cont = static_cast(ih); + TSContDestroy(cont); +} + +/////////////////////////////////////////////////////////////////////////////// +//// This is the main "entry" point for the plugin, called for every request. +//// +TSRemapStatus +TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo * /* rri */) +{ + if (nullptr == ih) { + return TSREMAP_NO_REMAP; + } + TSCont const cont = static_cast(ih); + TSHttpTxnHookAdd(txnp, TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, cont); + TSDebug(PLUGIN_NAME, "TSRemapDoRemap() added hook"); + + return TSREMAP_NO_REMAP; +} From d5b0dac72f37b79e2bc42b7c26ac09f1f6d81120 Mon Sep 17 00:00:00 2001 From: Vijay Mamidi Date: Wed, 3 Feb 2021 11:18:45 -0800 Subject: [PATCH 2/4] remove trailing whitespace --- plugins/experimental/cache_fill/Makefile.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/experimental/cache_fill/Makefile.inc b/plugins/experimental/cache_fill/Makefile.inc index 14085977211..6d837d88912 100644 --- a/plugins/experimental/cache_fill/Makefile.inc +++ b/plugins/experimental/cache_fill/Makefile.inc @@ -18,4 +18,4 @@ pkglib_LTLIBRARIES += experimental/cache_fill/cache_fill.la experimental_cache_fill_cache_fill_la_SOURCES = \ experimental/cache_fill/cache_fill.cc \ experimental/cache_fill/background_fetch.cc \ - experimental/cache_fill/background_fetch.h + experimental/cache_fill/background_fetch.h From a86796f313425869532079766df9ecaa1eece1aa Mon Sep 17 00:00:00 2001 From: Vijay Mamidi Date: Fri, 5 Feb 2021 18:07:27 -0800 Subject: [PATCH 3/4] Add documentation --- doc/admin-guide/plugins/cache_fill.en.rst | 46 +++++++++++++++++++++++ doc/admin-guide/plugins/index.en.rst | 1 + 2 files changed, 47 insertions(+) create mode 100644 doc/admin-guide/plugins/cache_fill.en.rst diff --git a/doc/admin-guide/plugins/cache_fill.en.rst b/doc/admin-guide/plugins/cache_fill.en.rst new file mode 100644 index 00000000000..e4f1944ba76 --- /dev/null +++ b/doc/admin-guide/plugins/cache_fill.en.rst @@ -0,0 +1,46 @@ +.. 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. + +.. _admin-plugins-cache-fill.so: +.. include:: /common.defs + +Cache Fill Plugin +*********************** + +The speed of the response served from the cache depends on the cache speed and the client filling the object. +This dependency could significantly impact all the clients requesting the object. +This plugin tries to eliminate the dependence by making the original request spawn a background request to fill the cache. +The initial version of this plugin relays the initial request to the origin server instead of waiting for the background request to start filling the cache as there is no easier way to find the wait time. +This plugin doesn't provide any improvement for smaller objects but could also degrade the performance as two outgoing requests for every cache update. + + +Using the plugin +---------------- + +This plugin functions as a per remap plugin. + +To activate the plugin, in :file:`remap.config`, simply append the +below to the specific remap line:: + + @plugin=cache_fill.so @pparam= + +Functionality +------------- + +Plugin decides to trigger a background fetch of the original (Client) request if the request/response is cacheable and cache status is TS_CACHE_LOOKUP_MISS/TS_CACHE_LOOKUP_HIT_STALE. + +Future additions +---------------- + +* Fetching the original request from the cache. + diff --git a/doc/admin-guide/plugins/index.en.rst b/doc/admin-guide/plugins/index.en.rst index 6f73b82083f..fdb7202466b 100644 --- a/doc/admin-guide/plugins/index.en.rst +++ b/doc/admin-guide/plugins/index.en.rst @@ -147,6 +147,7 @@ directory of the |TS| source tree. Experimental plugins can be compiled by passi :hidden: Access Control + Cache Fill Certifier Cert Reporting Tool Collapsed-Forwarding From 6e4b19aa18e22f04d03b3d4db8d7ef61d1411a34 Mon Sep 17 00:00:00 2001 From: Vijay Mamidi Date: Fri, 5 Feb 2021 18:47:20 -0800 Subject: [PATCH 4/4] Remove trailing whitespace --- doc/admin-guide/plugins/cache_fill.en.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/admin-guide/plugins/cache_fill.en.rst b/doc/admin-guide/plugins/cache_fill.en.rst index e4f1944ba76..2f22c382c98 100644 --- a/doc/admin-guide/plugins/cache_fill.en.rst +++ b/doc/admin-guide/plugins/cache_fill.en.rst @@ -20,7 +20,7 @@ Cache Fill Plugin The speed of the response served from the cache depends on the cache speed and the client filling the object. This dependency could significantly impact all the clients requesting the object. This plugin tries to eliminate the dependence by making the original request spawn a background request to fill the cache. -The initial version of this plugin relays the initial request to the origin server instead of waiting for the background request to start filling the cache as there is no easier way to find the wait time. +The initial version of this plugin relays the initial request to the origin server instead of waiting for the background request to start filling the cache as there is no easier way to find the wait time. This plugin doesn't provide any improvement for smaller objects but could also degrade the performance as two outgoing requests for every cache update.