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-06-11 15:37 +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. 

14 

15 

16""" 

17Write Once Action Cache 

18======================= 

19 

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. 

23 

24This can be used to wrap a different ActionCache implementation to provide 

25immutability of cache results. 

26 

27""" 

28 

29 

30import logging 

31 

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 

35 

36LOGGER = logging.getLogger(__name__) 

37 

38 

39class WriteOnceActionCache(ActionCacheABC): 

40 def __init__(self, action_cache: ActionCacheABC): 

41 super().__init__() 

42 self._action_cache = action_cache 

43 

44 def start(self) -> None: 

45 self._action_cache.start() 

46 

47 def stop(self) -> None: 

48 self._action_cache.stop() 

49 

50 @property 

51 def allow_updates(self) -> bool: 

52 return self._action_cache.allow_updates 

53 

54 def get_action_result(self, action_digest: Digest) -> ActionResult: 

55 """Retrieves the cached ActionResult for the given Action digest. 

56 

57 Args: 

58 action_digest (Digest): The digest of the Action to retrieve the 

59 cached result of. 

60 

61 Returns: 

62 The cached ActionResult matching the given digest or raises 

63 NotFoundError. 

64 

65 """ 

66 return self._action_cache.get_action_result(action_digest) 

67 

68 def update_action_result(self, action_digest: Digest, action_result: ActionResult) -> None: 

69 """Stores the result for a given digest in the cache. 

70 

71 If the digest already exists in the cache, then an UpdateNotAllowedError 

72 is raised instead of storing the result. 

73 

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. 

79 

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 ) 

90 

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)