You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by mi...@apache.org on 2011/06/23 02:32:00 UTC
svn commit: r1138701 - in
/db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access:
btree/BTreeController.java heap/HeapCompressScan.java
heap/HeapPostCommit.java
Author: mikem
Date: Thu Jun 23 00:32:00 2011
New Revision: 1138701
URL: http://svn.apache.org/viewvc?rev=1138701&view=rev
Log:
DERBY-5284 A derby crash at exactly right time during a btree split can cause a
corrupt db which can not be booted.
backport fix from trunk to 10.7 branch. Was a clean merge.
Fixed a problem during BTREE split. The first phase of btree split sees
if it can reclaim space from committed deleted rows. If it finds any
it purges these rows in a nested internal transaction. It needs to hold
the latch on the page until end of transaction, but did not. This allowed
a very small window of a few instructions where another insert could use
the space on the page and then a system crash could cause the purges to undo
but fail due to the insert.
The fix was to hold the latch and let commit release it.
Modified:
db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapCompressScan.java
db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapPostCommit.java
Modified: db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java?rev=1138701&r1=1138700&r2=1138701&view=diff
==============================================================================
--- db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java (original)
+++ db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java Thu Jun 23 00:32:00 2011
@@ -109,7 +109,11 @@ public class BTreeController extends Ope
* it would be a waste to merge the page only to split it again to allow
* the insert of the row causing the split.
*
- * @return true if at least one row was purged.
+ * @return true if at least one row was purged. If true, then the routine
+ * will leave the page latched, and the caller will release
+ * the latch by committing or aborting the transaction. The
+ * latch must be held to end transaction to insure space on
+ * the page remains available for a undo of the purge.
*
* @param open_btree The already open btree to use to get latch on page.
* @param pageno The page number of the leaf to attempt the reclaim on.
@@ -187,14 +191,23 @@ public class BTreeController extends Ope
}
finally
{
- if (controlRow != null) {
- if (purged_at_least_one_row) {
+ if (controlRow != null)
+ {
+ if (purged_at_least_one_row)
+ {
// Set a hint in the page that scans positioned on it
// need to reposition because rows have disappeared from
- // the page.
+ // the page. If at least one row has been purged, then
+ // do not release the latch. Purge requires latch to
+ // be held until commit, where it will be released after
+ // the commit log record has been logged.
controlRow.page.setRepositionNeeded();
}
- controlRow.release();
+ else
+ {
+ // Ok to release latch if no purging has happened.
+ controlRow.release();
+ }
}
}
@@ -308,6 +321,12 @@ public class BTreeController extends Ope
// don't split if we reclaim any rows.
do_split = !reclaim_deleted_rows(split_open_btree, leaf_pageno);
+ // on return if !do_split then the latch on leaf_pageno is held
+ // and will be released by the committing or aborting the
+ // transaction. If a purge has been done, no other action on
+ // the page should be attempted (ie. a split) before committing
+ // the purges.
+
split_open_btree.close();
}
}
@@ -315,6 +334,9 @@ public class BTreeController extends Ope
long new_leaf_pageno = leaf_pageno;
if (do_split)
{
+ // no space was reclaimed from deleted rows, so do split to allow
+ // space for a subsequent insert.
+
split_open_btree = new OpenBTree();
split_open_btree.init(
this.init_open_user_scans,
Modified: db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapCompressScan.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapCompressScan.java?rev=1138701&r1=1138700&r2=1138701&view=diff
==============================================================================
--- db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapCompressScan.java (original)
+++ db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapCompressScan.java Thu Jun 23 00:32:00 2011
@@ -208,7 +208,11 @@ class HeapCompressScan
// At this point assume table level lock, and that this
// transcation did not delete the row, so any
// deleted row must be a committed deleted row which can
- // be purged.
+ // be purged. Usually latches on purged pages must
+ // be held until end transaction to prevent other
+ // transactions from using space necessary for a possible
+ // undo of the purge, but in this case a table level
+ // lock is held and will insure correct undo behavior.
scan_position.current_page.purgeAtSlot(
scan_position.current_slot, 1, false);
Modified: db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapPostCommit.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapPostCommit.java?rev=1138701&r1=1138700&r2=1138701&view=diff
==============================================================================
--- db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapPostCommit.java (original)
+++ db/derby/code/branches/10.7/java/engine/org/apache/derby/impl/store/access/heap/HeapPostCommit.java Thu Jun 23 00:32:00 2011
@@ -222,7 +222,10 @@ class HeapPostCommit implements Servicea
{
// If no purge happened on the page and the page is not
// removed, feel free to unlatch it. Otherwise, let
- // transaction commit take care of it.
+ // transaction commit take care of it. The latch must be
+ // held until end transaction in order to insure no other
+ // transaction uses the space freed by the purge, which
+ // would cause a subquent undo of the purge to fail.
if (!purgingDone)
{
page.unlatch();