Return-Path: X-Original-To: apmail-directory-dev-archive@www.apache.org Delivered-To: apmail-directory-dev-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id D9D057473 for ; Sun, 2 Oct 2011 10:27:26 +0000 (UTC) Received: (qmail 2668 invoked by uid 500); 2 Oct 2011 10:27:26 -0000 Delivered-To: apmail-directory-dev-archive@directory.apache.org Received: (qmail 2623 invoked by uid 500); 2 Oct 2011 10:27:26 -0000 Mailing-List: contact dev-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Apache Directory Developers List" Delivered-To: mailing list dev@directory.apache.org Received: (qmail 2616 invoked by uid 99); 2 Oct 2011 10:27:26 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 02 Oct 2011 10:27:26 +0000 X-ASF-Spam-Status: No, hits=-0.7 required=5.0 tests=FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (athena.apache.org: domain of ayaselcuk@gmail.com designates 209.85.216.50 as permitted sender) Received: from [209.85.216.50] (HELO mail-qw0-f50.google.com) (209.85.216.50) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 02 Oct 2011 10:27:20 +0000 Received: by qabj34 with SMTP id j34so1345353qab.37 for ; Sun, 02 Oct 2011 03:26:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:date:message-id:subject:from:to:content-type :content-transfer-encoding; bh=Lc/QEVX0zC7Sor5FvU9vL26iIw2ORn9LSF7eFqWtIio=; b=u1zbbSepSTEXDVzTZX0FJsB9tMDiILRlPRuA7bq+ZUtBOT2xn02KpEoqNJyZT1lDHt 3Eou/HML2Yny2bnTSOSjoftgqZf7GLP/k0Jfe3kHRt/K5WtX847OohDAKkYqB+gp9AKf NO+lSZlWd6niQlKDNfQ69sA8y2Y0RcJbzfR8E= MIME-Version: 1.0 Received: by 10.224.215.138 with SMTP id he10mr9747163qab.167.1317551218465; Sun, 02 Oct 2011 03:26:58 -0700 (PDT) Received: by 10.224.73.135 with HTTP; Sun, 2 Oct 2011 03:26:58 -0700 (PDT) Date: Sun, 2 Oct 2011 13:26:58 +0300 Message-ID: Subject: Re: svn commit: r1177627 - in /directory/apacheds/trunk: i18n/src/main/java/org/apache/directory/server/i18n/ i18n/src/main/resources/org/apache/directory/server/i18n/ xdbm-partition/src/main/java/org/apache/directory/server/log/ xdbm-partition/src/m From: Selcuk AYA To: Apache Directory Developers List Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Hi Felix, changes under the package log and log.impl are part of an experimental implementation towards a transactional system and were not intended for the main branch. They accidentally ended up there as my sandbox external apacheds pointed to the main branch. I created a new branch for my implementation but left the current changes in the main branch as they are isolated and should not affect the rest of the system. As I mentioned in the commit, there is some todo for this code( test + some stuff like exception handling) and it might change as I implement more of this stuff. So no need to put fixes for this code yet. regards, Selcuk On Fri, Sep 30, 2011 at 10:11 PM, Felix Knecht wrote: > Hi Selcuk > > Please remember to set also a license header when adding new files to the > repository. For file below done in > http://svn.apache.org/viewvc?rev=3D1177780&view=3Drev > > Regards > Felix > > On 09/30/2011 02:29 PM, saya@apache.org wrote: >> >> Author: saya >> Date: Fri Sep 30 12:28:59 2011 >> New Revision: 1177627 >> >> URL: http://svn.apache.org/viewvc?rev=3D1177627&view=3Drev >> Log: >> First set of changes towards a transactional system over parititions. >> >> This is the first set of changes for the logging subsystem.: >> Log.java: interface to the logging subsystem. Logging subsystem logs >> uninterpreted blobs of user data. >> >> LogManager.java: Manages deletion, creation and formatting of log files >> and reading/writing of control file. ControlFile is a special file where >> critical information for the logging subsystem is held. It includes >> checkpoint information. Control file is updated by writing to a shadow f= ile >> first and then renaming(moving) the shadow file to the controlfile. >> >> LogFlushManager.java: Manager logging of data to log files. Manager an >> internal circular buffer where user data is appended first and then flus= hed >> to the underlying log file either when the buffer is full or when one of= the >> clients wants to sync the data. It is possible to specify a zero for the >> buffer size and directly append the data to the underlying file.Log flus= hing >> is done by the foreground threads(No special background thread is used t= o do >> it). >> >> LogScanner.java, DefaultLogScanner.java: Implements forwards scanning of >> log files. >> >> LogFileManager.java: defines an interface that exposes basic file >> operations on log files. It is possible to use different implementations= to >> satisfy this interface. Currently, randomaccessfile is used but FileChan= nel >> or HDFS files can be used as well. >> >> UserLogRecord.java: used to pass byte[] user log records and log positio= n >> information between the clients and the logging subsystem. >> >> LogFile format: Log file numbers start from 0 and keep increasing as new >> log files are created. A log file has a log file header which should be >> verified when the log file is opened for reading. User log records are >> uninterpreted blobs of data. A recordHeader is prepended and a record fo= oter >> is appended to the user log record. This record header and footer has al= so >> verification information to detect corrupt/partiallly written log record= s. >> Record header/footer and file headers are used by the LogScanner >> implementation to scan the logs. This format makes it possible to log an= y >> data in the logging subsystem. >> >> >> >> TODO: test, handle IO exceptions and other exceptions better. >> >> Added: >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/ >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/InvalidLogException.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/Log.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogAnchor.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogAnchorComparator.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogScanner.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/UserLogRecord.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/ >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/DefaultLogFileManager.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/DefaultLogScanner.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFileManager.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFileRecords.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFlushManager.java >> >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogManager.java >> Modified: >> >> directory/apacheds/trunk/i18n/src/main/java/org/apache/directory/server/= i18n/I18n.java >> >> directory/apacheds/trunk/i18n/src/main/resources/org/apache/directory/se= rver/i18n/errors.properties >> >> Modified: >> directory/apacheds/trunk/i18n/src/main/java/org/apache/directory/server/= i18n/I18n.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/i18n/src/main/java= /org/apache/directory/server/i18n/I18n.java?rev=3D1177627&r1=3D1177626&r2= =3D1177627&view=3Ddiff >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/i18n/src/main/java/org/apache/directory/server/= i18n/I18n.java >> (original) >> +++ >> directory/apacheds/trunk/i18n/src/main/java/org/apache/directory/server/= i18n/I18n.java >> Fri Sep 30 12:28:59 2011 >> @@ -778,7 +778,12 @@ public enum I18n >> >> =A0ERR_742_CANNOT_ENCODE_ENC_TICKET_PART("ERR_742_CANNOT_ENCODE_ENC_TICK= ET_PART"), >> =A0 =A0 =A0ERR_743_CANNOT_ENCODE_TYPED_DATA("ERR_743_CANNOT_ENCODE_TYPED= _DATA"), >> =A0 =A0 =A0ERR_744_NULL_PDU_LENGTH("ERR_744_NULL_PDU_LENGTH"), >> - =A0 =A0ERR_745_NOT_A_KERBEROS_STRING("ERR_745_NOT_A_KERBEROS_STRING"); >> + =A0 =A0ERR_745_NOT_A_KERBEROS_STRING("ERR_745_NOT_A_KERBEROS_STRING"), >> + =A0 =A0ERR_746("ERR_746"), >> + =A0 =A0ERR_747("ERR_747"), >> + =A0 =A0ERR_748("ERR_748"), >> + =A0 =A0ERR_749("ERR_749"), >> + =A0 =A0ERR_750("ERR_750"); >> >> =A0 =A0 =A0private static ResourceBundle errBundle =3D ResourceBundle >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.getBundle( "org.apache.directory.ser= ver.i18n.errors" ); >> >> Modified: >> directory/apacheds/trunk/i18n/src/main/resources/org/apache/directory/se= rver/i18n/errors.properties >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/i18n/src/main/reso= urces/org/apache/directory/server/i18n/errors.properties?rev=3D1177627&r1= =3D1177626&r2=3D1177627&view=3Ddiff >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/i18n/src/main/resources/org/apache/directory/se= rver/i18n/errors.properties >> (original) >> +++ >> directory/apacheds/trunk/i18n/src/main/resources/org/apache/directory/se= rver/i18n/errors.properties >> Fri Sep 30 12:28:59 2011 >> @@ -766,4 +766,9 @@ ERR_741_CANNOT_ENCODE_KRB_CRED=3DCannot en >> =A0ERR_742_CANNOT_ENCODE_ENC_TICKET_PART=3DCannot encode the EncTicketPa= rt >> object, the PDU size is {0} when only {1} bytes has been allocated >> =A0ERR_743_CANNOT_ENCODE_TYPED_DATA=3DCannot encode the TypedData object= , the >> PDU size is {0} when only {1} bytes has been allocated >> =A0ERR_744_NULL_PDU_LENGTH=3DThe PDU length is null, this is not allowed >> -ERR_745_NOT_A_KERBEROS_STRING=3DThe value {0} is not a valid KerberosSt= ring >> \ No newline at end of file >> +ERR_745_NOT_A_KERBEROS_STRING=3DThe value {0} is not a valid KerberosSt= ring >> +ERR_746=3DNot a valid log file number =A0{0} >> +ERR_747=3DNot a valid log file offset =A0{0} >> +ERR_748=3DInvalid log file bufferSize/ max size is sepcified bufferSize= {0} >> logFileSize {0} >> +ERR_749=3DLog Scanner is already closed >> +ERR_750=3DLog content is invalid >> \ No newline at end of file >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/InvalidLogException.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/InvalidLogException.java?rev=3D1= 177627&view=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/InvalidLogException.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/InvalidLogException.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,28 @@ >> + >> +package org.apache.directory.server.log; >> + >> +/** >> + * An exception used when the log content could be invalid. >> + * >> + * @authorApache Directory >> Project >> + */ >> +public class InvalidLogException extends Exception >> +{ >> + =A0 =A0public InvalidLogException() {} >> + >> + =A0 =A0public InvalidLogException(String s) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0super(s); >> + =A0 =A0} >> + >> + =A0 =A0public InvalidLogException(Throwable cause) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0super(cause); >> + =A0 =A0} >> + >> + =A0 =A0public InvalidLogException(String s, Throwable cause) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0super(s, cause); >> + =A0 =A0} >> + >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/Log.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/Log.java?rev=3D1177627&view=3Dau= to >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/Log.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/Log.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,40 @@ >> + >> +package org.apache.directory.server.log; >> + >> +import java.io.IOException; >> + >> +public interface Log >> +{ >> + >> + =A0 =A0/** >> + =A0 =A0 * Initializes the logging subsystem >> + =A0 =A0 * >> + =A0 =A0 * @param logFilepath log file path >> + =A0 =A0 * @param suffix suffix for log file. >> + =A0 =A0 * @param logBufferSize size of buffer that will hold unflushed= log >> changes. Specifigy zero if no buffering is desired >> + =A0 =A0 * @param logFileSize A soft limit on the log file size >> + =A0 =A0 */ >> + =A0 public void init( String logFilepath, String suffix, int >> logBufferSize, long logFileSize ); >> + >> + =A0 =A0/** >> + =A0 =A0 * Logs the given user record to the log. Position in the log f= iles >> where the record is logged is returned as part of >> + =A0 =A0 * userRecord. >> + =A0 =A0 * >> + =A0 =A0 * @param userLogRecord provides the user data to be logged >> + =A0 =A0 * @param sync if true, this calls returns after making sure th= at the >> appended data is reflected to the underlying media >> + =A0 =A0 * @throws IOException >> + =A0 =A0 * @throws InvalidLogException >> + =A0 =A0 */ >> + =A0 =A0public void log( UserLogRecord userRecord, boolean sync ) throw= s >> IOException, InvalidLogException; >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * Starts a san in the logs starting from the given log positio= n >> + =A0 =A0 * >> + =A0 =A0 * @param startPoint starting position of the scan. >> + =A0 =A0 * @return >> + =A0 =A0 */ >> + =A0 =A0public LogScanner beginScan( LogAnchor startPoint ); >> + >> + >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogAnchor.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/LogAnchor.java?rev=3D1177627&vie= w=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogAnchor.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogAnchor.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,83 @@ >> + >> +package org.apache.directory.server.log; >> + >> +import org.apache.directory.server.i18n.I18n; >> + >> +/** >> + * Implements a pointer in to the log files >> + * @authorApache Directory >> Project >> + */ >> +public class LogAnchor >> +{ >> + =A0 =A0// TODO move this to logger >> + =A0 =A0/** Invalid/unknown lsn. Log LSN starts at UNKNOWN_LSN + 1 and = is >> ever increasing */ >> + =A0 =A0public final static long UNKNOWN_LSN =3D Long.MIN_VALUE; >> + >> + =A0 =A0/** Min log file number */ >> + =A0 =A0public final static long MIN_LOG_NUMBER =3D 0; >> + >> + =A0 =A0/** Min log file offset */ >> + =A0 =A0public final static long MIN_LOG_OFFSET =3D 0; >> + >> + >> + =A0 =A0/** log file identifier of the anchor */ >> + =A0 =A0private long logFileNumber =3D 0 ; >> + >> + =A0 =A0/** Offset into the log file identified by logfilenumber */ >> + =A0 =A0private long logFileOffset =3D 0; >> + >> + =A0 =A0/** LSN corresponding to the logFileNumber and fileOffset */ >> + =A0 =A0private long logLSN =3D UNKNOWN_LSN; >> + >> + =A0 =A0public LogAnchor() >> + =A0 =A0{ >> + >> + =A0 =A0} >> + >> + =A0 =A0public LogAnchor( long logFileNumber, long logFileOffset, long = logLSN >> ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0this.resetLogAnchor( logFileNumber, logFileOffset, logL= SN ); >> + =A0 =A0} >> + >> + >> + =A0 =A0public void resetLogAnchor( long logFileNumber, long logFileOff= set, >> long logLSN ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if ( logFileNumber< =A00 ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0throw new IllegalArgumentException( I18n.err( I= 18n.ERR_746, >> logFileNumber ) ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( logFileOffset< =A00 ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0throw new IllegalArgumentException( I18n.err( I= 18n.ERR_747, >> logFileOffset ) ); >> + =A0 =A0 =A0 =A0} >> + >> + >> + =A0 =A0 =A0 =A0this.logFileNumber =3D logFileNumber; >> + =A0 =A0 =A0 =A0this.logFileOffset =3D logFileOffset; >> + =A0 =A0 =A0 =A0this.logLSN =3D logLSN; >> + =A0 =A0} >> + >> + =A0 =A0public void resetLogAnchor( LogAnchor logAnchor ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0this.resetLogAnchor( logAnchor.getLogFileNumber(), >> logAnchor.getLogFileOffset(), logAnchor.getLogLSN() ); >> + =A0 =A0} >> + >> + >> + =A0 =A0public long getLogFileNumber() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0return this.logFileNumber; >> + =A0 =A0} >> + >> + >> + =A0 =A0public long getLogFileOffset() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0return this.logFileOffset; >> + =A0 =A0} >> + >> + >> + =A0 =A0public long getLogLSN() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0return this.logLSN; >> + =A0 =A0} >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogAnchorComparator.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/LogAnchorComparator.java?rev=3D1= 177627&view=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogAnchorComparator.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogAnchorComparator.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,57 @@ >> + >> +package org.apache.directory.server.log; >> + >> +import java.util.Comparator; >> + >> +import org.apache.directory.server.i18n.I18n; >> + >> +public class LogAnchorComparator implements Comparator >> +{ >> + =A0 =A0/** >> + =A0 =A0 * Compare two log anchors. >> + =A0 =A0 * >> + =A0 =A0 * @param obj1 First object >> + =A0 =A0 * @param obj2 Second object >> + =A0 =A0 * @return a positive integer if obj1> =A0obj2, 0 if obj1 =3D= =3D obj2, >> + =A0 =A0 * =A0 =A0 =A0 =A0 and a negative integer if obj1< =A0obj2 >> + =A0 =A0 */ >> + =A0 =A0 public int compare( LogAnchor obj1, LogAnchor obj2 ) >> + =A0 =A0 { >> + =A0 =A0 =A0 =A0if ( obj1 =3D=3D null ) { >> + =A0 =A0 =A0 =A0 =A0 =A0throw new IllegalArgumentException( I18n.err( I= 18n.ERR_525 ) >> ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( obj2 =3D=3D null ) { >> + =A0 =A0 =A0 =A0 =A0 =A0throw new IllegalArgumentException( I18n.err( I= 18n.ERR_526 ) >> ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0long logFileNumber1 =3D obj1.getLogFileNumber(); >> + =A0 =A0 =A0 =A0long logFileOffset1 =3D obj1.getLogFileOffset(); >> + =A0 =A0 =A0 =A0long logFileNumber2 =3D obj2.getLogFileNumber(); >> + =A0 =A0 =A0 =A0long logFileOffset2 =3D obj2.getLogFileOffset(); >> + >> + =A0 =A0 =A0 =A0if ( logFileNumber1> =A0logFileNumber2 ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return 1; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0else if ( logFileNumber1 =3D=3D logFileNumber2 ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0if ( logFileOffset1> =A0logFileOffset2 ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return 1; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0else if ( logFileOffset1 =3D=3D logFileOffset2 = ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return 0; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -1; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return -1; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 } >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogScanner.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/LogScanner.java?rev=3D1177627&vi= ew=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogScanner.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/LogScanner.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,42 @@ >> + >> +package org.apache.directory.server.log; >> + >> + >> +import java.io.IOException; >> + >> +public interface LogScanner >> +{ >> + =A0 =A0/** >> + =A0 =A0 * Reads and returns the next user record from the log into a b= acking >> byte array >> + =A0 =A0 * and returns a reference to it. Returned array can be overwri= tten >> + =A0 =A0 * after the next call to getNextRecord() >> + =A0 =A0 * >> + =A0 =A0 * @param =A0log record to be filled in by >> + =A0 =A0 * @return true if there is a next record >> + =A0 =A0 * throws IOException >> + =A0 =A0 * throws InvalidLogException thrown if the log content is inva= lid >> + =A0 =A0 */ >> + =A0 =A0public boolean getNextRecord(UserLogRecord logRecord) throws >> IOException, InvalidLogException; >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * Returns the last successfully read log file number >> + =A0 =A0 * >> + =A0 =A0 * @return last successfully read log file number >> + =A0 =A0 */ >> + =A0 =A0public long getLastGoodFileNumber(); >> + >> + =A0 =A0/** >> + =A0 =A0 * Returns the last successfully read log file number >> + =A0 =A0 * >> + =A0 =A0 * @return last successfully read log file number >> + =A0 =A0 */ >> + =A0 =A0public long getLastGoodOffset(); >> + >> + =A0 =A0/** >> + =A0 =A0 * Closes the scanner and releases any >> + =A0 =A0 * resources. >> + =A0 =A0 * >> + =A0 =A0 */ >> + =A0 =A0public void close(); >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/UserLogRecord.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/UserLogRecord.java?rev=3D1177627= &view=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/UserLogRecord.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/UserLogRecord.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,47 @@ >> + >> +package org.apache.directory.server.log; >> + >> +/** >> + * A user log record that can be used to pass user record between the >> clients and the logger >> + * >> + * @authorApache Directory >> Project >> + */ >> +public class UserLogRecord >> +{ >> + =A0 =A0private final static int INITIAL_SIZE =3D =A01024; >> + >> + =A0 =A0/** array used to hold user log records */ >> + =A0 =A0private byte[] recordHolder; >> + >> + =A0 =A0/** offset int the =A0byte array where user record starts */ >> + =A0 =A0int offset; >> + >> + =A0 =A0/** length of the user record in the byte array */ >> + =A0 =A0int length; >> + >> + =A0 =A0/** Position of the log record in the log */ >> + =A0 =A0private LogAnchor logAnchor =3D new LogAnchor(); >> + >> + =A0 =A0public void setData( byte[] data, int length ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0this.recordHolder =3D recordHolder; >> + =A0 =A0} >> + >> + =A0 =A0public byte[] getDataBuffer() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0return recordHolder; >> + =A0 =A0} >> + >> + >> + =A0 =A0public int getDataLength() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0return length; >> + =A0 =A0} >> + >> + >> + =A0 =A0public LogAnchor getLogAnchor() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0return logAnchor; >> + =A0 =A0} >> + >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/DefaultLogFileManager.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/impl/DefaultLogFileManager.java?= rev=3D1177627&view=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/DefaultLogFileManager.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/DefaultLogFileManager.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,243 @@ >> + >> +package org.apache.directory.server.log.impl; >> + >> +import java.io.EOFException; >> +import java.io.File; >> +import java.io.IOException; >> +import java.io.FileNotFoundException; >> + >> +import java.io.RandomAccessFile; >> + >> +import org.apache.directory.server.i18n.I18n; >> +import org.apache.directory.server.log.impl.LogFileManager.LogFileReade= r; >> +import org.apache.directory.server.log.impl.LogFileManager.LogFileWrite= r; >> + >> +class DefaultLogFileManager implements LogFileManager >> +{ >> + =A0 =A0private String logFilePath; >> + =A0 =A0private String suffix; >> + >> + =A0 =A0/** >> + =A0 =A0 * Inits the log file manager to use the given logfile path and= the >> suffix. Each log file >> + =A0 =A0 * has name logFileName_.suffix >> + =A0 =A0 * >> + =A0 =A0 * @param logFilepath log file path >> + =A0 =A0 * @param suffix suffix for log file. >> + =A0 =A0 */ >> + =A0 =A0public void init( String logFilepath, String suffix ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0this.logFilePath =3D logFilePath; >> + =A0 =A0 =A0 =A0this.suffix =3D suffix; >> + =A0 =A0} >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public LogFileReader getReaderForLogFile( long logFileNumber ) = throws >> IOException, FileNotFoundException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0File logFile =3D this.makeLogFileName( logFileNumber ); >> + >> + =A0 =A0 =A0 =A0// This will throw a file not found exception if file d= oes not >> exist >> + =A0 =A0 =A0 =A0RandomAccessFile raf =3D new RandomAccessFile( logFile,= "r" ); >> + >> + =A0 =A0 =A0 =A0return new LogFileReader( raf, logFileNumber ); >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public LogFileWriter getWriterForLogFile( long logFileNumber ) = throws >> IOException, FileNotFoundException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0File logFile =3D this.makeLogFileName( logFileNumber ); >> + >> + =A0 =A0 =A0 =A0// This will throw a file not found exception if file d= oes not >> exist >> + =A0 =A0 =A0 =A0RandomAccessFile raf =3D new RandomAccessFile( logFile,= "rw" ); >> + >> + =A0 =A0 =A0 =A0return new LogFileWriter( raf, logFileNumber ); >> + =A0 =A0} >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public boolean createLogFile( long logFileNumber ) throws IOExc= eption >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0File logFile =3D this.makeLogFileName( logFileNumber ); >> + >> + =A0 =A0 =A0 =A0boolean fileAlreadyExists =3D !logFile.createNewFile(); >> + >> + =A0 =A0 =A0 =A0return fileAlreadyExists; >> + =A0 =A0} >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public void truncateLogFile( long logFileNumber, long size ) th= rows >> IOException, FileNotFoundException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if ( size< =A00 ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0throw new IllegalArgumentException( "Invalid fi= le size is >> specified for the log file: " + logFileNumber + " " + size ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0File logFile =3D this.makeLogFileName( logFileNumber ); >> + >> + =A0 =A0 =A0 =A0// This will throw a file not found exception if file d= oes not >> exist >> + =A0 =A0 =A0 =A0RandomAccessFile raf =3D new RandomAccessFile( logFile,= "rw" ); >> + >> + =A0 =A0 =A0 =A0raf.setLength( size ); >> + =A0 =A0 =A0 =A0raf.getFD().sync(); >> + =A0 =A0} >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public void deleteLogFile( long logFileNumber ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0File logFile =3D this.makeLogFileName( logFileNumber ); >> + >> + =A0 =A0 =A0 =A0logFile.delete(); >> + =A0 =A0} >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public boolean rename(long originalLogFileNumber, long >> newLongFileNumber) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0File oldLogFile =3D this.makeLogFileName( originalLogFi= leNumber ); >> + =A0 =A0 =A0 =A0boolean result =3D oldLogFile.renameTo( this.makeLogFil= eName( >> newLongFileNumber ) ); >> + =A0 =A0 =A0 =A0return result; >> + =A0 =A0} >> + >> + >> + =A0 =A0private File makeLogFileName( long logFileNumber ) >> + =A0 =A0{ >> + >> + =A0 =A0 =A0 =A0return new File( logFilePath + "/" + >> LogFileManager.LOG_NAME_PREFIX + logFileNumber + "." + suffix ); >> + =A0 =A0} >> + >> + =A0 =A0static class LogFileReader implements LogFileManager.LogFileRea= der >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0/** Underlying log file */ >> + =A0 =A0 =A0 =A0RandomAccessFile raf; >> + >> + =A0 =A0 =A0 =A0/** Log file identifier */ >> + =A0 =A0 =A0 =A0long logFileNumber; >> + >> + >> + =A0 =A0 =A0 =A0public LogFileReader( RandomAccessFile raf, long logFil= eNumber ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0this.raf =3D raf; >> + =A0 =A0 =A0 =A0 =A0 =A0this.logFileNumber =3D logFileNumber; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public int read( byte[] buffer, int offset, int length = ) throws >> IOException, EOFException >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0raf.readFully( buffer, offset, length ); >> + =A0 =A0 =A0 =A0 =A0 =A0return length; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void seek( long position ) throws IOException >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0raf.seek( position ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void close() throws IOException >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0raf.close(); >> + =A0 =A0 =A0 =A0} >> + >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public long logFileNumber() >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return logFileNumber; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public long getLength() throws IOException >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return raf.length(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public long getOffset() throws IOException >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return raf.getFilePointer(); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + >> + =A0 =A0static class LogFileWriter implements LogFileManager.LogFileWri= ter >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0/** Underlying log file */ >> + =A0 =A0 =A0 =A0RandomAccessFile raf; >> + >> + =A0 =A0 =A0 =A0/** Log file identifier */ >> + =A0 =A0 =A0 =A0long logFileNumber; >> + >> + >> + =A0 =A0 =A0 =A0public LogFileWriter( RandomAccessFile raf, long logFil= eNumber ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0this.raf =3D raf; >> + =A0 =A0 =A0 =A0 =A0 =A0this.logFileNumber =3D logFileNumber; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void append( byte[] buffer, int offset, int leng= th ) >> throws IOException >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0raf.write( buffer, offset, length ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void sync() throws IOException >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 raf.getFD().sync(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void close() throws IOException >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0raf.close(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 /** >> + =A0 =A0 =A0 =A0 =A0* {@inheritDoc} >> + =A0 =A0 =A0 =A0 =A0*/ >> + =A0 =A0 =A0 =A0public long logFileNumber() >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return logFileNumber; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * {@inheritDoc} >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public long getLength() throws IOException >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return raf.length(); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/DefaultLogScanner.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/impl/DefaultLogScanner.java?rev= =3D1177627&view=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/DefaultLogScanner.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/DefaultLogScanner.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,354 @@ >> + >> +package org.apache.directory.server.log.impl; >> + >> +import java.io.IOException; >> +import java.io.EOFException; >> +import java.io.FileNotFoundException; >> +import java.nio.ByteBuffer; >> + >> +import org.apache.directory.server.i18n.I18n; >> +import org.apache.directory.server.log.InvalidLogException; >> +import org.apache.directory.server.log.LogAnchor; >> +import org.apache.directory.server.log.LogScanner; >> +import org.apache.directory.server.log.UserLogRecord; >> + >> +public class DefaultLogScanner implements LogScanner >> +{ >> + =A0 =A0/** LSN of the last successfully read log record */ >> + =A0 =A0private long prevLSN =3D LogAnchor.UNKNOWN_LSN; >> + >> + =A0 =A0/** File number of the last successfully read position's file n= umber >> */ >> + =A0 =A0private long prevLogFileNumber =3D -1; >> + >> + =A0 =A0/** File number of the last known good offset */ >> + =A0 =A0private long prevLogFileOffset =3D -1; >> + >> + =A0 =A0/** Position to read the next record from */ >> + =A0 =A0private LogAnchor startingLogAnchor =3D new LogAnchor(); >> + >> + =A0 =A0/** Last Read Lsn */ >> + =A0 =A0private long lastReadLSN =3D LogAnchor.UNKNOWN_LSN; >> + >> + =A0 =A0/** Current log file pointer to read from */ >> + =A0 =A0LogFileManager.LogFileReader currentLogFile; >> + >> + =A0 =A0/** True if scanner is closed */ >> + =A0 =A0boolean closed =3D false; >> + >> + =A0 =A0/** True if scanner hit invalid content. No more reads will be = done >> after invalid log content is hit */ >> + =A0 =A0boolean invalidLog =3D false; >> + >> + =A0 =A0/** log file manager used to open files for reading */ >> + =A0 =A0LogFileManager logFileManager; >> + >> + =A0 =A0/** Buffer used to read log file markers */ >> + =A0 =A0byte markerBuffer[] =3D new byte[LogFileRecords.MAX_MARKER_SIZE= ]; >> + >> + =A0 =A0/** ByteBuffer wrapper for the marker buffer */ >> + =A0 =A0ByteBuffer markerHead =3D ByteBuffer.wrap( markerBuffer ); >> + >> + =A0 =A0public DefaultLogScanner( LogAnchor startingLogAnchor, LogFileM= anager >> logFileManger ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0startingLogAnchor.resetLogAnchor( startingLogAnchor ); >> + =A0 =A0 =A0 =A0this.logFileManager =3D logFileManager; >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public boolean getNextRecord(UserLogRecord logRecord) throws >> IOException, InvalidLogException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0boolean startingRead =3D false; >> + >> + =A0 =A0 =A0 =A0checkIfClosed(); >> + >> + =A0 =A0 =A0 =A0if ( invalidLog ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0throw new InvalidLogException( I18n.err( I18n.E= RR_750 ) ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0long fileLength; >> + =A0 =A0 =A0 =A0long fileOffset; >> + >> + >> + =A0 =A0 =A0 =A0try >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0if ( currentLogFile =3D=3D null ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0long startingOffset =3D >> startingLogAnchor.getLogFileOffset(); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Read and verify header >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0currentLogFile =3D this.readFileHeader( >> startingLogAnchor.getLogFileNumber() ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( currentLogFile =3D=3D null ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return false; // Nothing to rea= d >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( startingOffset> =A00 ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( startingOffset< >> =A0LogFileRecords.LOG_FILE_HEADER_SIZE ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Offset should be at = log file marker boundary >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.markScanInvalid(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0prevLogFileOffset =3D Math.max(= startingOffset, >> currentLogFile.getLength() ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0currentLogFile.seek( startingOf= fset ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0startingRead =3D true; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0while ( true ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fileLength =3D currentLogFile.getLength= (); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0fileOffset =3D currentLogFile.getOffset= (); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( fileOffset> =A0fileLength ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.markScanInvalid(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else if ( fileOffset =3D=3D fileLength = ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Switch to next file.. This r= eads and verifies the >> header of the new file >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0long nextLogFileNumber =3D >> currentLogFile.logFileNumber() + 1; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0currentLogFile.close(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0currentLogFile =3D this.readFil= eHeader( >> nextLogFileNumber ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( currentLogFile =3D=3D null= ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return false; // Done..= End of log stream >> + >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; =A0// break to read the = user record >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0// Read and verify record header >> + =A0 =A0 =A0 =A0 =A0 =A0int recordLength =3D this.readRecordHeader(); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0// If starting read, then check if we have the = expected lsn >> in case >> + =A0 =A0 =A0 =A0 =A0 =A0// expected lsn is known >> + =A0 =A0 =A0 =A0 =A0 =A0if ( startingRead ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0long startingLSN =3D startingLogAnchor.= getLogLSN(); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( ( startingLSN !=3D LogAnchor.UNKNO= WN_LSN )&& =A0( >> startingLSN !=3D lastReadLSN ) ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.markScanInvalid(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0// Read and verify user block >> + =A0 =A0 =A0 =A0 =A0 =A0this.readLogRecord( logRecord, recordLength ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0// Read and verify footer >> + =A0 =A0 =A0 =A0 =A0 =A0this.readRecordFooter(); >> + >> + >> + =A0 =A0 =A0 =A0 =A0 =A0// If we are here, then we successfully read th= e log record. >> + =A0 =A0 =A0 =A0 =A0 =A0// Set the read record's position, uptate last = read good >> location >> + =A0 =A0 =A0 =A0 =A0 =A0// and then return >> + =A0 =A0 =A0 =A0 =A0 =A0fileOffset =3D currentLogFile.getOffset(); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0LogAnchor userLogAnchor =3D logRecord.getLogAnc= hor(); >> + =A0 =A0 =A0 =A0 =A0 =A0userLogAnchor.resetLogAnchor( currentLogFile.lo= gFileNumber(), >> fileOffset - recordLength, lastReadLSN ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0prevLogFileOffset =3D fileOffset; >> + =A0 =A0 =A0 =A0 =A0 =A0prevLogFileNumber =3D currentLogFile.logFileNum= ber(); >> + =A0 =A0 =A0 =A0 =A0 =A0prevLSN =3D lastReadLSN; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0catch( EOFException e) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0// This means either the log record or the log = file header >> was >> + =A0 =A0 =A0 =A0 =A0 =A0// partially written. Treat this as invalid log= content >> + =A0 =A0 =A0 =A0 =A0 =A0this.markScanInvalid(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0return true; >> + >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public long getLastGoodFileNumber() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0return this.prevLogFileNumber; >> + =A0 =A0} >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public long getLastGoodOffset() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0return this.prevLogFileOffset; >> + =A0 =A0} >> + >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * {@inheritDoc} >> + =A0 =A0 */ >> + =A0 =A0public void close() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if ( closed =3D=3D false ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0closed =3D true; >> + =A0 =A0 =A0 =A0 =A0 =A0if (currentLogFile !=3D null) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0try >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0currentLogFile.close(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0currentLogFile =3D null; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0catch( IOException e ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Ignore >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0} >> + >> + >> + =A0 =A0private int readRecordHeader() throws IOException, >> InvalidLogException, EOFException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0boolean invalid =3D false; >> + >> + =A0 =A0 =A0 =A0markerHead.rewind(); >> + =A0 =A0 =A0 =A0currentLogFile.read( markerBuffer, 0, >> LogFileRecords.RECORD_HEADER_SIZE ); >> + =A0 =A0 =A0 =A0int magicNumber =3D markerHead.getInt(); >> + =A0 =A0 =A0 =A0int length =3D markerHead.getInt(); >> + =A0 =A0 =A0 =A0long lsn =3D markerHead.getLong(); >> + =A0 =A0 =A0 =A0long checksum =3D markerHead.getLong(); >> + >> + =A0 =A0 =A0 =A0if ( magicNumber !=3D LogFileRecords.RECORD_HEADER_MAGI= C_NUMBER ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalid =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( length<=3D ( LogFileRecords.RECORD_HEADER_SIZE + >> LogFileRecords.RECORD_FOOTER_SIZE ) ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalid =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( lsn< =A0prevLSN ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalid =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( checksum !=3D ( lsn ^ length ) ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalid =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( invalid =3D=3D true ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0this.markScanInvalid(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0// Everything went fine >> + =A0 =A0 =A0 =A0lastReadLSN =3D lsn; >> + =A0 =A0 =A0 =A0return length; >> + =A0 =A0} >> + >> + >> + =A0 =A0private void readRecordFooter() throws IOException, >> InvalidLogException, EOFException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0boolean invalid =3D false; >> + >> + =A0 =A0 =A0 =A0markerHead.rewind(); >> + =A0 =A0 =A0 =A0currentLogFile.read( markerBuffer, 0, >> LogFileRecords.RECORD_FOOTER_SIZE ); >> + =A0 =A0 =A0 =A0int checksum =3D markerHead.getInt(); >> + =A0 =A0 =A0 =A0int magicNumber =3D markerHead.getInt(); >> + >> + =A0 =A0 =A0 =A0if ( magicNumber !=3D LogFileRecords.RECORD_FOOTER_MAGI= C_NUMBER ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalid =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0// TODO compute checksum >> + >> + =A0 =A0 =A0 =A0if ( invalid =3D=3D true ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0this.markScanInvalid(); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0 =A0private void readLogRecord( UserLogRecord userRecord, int lengt= h ) >> throws IOException, EOFException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0byte dataBuffer[] =3D userRecord.getDataBuffer(); >> + >> + =A0 =A0 =A0 =A0if ( dataBuffer =3D=3D null || dataBuffer.length< =A0le= ngth ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0// Allocate a larger buffer >> + =A0 =A0 =A0 =A0 =A0 =A0dataBuffer =3D new byte[length]; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0currentLogFile.read( dataBuffer, 0, length ); >> + =A0 =A0 =A0 =A0userRecord.setData( dataBuffer, length ); >> + =A0 =A0} >> + >> + =A0 =A0private LogFileManager.LogFileReader readFileHeader( long >> logFileNumber ) throws IOException, InvalidLogException, EOFException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0boolean invalid =3D false; >> + =A0 =A0 =A0 =A0LogFileManager.LogFileReader logFile; >> + >> + =A0 =A0 =A0 =A0try >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0logFile =3D logFileManager.getReaderForLogFile(= logFileNumber >> ); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0catch ( FileNotFoundException e ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return null; // end of log scan >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0// File exists >> + =A0 =A0 =A0 =A0this.prevLogFileNumber =3D logFileNumber; >> + =A0 =A0 =A0 =A0this.prevLogFileOffset =3D 0; >> + >> + =A0 =A0 =A0 =A0markerHead.rewind(); >> + =A0 =A0 =A0 =A0currentLogFile.read( markerBuffer, 0, >> LogFileRecords.LOG_FILE_HEADER_SIZE ); >> + =A0 =A0 =A0 =A0long persistedLogFileNumber =3D markerHead.getLong(); >> + =A0 =A0 =A0 =A0int magicNumber =3D markerHead.getInt(); >> + >> + =A0 =A0 =A0 =A0if ( persistedLogFileNumber !=3D logFileNumber ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalid =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( magicNumber !=3D LogFileRecords.LOG_FILE_HEADER_MA= GIC_NUMBER ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalid =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + >> + =A0 =A0 =A0 =A0if ( invalid =3D=3D true ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0this.markScanInvalid(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0// Everything is fine, advance good file offset and ret= urn >> + =A0 =A0 =A0 =A0this.prevLogFileOffset =3D LogFileRecords.LOG_FILE_HEAD= ER_SIZE; >> + =A0 =A0 =A0 =A0return logFile; >> + =A0 =A0} >> + >> + =A0 =A0private void checkIfClosed() >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if ( closed =3D=3D true ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0throw new IllegalStateException( I18n.err( I18n= .ERR_749 ) ); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0 =A0private void markScanInvalid() throws InvalidLogException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0invalidLog =3D true; >> + =A0 =A0 =A0 =A0throw new InvalidLogException( I18n.err( I18n.ERR_750 )= ); >> + =A0 =A0} >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFileManager.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/impl/LogFileManager.java?rev=3D1= 177627&view=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFileManager.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFileManager.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,175 @@ >> +package org.apache.directory.server.log.impl; >> + >> +import java.io.IOException; >> +import java.io.EOFException; >> +import java.io.FileNotFoundException; >> + >> + >> +/** >> + * Defines an interface that log manager can use to manage log files. >> + * >> + * @authorApache Directory >> Project >> + */ >> +interface LogFileManager >> +{ >> + =A0 =A0final static String LOG_NAME_PREFIX =3D "log_"; >> + >> + =A0 =A0/** >> + =A0 =A0 * Inits the log file manager to use the given logfile path and= the >> suffix. Each log file >> + =A0 =A0 * has name logFileName_.suffix >> + =A0 =A0 * >> + =A0 =A0 * @param logFilepath log file path >> + =A0 =A0 * @param suffix suffix for log file. >> + =A0 =A0 */ >> + =A0 =A0public void init( String logFilepath, String suffix ); >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * Returns a reader for the given log file number >> + =A0 =A0 * >> + =A0 =A0 * @param logFileNumber identifier of the log file to read >> + =A0 =A0 * @return reader for the given logfile >> + =A0 =A0 * @throws IOException >> + =A0 =A0 * @throws FileNotFoundException >> + =A0 =A0 */ >> + =A0 =A0public LogFileReader getReaderForLogFile( long logFileNumber ) = throws >> IOException, FileNotFoundException; >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * Returns a writer for the given log file number >> + =A0 =A0 * >> + =A0 =A0 * @param logFileNumber identifier of the log file to read >> + =A0 =A0 * @return writer for the given logfile >> + =A0 =A0 * @throws IOException >> + =A0 =A0 * @throws FileNotFoundException >> + =A0 =A0 */ >> + =A0 =A0public LogFileWriter getWriterForLogFile( long logFileNumber ) = throws >> IOException, FileNotFoundException; >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * Create a log file with the given identifier >> + =A0 =A0 * >> + =A0 =A0 * @param logFileNumber identifier of the log file to write to. >> + =A0 =A0 * @return true if file already existed >> + =A0 =A0 * @throws IOException >> + =A0 =A0 */ >> + =A0 =A0public boolean createLogFile( long logFileNumber ) throws >> IOException; >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * Truncates the file to the given size. Mostly used for throwi= ng >> away >> + =A0 =A0 * junk at the end of log file after a log replay after a crash= . >> + =A0 =A0 * >> + =A0 =A0 * @param logFileNumber identifier of the log file >> + =A0 =A0 * @param size new size of the file >> + =A0 =A0 * @throws IOException >> + =A0 =A0 */ >> + =A0 =A0public void truncateLogFile( long logFileNumber, long size ) th= rows >> IOException; >> + >> + =A0 =A0/** >> + =A0 =A0 * Deletes the underlying log file. >> + =A0 =A0 * >> + =A0 =A0 * @param logFileNumber identifier of the log file >> + =A0 =A0 */ >> + =A0 =A0public void deleteLogFile( long logFileNumber ); >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * Moves the old log file to a new name >> + =A0 =A0 * >> + =A0 =A0 * @param orignalLogFileNumber identifier of the old file >> + =A0 =A0 * @param newLongFileNumber identifier of the new file >> + =A0 =A0 * @return true if the rename succeeded >> + =A0 =A0 */ >> + =A0 =A0public boolean rename(long orignalLogFileNumber, long >> newLongFileNumber); >> + >> + >> + =A0 =A0interface LogFileReader >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * >> + =A0 =A0 =A0 =A0 * Reads from the file at the current position >> + =A0 =A0 =A0 =A0 * >> + =A0 =A0 =A0 =A0 * @param buffer data destination >> + =A0 =A0 =A0 =A0 * @param offset destination offset >> + =A0 =A0 =A0 =A0 * @param length size of read >> + =A0 =A0 =A0 =A0 * @return number of bytes actually read. >> + =A0 =A0 =A0 =A0 * @throws IOException >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public int read( byte[] buffer, int offset, int length = ) throws >> IOException, EOFException; >> + >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * Repositions the reader at the given offset >> + =A0 =A0 =A0 =A0 * >> + =A0 =A0 =A0 =A0 * @param position >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void seek( long position ) throws IOException; >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * Close the log file reader and releases the resources >> + =A0 =A0 =A0 =A0 * >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void close() throws IOException; >> + >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * Each log file is assigned a sequence number. This me= thod >> + =A0 =A0 =A0 =A0 * returns that number >> + =A0 =A0 =A0 =A0 * >> + =A0 =A0 =A0 =A0 * @return number assigned to this log file >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public long logFileNumber(); >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * returns the length of the file >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public long getLength() throws IOException; >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * returns the offset of the next read >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public long getOffset() throws IOException; >> + =A0 =A0} >> + >> + =A0 =A0interface LogFileWriter >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * Append the given data to the log file >> + =A0 =A0 =A0 =A0 * >> + =A0 =A0 =A0 =A0 * @param buffer source of data >> + =A0 =A0 =A0 =A0 * @param offset offset into buffer >> + =A0 =A0 =A0 =A0 * @param length number of bytes to be appended >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void append( byte[] buffer, int offset, int leng= th ) >> throws IOException; >> + >> + >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * Sync the file contents to media >> + =A0 =A0 =A0 =A0 * >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void sync() throws IOException; >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * Close the log file reader and releases the resources >> + =A0 =A0 =A0 =A0 * >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public void close() throws IOException; >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * Each log file is assigned a sequence number. This me= thod >> + =A0 =A0 =A0 =A0 * returns that number >> + =A0 =A0 =A0 =A0 * >> + =A0 =A0 =A0 =A0 * @return number assigned to this log file >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public long logFileNumber(); >> + >> + =A0 =A0 =A0 =A0/** >> + =A0 =A0 =A0 =A0 * returns the length of the file >> + =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0public long getLength() throws IOException; >> + >> + =A0 =A0} >> + >> +} >> \ No newline at end of file >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFileRecords.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/impl/LogFileRecords.java?rev=3D1= 177627&view=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFileRecords.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFileRecords.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,62 @@ >> + >> +package org.apache.directory.server.log.impl; >> + >> + >> +public class LogFileRecords >> +{ >> + =A0 =A0/** >> + =A0 =A0 * When a user appends a log record, a header and >> + =A0 =A0 * footer that surrounds the log record is inserted >> + =A0 =A0 * into the log. Header and footer information makes >> + =A0 =A0 * it easier to scan the log, detect the end of >> + =A0 =A0 * log during log scan and verify the integrity of log. >> + =A0 =A0 */ >> + >> + =A0 =A0/** >> + =A0 =A0 * Record Header marker >> + =A0 =A0 * int RECORD_HEADER_MAGIC_NUMBER >> + =A0 =A0 * int length =A0length of header + user log record + legnth of= footer >> + =A0 =A0 * long recordLSN =A0 =A0 lsn of the log record >> + =A0 =A0 * long headerChecksum checksum to verify header >> + =A0 =A0 */ >> + >> + =A0 =A0/** Header magic number */ >> + =A0 =A0final static int RECORD_HEADER_MAGIC_NUMBER =3D 0x010F010F; >> + >> + =A0 =A0/** Total header size */ >> + =A0 =A0final static int RECORD_HEADER_SIZE =3D 24; >> + >> + =A0 =A0/** >> + =A0 =A0 * Record Footer marker >> + =A0 =A0 * int checksum >> + =A0 =A0 * int RECORD_FOOTER_MAGIC_NUMBER >> + =A0 =A0 */ >> + >> + =A0 =A0/** Footer magic number */ >> + =A0 =A0final static int RECORD_FOOTER_MAGIC_NUMBER =3D 0x0F010F01; >> + >> + =A0 =A0/** Total header size */ >> + =A0 =A0final static int RECORD_FOOTER_SIZE =3D 8; >> + >> + =A0 =A0/** >> + =A0 =A0 * LogFileHeader marker >> + =A0 =A0 * long log file number >> + =A0 =A0 * int LOG_FILE_HEADER_MAGIC_NUMBER 0xFF00FF00 >> + =A0 =A0 */ >> + >> + =A0 =A0/** Log file header marker size */ >> + =A0 =A0final static int LOG_FILE_HEADER_SIZE =3D 12; >> + >> + =A0 =A0/** Log file header magic number */ >> + =A0 =A0final static int LOG_FILE_HEADER_MAGIC_NUMBER =3D 0xFF00FF00; >> + >> + =A0 =A0/** Maximum marker size */ >> + =A0 =A0final static int MAX_MARKER_SIZE; >> + >> + =A0 =A0static >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0int markerSize =3D Math.max( RECORD_HEADER_SIZE, RECORD= _FOOTER_SIZE >> ); >> + =A0 =A0 =A0 =A0MAX_MARKER_SIZE =3D Math.max( markerSize, LOG_FILE_HEAD= ER_SIZE ); >> + =A0 =A0} >> + >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFlushManager.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/impl/LogFlushManager.java?rev=3D= 1177627&view=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFlushManager.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogFlushManager.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,500 @@ >> + >> +package org.apache.directory.server.log.impl; >> + >> +import java.nio.ByteBuffer; >> + >> +import java.util.concurrent.locks.Lock; >> +import java.util.concurrent.locks.ReentrantLock; >> +import java.util.concurrent.locks.Condition; >> +import java.util.concurrent.atomic.AtomicInteger; >> + >> + >> +import java.io.IOException; >> + >> +import org.apache.directory.server.i18n.I18n; >> +import org.apache.directory.server.log.InvalidLogException; >> +import org.apache.directory.server.log.LogAnchor; >> +import org.apache.directory.server.log.UserLogRecord; >> + >> +/** >> + * Manages the flushing of log to media and scanning of logs. All appen= ds >> to the log file go through this class. >> + * >> + * Internally it manages a circular =A0buffer where appends initially g= o. >> Appends are first >> + * appended to this in memory circular log. As the in memory circular l= og >> fills up or as the user requests >> + * =A0memory buffer is flushed to the underlying media. >> + * >> + * @authorApache Directory >> Project >> + */ >> +class LogFlushManager >> +{ >> + >> + =A0 =A0/** Ever increasing logical log sequence number assigned to use= r log >> records. Bumped up under append lock */ >> + =A0 =A0private long logLSN =3D Long.MIN_VALUE + 1; >> + >> + =A0 =A0/** Memory buffer size in bytes */ >> + =A0 =A0private final int logBufferSize; >> + >> + =A0 =A0/** Synchronizes appends */ >> + =A0 =A0private final Lock appendLock =3D new ReentrantLock(); >> + >> + =A0 =A0/** Synchronizes flushes to media */ >> + =A0 =A0private final Lock flushLock =3D new ReentrantLock(); >> + >> + =A0 =A0/** Used to wait on ongoing flush */ >> + =A0 =A0private final Condition flushCondition =3D flushLock.newConditi= on(); >> + >> + =A0 =A0/** In memory LogBuffer */ >> + =A0 =A0private LogBuffer logBuffer; >> + >> + =A0 =A0/** Flush status */ >> + =A0 =A0private FlushStatus flushStatus =3D new FlushStatus(); >> + >> + =A0 =A0/** Current LogFile appends go to */ >> + =A0 =A0private LogFileManager.LogFileWriter currentLogFile; >> + >> + =A0 =A0/** Log manager */ >> + =A0 =A0LogManager logManager; >> + >> + =A0 =A0/** Size of data appended to the currentLogFile so far */ >> + =A0 =A0long appendedSize; >> + >> + =A0 =A0/** Sof limit on the log file size */ >> + =A0 =A0long targetLogFileSize; >> + >> + =A0 =A0public LogFlushManager(LogManager logManager, int >> logMemoryBufferSize, long logFileSize ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if ( ( logMemoryBufferSize< =A00 ) || ( logFileSize< = =A00 ) ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0throw new IllegalArgumentException( I18n.err( I= 18n.ERR_748, >> logMemoryBufferSize, logFileSize ) ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0logBufferSize =3D logMemoryBufferSize; >> + =A0 =A0 =A0 =A0targetLogFileSize =3D logFileSize; >> + =A0 =A0 =A0 =A0this.logManager =3D logManager; >> + >> + =A0 =A0 =A0 =A0logBuffer =3D new LogBuffer( logBufferSize, currentLogF= ile ); >> + >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * Appends the given user record to the log. Position where the >> record is appended is returned as part of >> + =A0 =A0 * userRecord. >> + =A0 =A0 * >> + =A0 =A0 * @param userLogRecord provides the user data to be appended t= o the >> log >> + =A0 =A0 * @param sync if true, this calls returns after making sure th= at the >> appended data is reflected to the underlying file >> + =A0 =A0 * @throws IOException >> + =A0 =A0 * @throws InvalidLogException >> + =A0 =A0 */ >> + =A0 =A0public void append(UserLogRecord userRecord, boolean sync ) thr= ows >> IOException, InvalidLogException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0long lsn; >> + =A0 =A0 =A0 =A0boolean appendedRecord =3D false; >> + =A0 =A0 =A0 =A0byte[] userBuffer =3D userRecord.getDataBuffer(); >> + =A0 =A0 =A0 =A0int length =A0=3D userRecord.getDataLength(); >> + =A0 =A0 =A0 =A0LogAnchor userLogAnchor =3D userRecord.getLogAnchor(); >> + >> + =A0 =A0 =A0 =A0int recordSize =3D LogFileRecords.RECORD_HEADER_SIZE + >> LogFileRecords.RECORD_FOOTER_SIZE + length; >> + >> + =A0 =A0 =A0 =A0appendLock.lock(); >> + >> + =A0 =A0 =A0 =A0lsn =3D logLSN++; >> + >> + =A0 =A0 =A0 =A0if ( currentLogFile =3D=3D null ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0// We are just starting, get the current log fi= le >> + =A0 =A0 =A0 =A0 =A0 =A0currentLogFile =3D logManager.switchToNextLogFi= le( null ); >> + =A0 =A0 =A0 =A0 =A0 =A0appendedSize =3D currentLogFile.getLength(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( appendedSize> =A0this.targetLogFileSize ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0// Make sure everything outstanding goes to the= current log >> file >> + =A0 =A0 =A0 =A0 =A0 =A0this.flush( lsn, null, 0, 0, true); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0currentLogFile =3D logManager.switchToNextLogFi= le( >> currentLogFile ); >> + =A0 =A0 =A0 =A0 =A0 =A0appendedSize =3D currentLogFile.getLength(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( recordSize<=3D logBufferSize ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0ByteBuffer writeHead =3D logBuffer.writeHead; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0while ( !appendedRecord ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// First get the rewind count then the = position to which >> the readhead advanced >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int readHeadRewindCount =3D >> logBuffer.readHeadRewindCount.get(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int readHeadPosition =3D logBuffer.read= HeadPosition; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( ( logBuffer.writeHeadRewindCount = =3D=3D >> readHeadRewindCount ) || >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0( ( logBuffer.writeHeadRewindCo= unt =3D=3D >> readHeadRewindCount + 1 )&& >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0( readHeadPosition< =A0= writeHead.position() ) ) ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( writeHead.remaining()>=3D = recordSize ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.writeHeader( write= Head, length, lsn ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0writeHead.put( userBuff= er, 0, length ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.writeFooter( write= Head, 0 ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0appendedRecord =3D true= ; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else // ( writeHead.remaining()= < =A0recordSize ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( writeHead.remainin= g()>=3D >> LogFileRecords.RECORD_HEADER_SIZE ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Write a skip= record >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.writeHeade= r( writeHead, -1, -1 ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// rewind buffer now >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0writeHead.rewind(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0logBuffer.writeHeadRewi= ndCount++; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0assert( logBuffer.writeHeadRewi= ndCount =3D=3D ( >> readHeadRewindCount + 1 ) ) : >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Unexpected seq= uence number for read/write >> heads:" + logBuffer.writeHeadRewindCount + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0" " + readHeadR= ewindCount; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( ( readHeadPosition - write= Head.position() )> >> =A0recordSize ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.writeHeader( write= Head, length, lsn ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0writeHead.put( userBuff= er, 0, length ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.writeFooter( write= Head, 0 ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0appendedRecord =3D true= ; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.flush( lsn, null, = 0, 0, true); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0this.flush( lsn, userBuffer, 0, length, true ); >> + =A0 =A0 =A0 =A0} >> + >> + >> + >> + =A0 =A0 =A0 =A0userLogAnchor.resetLogAnchor( currentLogFile.logFileNum= ber(), >> appendedSize, lsn ); >> + =A0 =A0 =A0 =A0this.appendedSize +=3D recordSize; >> + >> + =A0 =A0 =A0 =A0appendLock.unlock(); >> + >> + =A0 =A0 =A0 =A0if ( sync ) >> + =A0 =A0 =A0 =A0 =A0 =A0this.flush( lsn, null, 0, 0, false ); >> + >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * Flushes the changes in the log buffer upto the given point. = The >> given point is determined as follows: >> + =A0 =A0 * appendLock is held: flushLSN is the highest lsn generated by= the >> logging system and no more appends can >> + =A0 =A0 * proceed. In this case log is flushed until where the write h= ead >> is.Log record with the flushLSN might not >> + =A0 =A0 * have been appended yet. >> + =A0 =A0 * >> + =A0 =A0 * Otherwise: Given flushLSN is appended to the log already. Lo= g is >> flushed upto max(flushLSN, current flashSatus.uptoLSN) >> + =A0 =A0 * >> + =A0 =A0 * Also userBuffer !=3D null =3D> =A0appendLockHeld =3D=3D true >> + =A0 =A0 * >> + =A0 =A0 * Only one thread can do flush. Once a thread find out that a = flush >> is already going on, it waits for the ongoing flush >> + =A0 =A0 * and is woken up to do its flush. >> + =A0 =A0 * >> + =A0 =A0 * flushStatus.uptoLSN represents the highest lsn that any thre= ad >> wanted to sync. If a couple of threads wait on sync to >> + =A0 =A0 * complete, the thread that wakes up and does the sync will ta= ke it >> for the team and sync upto flushStatus.uptoLSN so >> + =A0 =A0 * that logging is more efficient. >> + =A0 =A0 * >> + =A0 =A0 * >> + =A0 =A0 * >> + =A0 =A0 * @param flushLSN max LSN the calling thread wants to sync upt= o >> + =A0 =A0 * @param userBuffer if not null, user buffer is appended to th= e log >> without any buffering >> + =A0 =A0 * @param offset offset of data in user buffer >> + =A0 =A0 * @param length length of user data >> + =A0 =A0 * @param appendLockHeld true if append lock is held >> + =A0 =A0 * @throws IOException >> + =A0 =A0 */ >> + =A0 =A0private void flush( long flushLSN, byte[] userBuffer, int offse= t, int >> length, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0boolean appendLockHeld = ) throws IOException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0long uptoLSN =3D flushLSN; >> + >> + =A0 =A0 =A0 =A0if ( appendLockHeld =3D=3D true ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0uptoLSN--; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0flushLock.lock(); >> + >> + =A0 =A0 =A0 =A0// Update max requested lsn if necessary >> + =A0 =A0 =A0 =A0if ( uptoLSN> =A0flushStatus.uptoLSN ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0flushStatus.uptoLSN =3D uptoLSN; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0/* >> + =A0 =A0 =A0 =A0 * Check if we need to do flush and wait for ongoing fl= ush if >> + =A0 =A0 =A0 =A0 * necessary >> + =A0 =A0 =A0 =A0 */ >> + >> + =A0 =A0 =A0 =A0while ( true ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0if ( ( flushStatus.flushedLSN>=3D uptoLSN )&& = =A0( appendLockHeld >> =3D=3D false ) ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flushLock.unlock(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0if ( flushStatus.flushInProgress =3D=3D false ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0flushStatus.numWaiters++; >> + =A0 =A0 =A0 =A0 =A0 =A0flushCondition.awaitUninterruptibly(); >> + =A0 =A0 =A0 =A0 =A0 =A0flushStatus.numWaiters--; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0// Mark flush in progress and do the flush >> + =A0 =A0 =A0 =A0flushStatus.flushInProgress =3D true; >> + >> + =A0 =A0 =A0 =A0// If not appendlock held, adjust uptoLSN with the max = one >> requested by any thread >> + =A0 =A0 =A0 =A0if ( appendLockHeld =3D=3D false ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0uptoLSN =3D flushStatus.uptoLSN; >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0uptoLSN =3D flushLSN; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0flushLock.unlock(); >> + >> + =A0 =A0 =A0 =A0long flushedLSN =3D this.doFlush( uptoLSN, appendLockHe= ld ); >> + >> + =A0 =A0 =A0 =A0// Now if there is a user buffer, flush from that >> + =A0 =A0 =A0 =A0if ( userBuffer !=3D null ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0ByteBuffer headerFooterHead =3D logBuffer.heade= rFooterHead; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0headerFooterHead.rewind(); >> + =A0 =A0 =A0 =A0 =A0 =A0this.writeHeader( headerFooterHead, length, flu= shLSN ); >> + =A0 =A0 =A0 =A0 =A0 =A0currentLogFile.append( logBuffer.headerFooterBu= ffer, 0, >> LogFileRecords.RECORD_HEADER_MAGIC_NUMBER ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0currentLogFile.append( userBuffer, offset, leng= th ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0headerFooterHead.rewind(); >> + =A0 =A0 =A0 =A0 =A0 =A0this.writeFooter( headerFooterHead, 0 ); >> + =A0 =A0 =A0 =A0 =A0 =A0currentLogFile.append( logBuffer.headerFooterBu= ffer, 0, >> LogFileRecords.RECORD_FOOTER_SIZE ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0flushedLSN =3D flushLSN; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0currentLogFile.sync(); >> + >> + =A0 =A0 =A0 =A0flushLock.lock(); >> + >> + =A0 =A0 =A0 =A0if ( flushedLSN !=3D LogAnchor.UNKNOWN_LSN ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0flushStatus.flushedLSN =3D flushedLSN; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0if ( flushStatus.flushedLSN> =A0flushStatus.upt= oLSN ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// This should only happen with append = lock held >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0assert( appendLockHeld =3D=3D true ) : = "FlushedLSN went ahead >> of uptoLSN while appendlock is not held: " + flushStatus.flushedLSN + " = =A0" + >> flushStatus.uptoLSN; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flushStatus.uptoLSN =3D flushStatus.flu= shedLSN; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0flushStatus.flushInProgress =3D false; >> + >> + =A0 =A0 =A0 =A0if ( flushStatus.numWaiters !=3D 0 ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0flushCondition.signalAll(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0flushLock.unlock(); >> + =A0 =A0} >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * Walks the log buffer and writes it to the underlying log fil= e >> until the uptoLSN or current write head. >> + =A0 =A0 * >> + =A0 =A0 * @param uptoLSN max LSN until where log is flushed >> + =A0 =A0 * @param appendLockHeld true if appendlock held. >> + =A0 =A0 * @return lsn upto which flush is done. UNKNOWN_LSN if no flus= hing >> is done. >> + =A0 =A0 * @throws IOException >> + =A0 =A0 */ >> + =A0 =A0private long doFlush( long uptoLSN, boolean appendLockHeld =A0)= throws >> IOException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0ByteBuffer readHead =3D logBuffer.readHead; >> + =A0 =A0 =A0 =A0ByteBuffer writeHead =3D logBuffer.writeHead; >> + =A0 =A0 =A0 =A0boolean done =3D false; >> + >> + =A0 =A0 =A0 =A0int magicNumber; >> + =A0 =A0 =A0 =A0int length; >> + =A0 =A0 =A0 =A0long lsn =3D LogAnchor.UNKNOWN_LSN; >> + >> + =A0 =A0 =A0 =A0while ( !done ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0int totalLength =3D 0; >> + =A0 =A0 =A0 =A0 =A0 =A0while( true ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 * If append lock is held, we might hit= write head. We >> can read >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 * the write head here when append lock= is held >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( appendLockHeld ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( ( writeHead.position() =3D= =3D readHead.position() >> )&& >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0( logBuffer.wri= teHeadRewindCount =3D=3D >> logBuffer.readHeadRewindCount.get() ) ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0done =3D true; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// If less than header length left to p= rocess, then break >> and flush whatever we got so far >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( readHead.remaining()< >> =A0LogFileRecords.RECORD_HEADER_SIZE ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0magicNumber =3D readHead.getInt(); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0assert( magicNumber =3D=3D >> LogFileRecords.RECORD_HEADER_MAGIC_NUMBER ) : " Record header magic " + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "number do= es not match " + magicNumber + " >> expected "+ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 LogFileRec= ords.RECORD_HEADER_MAGIC_NUMBER; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0length =3D readHead.getInt(); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Did we hit a skip record at the end = of the buffer? >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( length =3D=3D LogBuffer.SKIP_RECOR= D_LENGTH ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Sanitize length, it includes header = and footer >> overhead >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0assert( length> =A0 ( >> LogFileRecords.RECORD_HEADER_MAGIC_NUMBER + >> LogFileRecords.RECORD_FOOTER_MAGIC_NUMBER) ) : >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Record length doesnt make sens= e:" + length + " >> expected:" + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0( LogFileRecords.RECORD_HEADER_= MAGIC_NUMBER + >> LogFileRecords.RECORD_FOOTER_MAGIC_NUMBER); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Add to the total length >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0totalLength +=3D length; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0lsn =3D readHead.getLong(); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Move to the next record, we processe= d 16 bytes already >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0readHead.position( readHead.position() = + length - 16 ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( lsn>=3D uptoLSN ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0done =3D true; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0// If there is something to flush, then do it n= ow >> + =A0 =A0 =A0 =A0 =A0 =A0if ( totalLength> =A00 ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0int offset; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0offset =3D logBuffer.readHeadPosition; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0currentLogFile.append( logBuffer.buffer= , offset, >> totalLength ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0//move the position to the next record >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0logBuffer.readHeadPosition =3D readHead= .position(); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0if ( !done ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// this means we need to rewind and kee= p flushing >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0logBuffer.readHeadPosition =3D 0; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0readHead.rewind(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0logBuffer.readHeadRewindCount.increment= AndGet(); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0return lsn; >> + >> + =A0 =A0} >> + >> + =A0 =A0private void writeHeader ( ByteBuffer buffer, int length, long = lsn ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0buffer.putInt( LogFileRecords.RECORD_HEADER_MAGIC_NUMBE= R ); >> + =A0 =A0 =A0 =A0buffer.putInt( length ); >> + =A0 =A0 =A0 =A0buffer.putLong( lsn ); >> + =A0 =A0 =A0 =A0buffer.putLong( length ^ lsn ); >> + =A0 =A0} >> + >> + =A0 =A0private void writeFooter ( ByteBuffer buffer, int checksum ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0buffer.putInt( checksum ); >> + =A0 =A0 =A0 =A0buffer.putInt( LogFileRecords.RECORD_FOOTER_MAGIC_NUMBE= R ); >> + =A0 =A0} >> + >> + >> + =A0 =A0/** >> + =A0 =A0 * Used to group the memory buffer data together >> + =A0 =A0 */ >> + =A0 =A0private static class LogBuffer >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0/** In memory buffer */ >> + =A0 =A0 =A0 =A0byte buffer[]; >> + >> + =A0 =A0 =A0 =A0/** Used to scan the buffer while reading it to flush *= / >> + =A0 =A0 =A0 =A0ByteBuffer readHead; >> + >> + =A0 =A0 =A0 =A0/** Advanced as readHead flushes data */ >> + =A0 =A0 =A0 =A0int readHeadPosition; >> + >> + =A0 =A0 =A0 =A0/** Rewind count of readHead..used to avoid overwriting >> nonflushed data */ >> + =A0 =A0 =A0 =A0AtomicInteger readHeadRewindCount; >> + >> + =A0 =A0 =A0 =A0/** Used to scan the buffer while appending records int= o it */ >> + =A0 =A0 =A0 =A0ByteBuffer writeHead; >> + >> + =A0 =A0 =A0 =A0/** Rewind count of writeHead..used to avoid overwritin= g >> nonflushed data */ >> + =A0 =A0 =A0 =A0int writeHeadRewindCount; >> + >> + =A0 =A0 =A0 =A0/** Used to mark records that should be skipped at the = end of the >> log buffer */ >> + =A0 =A0 =A0 =A0final static int SKIP_RECORD_LENGTH =3D -1; >> + >> + =A0 =A0 =A0 =A0/** Header footer buffer used when writing user buffers= directly >> */ >> + =A0 =A0 =A0 =A0byte headerFooterBuffer[]; >> + >> + =A0 =A0 =A0 =A0/** Used to format header footer buffer */ >> + =A0 =A0 =A0 =A0ByteBuffer headerFooterHead; >> + >> + =A0 =A0 =A0 =A0public LogBuffer( int bufferSize, LogFileManager.LogFil= eWriter >> currentLogFile ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0buffer =3D new byte[bufferSize]; >> + =A0 =A0 =A0 =A0 =A0 =A0readHead =3D ByteBuffer.wrap( buffer ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0readHeadRewindCount =3D new AtomicInteger( 0 ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0writeHead =3D ByteBuffer.wrap( buffer ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0headerFooterBuffer =3D new >> byte[LogFileRecords.MAX_MARKER_SIZE]; >> + =A0 =A0 =A0 =A0 =A0 =A0headerFooterHead =3D ByteBuffer.wrap( headerFoo= terBuffer ); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * Used to group the flush related data together >> + =A0 =A0 */ >> + =A0 =A0private static class FlushStatus >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0/** whether flush is going on */ >> + =A0 =A0 =A0 =A0boolean flushInProgress; >> + >> + =A0 =A0 =A0 =A0/** Current flush request */ >> + =A0 =A0 =A0 =A0long uptoLSN; >> + >> + >> + =A0 =A0 =A0 =A0/** Current flushed lsn */ >> + =A0 =A0 =A0 =A0long flushedLSN; >> + >> + >> + =A0 =A0 =A0 =A0/** Keeps track of the number of waiters */ >> + =A0 =A0 =A0 =A0int numWaiters; >> + =A0 =A0} >> +} >> >> Added: >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogManager.java >> URL: >> http://svn.apache.org/viewvc/directory/apacheds/trunk/xdbm-partition/src= /main/java/org/apache/directory/server/log/impl/LogManager.java?rev=3D11776= 27&view=3Dauto >> >> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D >> --- >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogManager.java >> (added) >> +++ >> directory/apacheds/trunk/xdbm-partition/src/main/java/org/apache/directo= ry/server/log/impl/LogManager.java >> Fri Sep 30 12:28:59 2011 >> @@ -0,0 +1,494 @@ >> + >> +package org.apache.directory.server.log.impl; >> + >> +import java.nio.ByteBuffer; >> + >> +import java.util.concurrent.locks.ReentrantLock; >> +import java.util.concurrent.locks.Lock; >> + >> +import java.io.IOException; >> +import java.io.FileNotFoundException; >> +import java.io.EOFException; >> + >> +import org.apache.directory.server.i18n.I18n; >> +import org.apache.directory.server.log.InvalidLogException; >> +import org.apache.directory.server.log.LogAnchor; >> +import org.apache.directory.server.log.LogAnchorComparator; >> +import org.apache.directory.server.log.LogScanner; >> +import org.apache.directory.server.log.UserLogRecord; >> + >> +class LogManager >> +{ >> + >> + =A0 =A0/** =A0Controlfile record size */ >> + =A0 =A0private final static int CONTROLFILE_RECORD_SIZE =3D 36; >> + >> + =A0 =A0/** Controlfile file magic number */ >> + =A0 =A0private final static int CONTROLFILE_MAGIC_NUMBER =3D 0xFF11FF1= 1; >> + >> + =A0 =A0/** Controlfile log file number */ >> + =A0 =A0private final static long CONTROLFILE_LOG_FILE_NUMBER =3D -1; >> + >> + =A0 =A0/** Shadow Controlfile log file number */ >> + =A0 =A0private final static long CONTROLFILE_SHADOW_LOG_FILE_NUMBER = =3D -2; >> + >> + =A0 =A0/** buffer used to do IO on controlfile */ >> + =A0 =A0byte controlFileBuffer[] =3D new byte[CONTROLFILE_RECORD_SIZE]; >> + >> + =A0 =A0/** ByteBuffer used to to IO on checkpoint file */ >> + =A0 =A0ByteBuffer controlFileMarker =3D ByteBuffer.wrap( controlFileBu= ffer ); >> + >> + =A0 =A0/** Current checkpoint record in memory */ >> + =A0 =A0ControlFileRecord controlFileRecord =3D new ControlFileRecord()= ; >> + >> + =A0 =A0/** Min neeeded point in the log */ >> + =A0 =A0LogAnchor minLogAnchor =3D new LogAnchor(); >> + >> + =A0 =A0/** Protects minLogAchor */ >> + =A0 =A0Lock minLogAnchorLock =3D new ReentrantLock(); >> + >> + =A0 =A0/** Log file manager */ >> + =A0 =A0LogFileManager logFileManager; >> + >> + =A0 =A0/** Log Anchor comparator */ >> + =A0 =A0LogAnchorComparator anchorComparator =3D new LogAnchorComparato= r(); >> + >> + =A0 =A0/** Current log file */ >> + =A0 =A0private long currentLogFileNumber; >> + >> + =A0 =A0/** Buffer used to read log file markers */ >> + =A0 =A0byte markerBuffer[] =3D new byte[LogFileRecords.LOG_FILE_HEADER= _SIZE]; >> + >> + =A0 =A0/** ByteBuffer wrapper for the marker buffer */ >> + =A0 =A0ByteBuffer markerHead =3D ByteBuffer.wrap( markerBuffer ); >> + >> + >> + =A0 =A0public LogManager( LogFileManager logFileManager ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0this.logFileManager =3D logFileManager; >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 *Initializes the log management: >> + =A0 =A0 * 1) Checks if control file exists and creates it if necesssar= y. If >> it exists, it reads it and loads the latest checkpoint. >> + =A0 =A0 * 2) Starts from the lates checkpoint ans scans forwards the l= ogs to >> check for corrupted logs and determine the end of the log. >> + =A0 =A0 * This scan ends either when a properly ended log file is foun= d or a >> partially written log record is found. >> + =A0 =A0 * >> + =A0 =A0 * @throws IOException >> + =A0 =A0 * @throws InvalidLogException >> + =A0 =A0 */ >> + =A0 =A0public void initLogManager() throws IOException, InvalidLogExce= ption >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0LogAnchor scanPoint =3D new LogAnchor(); >> + =A0 =A0 =A0 =A0LogScanner scanner; >> + =A0 =A0 =A0 =A0UserLogRecord logRecord; >> + =A0 =A0 =A0 =A0LogFileManager.LogFileReader reader; >> + >> + >> + >> + =A0 =A0 =A0 =A0// Read and verify control file >> + =A0 =A0 =A0 =A0boolean controlFileExists =3D true; >> + =A0 =A0 =A0 =A0try >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0this.readControlFile(); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0catch( FileNotFoundException e ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0controlFileExists =3D false; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( controlFileExists ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0boolean invalidLog =3D false; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0// Set the min log anchor from the control file >> + =A0 =A0 =A0 =A0 =A0 =A0minLogAnchor.resetLogAnchor( >> controlFileRecord.minNeededLogFile, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0controlFileRecord.minNeededLogF= ileOffset, >> controlFileRecord.minNeededLSN ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0scanPoint.resetLogAnchor( minLogAnchor ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0logRecord =3D new UserLogRecord(); >> + =A0 =A0 =A0 =A0 =A0 =A0scanner =3D new DefaultLogScanner( scanPoint, l= ogFileManager ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0try >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0while ( scanner.getNextRecord( logRecor= d ) ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// No need to do anything with = the log record >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0catch( InvalidLogException e ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0invalidLog =3D true; >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0finally >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0scanner.close(); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0long lastGoodLogFileNumber =3D scanner.getLastG= oodFileNumber(); >> + =A0 =A0 =A0 =A0 =A0 =A0long lastGoodLogFileOffset =3D scanner.getLastG= oodOffset(); >> + =A0 =A0 =A0 =A0 =A0 =A0currentLogFileNumber =3D lastGoodLogFileNumber; >> + >> + =A0 =A0 =A0 =A0 =A0 =A0if ( ( lastGoodLogFileNumber< =A0LogAnchor.MIN_= LOG_NUMBER ) || >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0( lastGoodLogFileOffset< =A0LogAnchor.M= IN_LOG_OFFSET )) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0throw new InvalidLogException( I18n.err= ( I18n.ERR_750 ) >> ); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0scanPoint.resetLogAnchor( lastGoodLogFileNumber= , >> lastGoodLogFileOffset, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0LogAnchor.UNKNOWN_LSN ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0if ( anchorComparator.compare( scanPoint, minLo= gAnchor )< =A00 >> ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0throw new InvalidLogException( I18n.err= ( I18n.ERR_750 ) >> ); >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0/* >> + =A0 =A0 =A0 =A0 =A0 =A0 * If invalid content at the end of file: >> + =A0 =A0 =A0 =A0 =A0 =A0 * if we are past the header of file, then >> + =A0 =A0 =A0 =A0 =A0 =A0 * truncate the file to the end of the last >> + =A0 =A0 =A0 =A0 =A0 =A0 * read log record, otherwise we read a partial= ly >> + =A0 =A0 =A0 =A0 =A0 =A0 * written log file header, in this case reform= at the log >> file. >> + =A0 =A0 =A0 =A0 =A0 =A0 * Also check next for the existence of next fi= le to make >> + =A0 =A0 =A0 =A0 =A0 =A0 * sure we really read the last log file. >> + =A0 =A0 =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0 =A0 =A0if ( invalidLog ) >> + =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Check if next log file exists >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reader =3D null; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0try >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reader =3D logFileManager.getRe= aderForLogFile( ( >> lastGoodLogFileNumber + 1 ) ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0catch ( FileNotFoundException e ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Fine, this is what we want >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0finally >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( reader !=3D null ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0reader.close(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if ( reader !=3D null ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0throw new InvalidLogException( = I18n.err( I18n.ERR_750 >> ) ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if =A0( lastGoodLogFileOffset>=3D >> LogFileRecords.LOG_FILE_HEADER_SIZE =A0) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0logFileManager.truncateLogFile( >> lastGoodLogFileNumber, lastGoodLogFileOffset ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0else >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Reformat the existing log fi= le >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0this.createNextLogFile( true); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0/* >> + =A0 =A0 =A0 =A0 =A0 =A0 * Control file does not exist. Either we are a= t the very >> beginning or >> + =A0 =A0 =A0 =A0 =A0 =A0 * maybe we crashed in the middle of creating t= he first log >> file. >> + =A0 =A0 =A0 =A0 =A0 =A0 * We =A0should have the min log file at most w= ith the file >> header formatted. >> + =A0 =A0 =A0 =A0 =A0 =A0 */ >> + =A0 =A0 =A0 =A0 =A0 reader =3D null; >> + =A0 =A0 =A0 =A0 =A0 boolean fileExists =3D false; >> + =A0 =A0 =A0 =A0 =A0 currentLogFileNumber =3D LogAnchor.MIN_LOG_NUMBER; >> + =A0 =A0 =A0 =A0 =A0 try >> + =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 reader =3D logFileManager.getReaderForLogF= ile( >> LogAnchor.MIN_LOG_NUMBER ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ( reader.getLength()> >> =A0LogFileRecords.LOG_FILE_HEADER_SIZE ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 throw new InvalidLogException( I18= n.err( I18n.ERR_750 >> ) ); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 fileExists =3D true; >> + =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 catch ( FileNotFoundException e ) >> + =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 // Fine, we will create the file >> + =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 finally >> + =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ( reader !=3D null ) >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 { >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 reader.close(); >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } >> + =A0 =A0 =A0 =A0 =A0 } >> + >> + >> + >> + =A0 =A0 =A0 =A0 =A0 this.createNextLogFile( fileExists ); >> + >> + =A0 =A0 =A0 =A0 =A0 =A0// Prepare the min log anchor and control file = and write the >> control file >> + =A0 =A0 =A0 =A0 =A0 minLogAnchor.resetLogAnchor( LogAnchor.MIN_LOG_NUM= BER, >> LogFileRecords.LOG_FILE_HEADER_SIZE, LogAnchor.UNKNOWN_LSN ); >> + >> + =A0 =A0 =A0 =A0 =A0 this.writeControlFile(); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * Called by LogFlushManager to switch to the next file. >> + =A0 =A0 * >> + =A0 =A0 * Note:Currently we do a checkpoint and delete unnecessary log= files >> when we switch to a new file. Some >> + =A0 =A0 * of this tasks can be delegated to a background thread later. >> + =A0 =A0 * >> + =A0 =A0 * @param currentWriter current log file used by the flush mana= ger. >> Null if the flush manager is just starting up. >> + =A0 =A0 * @return new lgo file to be used. >> + =A0 =A0 * @throws IOException >> + =A0 =A0 * @throws InvalidLogException >> + =A0 =A0 */ >> + =A0 =A0public LogFileManager.LogFileWriter switchToNextLogFile( >> LogFileManager.LogFileWriter currentWriter ) throws IOException, >> InvalidLogException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if ( currentWriter !=3D null ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0currentWriter.close(); >> + =A0 =A0 =A0 =A0 =A0 =A0this.writeControlFile(); >> + =A0 =A0 =A0 =A0 =A0 =A0this.createNextLogFile( false ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0return logFileManager.getWriterForLogFile( >> this.currentLogFileNumber ); >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * Called when the logging subsystem is notified about the mini= mum >> position >> + =A0 =A0 * in the log files that is needed. Log manager uses this infor= mation >> to advance >> + =A0 =A0 * its checkpoint and delete unnecessary log files. >> + =A0 =A0 * >> + =A0 =A0 * @param newLogAnchor min needed log anchor >> + =A0 =A0 */ >> + =A0 =A0public void advanceMinLogAnchor( LogAnchor newLogAnchor ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0if ( newLogAnchor =3D=3D null ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0return; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0minLogAnchorLock.lock(); >> + >> + =A0 =A0 =A0 =A0if ( anchorComparator.compare( minLogAnchor, newLogAnch= or )< =A00 ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0minLogAnchor.resetLogAnchor( newLogAnchor ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0minLogAnchorLock.unlock(); >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * Writes the control file. To make paritally written control f= iles >> unlikely, >> + =A0 =A0 * data is first written to a shadow file and then moved(rename= d) to >> the controlfile. >> + =A0 =A0 * Move of a file is atomic in POSIX systems, in GFS like file >> systems(in HDFS for example). >> + =A0 =A0 * On windows, it is not always atomic but atomic versions of r= ename >> operations started to >> + =A0 =A0 * appear in their recent file systems. >> + =A0 =A0 * >> + =A0 =A0 * @throws IOException >> + =A0 =A0 */ >> + =A0 =A0private void writeControlFile() throws IOException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0// Copy the min log file anchor >> + =A0 =A0 =A0 =A0minLogAnchorLock.lock(); >> + >> + =A0 =A0 =A0 =A0controlFileRecord.minNeededLogFile =3D >> minLogAnchor.getLogFileNumber(); >> + =A0 =A0 =A0 =A0controlFileRecord.minNeededLogFileOffset =3D >> minLogAnchor.getLogFileOffset(); >> + =A0 =A0 =A0 =A0controlFileRecord.minNeededLSN =3D minLogAnchor.getLogL= SN(); >> + >> + =A0 =A0 =A0 =A0minLogAnchorLock.unlock(); >> + >> + =A0 =A0 =A0 =A0if ( controlFileRecord.minNeededLogFile> >> =A0controlFileRecord.minExistingLogFile =A0) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0this.deleteUnnecessaryLogFiles( >> controlFileRecord.minExistingLogFile,controlFileRecord.minNeededLogFile = ); >> + =A0 =A0 =A0 =A0 =A0 =A0controlFileRecord.minExistingLogFile =3D >> controlFileRecord.minNeededLogFile; >> + >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0// TODO compute checksum for log record here >> + >> + >> + =A0 =A0 =A0 =A0controlFileMarker.rewind(); >> + =A0 =A0 =A0 =A0controlFileMarker.putLong( controlFileRecord.minExistin= gLogFile >> ); >> + =A0 =A0 =A0 =A0controlFileMarker.putLong( controlFileRecord.minNeededL= ogFile ); >> + =A0 =A0 =A0 =A0controlFileMarker.putLong( >> controlFileRecord.minNeededLogFileOffset ); >> + =A0 =A0 =A0 =A0controlFileMarker.putLong( controlFileRecord.minNeededL= SN ); >> + =A0 =A0 =A0 =A0controlFileMarker.putLong( controlFileRecord.checksum )= ; >> + =A0 =A0 =A0 =A0controlFileMarker.putInt( CONTROLFILE_MAGIC_NUMBER ); >> + >> + >> + =A0 =A0 =A0 =A0boolean shadowFileExists =3D logFileManager.createLogFi= le( >> CONTROLFILE_SHADOW_LOG_FILE_NUMBER =A0); >> + >> + =A0 =A0 =A0 =A0if ( shadowFileExists ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0logFileManager.truncateLogFile( >> CONTROLFILE_SHADOW_LOG_FILE_NUMBER, 0 ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0LogFileManager.LogFileWriter controlFileWriter =3D >> logFileManager.getWriterForLogFile( CONTROLFILE_SHADOW_LOG_FILE_NUMBER )= ; >> + >> + =A0 =A0 =A0 =A0try >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0controlFileWriter.append( controlFileBuffer, 0, >> CONTROLFILE_RECORD_SIZE); >> + =A0 =A0 =A0 =A0 =A0 =A0controlFileWriter.sync(); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0finally >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0controlFileWriter.close(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0// Do the move now >> + =A0 =A0 =A0 =A0logFileManager.rename( CONTROLFILE_SHADOW_LOG_FILE_NUMB= ER , >> CONTROLFILE_LOG_FILE_NUMBER ); >> + >> + >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * Read and verifies the control file. >> + =A0 =A0 * >> + =A0 =A0 * @throws IOException >> + =A0 =A0 * @throws InvalidLogException >> + =A0 =A0 * @throws FileNotFoundException >> + =A0 =A0 */ >> + =A0 =A0private void readControlFile() throws IOException, >> InvalidLogException, FileNotFoundException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0boolean invalidControlFile =3D false; >> + =A0 =A0 =A0 =A0LogFileManager.LogFileReader controlFileReader =3D >> logFileManager.getReaderForLogFile( CONTROLFILE_LOG_FILE_NUMBER ); >> + >> + =A0 =A0 =A0 =A0try >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0controlFileReader.read( controlFileBuffer, 0, >> CONTROLFILE_RECORD_SIZE ); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0catch( EOFException e ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0throw new InvalidLogException( I18n.err( I18n.E= RR_750 ) , e); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0finally >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0controlFileReader.close(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0controlFileMarker.rewind(); >> + =A0 =A0 =A0 =A0controlFileRecord.minExistingLogFile =3D >> controlFileMarker.getLong(); >> + =A0 =A0 =A0 =A0controlFileRecord.minNeededLogFile =3D controlFileMarke= r.getLong(); >> + =A0 =A0 =A0 =A0controlFileRecord.minNeededLogFileOffset =3D >> controlFileMarker.getLong(); >> + =A0 =A0 =A0 =A0controlFileRecord.minNeededLSN =3D controlFileMarker.ge= tLong(); >> + =A0 =A0 =A0 =A0controlFileRecord.checksum =3D controlFileMarker.getLon= g(); >> + =A0 =A0 =A0 =A0int magicNumber =3D controlFileMarker.getInt(); >> + >> + >> + =A0 =A0 =A0 =A0if ( controlFileRecord.minExistingLogFile< >> =A0LogAnchor.MIN_LOG_NUMBER ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalidControlFile =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( (controlFileRecord.minNeededLogFile< >> =A0LogAnchor.MIN_LOG_NUMBER ) || >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0( controlFileRecord.minNeededLogFileOffset< >> =A0LogAnchor.MIN_LOG_OFFSET ) ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalidControlFile =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( controlFileRecord.minExistingLogFile> >> =A0controlFileRecord.minNeededLogFile ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalidControlFile =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( magicNumber !=3D this.CONTROLFILE_MAGIC_NUMBER ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0invalidControlFile =3D true; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0// TODO compute and compare checksum >> + >> + =A0 =A0 =A0 =A0if ( invalidControlFile =3D=3D true ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0throw new InvalidLogException( I18n.err( I18n.E= RR_750 ) ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * Creates the next log file. If the log file already exists, t= hen it >> is reformatted, that is, >> + =A0 =A0 * its size is truncated to zero and file header is writtten ag= ain. >> + =A0 =A0 * >> + =A0 =A0 * @param reformatExistingFile log file already exists and shou= ld be >> formatted. If false, log file should not exist. >> + =A0 =A0 * @throws IOException >> + =A0 =A0 * @throws InvalidLogException >> + =A0 =A0 */ >> + =A0 =A0private void createNextLogFile( boolean reformatExistingFile ) = throws >> IOException, InvalidLogException >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0LogFileManager.LogFileWriter writer =3D null; >> + >> + =A0 =A0 =A0 =A0long logFileNumber =3D this.currentLogFileNumber; >> + >> + =A0 =A0 =A0 =A0if ( reformatExistingFile =3D=3D false ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0logFileNumber++; >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0// Try to create the file. >> + =A0 =A0 =A0 =A0boolean fileAlreadyExists =3D logFileManager.createLogF= ile( >> logFileNumber ); >> + >> + =A0 =A0 =A0 =A0if ( ( reformatExistingFile =3D=3D false )&& =A0( fileA= lreadyExists =3D=3D >> true ) ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0// Didnt expect the file to be around >> + =A0 =A0 =A0 =A0 =A0 =A0throw new InvalidLogException( I18n.err( I18n.E= RR_750 ) ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( ( reformatExistingFile =3D=3D true )&& =A0( fileAl= readyExists =3D=3D >> false ) ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0// Didnt expect the file to be around >> + =A0 =A0 =A0 =A0 =A0 =A0throw new InvalidLogException( I18n.err( I18n.E= RR_750 ) ); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0if ( reformatExistingFile ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0logFileManager.truncateLogFile( logFileNumber, >> LogAnchor.MIN_LOG_OFFSET ); >> + >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0writer =3D logFileManager.getWriterForLogFile( logFileN= umber ); >> + >> + =A0 =A0 =A0 =A0try >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0markerHead.rewind(); >> + =A0 =A0 =A0 =A0 =A0 =A0markerHead.putLong( logFileNumber ); >> + =A0 =A0 =A0 =A0 =A0 =A0markerHead.putInt( >> LogFileRecords.LOG_FILE_HEADER_MAGIC_NUMBER ); >> + =A0 =A0 =A0 =A0 =A0 =A0writer.append( markerBuffer, 0, >> LogFileRecords.LOG_FILE_HEADER_SIZE ); >> + =A0 =A0 =A0 =A0 =A0 =A0writer.sync(); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0 =A0 =A0finally >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0writer.close(); >> + =A0 =A0 =A0 =A0} >> + >> + =A0 =A0 =A0 =A0this.currentLogFileNumber =3D logFileNumber; >> + >> + =A0 =A0} >> + >> + =A0 =A0private void deleteUnnecessaryLogFiles( long startingLogFileNum= ber, >> long endingLogFileNumber ) >> + =A0 =A0{ >> + =A0 =A0 =A0 =A0for ( long logFileNumber =3D startingLogFileNumber; log= FileNumber< >> =A0endingLogFileNumber; >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0logFileNumber++ ) >> + =A0 =A0 =A0 =A0{ >> + =A0 =A0 =A0 =A0 =A0 =A0// Do a best effort delete >> + =A0 =A0 =A0 =A0 =A0 =A0logFileManager.deleteLogFile( logFileNumber ); >> + =A0 =A0 =A0 =A0} >> + =A0 =A0} >> + >> + =A0 =A0/** >> + =A0 =A0 * Checkpoint record >> + =A0 =A0 */ >> + =A0 =A0 private class ControlFileRecord >> + =A0 =A0 { >> + =A0 =A0 =A0 =A0 long minExistingLogFile; >> + =A0 =A0 =A0 =A0 long minNeededLogFile; >> + =A0 =A0 =A0 =A0 long minNeededLogFileOffset; >> + =A0 =A0 =A0 =A0 long minNeededLSN; >> + =A0 =A0 =A0 =A0 long checksum; >> + =A0 =A0 } >> + >> + >> + >> +} >> >> > >