--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.raw.log.LogCounter\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.store.raw.log;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.io.FormatIdUtil;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+import org.apache.derby.iapi.store.raw.log.LogInstant;\r
+import org.apache.derby.iapi.store.access.DatabaseInstant;\r
+import org.apache.derby.iapi.services.io.CompressedNumber;\r
+\r
+import java.io.IOException;\r
+import java.io.ObjectInput;\r
+import java.io.ObjectOutput;\r
+\r
+/**\r
+ A very simple log instant implementation.\r
+\r
+ Within the stored log record a log counter is represented as a long,\r
+ hence the getValueAsLong() method. Outside the LogFactory the instant\r
+ is passed around as a LogCounter (through its LogInstant interface).\r
+\r
+ The way the long is encoded is such that < == > correctly tells if\r
+ one log instant is lessThan, equals or greater than another.\r
+\r
+*/\r
+public class LogCounter implements LogInstant {\r
+\r
+ /********************************************************\r
+ **\r
+ ** This class implements Formatable. That means that it\r
+ ** can write itself to and from a formatted stream. If\r
+ ** you add more fields to this class, make sure that you\r
+ ** also write/read them with the writeExternal()/readExternal()\r
+ ** methods.\r
+ **\r
+ ** If, between releases, you add more fields to this class,\r
+ ** then you should bump the version number emitted by the getTypeFormatId()\r
+ ** method.\r
+ **\r
+ ********************************************************/\r
+ \r
+ /** A well defined value of an invalid log instant. */\r
+ public static final long INVALID_LOG_INSTANT = 0;\r
+ \r
+ // max possible log file number in versions before 10.1 is 2^22 -1\r
+ public static final long DERBY_10_0_MAX_LOGFILE_NUMBER = (long)0x003FFFFFL; // 4194303\r
+ // max possible log file number is 2^31 -1\r
+ public static final long MAX_LOGFILE_NUMBER = (long)0x7FFFFFFFL; // 2147483647 \r
+ // lower end of 32 bits in long type are used to store the log file position\r
+ private static final long FILE_NUMBER_SHIFT = 32;\r
+\r
+ // reserve top 4 bits in log file size for future use\r
+ public static final long MAX_LOGFILE_SIZE = (long)0x0FFFFFFFL; // 268435455\r
+ // 32 bits are used to store the log file postion\r
+ private static final long FILE_POSITION_MASK = (long)0x7FFFFFFFL;\r
+\r
+ private long fileNumber;\r
+ private long filePosition;\r
+\r
+ // contructors\r
+ public LogCounter(long value) {\r
+ fileNumber = getLogFileNumber(value);\r
+ filePosition = getLogFilePosition(value);\r
+ }\r
+\r
+ public LogCounter(long fileNumber, long position) {\r
+\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(fileNumber > 0, "illegal fileNumber");\r
+ SanityManager.ASSERT(position > 0, "illegal file position");\r
+\r
+ SanityManager.ASSERT(position < MAX_LOGFILE_SIZE,\r
+ "log file position exceeded max log file size");\r
+ SanityManager.ASSERT(fileNumber < MAX_LOGFILE_NUMBER,\r
+ "log file number exceeded max log file number");\r
+ }\r
+\r
+ this.fileNumber = fileNumber;\r
+ this.filePosition = position;\r
+ }\r
+\r
+ /**\r
+ * Public niladic constructor needed for Formatable interface.\r
+ */\r
+ public LogCounter() {}\r
+ \r
+ /** \r
+ Static functions that can only be used inside the RawStore's log\r
+ factory which passes the log counter around encoded as a long\r
+ */\r
+\r
+ // make a log instant from 2 longs and return a long which is the long\r
+ // representatin of a LogCounter\r
+ static public final long makeLogInstantAsLong(long filenum, long filepos)\r
+ {\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(filenum > 0, "illegal fileNumber");\r
+ SanityManager.ASSERT(filepos > 0, "illegal file position");\r
+\r
+ SanityManager.ASSERT(filepos < MAX_LOGFILE_SIZE,\r
+ "log file position exceeded max log file size");\r
+ SanityManager.ASSERT(filenum < MAX_LOGFILE_NUMBER,\r
+ "log file number exceeded max log file number");\r
+ }\r
+\r
+ return ((filenum << FILE_NUMBER_SHIFT) | filepos);\r
+ }\r
+\r
+\r
+ static public final long getLogFilePosition(long valueAsLong)\r
+ {\r
+ return valueAsLong & FILE_POSITION_MASK;\r
+ }\r
+\r
+ static public final long getLogFileNumber(long valueAsLong)\r
+ {\r
+ return valueAsLong >>> FILE_NUMBER_SHIFT;\r
+ }\r
+\r
+ /** LogScan methods */\r
+\r
+ public boolean lessThan(DatabaseInstant other) {\r
+ LogCounter compare = (LogCounter)other;\r
+\r
+ return (fileNumber == compare.fileNumber) ?\r
+ filePosition < compare.filePosition :\r
+ fileNumber < compare.fileNumber;\r
+ }\r
+\r
+ public boolean equals(Object other) {\r
+ if (this == other)\r
+ return true;\r
+\r
+ if (!(other instanceof LogCounter))\r
+ return false;\r
+\r
+ LogCounter compare = (LogCounter)other;\r
+\r
+ return fileNumber == compare.fileNumber &&\r
+ filePosition == compare.filePosition;\r
+ }\r
+\r
+ public DatabaseInstant next() {\r
+ return new LogCounter( makeLogInstantAsLong(fileNumber, filePosition) + 1);\r
+ }\r
+ \r
+ public DatabaseInstant prior() {\r
+ return new LogCounter( makeLogInstantAsLong(fileNumber, filePosition) - 1);\r
+ }\r
+ \r
+ public int hashCode() {\r
+ return (int) (filePosition ^ fileNumber);\r
+ }\r
+\r
+ public String toString() {\r
+ return "(" + fileNumber + "," + filePosition + ")";\r
+ }\r
+\r
+ public static String toDebugString(long instant)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ return "(" + getLogFileNumber(instant) + "," + getLogFilePosition(instant) + ")";\r
+ else\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ These following methods are only intended to be called by an\r
+ implementation of a log factory. All other uses of this object should\r
+ only see it as a log instant.\r
+ */\r
+ public long getValueAsLong() {\r
+ return makeLogInstantAsLong(fileNumber, filePosition);\r
+ }\r
+\r
+ public long getLogFilePosition()\r
+ {\r
+ return filePosition;\r
+ }\r
+\r
+ public long getLogFileNumber()\r
+ {\r
+ return fileNumber;\r
+ }\r
+\r
+ \r
+ /*\r
+ * methods for the Formatable interface\r
+ */\r
+\r
+ /**\r
+ * Read this in.\r
+ * @exception IOException error reading from log stream\r
+ * @exception ClassNotFoundException corrupted log stream\r
+ */\r
+ public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException {\r
+ fileNumber = CompressedNumber.readLong(oi);\r
+ filePosition = CompressedNumber.readLong(oi);\r
+ }\r
+ \r
+ /**\r
+ * Write this out.\r
+ * @exception IOException error writing to log stream\r
+ */\r
+ public void writeExternal(ObjectOutput oo) throws IOException {\r
+ CompressedNumber.writeLong(oo,fileNumber);\r
+ CompressedNumber.writeLong(oo,filePosition);\r
+ }\r
+ \r
+ /**\r
+ * Get the formatID which corresponds to this class.\r
+ *\r
+ * @return the formatID of this class\r
+ */\r
+ public int getTypeFormatId() { return StoredFormatIds.LOG_COUNTER; }\r
+\r
+}\r