-
Notifications
You must be signed in to change notification settings - Fork 858
Optimize cache miss path with deferred cache write #12782
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -623,6 +623,11 @@ struct OverridableHttpConfigParams { | |
|
|
||
| MgmtByte cache_open_write_fail_action = 0; | ||
|
|
||
| //////////////////////////////////////////////// | ||
| // Defer cache open write until response hdrs // | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably a useful comment, but this is almost too short :) Shouldn't it be something like "...until response headers are received" ? |
||
| //////////////////////////////////////////////// | ||
| MgmtByte cache_defer_write_on_miss = 0; | ||
|
|
||
| //////////////////////// | ||
| // Check Post request // | ||
| //////////////////////// | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -697,6 +697,10 @@ class HttpTransact | |
| bool is_method_stats_incremented = false; | ||
| bool skip_ip_allow_yaml = false; | ||
|
|
||
| /// True if we deferred opening the cache for write until after response headers. | ||
| /// This is an optimization to avoid cache overhead for non-cacheable responses. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The second comment here sounds like something that would be documented as part of the new setting. We know why we added this ... |
||
| bool cache_open_write_deferred = false; | ||
|
|
||
| /// True if the response is cacheable because of negative caching configuration. | ||
| /// | ||
| /// This being true implies the following: | ||
|
|
@@ -1018,6 +1022,7 @@ class HttpTransact | |
| static void handle_cache_write_lock(State *s); | ||
| static void handle_cache_write_lock_go_to_origin(State *s); | ||
| static void handle_cache_write_lock_go_to_origin_continue(State *s); | ||
| static void handle_deferred_cache_write_complete(State *s); | ||
| static void HandleResponse(State *s); | ||
| static void HandleUpdateCachedObject(State *s); | ||
| static void HandleUpdateCachedObjectContinue(State *s); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3333,6 +3333,62 @@ HttpTransact::handle_cache_write_lock_go_to_origin_continue(State *s) | |
| } | ||
| } | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////////// | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a good comment :) |
||
| // Name : handle_deferred_cache_write_complete | ||
| // Description: Called after cache write opens for deferred cache write. | ||
| // We already have the server response headers, so we continue | ||
| // with cache write handling. | ||
| // | ||
| // Possible Next States From Here: | ||
| // - handle_cache_operation_on_forward_server_response (if cache write succeeded) | ||
| // - handle_no_cache_operation_on_forward_server_response (if cache write failed) | ||
| // | ||
| /////////////////////////////////////////////////////////////////////////////// | ||
| void | ||
| HttpTransact::handle_deferred_cache_write_complete(State *s) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one is hard to review :) Are there any existing tests that hits this code (with the setting enabled, obviously)? If not, this feels like we ought to have an autest (ideally start a new proxy-verify "framework" test?). |
||
| { | ||
| TxnDbg(dbg_ctl_http_trans, "handle_deferred_cache_write_complete"); | ||
| TxnDbg(dbg_ctl_http_seq, "Entering handle_deferred_cache_write_complete"); | ||
|
|
||
| ink_assert(s->cache_info.action == CacheAction_t::PREPARE_TO_WRITE); | ||
|
|
||
| switch (s->cache_info.write_lock_state) { | ||
| case CacheWriteLock_t::SUCCESS: | ||
| // Cache write lock acquired successfully | ||
| TxnDbg(dbg_ctl_http_trans, "[hdcwc] cache write lock acquired"); | ||
| SET_UNPREPARE_CACHE_ACTION(s->cache_info); | ||
| // Now we have WRITE action, handle the response with caching | ||
| handle_cache_operation_on_forward_server_response(s); | ||
| return; | ||
|
|
||
| case CacheWriteLock_t::FAIL: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From Claude, sounds like there's a bit of overlap between these two settings, that should at least be documented.
|
||
| // Could not get cache write lock, continue without caching | ||
| TxnDbg(dbg_ctl_http_trans, "[hdcwc] cache write lock failed, continuing without cache"); | ||
| Metrics::Counter::increment(http_rsb.cache_open_write_fail_count); | ||
| s->cache_info.action = CacheAction_t::NO_ACTION; | ||
| s->cache_info.write_status = CacheWriteStatus_t::LOCK_MISS; | ||
| break; | ||
|
|
||
| case CacheWriteLock_t::READ_RETRY: | ||
| // This shouldn't happen for deferred write since we don't have an object to read | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this shouldn't happen, should it be a InkAssert() at least ? Not sure that TxnDbg is the right choice here either, maybe a notice or something else ? |
||
| TxnDbg(dbg_ctl_http_trans, "[hdcwc] unexpected READ_RETRY for deferred write"); | ||
| s->cache_info.action = CacheAction_t::NO_ACTION; | ||
| s->cache_info.write_status = CacheWriteStatus_t::LOCK_MISS; | ||
| break; | ||
|
|
||
| case CacheWriteLock_t::INIT: | ||
| default: | ||
| ink_release_assert(0); | ||
| break; | ||
| } | ||
|
|
||
| // If we get here, cache write failed - continue without caching | ||
| // The original handle_no_cache_operation_on_forward_server_response will be called | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, yeah, I can see that handle_no_cache_operation_on_forward_server_response is called ... |
||
| // but we need to skip the deferred cache write check since we just tried it | ||
| // s->cache_open_write_deferred is already false from the first call | ||
|
bryancall marked this conversation as resolved.
|
||
| handle_no_cache_operation_on_forward_server_response(s); | ||
| } | ||
|
|
||
| /////////////////////////////////////////////////////////////////////////////// | ||
| // Name : HandleCacheOpenReadMiss | ||
| // Description: cache looked up, miss or hit, but needs authorization | ||
|
|
@@ -3378,6 +3434,13 @@ HttpTransact::HandleCacheOpenReadMiss(State *s) | |
| s->cache_info.action = CacheAction_t::NO_ACTION; | ||
| } else if (s->api_server_response_no_store) { // plugin may have decided not to cache the response | ||
| s->cache_info.action = CacheAction_t::NO_ACTION; | ||
| } else if (s->txn_conf->cache_defer_write_on_miss) { | ||
| // Defer cache open write until after response headers are received. | ||
| // This avoids cache overhead for non-cacheable responses but may | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In general, I find Claud's comments to be overly verbose. If needed, this feels like it can be a one-line. It's pretty clear that will "defer cache open write" ... If the code is self documenting, we shouldn't state the obvious. I'd suggest you look through all the comments (or ask to) and remove the comments that are obvious. |
||
| // affect read-while-write and request coalescing for popular URLs. | ||
| s->cache_open_write_deferred = true; | ||
| s->cache_info.action = CacheAction_t::NO_ACTION; | ||
| TxnDbg(dbg_ctl_http_trans, "[HandleCacheOpenReadMiss] deferring cache open write until response"); | ||
| } else if (s->cache_info.write_lock_state == CacheWriteLock_t::READ_RETRY) { | ||
| // READ_RETRY cache read failed (no fresh object found). | ||
| // Check if we have a stale fallback (saved from action 6 revalidation case). | ||
|
|
@@ -4849,6 +4912,24 @@ HttpTransact::handle_no_cache_operation_on_forward_server_response(State *s) | |
| TxnDbg(dbg_ctl_http_trans, "(hncoofsr)"); | ||
| TxnDbg(dbg_ctl_http_seq, "Entering handle_no_cache_operation_on_forward_server_response"); | ||
|
|
||
| // Check if we deferred the cache open write and the response is cacheable. | ||
| // If so, we need to open the cache for write now. | ||
| if (s->cache_open_write_deferred && s->txn_conf->cache_http) { | ||
| bool cacheable = is_response_cacheable(s, &s->hdr_info.client_request, &s->hdr_info.server_response); | ||
| TxnDbg(dbg_ctl_http_trans, "[hncoofsr] deferred cache write, response %s cacheable", cacheable ? "is" : "is not"); | ||
|
|
||
| if (cacheable) { | ||
| // Response is cacheable - open the cache for write now | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, stating the obvious in this comment, if (cacheable) is self explanatory. |
||
| s->cache_open_write_deferred = false; | ||
| s->cache_info.action = CacheAction_t::PREPARE_TO_WRITE; | ||
| s->cache_info.write_lock_state = CacheWriteLock_t::INIT; | ||
| // After cache write opens, continue with handle_cache_operation_on_forward_server_response | ||
| TRANSACT_RETURN(StateMachineAction_t::CACHE_ISSUE_WRITE, handle_deferred_cache_write_complete); | ||
| } | ||
| // Not cacheable - continue with no-cache operation | ||
| s->cache_open_write_deferred = false; | ||
| } | ||
|
|
||
| bool keep_alive = s->current.server->keep_alive == HTTPKeepAlive::KEEPALIVE; | ||
| const char *warn_text = nullptr; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -623,6 +623,13 @@ static constexpr RecordElement RecordsConfig[] = | |
| // # 6 - retry cache read on write lock failure, if retries exhausted serve stale if allowed, otherwise goto origin | ||
| {RECT_CONFIG, "proxy.config.http.cache.open_write_fail_action", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} | ||
| , | ||
| // # defer_write_on_miss: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know that we need this verbose documentation here either, either leave it out, or refer to the Docs section as before. |
||
| // # 0 - disabled (default). Open cache for write immediately on miss. | ||
| // # 1 - enabled. Defer cache open write until response headers received. | ||
| // # Improves performance for non-cacheable responses but may affect | ||
| // # read-while-write and request coalescing for popular uncached URLs. | ||
| {RECT_CONFIG, "proxy.config.http.cache.defer_write_on_miss", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL} | ||
| , | ||
| // # when_to_revalidate has 4 options: | ||
| // # | ||
| // # 0 - default. use cache directives or heuristic | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this long comment, shouldn't it just link to the relevant docs anchor?