1 | /* |
2 | |
3 | Derby - Class org.apache.derby.impl.store.raw.log.LogCounter |
4 | |
5 | Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. |
6 | |
7 | Licensed under the Apache License, Version 2.0 (the "License"); |
8 | you may not use this file except in compliance with the License. |
9 | You may obtain a copy of the License at |
10 | |
11 | http://www.apache.org/licenses/LICENSE-2.0 |
12 | |
13 | Unless required by applicable law or agreed to in writing, software |
14 | distributed under the License is distributed on an "AS IS" BASIS, |
15 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16 | See the License for the specific language governing permissions and |
17 | limitations under the License. |
18 | |
19 | */ |
20 | |
21 | package org.apache.derby.impl.store.raw.log; |
22 | |
23 | import org.apache.derby.iapi.services.sanity.SanityManager; |
24 | import org.apache.derby.iapi.services.io.FormatIdUtil; |
25 | import org.apache.derby.iapi.services.io.StoredFormatIds; |
26 | import org.apache.derby.iapi.store.raw.log.LogInstant; |
27 | import org.apache.derby.iapi.store.access.DatabaseInstant; |
28 | import org.apache.derby.iapi.services.io.CompressedNumber; |
29 | |
30 | import java.io.IOException; |
31 | import java.io.ObjectInput; |
32 | import java.io.ObjectOutput; |
33 | |
34 | /** |
35 | A very simple log instant implementation. |
36 | |
37 | Within the stored log record a log counter is represented as a long, |
38 | hence the getValueAsLong() method. Outside the LogFactory the instant |
39 | is passed around as a LogCounter (through its LogInstant interface). |
40 | |
41 | The way the long is encoded is such that < == > correctly tells if |
42 | one log instant is lessThan, equals or greater than another. |
43 | |
44 | */ |
45 | public class LogCounter implements LogInstant { |
46 | |
47 | /******************************************************** |
48 | ** |
49 | ** This class implements Formatable. That means that it |
50 | ** can write itself to and from a formatted stream. If |
51 | ** you add more fields to this class, make sure that you |
52 | ** also write/read them with the writeExternal()/readExternal() |
53 | ** methods. |
54 | ** |
55 | ** If, between releases, you add more fields to this class, |
56 | ** then you should bump the version number emitted by the getTypeFormatId() |
57 | ** method. |
58 | ** |
59 | ********************************************************/ |
60 | |
61 | /** A well defined value of an invalid log instant. */ |
62 | public static final long INVALID_LOG_INSTANT = 0; |
63 | |
64 | // max possible log file number in versions before 10.1 is 2^22 -1 |
65 | public static final long DERBY_10_0_MAX_LOGFILE_NUMBER = (long)0x003FFFFFL; // 4194303 |
66 | // max possible log file number is 2^31 -1 |
67 | public static final long MAX_LOGFILE_NUMBER = (long)0x7FFFFFFFL; // 2147483647 |
68 | // lower end of 32 bits in long type are used to store the log file position |
69 | private static final long FILE_NUMBER_SHIFT = 32; |
70 | |
71 | // reserve top 4 bits in log file size for future use |
72 | public static final long MAX_LOGFILE_SIZE = (long)0x0FFFFFFFL; // 268435455 |
73 | // 32 bits are used to store the log file postion |
74 | private static final long FILE_POSITION_MASK = (long)0x7FFFFFFFL; |
75 | |
76 | private long fileNumber; |
77 | private long filePosition; |
78 | |
79 | // contructors |
80 | public LogCounter(long value) { |
81 | fileNumber = getLogFileNumber(value); |
82 | filePosition = getLogFilePosition(value); |
83 | } |
84 | |
85 | public LogCounter(long fileNumber, long position) { |
86 | |
87 | if (SanityManager.DEBUG) { |
88 | SanityManager.ASSERT(fileNumber > 0, "illegal fileNumber"); |
89 | SanityManager.ASSERT(position > 0, "illegal file position"); |
90 | |
91 | SanityManager.ASSERT(position < MAX_LOGFILE_SIZE, |
92 | "log file position exceeded max log file size"); |
93 | SanityManager.ASSERT(fileNumber < MAX_LOGFILE_NUMBER, |
94 | "log file number exceeded max log file number"); |
95 | } |
96 | |
97 | this.fileNumber = fileNumber; |
98 | this.filePosition = position; |
99 | } |
100 | |
101 | /** |
102 | * Public niladic constructor needed for Formatable interface. |
103 | */ |
104 | public LogCounter() {} |
105 | |
106 | /** |
107 | Static functions that can only be used inside the RawStore's log |
108 | factory which passes the log counter around encoded as a long |
109 | */ |
110 | |
111 | // make a log instant from 2 longs and return a long which is the long |
112 | // representatin of a LogCounter |
113 | static public final long makeLogInstantAsLong(long filenum, long filepos) |
114 | { |
115 | if (SanityManager.DEBUG) { |
116 | SanityManager.ASSERT(filenum > 0, "illegal fileNumber"); |
117 | SanityManager.ASSERT(filepos > 0, "illegal file position"); |
118 | |
119 | SanityManager.ASSERT(filepos < MAX_LOGFILE_SIZE, |
120 | "log file position exceeded max log file size"); |
121 | SanityManager.ASSERT(filenum < MAX_LOGFILE_NUMBER, |
122 | "log file number exceeded max log file number"); |
123 | } |
124 | |
125 | return ((filenum << FILE_NUMBER_SHIFT) | filepos); |
126 | } |
127 | |
128 | |
129 | static public final long getLogFilePosition(long valueAsLong) |
130 | { |
131 | return valueAsLong & FILE_POSITION_MASK; |
132 | } |
133 | |
134 | static public final long getLogFileNumber(long valueAsLong) |
135 | { |
136 | return valueAsLong >>> FILE_NUMBER_SHIFT; |
137 | } |
138 | |
139 | /** LogScan methods */ |
140 | |
141 | public boolean lessThan(DatabaseInstant other) { |
142 | LogCounter compare = (LogCounter)other; |
143 | |
144 | return (fileNumber == compare.fileNumber) ? |
145 | filePosition < compare.filePosition : |
146 | fileNumber < compare.fileNumber; |
147 | } |
148 | |
149 | public boolean equals(Object other) { |
150 | if (this == other) |
151 | return true; |
152 | |
153 | if (!(other instanceof LogCounter)) |
154 | return false; |
155 | |
156 | LogCounter compare = (LogCounter)other; |
157 | |
158 | return fileNumber == compare.fileNumber && |
159 | filePosition == compare.filePosition; |
160 | } |
161 | |
162 | public DatabaseInstant next() { |
163 | return new LogCounter( makeLogInstantAsLong(fileNumber, filePosition) + 1); |
164 | } |
165 | |
166 | public DatabaseInstant prior() { |
167 | return new LogCounter( makeLogInstantAsLong(fileNumber, filePosition) - 1); |
168 | } |
169 | |
170 | public int hashCode() { |
171 | return (int) (filePosition ^ fileNumber); |
172 | } |
173 | |
174 | public String toString() { |
175 | return "(" + fileNumber + "," + filePosition + ")"; |
176 | } |
177 | |
178 | public static String toDebugString(long instant) |
179 | { |
180 | if (SanityManager.DEBUG) |
181 | return "(" + getLogFileNumber(instant) + "," + getLogFilePosition(instant) + ")"; |
182 | else |
183 | return null; |
184 | } |
185 | |
186 | /** |
187 | These following methods are only intended to be called by an |
188 | implementation of a log factory. All other uses of this object should |
189 | only see it as a log instant. |
190 | */ |
191 | public long getValueAsLong() { |
192 | return makeLogInstantAsLong(fileNumber, filePosition); |
193 | } |
194 | |
195 | public long getLogFilePosition() |
196 | { |
197 | return filePosition; |
198 | } |
199 | |
200 | public long getLogFileNumber() |
201 | { |
202 | return fileNumber; |
203 | } |
204 | |
205 | |
206 | /* |
207 | * methods for the Formatable interface |
208 | */ |
209 | |
210 | /** |
211 | * Read this in. |
212 | * @exception IOException error reading from log stream |
213 | * @exception ClassNotFoundException corrupted log stream |
214 | */ |
215 | public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException { |
216 | fileNumber = CompressedNumber.readLong(oi); |
217 | filePosition = CompressedNumber.readLong(oi); |
218 | } |
219 | |
220 | /** |
221 | * Write this out. |
222 | * @exception IOException error writing to log stream |
223 | */ |
224 | public void writeExternal(ObjectOutput oo) throws IOException { |
225 | CompressedNumber.writeLong(oo,fileNumber); |
226 | CompressedNumber.writeLong(oo,filePosition); |
227 | } |
228 | |
229 | /** |
230 | * Get the formatID which corresponds to this class. |
231 | * |
232 | * @return the formatID of this class |
233 | */ |
234 | public int getTypeFormatId() { return StoredFormatIds.LOG_COUNTER; } |
235 | |
236 | } |