%% @private -module(http_cache_store_native). -include("http_cache_store_native.hrl"). -behaviour(http_cache_store). -export([list_candidates/2, get_response/2, put/6, notify_response_used/2, invalidate_url/2, invalidate_by_alternate_key/2, delete_object/2, object_key/2, lru/2]). list_candidates(RequestKey, _Opts) -> Spec = [{{{RequestKey, '$1'}, '$2', '_', {'$3', '$4', '_'}, '$5', '_'}, [], [['$1', '$2', '$3', '$4', '$5']]}], Now = unix_now(), [{{RequestKey, SecondKeyPart}, Status, RespHeaders, VaryHeaders, RespMetadata} || [SecondKeyPart, VaryHeaders, Status, RespHeaders, RespMetadata] <- ets:select(?OBJECT_TABLE, Spec), Now < map_get(grace, RespMetadata)]. get_response(ObjectKey, _Opts) -> case ets:lookup(?OBJECT_TABLE, ObjectKey) of [{_ObjectKey, _VaryHeaders, _UrlDigest, {Status, RespHeaders, RespBody}, RespMetadata, _SeqNumber}] -> {Status, RespHeaders, RespBody, RespMetadata}; [] -> undefined end. put(RequestKey, UrlDigest, VaryHeaders, Response, #{grace := _} = RespMetadata, _Opts) -> case http_cache_store_native_worker_sup:start_worker({cache_object, {RequestKey, UrlDigest, VaryHeaders, Response, RespMetadata}}) of ok -> ObjectKey = object_key(RequestKey, VaryHeaders), Expires = map_get(grace, RespMetadata), http_cache_store_native_cluster_mon:broadcast_object_available(ObjectKey, Expires), ok; {error, _} = Error -> Error end. invalidate_url(UrlDigest, _Opts) -> http_cache_store_native_cluster_mon:broadcast_invalidate_url(UrlDigest), case http_cache_store_native_worker_sup:start_worker({invalidate_url, UrlDigest}) of ok -> {ok, undefined}; {error, _} = Error -> Error end. invalidate_by_alternate_key(AltKeys, _Opts) -> http_cache_store_native_cluster_mon:broadcast_invalidate_by_alternate_key(AltKeys), case http_cache_store_native_worker_sup:start_worker({invalidate_by_alternate_key, AltKeys}) of ok -> {ok, undefined}; {error, _} = Error -> Error end. notify_response_used(ObjectKey, _Opts) -> SeqNumber = erlang:unique_integer(), case ets:update_element(?OBJECT_TABLE, ObjectKey, {6, SeqNumber}) of true -> lru(ObjectKey, SeqNumber), ok; false -> ok end. delete_object(ObjectKey, Reason) -> telemetry:execute([http_cache_store_native, object_deleted], #{}, #{reason => Reason}), ets:delete(?OBJECT_TABLE, ObjectKey), ok. object_key(RequestKey, VaryHeaders) -> {RequestKey, crypto:hash(sha256, erlang:term_to_binary(VaryHeaders))}. lru(ObjectKey, SeqNumber) -> ets:insert(?LRU_TABLE, {{unix_now(), ObjectKey, SeqNumber}}). unix_now() -> os:system_time(second).