package com.sleepycat.je.utilint; import java.util.Arrays; import com.sleepycat.je.log.FileManager; import com.sleepycat.je.log.LogReadable; import com.sleepycat.je.tree.TreeUtils; import de.ovgu.cide.jakutil.*; /** * DbLsn is a class that operates on Log Sequence Numbers (LSNs). An LSN is a * long comprised of a file number (32b) and offset within that file (32b) * which references a unique record in the database environment log. While * LSNs are represented as long's, we operate on them using an abstraction and * return longs from these methods so that we don't have to worry about the * lack of unsigned quantities. */ public class DbLsn { static final long INT_MASK=0xFFFFFFFFL; public static final long MAX_FILE_OFFSET=0xFFFFFFFFL; public static final long NULL_LSN=-1; private DbLsn(){ } public static long makeLsn( long fileNumber, long fileOffset){ return fileOffset & INT_MASK | ((fileNumber & INT_MASK) << 32); } public static long longToLsn( Long lsn){ if (lsn == null) { return NULL_LSN; } return lsn.longValue(); } /** * Return the file number for this DbLsn. * @return the number for this DbLsn. */ public static long getFileNumber( long lsn){ return (lsn >> 32) & INT_MASK; } /** * Return the file offset for this DbLsn. * @return the offset for this DbLsn. */ public static long getFileOffset( long lsn){ return (lsn & INT_MASK); } private static int compareLong( long l1, long l2){ if (l1 < l2) { return -1; } else if (l1 > l2) { return 1; } else { return 0; } } public static int compareTo( long lsn1, long lsn2){ if (lsn1 == NULL_LSN || lsn2 == NULL_LSN) { throw new NullPointerException(); } long fileNumber1=getFileNumber(lsn1); long fileNumber2=getFileNumber(lsn2); if (fileNumber1 == fileNumber2) { return compareLong(getFileOffset(lsn1),getFileOffset(lsn2)); } else { return compareLong(fileNumber1,fileNumber2); } } public static String toString( long lsn){ return "<DbLsn val=\"0x" + Long.toHexString(getFileNumber(lsn)) + "/0x"+ Long.toHexString(getFileOffset(lsn))+ "\"/>"; } public static String getNoFormatString( long lsn){ return "0x" + Long.toHexString(getFileNumber(lsn)) + "/0x"+ Long.toHexString(getFileOffset(lsn)); } public static String dumpString( long lsn, int nSpaces){ StringBuffer sb=new StringBuffer(); sb.append(TreeUtils.indent(nSpaces)); sb.append(toString(lsn)); return sb.toString(); } /** * Return the logsize in bytes between these two LSNs. This is an * approximation; the logs might actually be a little more or less in * size. This assumes that no log files have been cleaned. */ public static long getNoCleaningDistance( long thisLsn, long otherLsn, long logFileSize){ long diff=0; assert thisLsn != NULL_LSN; long myFile=getFileNumber(thisLsn); if (otherLsn == NULL_LSN) { otherLsn=0; } long otherFile=getFileNumber(otherLsn); if (myFile == otherFile) { diff=Math.abs(getFileOffset(thisLsn) - getFileOffset(otherLsn)); } else if (myFile > otherFile) { diff=calcDiff(myFile - otherFile,logFileSize,thisLsn,otherLsn); } else { diff=calcDiff(otherFile - myFile,logFileSize,otherLsn,thisLsn); } return diff; } /** * Return the logsize in bytes between these two LSNs. This is an * approximation; the logs might actually be a little more or less in * size. This assumes that log files might have been cleaned. */ public static long getWithCleaningDistance( long thisLsn, FileManager fileManager, long otherLsn, long logFileSize){ long diff=0; assert thisLsn != NULL_LSN; long myFile=getFileNumber(thisLsn); if (otherLsn == NULL_LSN) { otherLsn=0; } long otherFile=getFileNumber(otherLsn); if (myFile == otherFile) { diff=Math.abs(getFileOffset(thisLsn) - getFileOffset(otherLsn)); } else { Long[] fileNums=fileManager.getAllFileNumbers(); int myFileIdx=Arrays.binarySearch(fileNums,new Long(myFile)); int otherFileIdx=Arrays.binarySearch(fileNums,new Long(otherFile)); if (myFileIdx > otherFileIdx) { diff=calcDiff(myFileIdx - otherFileIdx,logFileSize,thisLsn,otherLsn); } else { diff=calcDiff(otherFileIdx - myFileIdx,logFileSize,otherLsn,thisLsn); } } return diff; } private static long calcDiff( long fileDistance, long logFileSize, long laterLsn, long earlierLsn){ long diff=fileDistance * logFileSize; diff+=getFileOffset(laterLsn); diff-=getFileOffset(earlierLsn); return diff; } /** * @see LogReadable#logEntryIsTransactional. */ public boolean logEntryIsTransactionalX(){ return false; } /** * @see LogReadable#getTransactionId */ public long getTransactionIdX(){ return 0; } }