You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2013/12/28 20:47:40 UTC
svn commit: r1553900 -
/directory/mavibot/trunk/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
Author: elecharny
Date: Sat Dec 28 19:47:39 2013
New Revision: 1553900
URL: http://svn.apache.org/r1553900
Log:
o Added the BtreeOfBtree tree
o Removed useless constants
o Created a helper method for file creation
o The RMHeader now contains two more pointers to the BOB trees
o Removed all the references to the LastFreePage : t's never used
Modified:
directory/mavibot/trunk/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
Modified: directory/mavibot/trunk/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
URL: http://svn.apache.org/viewvc/directory/mavibot/trunk/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java?rev=1553900&r1=1553899&r2=1553900&view=diff
==============================================================================
--- directory/mavibot/trunk/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java (original)
+++ directory/mavibot/trunk/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java Sat Dec 28 19:47:39 2013
@@ -77,12 +77,11 @@ public class RecordManager
/** The first and last free page */
private long firstFreePage;
- private long lastFreePage;
/** The list of available free pages */
List<PageIO> freePages = new ArrayList<PageIO>();
- /** A counter to track the number of free pages */
+ /** Some counters to track the number of free pages */
public AtomicLong nbFreedPages = new AtomicLong( 0 );
public AtomicLong nbCreatedPages = new AtomicLong( 0 );
public AtomicLong nbReusedPages = new AtomicLong( 0 );
@@ -105,15 +104,9 @@ public class RecordManager
/** A constant for an offset on a non existing page */
private static final long NO_PAGE = -1L;
- /** The number of stored BTrees */
- private static final int NB_TREE_SIZE = 4;
-
/** The header page size */
private static final int PAGE_SIZE = 4;
- /** The size of the data size in a page */
- private static final int DATA_SIZE = 4;
-
/** The size of the link to next page */
private static final int LINK_SIZE = 8;
@@ -122,10 +115,6 @@ public class RecordManager
private static final int INT_SIZE = 4;
private static final int LONG_SIZE = 8;
- /** The size of the link to the first and last free page */
- private static final int FIRST_FREE_PAGE_SIZE = 8;
- private static final int LAST_FREE_PAGE_SIZE = 8;
-
/** The default page size */
private static final int DEFAULT_PAGE_SIZE = 512;
@@ -138,7 +127,7 @@ public class RecordManager
/** A static buffer used to store the header */
private static byte[] HEADER_BYTES;
- /** The length of an Offset, as a nagative value */
+ /** The length of an Offset, as a negative value */
private static byte[] LONG_LENGTH = new byte[]
{ ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xF8 };
@@ -173,6 +162,15 @@ public class RecordManager
/** A map of pending pages */
private Map<Page<?, ?>, BTree<?, ?>> pendingPages = new LinkedHashMap<Page<?, ?>, BTree<?, ?>>();
+ /** The Btree of Btrees */
+ private BTree<NameRevision, Long> btreeOfBtrees;
+
+ private static final String BOB_ONE_NAME = "_BTREE_OF_BTREES_";
+
+ /** The two latest revisions of the BOB */
+ private long bobCurrentRevision;
+ private long bobOldRevision;
+
/**
* Create a Record manager which will either create the underlying file
* or load an existing one. If a folder is provided, then we will create
@@ -204,50 +202,15 @@ public class RecordManager
// Open the file or create it
File tmpFile = new File( fileName );
- boolean isNewFile = false;
if ( tmpFile.isDirectory() )
{
// It's a directory. Check that we don't have an existing mavibot file
- File mavibotFile = new File( tmpFile, DEFAULT_FILE_NAME );
-
- if ( !mavibotFile.exists() )
- {
- // We have to create a new file
- try
- {
- mavibotFile.createNewFile();
- isNewFile = true;
- }
- catch ( IOException ioe )
- {
- LOG.error( "Cannot create the file {}", mavibotFile.getName() );
- return;
- }
- }
-
- file = mavibotFile;
+ tmpFile = new File( tmpFile, DEFAULT_FILE_NAME );
}
- else
- {
- // It's a file. Let's see if it exists, otherwise create it
- if ( !tmpFile.exists() || ( tmpFile.length() == 0 ) )
- {
- isNewFile = true;
- try
- {
- tmpFile.createNewFile();
- }
- catch ( IOException ioe )
- {
- LOG.error( "Cannot create the file {}", tmpFile.getName() );
- return;
- }
- }
-
- file = tmpFile;
- }
+ // We have to create a new file, if it does not already exist
+ boolean isNewFile = createFile( tmpFile );
try
{
@@ -277,21 +240,53 @@ public class RecordManager
/**
+ * Create the mavibot file if it does not exist
+ */
+ private boolean createFile( File mavibotFile )
+ {
+ try
+ {
+ boolean creation = mavibotFile.createNewFile();
+
+ file = mavibotFile;
+
+ if ( mavibotFile.length() == 0 )
+ {
+ return true;
+ }
+ else
+ {
+ return creation;
+ }
+ }
+ catch ( IOException ioe )
+ {
+ LOG.error( "Cannot create the file {}", mavibotFile.getName() );
+ return false;
+ }
+
+ }
+
+ /**
* We will create a brand new RecordManager file, containing nothing, but the header,
* a BTree to manage the old revisions we want to keep and
* a BTree used to manage pages associated with old versions.
* <br/>
* The Header contains the following details :
* <pre>
- * +-----------+
- * | PageSize | 4 bytes : The size of a physical page (default to 4096)
- * +-----------+
- * | NbTree | 4 bytes : The number of managed BTrees (at least 1)
- * +-----------+
- * | FirstFree | 8 bytes : The offset of the first free page
- * +-----------+
- * | LastFree | 8 bytes : The offset of the last free page
- * +-----------+
+ * +---------------+
+ * | PageSize | 4 bytes : The size of a physical page (default to 4096)
+ * +---------------+
+ * | NbTree | 4 bytes : The number of managed BTrees (at least 1)
+ * +---------------+
+ * | FirstFree | 8 bytes : The offset of the first free page
+ * +---------------+
+ * | currentBoB | 1 byte : The current BoB in use
+ * +---------------+
+ * | BoB offset[0] | 8 bytes : The offset of the first BoB
+ * +---------------+
+ * | BoB offset[1] | 8 bytes : The offset of the second BoB
+ * +---------------+
* </pre>
*
* We then store the BTree managing the pages that have been copied when we have added
@@ -304,12 +299,18 @@ public class RecordManager
// Create a new Header
nbBtree = 0;
firstFreePage = NO_PAGE;
- lastFreePage = NO_PAGE;
+ bobCurrentRevision = 0L;
+ bobOldRevision = 0L;
+
updateRecordManagerHeader();
// Set the offset of the end of the file
endOfFileOffset = fileChannel.size();
+ // First, create the btree of btrees <NameRevision, Long>
+ btreeOfBtrees = BTreeFactory.createPersistedBTree( BOB_ONE_NAME, new NameRevisionSerializer(),
+ new LongSerializer() );
+
// Now, initialize the Copied Page BTree
copiedPageBTree = BTreeFactory.createPersistedBTree( COPIED_PAGE_BTREE_NAME, new RevisionNameSerializer(),
new LongArraySerializer() );
@@ -352,6 +353,19 @@ public class RecordManager
header.rewind();
+ // read the RecordManager Header :
+ // +----------------+
+ // | PageSize | 4 bytes : The size of a physical page (default to 4096)
+ // +----------------+
+ // | NbTree | 4 bytes : The number of managed BTrees (at least 1)
+ // +----------------+
+ // | FirstFree | 8 bytes : The offset of the first free page
+ // +----------------+
+ // | BoB old offset | 8 bytes : The previous BoB revision
+ // +----------------+
+ // | BoB new offset | 8 bytes : The current BoB revision
+ // +----------------+
+
// The page size
pageSize = header.getInt();
@@ -360,7 +374,27 @@ public class RecordManager
// The first and last free page
firstFreePage = header.getLong();
- lastFreePage = header.getLong();
+
+ // The BOB revisions
+ long bobRevision1 = header.getLong();
+ long bobRevision2 = header.getLong();
+
+ if ( bobRevision1 < bobRevision2 )
+ {
+ bobOldRevision = bobRevision1;
+ bobCurrentRevision = bobRevision2;
+ }
+ else if ( bobRevision1 > bobRevision2 )
+ {
+ bobOldRevision = bobRevision2;
+ bobCurrentRevision = bobRevision1;
+ }
+ else
+ {
+ // Special case : the RecordManage has been shtudown correctly
+ bobOldRevision = bobRevision1;
+ bobCurrentRevision = bobRevision2;
+ }
// Now read each BTree. The first one is the one which
// manage the modified pages. Once read, we can discard all
@@ -406,7 +440,7 @@ public class RecordManager
managedBTrees.put( btree.getName(), btree );
}
- // We are done ! Let's finish with the last initilization parts
+ // We are done ! Let's finish with the last initialization parts
endOfFileOffset = fileChannel.size();
}
}
@@ -1430,7 +1464,22 @@ public class RecordManager
/**
- * Update the header, injecting the nbBtree, firstFreePage and lastFreePage
+ * Update the header, injecting the following data :
+ * <pre>
+ * +---------------+
+ * | PageSize | 4 bytes : The size of a physical page (default to 4096)
+ * +---------------+
+ * | NbTree | 4 bytes : The number of managed BTrees (at least 1)
+ * +---------------+
+ * | FirstFree | 8 bytes : The offset of the first free page
+ * +---------------+
+ * | currentBoB | 1 byte : The current BoB in use
+ * +---------------+
+ * | BoB offset[0] | 8 bytes : The offset of the first BoB
+ * +---------------+
+ * | BoB offset[1] | 8 bytes : The offset of the second BoB
+ * +---------------+
+ * </pre>
*/
public void updateRecordManagerHeader() throws IOException
{
@@ -1456,21 +1505,31 @@ public class RecordManager
HEADER_BYTES[14] = ( byte ) ( firstFreePage >>> 8 );
HEADER_BYTES[15] = ( byte ) ( firstFreePage );
- // The last free page
- HEADER_BYTES[16] = ( byte ) ( lastFreePage >>> 56 );
- HEADER_BYTES[17] = ( byte ) ( lastFreePage >>> 48 );
- HEADER_BYTES[18] = ( byte ) ( lastFreePage >>> 40 );
- HEADER_BYTES[19] = ( byte ) ( lastFreePage >>> 32 );
- HEADER_BYTES[20] = ( byte ) ( lastFreePage >>> 24 );
- HEADER_BYTES[21] = ( byte ) ( lastFreePage >>> 16 );
- HEADER_BYTES[22] = ( byte ) ( lastFreePage >>> 8 );
- HEADER_BYTES[23] = ( byte ) ( lastFreePage );
+ // The offset of the first BoB
+ HEADER_BYTES[17] = ( byte ) ( bobOldRevision >>> 56 );
+ HEADER_BYTES[18] = ( byte ) ( bobOldRevision >>> 48 );
+ HEADER_BYTES[19] = ( byte ) ( bobOldRevision >>> 40 );
+ HEADER_BYTES[20] = ( byte ) ( bobOldRevision >>> 32 );
+ HEADER_BYTES[21] = ( byte ) ( bobOldRevision >>> 24 );
+ HEADER_BYTES[22] = ( byte ) ( bobOldRevision >>> 16 );
+ HEADER_BYTES[23] = ( byte ) ( bobOldRevision >>> 8 );
+ HEADER_BYTES[24] = ( byte ) ( bobOldRevision );
+
+ // The offset of the second BoB
+ HEADER_BYTES[17] = ( byte ) ( bobCurrentRevision >>> 56 );
+ HEADER_BYTES[18] = ( byte ) ( bobCurrentRevision >>> 48 );
+ HEADER_BYTES[19] = ( byte ) ( bobCurrentRevision >>> 40 );
+ HEADER_BYTES[20] = ( byte ) ( bobCurrentRevision >>> 32 );
+ HEADER_BYTES[21] = ( byte ) ( bobCurrentRevision >>> 24 );
+ HEADER_BYTES[22] = ( byte ) ( bobCurrentRevision >>> 16 );
+ HEADER_BYTES[23] = ( byte ) ( bobCurrentRevision >>> 8 );
+ HEADER_BYTES[24] = ( byte ) ( bobCurrentRevision );
// Write the header on disk
HEADER_BUFFER.put( HEADER_BYTES );
HEADER_BUFFER.flip();
- LOG.debug( "Update RM header, FF : {}, LF : {}", firstFreePage, lastFreePage );
+ LOG.debug( "Update RM header, FF : {}", firstFreePage );
fileChannel.write( HEADER_BUFFER, 0 );
HEADER_BUFFER.clear();
@@ -1479,11 +1538,14 @@ public class RecordManager
/**
- * Update the BTree header after a BTree modification. We update the following fields :
+ * Update the BTree header after a BTree modification. This will make the latest modification
+ * visible.
+ * We update the following fields :
* <ul>
* <li>the revision</li>
* <li>the number of elements</li>
- * <li>the rootPage offset</li>
+ * <li>the reference to the current BTree revisions</li>
+ * <li>the reference to the old BTree revisions</li>
* </ul>
* @param btree
* @throws IOException
@@ -2071,12 +2133,6 @@ public class RecordManager
LOG.debug( "Reused page at offset {}", pageIo.getOffset() );
- // If we don't have any more free page, update the last free page pointer too
- if ( firstFreePage == NO_PAGE )
- {
- lastFreePage = NO_PAGE;
- }
-
return pageIo;
}
}
@@ -2243,7 +2299,6 @@ public class RecordManager
// The first and last free page
long firstFreePage = header.getLong();
- long lastFreePage = header.getLong();
if ( LOG.isDebugEnabled() )
{
@@ -2254,7 +2309,6 @@ public class RecordManager
LOG.debug( " page size : {}", pageSize );
LOG.debug( " nbTree : {}", nbBTree );
LOG.debug( " firstFreePage : {}", firstFreePage );
- LOG.debug( " lastFreePage : {}", lastFreePage );
}
long position = HEADER_SIZE;
@@ -2450,7 +2504,7 @@ public class RecordManager
// And flush it to disk
flushPages( pageIo );
- // We can update the lastFreePage offset
+ // We can update the firstFreePage offset
firstFreePage = firstOffset;
}
}
@@ -2580,24 +2634,12 @@ public class RecordManager
* @param checkedPages
* @throws IOException
*/
- private void checkFreePages( long[] checkedPages, int pageSize, long firstFreePage, long lastFreePage )
+ private void checkFreePages( long[] checkedPages, int pageSize, long firstFreePage )
throws IOException
{
if ( firstFreePage == NO_PAGE )
{
- if ( lastFreePage == NO_PAGE )
- {
- return;
- }
- else
- {
- throw new FreePageException( "Wrong last free page : " + lastFreePage );
- }
- }
-
- if ( lastFreePage != NO_PAGE )
- {
- throw new FreePageException( "Wrong last free page : " + lastFreePage );
+ return;
}
// Now, read all the free pages
@@ -2975,15 +3017,6 @@ public class RecordManager
throw new InvalidBTreeException( "First free page not pointing to a correct offset : " + firstFreePage );
}
- // The last free page offset. It must be -1
- long lastFreePage = header.getLong();
-
- if ( ( ( lastFreePage != NO_PAGE ) && ( ( ( lastFreePage - HEADER_SIZE ) % pageSize ) != 0 ) ) )
- //|| ( lastFreePage != 0 ) )
- {
- throw new InvalidBTreeException( "Invalid last free page : " + lastFreePage );
- }
-
int nbPageBits = ( int ) ( nbPages / 64 );
// Create an array of pages to be checked
@@ -2992,7 +3025,7 @@ public class RecordManager
long[] checkedPages = new long[nbPageBits + 1];
// Then the free files
- checkFreePages( checkedPages, pageSize, firstFreePage, lastFreePage );
+ checkFreePages( checkedPages, pageSize, firstFreePage );
// The BTrees
checkBTrees( checkedPages, pageSize, nbBTrees );