Return-Path: Delivered-To: apmail-hadoop-zookeeper-commits-archive@minotaur.apache.org Received: (qmail 30208 invoked from network); 27 Jul 2010 15:11:58 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 27 Jul 2010 15:11:58 -0000 Received: (qmail 80787 invoked by uid 500); 27 Jul 2010 15:11:58 -0000 Delivered-To: apmail-hadoop-zookeeper-commits-archive@hadoop.apache.org Received: (qmail 80757 invoked by uid 500); 27 Jul 2010 15:11:58 -0000 Mailing-List: contact zookeeper-commits-help@hadoop.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: zookeeper-dev@ Delivered-To: mailing list zookeeper-commits@hadoop.apache.org Received: (qmail 80749 invoked by uid 99); 27 Jul 2010 15:11:57 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 27 Jul 2010 15:11:57 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED,NORMAL_HTTP_TO_IP X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 27 Jul 2010 15:11:56 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 8E460238899C; Tue, 27 Jul 2010 15:11:04 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r979742 - in /hadoop/zookeeper/trunk: CHANGES.txt src/contrib/zkpython/src/examples/ src/contrib/zkpython/src/examples/README src/contrib/zkpython/src/examples/watch_znode_for_changes.py Date: Tue, 27 Jul 2010 15:11:04 -0000 To: zookeeper-commits@hadoop.apache.org From: mahadev@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100727151104.8E460238899C@eris.apache.org> Author: mahadev Date: Tue Jul 27 15:11:04 2010 New Revision: 979742 URL: http://svn.apache.org/viewvc?rev=979742&view=rev Log: ZOOKEEPER-765. Add python example script (Travis and Andrei via mahadev) Added: hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/ hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/README hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/watch_znode_for_changes.py Modified: hadoop/zookeeper/trunk/CHANGES.txt Modified: hadoop/zookeeper/trunk/CHANGES.txt URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/CHANGES.txt?rev=979742&r1=979741&r2=979742&view=diff ============================================================================== --- hadoop/zookeeper/trunk/CHANGES.txt (original) +++ hadoop/zookeeper/trunk/CHANGES.txt Tue Jul 27 15:11:04 2010 @@ -97,6 +97,8 @@ IMPROVEMENTS: ZOOKEEPER-821. Add ZooKeeper version information to zkpython (Rich Schumacher via mahadev) + ZOOKEEPER-765. Add python example script (Travis and Andrei via mahadev) + NEW FEATURES: ZOOKEEPER-729. Java client API to recursively delete a subtree. (Kay Kay via henry) Added: hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/README URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/README?rev=979742&view=auto ============================================================================== --- hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/README (added) +++ hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/README Tue Jul 27 15:11:04 2010 @@ -0,0 +1,8 @@ + +This folder contains sample showing how you can use ZooKeeper from Python. + +You should also check the following projects: + +* http://github.com/phunt/zk-smoketest +* http://github.com/henryr/pyzk-recipes + Added: hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/watch_znode_for_changes.py URL: http://svn.apache.org/viewvc/hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/watch_znode_for_changes.py?rev=979742&view=auto ============================================================================== --- hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/watch_znode_for_changes.py (added) +++ hadoop/zookeeper/trunk/src/contrib/zkpython/src/examples/watch_znode_for_changes.py Tue Jul 27 15:11:04 2010 @@ -0,0 +1,202 @@ +#!/usr/bin/env python2.6 +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" ZNode Change Watcher Skeleton Script + +This script shows you how to write a python program that watches a specific +znode for changes and reacts to them. + +Steps to understand how this script works: + +1. start a standalone ZooKeeper server (by default it listens on localhost:2181) + +Did you know you can deploy "local clusters" by using zkconf[1]? +[1] http://github.com/phunt/zkconf + +2. enter the command line console + +3. create the test node: + [zk: (CONNECTED) 1] create /watch-test dummy-data + Created /watch-test + +4. in another shell start this script in verbose mode + $ python watch_znode_for_changes.py -v + + # you should see a lot of log messages. have a look over them because + # you can easily understand how zookeeper works + +5. update the node data: + + [zk: (CONNECTED) 2] set /watch-test new-data + cZxid = 0xa0000001a + ctime = Fri Jul 09 19:14:45 EEST 2010 + mZxid = 0xa0000001e + mtime = Fri Jul 09 19:18:18 EEST 2010 + pZxid = 0xa0000001a + cversion = 0 + dataVersion = 1 + aclVersion = 0 + ephemeralOwner = 0x0 + dataLength = 8 + numChildren = 0 + + ... and you should see similar log messages: + + 2010-07-09 19:18:18,537:11542(0xb6ea5b70):ZOO_DEBUG@process_completions@1765: Calling a watcher for node [/watch-test], type = -1 event=ZOO_CHANGED_EVENT + 2010-07-09 19:18:18,537 watch_znode_for_changes.py:83 - Running watcher: zh=0 event=3 state=3 path=/watch-test + 2010-07-09 19:18:18,537:11542(0xb6ea5b70):ZOO_DEBUG@zoo_awget@2400: Sending request xid=0x4c374b33 for path [/watch-test] to 127.0.0.1:2181 + 2010-07-09 19:18:18,545:11542(0xb76a6b70):ZOO_DEBUG@zookeeper_process@1980: Queueing asynchronous response + 2010-07-09 19:18:18,545:11542(0xb6ea5b70):ZOO_DEBUG@process_completions@1772: Calling COMPLETION_DATA for xid=0x4c374b33 rc=0 + 2010-07-09 19:18:18,545 watch_znode_for_changes.py:54 - This is where your application does work. + + You can repeat this step multiple times. + +6. that's all. in the end you can delete the node and you should see a ZOO_DELETED_EVENT + +""" + +import logging +import logging.handlers +import signal +import sys +import time +import threading +import zookeeper + +from optparse import OptionParser + +logger = logging.getLogger() + +class MyClass(threading.Thread): + znode = '/watch-test' + + def __init__(self, options, args): + threading.Thread.__init__(self) + + logger.debug('Initializing MyClass thread.') + if options.verbose: + zookeeper.set_debug_level(zookeeper.LOG_LEVEL_DEBUG) + + self.zh = zookeeper.init(options.servers) + if zookeeper.OK != zookeeper.aget(self.zh, self.znode, + self.watcher, self.handler): + logger.critical('Unable to get znode! Exiting.') + sys.exit(1) + + def __del__(self): + zookeeper.close(self.zh) + + def aget(self): + return zookeeper.aget(self.zh, self.znode, self.watcher, self.handler) + + def handler(self, zh, rc, data, stat): + """Handle zookeeper.aget() responses. + + This code handles the zookeeper.aget callback. It does not handle watches. + + Numeric arguments map to constants. See ``DATA`` in ``help(zookeeper)`` + for more information. + + Args: + zh Zookeeper handle that made this request. + rc Return code. + data Data stored in the znode. + + Does not provide a return value. + """ + if zookeeper.OK == rc: + logger.debug('This is where your application does work.') + else: + if zookeeper.NONODE == rc: + # avoid sending too many requests if the node does not yet exists + logger.info('Node not found. Trying again to set the watch.') + time.sleep(1) + + if zookeeper.OK != self.aget(): + logger.critical('Unable to get znode! Exiting.') + sys.exit(1) + + def watcher(self, zh, event, state, path): + """Handle zookeeper.aget() watches. + + This code is called when a znode changes and triggers a data watch. + It is not called to handle the zookeeper.aget call itself. + + Numeric arguments map to constants. See ``DATA`` in ``help(zookeeper)`` + for more information. + + Args: + zh Zookeeper handle that set this watch. + event Event that caused the watch (often called ``type`` elsewhere). + state Connection state. + path Znode that triggered this watch. + + Does not provide a return value. + """ + out = ['Running watcher:', + 'zh=%d' % zh, + 'event=%d' % event, + 'state=%d' % state, + 'path=%s' % path] + logger.debug(' '.join(out)) + if event == zookeeper.CHANGED_EVENT and \ + state == zookeeper.CONNECTED_STATE and \ + self.znode == path: + if zookeeper.OK != self.aget(): + logger.critical('Unable to get znode! Exiting.') + sys.exit(1) + + def run(self): + while True: + time.sleep(86400) + + +def main(argv=None): + # Allow Ctrl-C + signal.signal(signal.SIGINT, signal.SIG_DFL) + + parser = OptionParser() + parser.add_option('-v', '--verbose', + dest='verbose', + default=False, + action='store_true', + help='Verbose logging. (default: %default)') + parser.add_option('-s', '--servers', + dest='servers', + default='localhost:2181', + help='Comma-separated list of host:port pairs. (default: %default)') + + (options, args) = parser.parse_args() + + if options.verbose: + logger.setLevel(logging.DEBUG) + else: + logger.setLevel(logging.INFO) + + formatter = logging.Formatter("%(asctime)s %(filename)s:%(lineno)d - %(message)s") + stream_handler = logging.StreamHandler() + stream_handler.setFormatter(formatter) + logger.addHandler(stream_handler) + + logger.info('Starting Zookeeper python example: %s' % ' '.join(sys.argv)) + + mc = MyClass(options, args) + mc.start() + mc.join() + + +if __name__ == '__main__': + main()