Coverage for /builds/BuildGrid/buildgrid/buildgrid/server/actioncache/caches/write_once_cache.py: 85.71%

21 statements  

« prev     ^ index     » next       coverage.py v6.4.1, created at 2022-06-22 21:04 +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 ( 

34 ActionResult, 

35 Digest 

36) 

37from buildgrid.server.actioncache.caches.action_cache_abc import ActionCacheABC 

38 

39 

40class WriteOnceActionCache(ActionCacheABC): 

41 

42 def __init__(self, action_cache: ActionCacheABC): 

43 ActionCacheABC.__init__(self) 

44 self._logger = logging.getLogger(__name__) 

45 self._action_cache = action_cache 

46 

47 @property 

48 def allow_updates(self): 

49 return self._action_cache.allow_updates 

50 

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

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

53 

54 Args: 

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

56 cached result of. 

57 

58 Returns: 

59 The cached ActionResult matching the given digest or raises 

60 NotFoundError. 

61 

62 """ 

63 return self._action_cache.get_action_result(action_digest) 

64 

65 def update_action_result(self, action_digest: Digest, 

66 action_result: ActionResult) -> None: 

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

68 

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

70 is raised instead of storing the result. 

71 

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. 

77 

78 """ 

79 try: 

80 self._action_cache.get_action_result(action_digest) 

81 # This should throw NotFoundError or actually exist 

82 self._logger.warning("Result already cached for action " 

83 f"[{action_digest.hash}/{action_digest.size_bytes}], " 

84 "WriteOnceActionCache won't overwrite it to " 

85 f"the new action_result=[{action_result}]") 

86 

87 raise UpdateNotAllowedError("Result already stored for this action digest;" 

88 "WriteOnceActionCache doesn't allow updates.") 

89 except NotFoundError: 

90 self._action_cache.update_action_result(action_digest, action_result)