[ZODB-Dev] Commit or lock object accross transactions

Roché Compaan roche at upfrontsystems.co.za
Thu Aug 7 09:13:28 EDT 2003


* Christian Reis <kiko at async.com.br> [2003-08-06 04:24]:
> On Tue, Aug 05, 2003 at 08:52:04PM +0200, Roché Compaan wrote:
> > * Chris Withers <chrisw at nipltd.com> [2003-07-31 19:00]:
> > > Roché Compaan wrote:
> > > <snip>
> > > >FWIW, this works great. I can now request a counter for a string key
> > > >from my storage and be confident that there will be no duplicates.
> > > >
> > > >I am very glad there is an easy way to do this :-)
> > > 
> > > Does that mean you've implemented the code?
> > 
> > Yes. All I did was to add a method 'unique_id' to BaseStorage that takes
> > any string prefix as paremeter and increments a counter in a mapping
> > keyed on the prefix. In addition I had to make on-liner modifications to
> > ZODB.Connection and ZEO.StorageServer. I also added 'unique_ids' to
> > ZEO.ClientStorage that requests a block of ids from the master.
> > 
> > Is this what you had in mind too, Christian?
> 
> Well, that's the general idea I had. Method names such as
> generate_serial() or generate_id() for the storage and
> get_serial_block() or get_id_block() for ClientStorage might be more
> appropriate, but that's details.

I like generate_id.

> I'm curious about how you handled the zRPC bits.

Looks exactly like the new_oid calls.

> Could you produce a diff -u so we can take a look at the code? A
> testcase would be doubly appreciated, so if you can attach a simple one,
> it would be even better.


Here u go:

Index: ZEO/ClientStorage.py
===================================================================
RCS file: /cvs-repository/ZODB3/ZEO/ClientStorage.py,v
retrieving revision 1.108
diff -u -r1.108 ClientStorage.py
--- ZEO/ClientStorage.py	6 Aug 2003 15:51:23 -0000	1.108
+++ ZEO/ClientStorage.py	7 Aug 2003 06:06:44 -0000
@@ -776,6 +776,28 @@
         finally:
             self._oid_lock.release()
 
+    def get_id_block(self, key):
+        if not hasattr(self, '_id_blocks'):
+            self._id_blocks = {}
+        if not self._id_blocks.has_key(key):
+            self._id_blocks[key] = []
+        return self._id_blocks[key]
+
+    def generate_id(self, key=""):
+        """return the next id in a sequence for a given key."""
+        if self._is_read_only:
+            raise POSException.ReadOnlyError()
+        # avoid multiple id requests to server at the same time
+        self._oid_lock.acquire()
+        try:
+            block = self.get_id_block(key)
+            if not block:
+                self._id_blocks[key] = self._server.generate_ids(key)
+                self._id_blocks[key].reverse()
+            return self._id_blocks[key].pop()
+        finally:
+            self._oid_lock.release()
+
     def pack(self, t=None, referencesf=None, wait=1, days=0):
         """Storage API: pack the storage.
 
Index: ZEO/StorageServer.py
===================================================================
RCS file: /cvs-repository/ZODB3/ZEO/StorageServer.py,v
retrieving revision 1.98
diff -u -r1.98 StorageServer.py
--- ZEO/StorageServer.py	13 Jun 2003 19:50:05 -0000	1.98
+++ ZEO/StorageServer.py	7 Aug 2003 06:06:45 -0000
@@ -327,6 +327,16 @@
             n = 1
         return [self.storage.new_oid() for i in range(n)]
 
+    def generate_ids(self, key="", n=100):
+        """ Return a sequence of n new ids for 'key', where n
+            defaults to 100
+        """
+        if self.read_only:
+            raise ReadOnlyError()
+        if n <= 0:
+            n = 1
+        return [self.storage.generate_id(key) for i in range(n)]
+
     def undo(self, transaction_id):
         if self.read_only:
             raise ReadOnlyError()
Index: ZODB/BaseStorage.py
===================================================================
RCS file: /cvs-repository/ZODB3/ZODB/BaseStorage.py,v
retrieving revision 1.34
diff -u -r1.34 BaseStorage.py
--- ZODB/BaseStorage.py	10 Jun 2003 15:46:31 -0000	1.34
+++ ZODB/BaseStorage.py	7 Aug 2003 06:06:45 -0000
@@ -47,6 +47,7 @@
             self._oid='\0\0\0\0\0\0\0\0'
         else:
             self._oid=base._oid
+        self._counters = {}
 
     def abortVersion(self, src, transaction):
         if transaction is not self._transaction:
@@ -100,6 +101,24 @@
             d=ord(last[-1])
             if d < 255: return last[:-1]+chr(d+1)+'\0'*(8-len(last))
             else:       return self.new_oid(last[:-1])
+
+    def getCounter(self, key):
+        if not hasattr(self, '_counters'):
+            self._counters = {}
+        if not self._counters.has_key(key):
+            self._counters[key] = 0
+        return self._counters[key]
+
+    def generate_id(self, key=""):
+        if self._is_read_only:
+            raise POSException.ReadOnlyError()
+        self._lock_acquire()
+        try:
+            count = self.getCounter(key) + 1
+            self._counters[key] = count
+            return count
+        finally:
+            self._lock_release()
 
     def registerDB(self, db, limit):
         pass # we don't care
Index: ZODB/Connection.py
===================================================================
RCS file: /cvs-repository/ZODB3/ZODB/Connection.py,v
retrieving revision 1.98
diff -u -r1.98 Connection.py
--- ZODB/Connection.py	13 Jun 2003 21:53:08 -0000	1.98
+++ ZODB/Connection.py	7 Aug 2003 06:06:45 -0000
@@ -233,6 +233,7 @@
         self._storage=s=odb._storage
         self._sortKey = odb._storage.sortKey
         self.new_oid=s.new_oid
+        self.generate_id=getattr(s, 'generate_id', None)
         if self._code_timestamp != global_code_timestamp:
             # New code is in place.  Start a new cache.
             self._resetCache()
@@ -290,7 +291,8 @@
                     LOG('ZODB',ERROR, 'Close callback failed for %s' % f,
                         error=sys.exc_info())
             self.__onCloseCallbacks = None
-        self._storage = self._tmp = self.new_oid = self._opened = None
+        self._storage = self._tmp = self.new_oid = self._opened = \
+            self.generate_id = None
         self._debug_info = ()
         # Return the connection to the pool.
         self._db._closeConnection(self)

-- 
Roché Compaan
Upfront Systems                 http://www.upfrontsystems.co.za



More information about the ZODB-Dev mailing list