001: /*-
002: * See the file LICENSE for redistribution information.
003: *
004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
005: *
006: * $Id: DbLsn.java,v 1.51.2.3 2008/01/07 15:14:18 cwl Exp $
007: */
008:
009: package com.sleepycat.je.utilint;
010:
011: import java.util.Arrays;
012:
013: import com.sleepycat.je.log.FileManager;
014: import com.sleepycat.je.tree.TreeUtils;
015:
016: /**
017: * DbLsn is a class that operates on Log Sequence Numbers (LSNs). An LSN is a
018: * long comprised of a file number (32b) and offset within that file (32b)
019: * which references a unique record in the database environment log. While
020: * LSNs are represented as long's, we operate on them using an abstraction and
021: * return longs from these methods so that we don't have to worry about the
022: * lack of unsigned quantities.
023: */
024: public class DbLsn {
025: static final long INT_MASK = 0xFFFFFFFFL;
026:
027: public static final long MAX_FILE_OFFSET = 0xFFFFFFFFL;
028:
029: public static final long NULL_LSN = -1;
030:
031: private DbLsn() {
032: }
033:
034: public static long makeLsn(long fileNumber, long fileOffset) {
035: return fileOffset & INT_MASK | ((fileNumber & INT_MASK) << 32);
036: }
037:
038: public static long longToLsn(Long lsn) {
039: if (lsn == null) {
040: return NULL_LSN;
041: }
042:
043: return lsn.longValue();
044: }
045:
046: /**
047: * Return the file number for this DbLsn.
048: * @return the number for this DbLsn.
049: */
050: public static long getFileNumber(long lsn) {
051: return (lsn >> 32) & INT_MASK;
052: }
053:
054: /**
055: * Return the file offset for this DbLsn.
056: * @return the offset for this DbLsn.
057: */
058: public static long getFileOffset(long lsn) {
059: return (lsn & INT_MASK);
060: }
061:
062: private static int compareLong(long l1, long l2) {
063: if (l1 < l2) {
064: return -1;
065: } else if (l1 > l2) {
066: return 1;
067: } else {
068: return 0;
069: }
070: }
071:
072: public static int compareTo(long lsn1, long lsn2) {
073: if (lsn1 == NULL_LSN || lsn2 == NULL_LSN) {
074: throw new NullPointerException();
075: }
076:
077: long fileNumber1 = getFileNumber(lsn1);
078: long fileNumber2 = getFileNumber(lsn2);
079: if (fileNumber1 == fileNumber2) {
080: return compareLong(getFileOffset(lsn1), getFileOffset(lsn2));
081: } else {
082: return compareLong(fileNumber1, fileNumber2);
083: }
084: }
085:
086: public static String toString(long lsn) {
087: return "<DbLsn val=\"0x" + Long.toHexString(getFileNumber(lsn))
088: + "/0x" + Long.toHexString(getFileOffset(lsn)) + "\"/>";
089: }
090:
091: public static String getNoFormatString(long lsn) {
092: return "0x" + Long.toHexString(getFileNumber(lsn)) + "/0x"
093: + Long.toHexString(getFileOffset(lsn));
094: }
095:
096: public static String dumpString(long lsn, int nSpaces) {
097: StringBuffer sb = new StringBuffer();
098: sb.append(TreeUtils.indent(nSpaces));
099: sb.append(toString(lsn));
100: return sb.toString();
101: }
102:
103: /**
104: * Return the logsize in bytes between these two LSNs. This is an
105: * approximation; the logs might actually be a little more or less in
106: * size. This assumes that no log files have been cleaned.
107: */
108: public static long getNoCleaningDistance(long this Lsn,
109: long otherLsn, long logFileSize) {
110: long diff = 0;
111:
112: assert this Lsn != NULL_LSN;
113: /* First figure out how many files lay between the two. */
114: long myFile = getFileNumber(this Lsn);
115: if (otherLsn == NULL_LSN) {
116: otherLsn = 0;
117: }
118: long otherFile = getFileNumber(otherLsn);
119: if (myFile == otherFile) {
120: diff = Math.abs(getFileOffset(this Lsn)
121: - getFileOffset(otherLsn));
122: } else if (myFile > otherFile) {
123: diff = calcDiff(myFile - otherFile, logFileSize, this Lsn,
124: otherLsn);
125: } else {
126: diff = calcDiff(otherFile - myFile, logFileSize, otherLsn,
127: this Lsn);
128: }
129: return diff;
130: }
131:
132: /**
133: * Return the logsize in bytes between these two LSNs. This is an
134: * approximation; the logs might actually be a little more or less in
135: * size. This assumes that log files might have been cleaned.
136: */
137: public static long getWithCleaningDistance(long this Lsn,
138: FileManager fileManager, long otherLsn, long logFileSize) {
139: long diff = 0;
140:
141: assert this Lsn != NULL_LSN;
142: /* First figure out how many files lay between the two. */
143: long myFile = getFileNumber(this Lsn);
144: if (otherLsn == NULL_LSN) {
145: otherLsn = 0;
146: }
147: long otherFile = getFileNumber(otherLsn);
148: if (myFile == otherFile) {
149: diff = Math.abs(getFileOffset(this Lsn)
150: - getFileOffset(otherLsn));
151: } else {
152: /* Figure out how many files lie between. */
153: Long[] fileNums = fileManager.getAllFileNumbers();
154: int myFileIdx = Arrays.binarySearch(fileNums, new Long(
155: myFile));
156: int otherFileIdx = Arrays.binarySearch(fileNums, new Long(
157: otherFile));
158: if (myFileIdx > otherFileIdx) {
159: diff = calcDiff(myFileIdx - otherFileIdx, logFileSize,
160: this Lsn, otherLsn);
161: } else {
162: diff = calcDiff(otherFileIdx - myFileIdx, logFileSize,
163: otherLsn, this Lsn);
164: }
165: }
166: return diff;
167: }
168:
169: private static long calcDiff(long fileDistance, long logFileSize,
170: long laterLsn, long earlierLsn) {
171: long diff = fileDistance * logFileSize;
172: diff += getFileOffset(laterLsn);
173: diff -= getFileOffset(earlierLsn);
174: return diff;
175: }
176: }
|