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()
+ 
+ }}}
+