You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by go...@apache.org on 2012/08/28 03:50:18 UTC
svn commit: r1377938 -
/directory/jdbm/branches/txn/jdbm2/src/main/java/jdbm/recman/RecordFile.java
Author: gokturk
Date: Tue Aug 28 01:50:18 2012
New Revision: 1377938
URL: http://svn.apache.org/viewvc?rev=1377938&view=rev
Log:
Fixed JDBM's crash recovery bug on DEBUG sessions. Now every RecordFile is recovered before being served.
Modified:
directory/jdbm/branches/txn/jdbm2/src/main/java/jdbm/recman/RecordFile.java
Modified: directory/jdbm/branches/txn/jdbm2/src/main/java/jdbm/recman/RecordFile.java
URL: http://svn.apache.org/viewvc/directory/jdbm/branches/txn/jdbm2/src/main/java/jdbm/recman/RecordFile.java?rev=1377938&r1=1377937&r2=1377938&view=diff
==============================================================================
--- directory/jdbm/branches/txn/jdbm2/src/main/java/jdbm/recman/RecordFile.java (original)
+++ directory/jdbm/branches/txn/jdbm2/src/main/java/jdbm/recman/RecordFile.java Tue Aug 28 01:50:18 2012
@@ -72,15 +72,15 @@ public final class RecordFile
// free is a cache, thus a FIFO. The rest are hashes.
/** The list of free pages */
private final LinkedList<BlockIo> free = new LinkedList<BlockIo>();
-
+
/** The map of pages being currently used */
- private final HashMap<Long,BlockIo> inUse = new HashMap<Long,BlockIo>();
-
+ private final HashMap<Long, BlockIo> inUse = new HashMap<Long, BlockIo>();
+
/** The map of dirty pages (page being modified) */
- private final HashMap<Long,BlockIo> dirty = new HashMap<Long,BlockIo>();
-
+ private final HashMap<Long, BlockIo> dirty = new HashMap<Long, BlockIo>();
+
/** The map of page in a transaction */
- private final HashMap<Long,BlockIo> inTxn = new HashMap<Long,BlockIo>();
+ private final HashMap<Long, BlockIo> inTxn = new HashMap<Long, BlockIo>();
/** A flag set if transactions is disabled. Default to false */
private boolean transactionsDisabled = false;
@@ -96,11 +96,11 @@ public final class RecordFile
/** The underlying file */
private RandomAccessFile file;
-
+
/** The file name */
private final String fileName;
-
+
/**
* Creates a new object on the indicated filename. The file is
* opened in read/write mode.
@@ -114,6 +114,11 @@ public final class RecordFile
{
this.fileName = fileName;
file = new RandomAccessFile( fileName + EXTENSION, "rw" );
+
+ // will cause initialization of Jdbm's TxnManager,
+ // which will do its recovery first.
+ // So that this RecordFile instance can recover itself.
+ getTxnMgr();
}
@@ -127,12 +132,12 @@ public final class RecordFile
{
throw new IllegalStateException( "Transactions are disabled." );
}
-
+
if ( transactionManager == null )
{
transactionManager = new TransactionManager( this );
}
-
+
return transactionManager;
}
@@ -145,7 +150,7 @@ public final class RecordFile
return fileName;
}
-
+
/**
* Disables transactions: doesn't sync and doesn't use the
* transaction manager.
@@ -155,7 +160,7 @@ public final class RecordFile
transactionsDisabled = true;
}
-
+
/**
* Gets a block from the file. The returned byte array is the in-memory
* copy of the record, and thus can be written (and subsequently released
@@ -163,64 +168,64 @@ public final class RecordFile
*
* @param blockId The record number to retrieve.
*/
- BlockIo get( long blockId ) throws IOException
- {
- // try in transaction list, dirty list, free list
- BlockIo blockIo = inTxn.get( blockId );
-
- if ( blockIo != null )
- {
- inTxn.remove( blockId );
- inUse.put( blockId, blockIo );
-
- return blockIo;
- }
-
- blockIo = dirty.get( blockId );
-
- if ( blockIo != null )
- {
- dirty.remove( blockId );
- inUse.put( blockId, blockIo );
-
- return blockIo;
- }
-
- for ( Iterator<BlockIo> iterator = free.iterator(); iterator.hasNext(); )
- {
- BlockIo cur = iterator.next();
-
- if ( cur.getBlockId() == blockId )
- {
- blockIo = cur;
- iterator.remove();
- inUse.put( blockId, blockIo );
-
- return blockIo;
- }
- }
-
- // sanity check: can't be on in use list
- if ( inUse.get( blockId ) != null )
- {
- throw new Error( I18n.err( I18n.ERR_554, blockId ) );
- }
-
- // get a new node and read it from the file
- blockIo = getNewBlockIo( blockId );
- long offset = blockId * BLOCK_SIZE;
- long fileLength = file.length();
-
- if ( ( fileLength > 0 ) && ( offset <= fileLength ) )
- {
- read( file, offset, blockIo.getData(), BLOCK_SIZE );
- }
-
- inUse.put( blockId, blockIo );
- blockIo.setClean();
-
- return blockIo;
- }
+ BlockIo get( long blockId ) throws IOException
+ {
+ // try in transaction list, dirty list, free list
+ BlockIo blockIo = inTxn.get( blockId );
+
+ if ( blockIo != null )
+ {
+ inTxn.remove( blockId );
+ inUse.put( blockId, blockIo );
+
+ return blockIo;
+ }
+
+ blockIo = dirty.get( blockId );
+
+ if ( blockIo != null )
+ {
+ dirty.remove( blockId );
+ inUse.put( blockId, blockIo );
+
+ return blockIo;
+ }
+
+ for ( Iterator<BlockIo> iterator = free.iterator(); iterator.hasNext(); )
+ {
+ BlockIo cur = iterator.next();
+
+ if ( cur.getBlockId() == blockId )
+ {
+ blockIo = cur;
+ iterator.remove();
+ inUse.put( blockId, blockIo );
+
+ return blockIo;
+ }
+ }
+
+ // sanity check: can't be on in use list
+ if ( inUse.get( blockId ) != null )
+ {
+ throw new Error( I18n.err( I18n.ERR_554, blockId ) );
+ }
+
+ // get a new node and read it from the file
+ blockIo = getNewBlockIo( blockId );
+ long offset = blockId * BLOCK_SIZE;
+ long fileLength = file.length();
+
+ if ( ( fileLength > 0 ) && ( offset <= fileLength ) )
+ {
+ read( file, offset, blockIo.getData(), BLOCK_SIZE );
+ }
+
+ inUse.put( blockId, blockIo );
+ blockIo.setClean();
+
+ return blockIo;
+ }
/**
@@ -232,21 +237,21 @@ public final class RecordFile
void release( long blockId, boolean isDirty ) throws IOException
{
BlockIo blockIo = inUse.get( blockId );
-
+
if ( blockIo == null )
{
throw new IOException( I18n.err( I18n.ERR_555, blockId ) );
}
-
- if ( ! blockIo.isDirty() && isDirty )
+
+ if ( !blockIo.isDirty() && isDirty )
{
blockIo.setDirty();
}
-
+
release( blockIo );
}
-
+
/**
* Releases a block.
*
@@ -255,7 +260,7 @@ public final class RecordFile
void release( BlockIo block )
{
inUse.remove( block.getBlockId() );
-
+
if ( block.isDirty() )
{
// System.out.println( "Dirty: " + key + block );
@@ -263,7 +268,7 @@ public final class RecordFile
}
else
{
- if ( ! transactionsDisabled && block.isInTransaction() )
+ if ( !transactionsDisabled && block.isInTransaction() )
{
inTxn.put( block.getBlockId(), block );
}
@@ -273,7 +278,7 @@ public final class RecordFile
}
}
}
-
+
/**
* Discards a block (will not write the block even if it's dirty)
@@ -288,14 +293,14 @@ public final class RecordFile
// it's considered invalid
}
-
+
/**
* Commits the current transaction by flushing all dirty buffers to disk.
*/
void commit() throws IOException
{
// debugging...
- if ( ! inUse.isEmpty() && inUse.size() > 1 )
+ if ( !inUse.isEmpty() && inUse.size() > 1 )
{
showList( inUse.values().iterator() );
throw new Error( I18n.err( I18n.ERR_556, inUse.size() ) );
@@ -309,13 +314,11 @@ public final class RecordFile
return;
}
-
- if ( ! transactionsDisabled )
+ if ( !transactionsDisabled )
{
getTxnMgr().start();
}
-
for ( BlockIo blockIo : dirty.values() )
{
// System.out.println("node " + node + " map size now " + dirty.size());
@@ -331,74 +334,74 @@ public final class RecordFile
inTxn.put( blockIo.getBlockId(), blockIo );
}
}
-
+
dirty.clear();
- if ( ! transactionsDisabled )
+ if ( !transactionsDisabled )
{
getTxnMgr().commit();
}
}
-
+
/**
* Rollback the current transaction by discarding all dirty buffers
*/
void rollback() throws IOException
{
// debugging...
- if ( ! inUse.isEmpty() )
+ if ( !inUse.isEmpty() )
{
showList( inUse.values().iterator() );
throw new Error( I18n.err( I18n.ERR_557, inUse.size() ) );
}
-
+
// System.out.println("rollback...");
dirty.clear();
- if ( ! transactionsDisabled )
+ if ( !transactionsDisabled )
{
getTxnMgr().synchronizeLogFromDisk();
}
- if ( ! inTxn.isEmpty() )
+ if ( !inTxn.isEmpty() )
{
showList( inTxn.values().iterator() );
throw new Error( I18n.err( I18n.ERR_558, inTxn.size() ) );
}
}
-
+
/**
* Commits and closes file.
*/
void close() throws IOException
{
- if ( ! dirty.isEmpty() )
+ if ( !dirty.isEmpty() )
{
commit();
}
-
- if( ! transactionsDisabled )
+
+ if ( !transactionsDisabled )
{
getTxnMgr().shutdown();
}
- if ( ! inTxn.isEmpty() )
+ if ( !inTxn.isEmpty() )
{
showList( inTxn.values().iterator() );
throw new Error( I18n.err( I18n.ERR_559 ) );
}
// these actually ain't that bad in a production release
- if ( ! dirty.isEmpty() )
+ if ( !dirty.isEmpty() )
{
System.out.println( "ERROR: dirty blocks at close time" );
showList( dirty.values().iterator() );
throw new Error( I18n.err( I18n.ERR_560 ) );
}
-
- if ( ! inUse.isEmpty() )
+
+ if ( !inUse.isEmpty() )
{
System.out.println( "ERROR: inUse blocks at close time" );
showList( inUse.values().iterator() );
@@ -418,14 +421,14 @@ public final class RecordFile
*/
void forceClose() throws IOException
{
- if ( ! transactionsDisabled )
+ if ( !transactionsDisabled )
{
getTxnMgr().forceClose();
}
file.close();
}
-
+
/**
* Prints contents of a list
*/
@@ -448,22 +451,22 @@ public final class RecordFile
{
BlockIo blockIo = null;
- if ( ! free.isEmpty() )
+ if ( !free.isEmpty() )
{
blockIo = free.removeFirst();
blockIo.setBlockId( blockId );
}
-
+
if ( blockIo == null )
{
blockIo = new BlockIo( blockId, new byte[BLOCK_SIZE] );
}
-
+
blockIo.setView( null );
-
+
return blockIo;
}
-
+
/**
* Synchronizes a BlockIo to disk. This is called by the transaction manager's
@@ -475,7 +478,7 @@ public final class RecordFile
void sync( BlockIo blockIo ) throws IOException
{
byte[] data = blockIo.getData();
-
+
if ( data != null )
{
// Write the data to disk now.
@@ -485,7 +488,7 @@ public final class RecordFile
}
}
-
+
/**
* Releases a node from the transaction list, if it was sitting there.
*
@@ -498,7 +501,7 @@ public final class RecordFile
free.add( node );
}
}
-
+
/**
* Synchronizes the file.
@@ -529,20 +532,20 @@ public final class RecordFile
pos += read;
}
}
-
-
+
+
/**
* {@inheritDoc}
*/
public String toString()
{
StringBuilder sb = new StringBuilder();
-
+
sb.append( "RecordFile<" ).append( fileName ).append( ", " );
-
+
// The file size
sb.append( "size : " );
-
+
try
{
sb.append( file.length() ).append( "bytes" );
@@ -551,7 +554,7 @@ public final class RecordFile
{
sb.append( "unknown" );
}
-
+
// Transactions
if ( transactionsDisabled )
{
@@ -561,44 +564,43 @@ public final class RecordFile
{
sb.append( "(Tx)" );
}
-
+
// Dump the free blocks
sb.append( "\n Free blockIo : " ).append( free.size() );
-
+
for ( BlockIo blockIo : free )
{
sb.append( "\n " );
sb.append( blockIo );
}
-
+
// Dump the inUse blocks
sb.append( "\n InUse blockIo : " ).append( inUse.size() );
-
+
for ( BlockIo blockIo : inUse.values() )
{
sb.append( "\n " );
sb.append( blockIo );
}
-
+
// Dump the dirty blocks
sb.append( "\n Dirty blockIo : " ).append( dirty.size() );
-
+
for ( BlockIo blockIo : dirty.values() )
{
sb.append( "\n " );
sb.append( blockIo );
}
-
+
// Dump the inTxn blocks
sb.append( "\n InTxn blockIo : " ).append( inTxn.size() );
-
+
for ( BlockIo blockIo : inTxn.values() )
{
sb.append( "\n " );
sb.append( blockIo );
}
-
return sb.toString();
}
}