Coverage for /builds/BuildGrid/buildgrid/buildgrid/server/actioncache/caches/action_cache_abc.py: 77.59%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

58 statements  

1# Copyright (C) 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 

16from abc import ABC, abstractmethod 

17import logging 

18 

19from buildgrid._protos.build.bazel.remote.execution.v2.remote_execution_pb2 import ( 

20 ActionResult, 

21 Digest, 

22 Tree 

23) 

24from buildgrid.utils import get_hash_type 

25 

26 

27class ActionCacheABC(ABC): 

28 

29 def __init__(self, allow_updates=False, storage=None): 

30 self._logger = logging.getLogger(__name__) 

31 self._instance_name = None 

32 self._allow_updates = allow_updates 

33 self._storage = storage 

34 

35 @property 

36 def instance_name(self): 

37 return self._instance_name 

38 

39 @instance_name.setter 

40 def instance_name(self, instance_name): 

41 self._instance_name = instance_name 

42 

43 @property 

44 def allow_updates(self): 

45 return self._allow_updates 

46 

47 def hash_type(self): 

48 return get_hash_type() 

49 

50 def setup_grpc(self): 

51 pass 

52 

53 # NOTE: This method exists for compatibility reasons. Ideally it should never 

54 # be used with an up-to-date configuration. 

55 def register_instance_with_server(self, instance_name, server): 

56 """Names and registers the action-cache instance with a given server.""" 

57 if hasattr(self, '_logger'): 

58 self._logger.warning( 

59 "Cache instances should be defined in a 'caches' list and passed " 

60 "to an ActionCache service, rather than defined in the 'services' " 

61 "list themselves.") 

62 if self._instance_name is None: 

63 server.add_action_cache_instance(self, instance_name) 

64 

65 self._instance_name = instance_name 

66 

67 else: 

68 raise AssertionError("Instance already registered") 

69 

70 @abstractmethod 

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

72 raise NotImplementedError() 

73 

74 @abstractmethod 

75 def update_action_result(self, action_digest: Digest, 

76 action_result: ActionResult) -> None: 

77 raise NotImplementedError() 

78 

79 def _action_result_blobs_still_exist(self, action_result: ActionResult) -> bool: 

80 """Checks CAS for ActionResult output blobs existence. 

81 

82 Args: 

83 action_result (ActionResult): ActionResult to search referenced 

84 output blobs for. 

85 

86 Returns: 

87 True if all referenced blobs are present in CAS, False otherwise. 

88 """ 

89 if not self._storage: 

90 return True 

91 blobs_needed = [] 

92 

93 for output_file in action_result.output_files: 

94 blobs_needed.append(output_file.digest) 

95 

96 for output_directory in action_result.output_directories: 

97 blobs_needed.append(output_directory.tree_digest) 

98 tree = self._storage.get_message(output_directory.tree_digest, Tree) 

99 if tree is None: 

100 return False 

101 

102 for file_node in tree.root.files: 

103 blobs_needed.append(file_node.digest) 

104 

105 for child in tree.children: 

106 for file_node in child.files: 

107 blobs_needed.append(file_node.digest) 

108 

109 if action_result.stdout_digest.hash and not action_result.stdout_raw: 

110 blobs_needed.append(action_result.stdout_digest) 

111 

112 if action_result.stderr_digest.hash and not action_result.stderr_raw: 

113 blobs_needed.append(action_result.stderr_digest) 

114 

115 missing = self._storage.missing_blobs(blobs_needed) 

116 if len(missing) != 0: 

117 self._logger.debug(f"Missing {len(missing)}/{len(blobs_needed)} blobs") 

118 return False 

119 return True