You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by Apache Wiki <wi...@apache.org> on 2010/02/07 22:06:35 UTC
[Couchdb Wiki] Update of "Regenerating_views_on_update" by JamesArthur
Dear Wiki user,
You have subscribed to a wiki page or wiki category on "Couchdb Wiki" for change notification.
The "Regenerating_views_on_update" page has been changed by JamesArthur.
The comment on this change is: Adding an equivalent example in Python.
http://wiki.apache.org/couchdb/Regenerating_views_on_update?action=diff&rev1=5&rev2=6
--------------------------------------------------
The view_updater.rb itself has to be made executable by CouchDB (chmod 0700?).
+ == Example using Python ==
+
+ {{{
+
+ #!/usr/bin/env python
+ # -*- coding: utf-8 -*-
+
+ """Updater script to regenerate couchdb views on update.
+ """
+
+ import logging
+ logging.basicConfig(level=logging.INFO)
+
+ import fcntl
+ import os
+ import re
+ import sys
+ import time
+ import urllib2
+
+ from threading import Thread
+
+ is_running = True
+ changed_docs = {}
+
+ class ViewUpdater(object):
+ """Updates the views.
+ """
+
+ # The smallest amount of changed documents before the views are updated
+ MIN_NUM_OF_CHANGED_DOCS = 50
+
+ # Set the minimum pause between calls to the database
+ PAUSE = 5 # seconds
+
+ # URL to the DB on the CouchDB server
+ URL = "http://localhost:5984"
+
+ # One entry for each design document
+ # in each database
+ VIEWS = {
+ 'my_db': {
+ 'design_doc': [
+ 'view_name',
+ # ...
+ ]
+ }
+ }
+
+ def start(self):
+ Thread(target=self._run).start()
+
+
+ def _run(self):
+ """Loop, checking for enough ``changed_docs`` to trigger a
+ request to CouchDB to re-index.
+ """
+
+ global is_running
+ while is_running:
+ try:
+ for db_name, number_of_docs in changed_docs.items():
+ if number_of_docs >= self.MIN_NUM_OF_CHANGED_DOCS:
+ # Reset the value
+ del changed_docs[db_name]
+ # If there are views in the database, get them
+ if db_name in self.VIEWS:
+ logging.info('regenerating %s' % db_name)
+ db_views = self.VIEWS[db_name]
+ for design, views in db_views.iteritems():
+ for view in views:
+ url = '%s/%s/_design/%s/_view/%s?limit=0' % (
+ self.URL, db_name, design, view
+ )
+ urllib2.urlopen(url)
+ time.sleep(self.PAUSE)
+ except Exception:
+ is_running = False
+ raise
+
+
+
+
+
+
+
+ class NotificationConsumer(object):
+ """Receives the update notification from CouchDB.
+ """
+
+ DB_NAME_EXPRESSION = re.compile(r'\"db\":\"(\w+)\"')
+
+ def __init__(self):
+ """Make stdin a non-blocking file
+ """
+
+ fd = sys.stdin.fileno()
+ fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+ fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+
+
+
+ def run(self):
+ """Consume update notifications from stdin.
+ """
+
+ global is_running
+ while is_running:
+ try:
+ data = sys.stdin.readline()
+ except:
+ continue
+ else:
+ if not data: # exit
+ is_running = False
+ break
+ result = self.DB_NAME_EXPRESSION.search(data)
+ if result:
+ db_name = result.groups()[0]
+ # Set to 0 if it hasn't been initialized before
+ if db_name not in changed_docs:
+ changed_docs[db_name] = 0
+ # Add one pending changed document to the list
+ # of documents in the DB
+ changed_docs[db_name] += 1
+
+
+
+
+
+
+
+
+ def main():
+ logging.info('update_notification handler (re)starting')
+ consumer = NotificationConsumer()
+ updater = ViewUpdater()
+ updater.start()
+ try:
+ consumer.run()
+ except KeyboardInterrupt, err:
+ is_running = False
+
+
+
+ if __name__ == '__main__':
+ main()
+
+ }}}
+