On Tuesday 27 January 2004 09:39, Mario Lorenz wrote:

> Given that this property is not that widely published (in the various
> tutorials etc.), I wonder if it might be a good idea to improve that loop
> check code, and walk through the ring not more than once, using a counter,
> and not the comparison vs. the ring start, which, as we have seen, may be a
> target that moves too quickly.

You got me curious....

The attached patch to 2.6 uses an extra temporary ring node to mark where 
scanning should stop. Normally this will be right next to the home node, and 
behaviour is unchanged. Any of these troublesome objects that move themselves 
to the top of the LRU list *during* the scan will end up *after* the scan 
terminator node, and therefore do not get rescanned.

This works for me on 2.6, which is the only branch Im set up to use at the 
moment.

-- 
Toby Dickenson
? diff
? diff2
Index: cPickleCache.c
===================================================================
RCS file: /cvs-repository/Zope/lib/python/ZODB/Attic/cPickleCache.c,v
retrieving revision 1.68.10.3
diff -c -4 -r1.68.10.3 cPickleCache.c
*** cPickleCache.c	30 Apr 2003 17:03:34 -0000	1.68.10.3
--- cPickleCache.c	27 Jan 2004 23:02:06 -0000
***************
*** 216,224 ****
  #endif
  
  
  static int
! scan_gc_items(ccobject *self,int target)
  {
      /* This function must only be called with the ring lock held,
         because it places a non-object placeholder in the ring.
      */
--- 216,224 ----
  #endif
  
  
  static int
! scan_gc_items(ccobject *self,int target,CPersistentRing *terminal)
  {
      /* This function must only be called with the ring lock held,
         because it places a non-object placeholder in the ring.
      */
***************
*** 265,281 ****
              return -1;
          }
  #endif
  
! 	/* back to the home position. stop looking */
!         if (here == &self->ring_home)
!             return 0;
  
          /* At this point we know that the ring only contains nodes
! 	   from persistent objects, plus our own home node. We know
! 	   this because the ring lock is held.  We can safely assume
! 	   the current ring node is a persistent object now we know it
! 	   is not the home */
          object = OBJECT_FROM_RING(self, here, "scan_gc_items");
          if (!object) 
  	    return -1;
  
--- 265,288 ----
              return -1;
          }
  #endif
  
!         /* reached the end position. stop looking */
!         if (here == terminal)
!               return 0;
! 
!         /* back to the home position. should not happen */
!         if (here == &self->ring_home) {
!             PyErr_SetString(PyExc_RuntimeError,
!                   "reached home before terminal, in scan_gc_items");
!             return -1;
!         }
  
          /* At this point we know that the ring only contains nodes
! 	   from persistent objects, plus our own home node, plus the
!            terminal node. We know this because the ring lock is held.
!            We can safely assume the current ring node is a persistent
!            object now. */
          object = OBJECT_FROM_RING(self, here, "scan_gc_items");
          if (!object) 
  	    return -1;
  
***************
*** 325,332 ****
--- 332,343 ----
  
  static PyObject *
  lockgc(ccobject *self, int target_size)
  {
+     int error;
+     CPersistentRing terminal;
+ 
+ 
      /* This is thread-safe because of the GIL, and there's nothing
       * in between checking the ring_lock and acquiring it that calls back
       * into Python.
       */
***************
*** 338,350 ****
      if (IS_RING_CORRUPT(self, "pre-gc")) 
  	return NULL;
      ENGINE_NOISE("<");
      self->ring_lock = 1;
!     if (scan_gc_items(self, target_size)) {
!         self->ring_lock = 0;
!         return NULL;
!     }
      self->ring_lock = 0;
      ENGINE_NOISE(">\n");
      if (IS_RING_CORRUPT(self, "post-gc")) 
  	return NULL;
  
--- 349,376 ----
      if (IS_RING_CORRUPT(self, "pre-gc")) 
  	return NULL;
      ENGINE_NOISE("<");
      self->ring_lock = 1;
! 
!     /* insert a placeholder just before the head node. This will be used to
!      * terminate the scan_gc_items loop. Items touched during the
!      * deactivation run will get inserted between the head and this terminal
!      * node, and will not get re-scanned. */
!     terminal.next = &self->ring_home;
!     terminal.prev = self->ring_home.prev;
!     self->ring_home.prev->next = &terminal;
!     self->ring_home.prev = &terminal;
! 
!     error = scan_gc_items(self, target_size, &terminal);
! 
!     /* unlink the placeholder from the ring */
!     terminal.next->prev = terminal.prev;
!     terminal.prev->next = terminal.next;
! 
      self->ring_lock = 0;
+     if (error)
+         return NULL;
+ 
      ENGINE_NOISE(">\n");
      if (IS_RING_CORRUPT(self, "post-gc")) 
  	return NULL;
  
_______________________________________________
Zope-Dev maillist  -  [EMAIL PROTECTED]
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 http://mail.zope.org/mailman/listinfo/zope-announce
 http://mail.zope.org/mailman/listinfo/zope )

Reply via email to