[ZODB-Dev] Relstorage pack problems

Shane Hathaway shane at hathawaymix.org
Fri Jan 23 14:45:12 EST 2009


Shane Hathaway wrote:
> Assuming your bad script caused your problem, it is likely that packing 
> will still mess up your database, since you still probably have mixed-up 
> object_state rows.  Don't pack until I've had a chance to look again.

Here is some more analysis.  Now that I understand you accidentally 
merged two databases into one by forcing copyTransactionsFrom() to run 
when it shouldn't, I looked for the transactions you merged.  First I 
looked for the OIDs with a confused transaction ID.


=> select zoid from current_object where tid != (select max(tid) from 
object_state where object_state.zoid = current_object.zoid);
  zoid
------
     7
    10
    12
    11
     9
     8
(6 rows)


Then I listed all non-current transaction IDs for those objects.


=>  select zoid, tid from object_state where zoid in (7,8,9,10,11,12) 
and tid != (select tid from current_object where current_object.zoid = 
object_state.zoid);
  zoid |        tid
------+--------------------
     8 | 250499913748614178
     9 | 250499913748614178
    10 | 250499913748614178
    11 | 250499913748614178
    12 | 250499913748614178
     7 | 250499913748614178
(6 rows)


Based on this information and the information in my last email, I can 
deduce that you fortunately merged only two transactions from another 
database and that while the merge caused conflicts, these objects 
haven't been otherwise modified.  Note that the bad database merge could 
have happened at any time, not necessarily November 17 when these 
transactions were created.  Anyone with access to your database and your 
broken script could cause this problem again.  Fix the script quickly.

Here are the two bad transactions:

250499913441768123 | initial database creation
250499913748614178 | /manage_main\012\012Created Zope Application

You need to delete all traces of these two transactions from your 
database.  Before you do, please ensure nothing is actually using them. 
  The query below should not return any rows.


select * from current_object where tid in (250499913441768123, 
250499913748614178);


Assuming that query returns no rows, here is how you can remove the bad 
transactions:


update object_state set prev_tid = 0 where prev_tid in 
(250499913441768123, 250499913748614178);
delete from object_state where tid in (250499913441768123, 
250499913748614178);
delete from object_ref where tid in (250499913441768123, 
250499913748614178);
delete from object_refs_added where tid in (250499913441768123, 
250499913748614178);
delete from transaction where tid in (250499913441768123, 
250499913748614178);
commit;


Once you've done that, you should see no more anomalies in current_object:


=>  select zoid from current_object where tid != (select max(tid) from 
object_state where object_state.zoid = current_object.zoid);
  zoid
------
(0 rows)


I used several shortcuts for this solution, particularly the statement 
that sets prev_tid to 0.  If you had merged a more complex database, I 
wouldn't have been able to use shortcuts.

I'm glad to know RelStorage didn't do anything wrong after all.  Perhaps 
the copyTransactionsFrom() method could work harder to prevent a mishap 
like this, but that method is part of the ZODB API, not RelStorage, so I 
don't have as much control over it.

However, I still don't want you to pack yet because my experiments with 
packing your database has revealed some unexpected behavior.  I'm going 
to look into it.

Shane



More information about the ZODB-Dev mailing list