Package concurrent_tree_crawler :: Module tree_accessor
[hide private]
[frames] | no frames]

Source Code for Module concurrent_tree_crawler.tree_accessor

  1  import logging 
  2  import threading 
  3   
  4  from concurrent_tree_crawler.abstract_tree_accessor import \ 
  5          AbstractTreeAccessor, NodeAction 
  6  from concurrent_tree_crawler.abstract_node import NodeState 
  7   
8 -class TreeAccessor(AbstractTreeAccessor):
9 """ 10 An interface for the tree made of L{AbstractNode}s. 11 Access to sensitive methods is protected by concurrent programming objects: 12 locks and conditions. 13 """
14 - def __init__(self, sentinel):
15 """ 16 @param sentinel: a technical node which will be made parent of the 17 root node. 18 @type sentinel: L{AbstractNode} 19 """ 20 21 self.__sentinel = sentinel 22 """ 23 The sentinel is a purely technical object. It shouldn't be 24 analyzed by the navigator. It is here just to make sure that the 25 root of the tree has a parent. This is because it is required by our 26 algorithm that all of the nodes in the tree have a parent. 27 """ 28 29 self.__root = None 30 """The main business-level element of the tree""" 31 32 ## The one and only child of the sentinel is the root node 33 if self.__sentinel.has_child("root"): 34 self.__root = self.__sentinel.get_child("root") 35 else: 36 self.__root = self.__sentinel.add_child("root", NodeState.OPEN)
37
38 - def get_sentinel(self):
39 return self.__sentinel
40
41 - def get_root(self):
42 return self.__root
43
44 - def update_and_get_child(self, node, possible_children_names):
45 while True: 46 node.get_children_cond().acquire() 47 try: 48 child = node.update_and_get_child(possible_children_names) 49 if child is None: ## No accessible children are available 50 return None 51 state = child.get_state() 52 if state == NodeState.OPEN: 53 child.set_state(NodeState.PROCESSING) 54 return (child, NodeAction.TO_PROCESS) 55 elif state == NodeState.VISITED: 56 return (child, NodeAction.TO_VISIT) 57 elif state == NodeState.PROCESSING: 58 self.__log("Starting to wait on \"{}\" node children".\ 59 format(node.get_name())) 60 node.get_children_cond().wait() 61 self.__log("Done waiting on \"{}\" node children".format( 62 node.get_name())) 63 else: 64 assert False, "Unknown node state: {}".format(state) 65 finally: 66 node.get_children_cond().release()
67
68 - def set_node_type(self, node, is_leaf):
69 assert node != self.__sentinel, "Processing sentinel is not allowed" 70 parent = node.get_parent() 71 parent.get_children_cond().acquire() 72 try: 73 if is_leaf: 74 node.set_state(NodeState.CLOSED) 75 self.__internal_update_node_state(parent) 76 else: 77 node.set_state(NodeState.VISITED) 78 finally: 79 parent.get_children_cond().notify_all() 80 parent.get_children_cond().release()
81
82 - def set_error(self, node):
84
85 - def __set_node_state_and_update(self, node, new_state):
86 assert node != self.__sentinel, "Changing sentinel state is not allowed" 87 parent = node.get_parent() 88 parent.get_children_cond().acquire() 89 try: 90 node.set_state(new_state) 91 self.__internal_update_node_state(parent) 92 finally: 93 parent.get_children_cond().notify_all() 94 parent.get_children_cond().release()
95
96 - def __internal_update_node_state(self, node):
97 """@param node: L{AbstractNode}""" 98 if node == self.__sentinel: 99 ## The state of the sentinel is undefined and not used 100 ## in the program, it should not be changed 101 return 102 new_state = None 103 if node.all_children_are_in_one_of_states({NodeState.CLOSED}): 104 new_state = NodeState.CLOSED 105 elif node.all_children_are_in_one_of_states( 106 {NodeState.ERROR, NodeState.CLOSED}): 107 new_state = NodeState.ERROR 108 ## Node state does not have to be changed 109 if new_state is None: 110 return 111 parent = node.get_parent() 112 parent.get_children_cond().acquire() 113 try: 114 node.set_state(new_state) 115 self.__internal_update_node_state(parent) 116 finally: 117 parent.get_children_cond().notify_all() 118 parent.get_children_cond().release()
119
120 - def __log(self, message):
121 """ 122 @type message: string 123 """ 124 logging.debug("thread=\"{}\", {}".format( 125 threading.current_thread().name, message))
126