diff options
Diffstat (limited to 'python/pgq/setadmin.py')
-rw-r--r-- | python/pgq/setadmin.py | 144 |
1 files changed, 99 insertions, 45 deletions
diff --git a/python/pgq/setadmin.py b/python/pgq/setadmin.py index 4f33794a..0c500468 100644 --- a/python/pgq/setadmin.py +++ b/python/pgq/setadmin.py @@ -6,10 +6,30 @@ from pgq.setinfo import * __all__ = ['SetAdmin'] -command_usage = """ +command_usage = """\ %prog [options] INI CMD [subcmd args] -commands: +Node Initialization: + init-root NODE_NAME NODE_CONSTR + init-branch NODE_NAME NODE_CONSTR --provider=<constr> + init-leaf NODE_NAME NODE_CONSTR --provider=<constr> + Initializes node. Given connstr is kept as global connstring + for that node. Those commands ignore node_db in .ini. + The --provider connstr is used only for initial set info + fetching, later actual provider's connect string is used. + +Node Administration: + status Show set state + members Show members in set + rename-node OLD NEW Rename a node + change-provider NODE NEWSRC + pause NODE + resume NODE + + switchover NEWROOT + failover NEWROOT + tag-dead NODE .. Tag node as dead + tag-alive NODE .. Tag node as alive """ class SetAdmin(skytools.AdminScript): @@ -37,20 +57,16 @@ class SetAdmin(skytools.AdminScript): # Node initialization. # - def cmd_init_root(self, args): - if len(args) != 2: - raise Exception('init-root needs 2 args') - self.init_node('root', args[0], args[1]) + def cmd_init_root(self, node_name, node_location): + self.init_node('root', node_name, node_location) - def cmd_init_branch(self, args): + def cmd_init_branch(self, node_name, node_location): if len(args) != 2: raise Exception('init-branch needs 2 args') - self.init_node('branch', args[0], args[1]) + self.init_node('branch', node_name, node_location) - def cmd_init_leaf(self, args): - if len(args) != 2: - raise Exception('init-leaf needs 2 args') - self.init_node('leaf', args[0], args[1]) + def cmd_init_leaf(self, node_name, node_location): + self.init_node('leaf', node_name, node_location) def init_node(self, node_type, node_name, node_location): provider_loc = self.options.provider @@ -186,7 +202,7 @@ class SetAdmin(skytools.AdminScript): # Print status of whole set. # - def cmd_status(self, args): + def cmd_status(self): root_db = self.find_root_db() sinf = self.load_set_info(root_db) @@ -209,9 +225,7 @@ class SetAdmin(skytools.AdminScript): # Normal commands. # - def cmd_change_provider(self, args): - node_name = args[0] - new_provider = args[1] + def cmd_change_provider(self, node_name, new_provider): old_provider = None self.load_local_info() @@ -248,9 +262,7 @@ class SetAdmin(skytools.AdminScript): # resume node self.resume_node(node_name) - def cmd_rename_node(self, args): - old_name = args[0] - new_name = args[1] + def cmd_rename_node(self, old_name, new_name): self.load_local_info() @@ -260,6 +272,7 @@ class SetAdmin(skytools.AdminScript): self.pause_node(old_name) node = self.load_node_info(old_name) provider_node = node.provider_node + subscriber_list = self.get_node_subscriber_list(old_name) # create copy of member info / subscriber+queue info @@ -271,41 +284,76 @@ class SetAdmin(skytools.AdminScript): self.exec_cmd(root_db, step1, [self.set_name, old_name, new_name]) self.node_cmd(provider_node, step1, [self.set_name, old_name, new_name]) self.node_cmd(old_name, step1, [self.set_name, old_name, new_name]) + for child in subscriber_list: + self.node_cmd(child, step1, [self.set_name, old_name, new_name]) # step1 self.node_cmd(old_name, step2, [self.set_name, old_name, new_name]) self.node_cmd(provider_node, step1, [self.set_name, old_name, new_name]) + for child in subscriber_list: + self.node_cmd(child, step2, [self.set_name, old_name, new_name]) self.exec_cmd(root_db, step2, [self.set_name, old_name, new_name]) # resume node self.resume_node(old_name) - def cmd_promote(self): - old_root = 'foo' - new_root = '' - self.pause_node(old_root) - ctx = self.load_node_info(old_root) - [['old-root', 'PAUSE']] - [['old-root', 'demote, set-provider?']] - [['new-root', 'wait-for-catch-up']] - [['new-root', 'pause']] - [['new-root', 'promote']] - [['new-root', 'resume']] - [['old-root', 'resume']] - [['new_parent', 'select * from pgq_set.subscribe_node(%(set_name)s, %(node_name)s, %(node_pos)s)']] - [['node', 'select * from pgq_set.change_provider(%(set_name)s, %(new_provider)s)']] - [['old_parent', 'select * from pgq_set.unsubscribe_node(%(set_name)s, %(node_name)s, %(node_pos)s)']] - [['node', 'RESUME']] - - def cmd_pause(self, args): + def switchover_nonroot(self, old_node, new_node): + # see if we need to change new nodes' provider + tmp_node = new_node + while 1: + if tmp_node.is_root(): + break + if tmp_node.name == old_node: + # yes, old_node is new_nodes provider, + # switch it around + self.change_provider(new_node, old_node.parent_node) + break + self.change_provider(old_node.name, new_node.name) + + def switchover_root(self, old_node, new_node): + self.pause_node(old_node.name) + self.extra_lockdown(old_node) + + self.wait_for_catchup(new_node, old_node) + self.pause_node(new_node.name) + self.promote_node(new_node.name) + self.subscribe_node(new_node.name, old_node.name, tick_pos) + self.unsubscribe_node(new_node.parent_node, new_node.name) + self.resume_node(new_node.name) + + # demote & set provider on node + q = 'select * from pgq_set.demote_root(%s, %s)' + self.node_cmd(old_node.name, q, [self.set_name, new_node.name]) + + self.resume_node(old_node.name) + + def cmd_switchover(self, old_node_name, new_node_name): self.load_local_info() - self.pause_node(args[0]) + old_node = self.get_node_info(old_node_name) + new_node = self.get_node_info(new_node_name) + if old_node.name == new_node.name: + self.log.info("same node?") + return - def cmd_resume(self, args): + if old_node.is_root(): + self.switchover_root(old_node, new_node) + else: + self.switchover_nonroot(old_node, new_node) + + # switch subscribers around + if self.options.all: + for n in self.get_node_subscriber_list(old_node.name): + self.change_provider(n, new_node.name) + + def cmd_pause(self, node_name): + self.load_local_info() + self.pause_node(node_name) + + def cmd_resume(self, node_name): self.load_local_info() - self.resume_node(args[0]) + self.resume_node(node_name) - def cmd_members(self, args): + def cmd_members(self): db = self.get_database(self.initial_db_name) q = "select node_name from pgq_set.get_node_info(%s)" rows = self.exec_query(db, q, [self.set_name]) @@ -382,11 +430,11 @@ class SetAdmin(skytools.AdminScript): def subscribe_node(self, target_node, subscriber_node, tick_pos): q = "select * from pgq_set.subscribe_node(%s, %s, %s)" - self.node_cmd(target_node, q, [self.set_name, target_node, tick_pos]) + self.node_cmd(target_node, q, [self.set_name, subscribe_node, tick_pos]) - def unsubscribe_node(self, target_node, subscriber_node, tick_pos): - q = "select * from pgq_set.subscribe_node(%s, %s, %s)" - self.node_cmd(target_node, q, [self.set_name, target_node, tick_pos]) + def unsubscribe_node(self, target_node, subscriber_node): + q = "select * from pgq_set.unsubscribe_node(%s, %s)" + self.node_cmd(target_node, q, [self.set_name, subscribe_node]) def load_node_info(self, node_name): db = self.get_node_database(node_name) @@ -403,6 +451,12 @@ class SetAdmin(skytools.AdminScript): return SetInfo(self.set_name, info, member_list) + def get_node_subscriber_list(self, node_name): + q = "select node_name, local_watermark from pgq_set.get_subscriber_info(%s)" + db = self.get_node_database(node_name) + rows = self.exec_query(db, q, [self.set_name]) + return [r['node_name'] for r in rows] + if __name__ == '__main__': script = SetAdmin('set_admin', sys.argv[1:]) script.start() |