KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > core > storage > gammaStore > LongLoc


1 // You can redistribute this software and/or modify it under the terms of
2
// the Ozone Core License version 1 published by ozone-db.org.
3
//
4
// Copyright (C) 2003-@year@, Leo Mekenkamp. All rights reserved.
5
//
6
// $Id$
7

8 package org.ozoneDB.core.storage.gammaStore;
9
10 import java.io.Serializable JavaDoc;
11
12 /**
13  * <p>Provides a primitive mapping-like meganism in which there is only a key (a
14  * primitive <code>long</code> in this case). This key can be put in and
15  * retrieved by <code>getKey(long)</code> and <code>putKey(long)</code>. Both
16  * methods return a handle, which can be used as a handle or magic cookie, to
17  * find the key. Implementing classes can and should provide their own get and
18  * put methods for each and every object or primitive that is mapped to the key.
19  * </p>
20  * <p>Extending classes should extend <code>move(int, int)</code></p>
21  *
22  * <p>This implementation is very fast when every value passed to <code>putKey(int)</code>
23  * is bigger than all previous passed values (O(1)). If not, it is quite slow
24  * (max O(size)). Because this class is used to store object ids and cluster ids
25  * this means the greatest performance benefits occur in normal 'everyday' use.
26  * Only when the database or OS has crashed (powerfailure) and the index has to
27  * be rebuild does the speed disadvantage make itself known.</p>
28  *
29  * @author <a HREF="mailto:leoATmekenkampD0Tcom">Leo Mekenkamp (mind the anti sp@m)</a>
30  * @version $Id$
31  */

32 public class LongLoc implements Serializable JavaDoc {
33     
34     protected long[] keys;
35     private int[] inUse;
36     private int capacity;
37     private int size;
38     private int handleToLast;
39
40     public LongLoc(int capacity, int slack) {
41         this.capacity = capacity;
42         keys = new long[capacity + slack];
43         int inUseSize = keys.length / 32;
44         if (keys.length % 32 != 0) {
45             inUseSize++;
46         }
47         inUse = new int[inUseSize];
48         handleToLast = -1;
49     }
50     
51     public LongLoc(int capacity, float relSlack) {
52         this(capacity, (int) (relSlack * capacity) > 0 ? (int) (relSlack * capacity) : 1);
53     }
54
55     /**
56      * Returns a handle to the given value. If there is no such value, then
57      * the return value is negative. The returned handle is only valid until
58      * the next call to <code>putKey(long)</code> or <code>compress()</code>.
59      */

60     public int getKeyPos(long key) {
61         int result = search(key);
62         if (!isInUse(result) || key != keys[result]) {
63             result = -1;
64         }
65         return result;
66     }
67     
68     /** Returns the key found at the specified location.
69      * @param pos position to get the key from
70      * @return key at that location
71      * @throws IllegalArgumentException the specified position is not in use
72      */

73     public long getKey(int pos) {
74         if (!isInUse(pos)) {
75             throw new IllegalArgumentException JavaDoc("position not in use");
76         }
77         return keys[pos];
78     }
79     
80     /**
81      * Returns a handle to the given key, or, if that key does not exist, to
82      * the smallest key larger than specified key. If there is no such value,
83      * then the return value is negative. The returned handle is only valid
84      * until the next call to <code>putKey(long)</code> or <code>compress()</code>.
85      */

86     public int getKeyPosOrNearestGreater(long key) {
87         int result = -1;
88         for(int handle = search(key); handle <= handleToLast; handle++) {
89             if (isInUse(handle) && keys[handle] >= key) {
90                 result = handle;
91                 break;
92             }
93         }
94         return result;
95     }
96     
97     /**
98      * Returns a handle to the given key, or, if that key does not exist, to
99      * the largest key smaller than specified key. If there is no such value,
100      * then the return value is negative. The returned handle is only valid
101      * until the next call to <code>putKey(long)</code> or <code>compress()</code>.
102      */

103     public int getKeyPosOrNearestSmaller(long key) {
104         int result = -1;
105         for(int handle = search(key); handle >= 0; handle--) {
106             if (isInUse(handle) && keys[handle] <= key) {
107                 result = handle;
108                 break;
109             }
110         }
111         return result;
112     }
113     
114     /**
115      * Returns a handle to the given value and removes that key. If there is no
116      * such key, then the return value is negative. The returned handle is only
117      * valid until the next call to <code>putKey(long)</code> or <code>compress()</code>.
118      * The returned handle can also never be retrieved again.
119      */

120     public int removeKey(long key) {
121         int result = getKeyPos(key);
122         if (result < 0) {
123             throw new IllegalArgumentException JavaDoc("key not found");
124         }
125         setInUse(result, false);
126         size--;
127         return result;
128     }
129     
130     /**
131      * <p>Inserts (or overwrites) a key and returns a handle to it. The returned
132      * handle is only valid until the next call to <code>putKey(long)</code> or
133      * <code>compress()</code>.</p>
134      * <p>This method is highly optimized for keys that are bigger than any
135      * other key in this instance; performance is then O(1). When this is not
136      * the case, thus the keys are inserted in random fashion (2,7,4,8,9,1
137      * instead of 1,2,4,7,8,9) performance can be up to O(size)</p>
138      */

139     public int putKey(long key) {
140         if (handleToLast == -1 || keys[handleToLast] < key) {
141             if (handleToLast == keys.length - 1) {
142                 compress();
143             }
144             // since the key is bigger than all others, append to end of array
145
if (size >= capacity) {
146                 throw new IndexOutOfBoundsException JavaDoc("cannot grow any larger");
147             }
148             handleToLast++;
149             keys[handleToLast] = key;
150             setInUse(handleToLast, true);
151             size++;
152             return handleToLast;
153         }
154
155         // Ouch, we got a key that is not the largest in this instance; we have
156
// to do a (costly) insert. Must do a compress to make sure that keys
157
// do not appear twice or more times (one time as inUse and possible
158
// others not inUse...
159
compress();
160         int result = getKeyPosOrNearestGreater(key);
161         if (result >= 0) {
162             if (isInUse(result) || keys[result] == key) {
163                 return result;
164             }
165         } else {
166             result = handleToLast;
167         }
168         
169         if (size >= capacity) {
170             throw new IndexOutOfBoundsException JavaDoc("cannot grow any larger");
171         }
172         
173         for (int i = keys.length - 2; i >= result; i--) {
174             if (isInUse(i)) {
175                 // note that handle keys.length - 1 is never in use here, because
176
// of the compress() at the start of this method
177
move(i, i + 1);
178                 if (handleToLast <= i) {
179                     handleToLast = i + 1;
180                 }
181             }
182         }
183         keys[result] = key;
184         setInUse(result, true);
185         size++;
186         return result;
187     }
188     
189     /**
190      * Returns the handle to the key that is the smallest of all larger keys.
191      * Returns < 0 if there is no such key. Note that if handle <0 then the
192      * first handle in use is returned (which may of course be < 0 if there is
193      * no key in this instance
194      */

195     public int next(int handle) {
196         if (handle >= 0 && !isInUse(handle)) {
197             throw new IllegalArgumentException JavaDoc("handle is not in use");
198         }
199         handle++;
200         int result;
201         for(result = -1; result < 0 && handle <= handleToLast; handle++) {
202             if (isInUse(handle)) {
203                 result = handle;
204             }
205         }
206         return result;
207     }
208     
209     /**
210      * Returns true iff the given handle is in use
211      */

212     private boolean isInUse(int handle) {
213         int pos = handle / 32;
214         int mask = 1 << (handle % 32);
215         return (inUse[pos] & mask ) != 0;
216     }
217     
218     private void setInUse(int handle, boolean inUse) {
219         int pos = handle / 32;
220         int mask = 1 << (handle % 32);
221         if (inUse) {
222             this.inUse[pos] |= mask;
223         } else {
224             this.inUse[pos] &= ~mask;
225         }
226     }
227     
228     /**
229      * Searches for the given value. If the value could not be found then one of
230      * the handles of the nearest value is returned. Note that the returned
231      * handle may not be in use.
232      */

233     private int search(long key) {
234         return (handleToLast < 0) ? 0 : search(key, 0, handleToLast);
235     }
236     
237     /**
238      * note: searching beyond high > index is NOT supported and may yield
239      * strange results. Search may return a handle to either 1) the specified
240      * key, or if that key does not exist: 2) the greatest key smaller
241      * than the specified key; or: 3) the smallest key greater than
242      * the specified key. Returned handle may be invalid!
243      */

244     private int search(long key, int low, int high) {
245         if (low > high) {
246             throw new IllegalArgumentException JavaDoc("low should be <= high; low == " + low + ", high == " + high + ", key == " + key + ", handleToLast == " + handleToLast);
247         }
248         for(;;) {
249             int result = (low + high) / 2;
250             if (low >= high || keys[result] == key) {
251                 return result;
252             }
253             if (key < keys[result]) {
254                 high = result - 1;
255             } else {
256                 low = result + 1;
257             }
258         }
259     }
260     
261     /**
262      * Moves all keys to remove unused (deleted) slots.
263      */

264     private void compress() {
265         handleToLast = -1;
266         for(int i = 0; i < keys.length; i++) {
267             if (isInUse(i)) {
268                 handleToLast++;
269                 if (i > handleToLast) {
270                     move(i, handleToLast);
271                 }
272             } else {
273                 // Having a lot of 0s in a row makes for better compression when this
274
// instance is serialized and put through a compressing stream.
275
keys[i] = 0;
276             }
277         }
278     }
279     
280     protected void move(int handleFrom, int handleTo) {
281         if (!isInUse(handleFrom) || isInUse(handleTo)) {
282             throw new IllegalArgumentException JavaDoc("handleFrom must be in use and handleTo must not");
283         }
284         keys[handleTo] = keys[handleFrom];
285         // Having a lot of 0s in a row makes for better compression when this
286
// instance is serialized and put through a compressing stream.
287
keys[handleFrom] = 0;
288         setInUse(handleFrom, false);
289         setInUse(handleTo, true);
290     }
291     
292     public String JavaDoc toString() {
293         StringBuffer JavaDoc result = new StringBuffer JavaDoc("[handleToLast=");
294         result.append(handleToLast).append(";");
295         for (int i = 0; i < keys.length; i++) {
296             result.append(keys[i]);
297             if (!isInUse(i)) {
298                 result.append("D");
299             }
300             result.append(",");
301         }
302         return result.toString();
303     }
304     
305     /**
306      * Returns the number of keys in use.
307      */

308     public int size() {
309         return size;
310     }
311         
312 // DEBUG code only following
313

314 // public static void main(String[] args) {
315
// int capacity = 6;
316
// int slack = 3;
317
// LongLoc l = new LongLoc(capacity, slack);
318
// System.out.println(l);
319
// for (long i = 0; i < capacity; i++) {
320
// int handle = l.putKey(i * 3);
321
// System.out.println(l);
322
// }
323
// l.removeKey(6L);
324
// System.out.println(l);
325
// System.out.println("find eq or gr 16L: " + l.getKeyOrNearestGreater(16L));
326
// System.out.println("find eq or gr 15L: " + l.getKeyOrNearestGreater(15L));
327
// System.out.println("find eq or gr 14L: " + l.getKeyOrNearestGreater(14L));
328
// System.out.println("find eq or gr 9L: " + l.getKeyOrNearestGreater(9L));
329
// System.out.println("find eq or gr 8L: " + l.getKeyOrNearestGreater(8L));
330
// System.out.println("find eq or gr 7L: " + l.getKeyOrNearestGreater(7L));
331
// System.out.println("find eq or gr 6L: " + l.getKeyOrNearestGreater(6L));
332
// System.out.println("find eq or gr 5L: " + l.getKeyOrNearestGreater(5L));
333
// System.out.println("find eq or gr 0L: " + l.getKeyOrNearestGreater(0L));
334
// System.out.println("find eq or sm 16L: " + l.getKeyOrNearestSmaller(16L));
335
// System.out.println("find eq or sm 15L: " + l.getKeyOrNearestSmaller(15L));
336
// System.out.println("find eq or sm 14L: " + l.getKeyOrNearestSmaller(14L));
337
// System.out.println("find eq or sm 9L: " + l.getKeyOrNearestSmaller(9L));
338
// System.out.println("find eq or sm 8L: " + l.getKeyOrNearestSmaller(8L));
339
// System.out.println("find eq or sm 7L: " + l.getKeyOrNearestSmaller(7L));
340
// System.out.println("find eq or sm 6L: " + l.getKeyOrNearestSmaller(6L));
341
// System.out.println("find eq or sm 5L: " + l.getKeyOrNearestSmaller(5L));
342
// System.out.println("find eq or sm 0L: " + l.getKeyOrNearestSmaller(0L));
343
// l.removeKey(0L);
344
// l.removeKey(3L);
345
// l.removeKey(12L);
346
// System.out.println(l);
347
// l.putKey(10L);
348
// System.out.println(l);
349
// l.putKey(4L);
350
// System.out.println(l);
351
// l.putKey(6L);
352
// System.out.println(l);
353
// System.out.println("find 10L: " + l.getKeyOrNearestGreater(10L));
354
// l.putKey(5L);
355
// System.out.println(l);
356
// }
357
}
358
Popular Tags