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 2024-04-15 14:01 +0000
« prev ^ index » next coverage.py v7.4.1, created at 2024-04-15 14:01 +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"""
30import logging
32from buildgrid._exceptions import NotFoundError, UpdateNotAllowedError
33from buildgrid._protos.build.bazel.remote.execution.v2.remote_execution_pb2 import ActionResult, Digest
34from buildgrid.server.actioncache.caches.action_cache_abc import ActionCacheABC
36LOGGER = logging.getLogger(__name__)
39class WriteOnceActionCache(ActionCacheABC):
40 def __init__(self, action_cache: ActionCacheABC):
41 super().__init__()
42 self._action_cache = action_cache
44 def start(self) -> None:
45 self._action_cache.start()
47 def stop(self) -> None:
48 self._action_cache.stop()
50 @property
51 def allow_updates(self) -> bool:
52 return self._action_cache.allow_updates
54 def get_action_result(self, action_digest: Digest) -> ActionResult:
55 """Retrieves the cached ActionResult for the given Action digest.
57 Args:
58 action_digest (Digest): The digest of the Action to retrieve the
59 cached result of.
61 Returns:
62 The cached ActionResult matching the given digest or raises
63 NotFoundError.
65 """
66 return self._action_cache.get_action_result(action_digest)
68 def update_action_result(self, action_digest: Digest, action_result: ActionResult) -> None:
69 """Stores the result for a given digest in the cache.
71 If the digest already exists in the cache, then an UpdateNotAllowedError
72 is raised instead of storing the result.
74 Args:
75 action_digest (Digest): The digest of the Action whose result is
76 being cached.
77 action_result (ActionResult): The result to cache for the given
78 Action digest.
80 """
81 try:
82 self._action_cache.get_action_result(action_digest)
83 # This should throw NotFoundError or actually exist
84 LOGGER.warning(
85 "Result already cached for action "
86 f"[{action_digest.hash}/{action_digest.size_bytes}], "
87 "WriteOnceActionCache won't overwrite it to "
88 f"the new action_result=[{action_result}]"
89 )
91 raise UpdateNotAllowedError(
92 "Result already stored for this action digest;WriteOnceActionCache doesn't allow updates."
93 )
94 except NotFoundError:
95 self._action_cache.update_action_result(action_digest, action_result)