Coverage for /builds/BuildGrid/buildgrid/buildgrid/server/actioncache/caches/write_once_cache.py: 80.77%
26 statements
« prev ^ index » next coverage.py v7.4.1, created at 2025-05-21 15:45 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2025-05-21 15:45 +0000
1# Copyright (C) 2019, 2020 Bloomberg LP
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# <http://www.apache.org/licenses/LICENSE-2.0>
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
16"""
17Write Once Action Cache
18=======================
20An ActionCache backend implementation which only allows each digest to
21be written to once. Any subsequent requests to cache a result for the
22same digests will not be permitted.
24This can be used to wrap a different ActionCache implementation to provide
25immutability of cache results.
27"""
29from buildgrid._protos.build.bazel.remote.execution.v2.remote_execution_pb2 import ActionResult, Digest
30from buildgrid.server.actioncache.caches.action_cache_abc import ActionCacheABC
31from buildgrid.server.exceptions import NotFoundError, UpdateNotAllowedError
32from buildgrid.server.logging import buildgrid_logger
34LOGGER = buildgrid_logger(__name__)
37class WriteOnceActionCache(ActionCacheABC):
38 def __init__(self, action_cache: ActionCacheABC):
39 super().__init__()
40 self._action_cache = action_cache
42 def start(self) -> None:
43 self._action_cache.start()
45 def stop(self) -> None:
46 self._action_cache.stop()
48 @property
49 def allow_updates(self) -> bool:
50 return self._action_cache.allow_updates
52 def get_action_result(self, action_digest: Digest) -> ActionResult:
53 """Retrieves the cached ActionResult for the given Action digest.
55 Args:
56 action_digest (Digest): The digest of the Action to retrieve the
57 cached result of.
59 Returns:
60 The cached ActionResult matching the given digest or raises
61 NotFoundError.
63 """
64 return self._action_cache.get_action_result(action_digest)
66 def update_action_result(self, action_digest: Digest, action_result: ActionResult) -> None:
67 """Stores the result for a given digest in the cache.
69 If the digest already exists in the cache, then an UpdateNotAllowedError
70 is raised instead of storing the result.
72 Args:
73 action_digest (Digest): The digest of the Action whose result is
74 being cached.
75 action_result (ActionResult): The result to cache for the given
76 Action digest.
78 """
79 try:
80 self._action_cache.get_action_result(action_digest)
81 # This should throw NotFoundError or actually exist
82 LOGGER.warning(
83 "Result already cached for action, WriteOnceActionCache won't overwrite it to the new action result.",
84 tags=dict(digest=action_digest, action_result=action_result),
85 )
87 raise UpdateNotAllowedError(
88 "Result already stored for this action digest;WriteOnceActionCache doesn't allow updates."
89 )
90 except NotFoundError:
91 self._action_cache.update_action_result(action_digest, action_result)