forked from I2P_Developers/i2p.i2p
- Use new UTF8StringBytes
- Track number of SkipLevels in a SkipList - More double-checks - Cleanups, logging, generics
This commit is contained in:
@ -35,6 +35,7 @@ import net.i2p.util.SecureFileOutputStream;
|
||||
|
||||
import net.metanotion.io.Serializer;
|
||||
import net.metanotion.io.block.BlockFile;
|
||||
import net.metanotion.io.data.UTF8StringBytes;
|
||||
import net.metanotion.util.skiplist.SkipIterator;
|
||||
import net.metanotion.util.skiplist.SkipList;
|
||||
|
||||
@ -79,7 +80,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
private volatile boolean _isClosed;
|
||||
|
||||
private static final Serializer _infoSerializer = new PropertiesSerializer();
|
||||
private static final Serializer _stringSerializer = new StringSerializer();
|
||||
private static final Serializer _stringSerializer = new UTF8StringBytes();
|
||||
private static final Serializer _destSerializer = new DestEntrySerializer();
|
||||
|
||||
private static final String HOSTS_DB = "hostsdb.blockfile";
|
||||
@ -743,28 +744,6 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UTF-8 Serializer (the one in the lib is US-ASCII).
|
||||
* Used for all keys.
|
||||
*/
|
||||
private static class StringSerializer implements Serializer {
|
||||
public byte[] getBytes(Object o) {
|
||||
try {
|
||||
return ((String) o).getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
throw new RuntimeException("No UTF-8", uee);
|
||||
}
|
||||
}
|
||||
|
||||
public Object construct(byte[] b) {
|
||||
try {
|
||||
return new String(b, "UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
throw new RuntimeException("No UTF-8", uee);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for the values in the header skiplist
|
||||
* Take care not to throw on any error.
|
||||
|
@ -65,14 +65,14 @@ public class BSkipLevels extends SkipLevels {
|
||||
if (magic != MAGIC)
|
||||
throw new IOException("Bad SkipLevels magic number 0x" + Long.toHexString(magic) + " on page " + levelPage);
|
||||
|
||||
bsl.levelHash.put(new Integer(this.levelPage), this);
|
||||
bsl.levelHash.put(Integer.valueOf(this.levelPage), this);
|
||||
|
||||
int maxLen = bf.file.readUnsignedShort();
|
||||
int nonNull = bf.file.readUnsignedShort();
|
||||
if(maxLen < 1 || maxLen > MAX_SIZE || nonNull > maxLen)
|
||||
throw new IOException("Invalid Level Skip size " + nonNull + " / " + maxLen);
|
||||
spanPage = bf.file.readUnsignedInt();
|
||||
bottom = (BSkipSpan) bsl.spanHash.get(new Integer(spanPage));
|
||||
bottom = bsl.spanHash.get(Integer.valueOf(spanPage));
|
||||
|
||||
this.levels = new BSkipLevels[maxLen];
|
||||
if (BlockFile.log.shouldLog(Log.DEBUG))
|
||||
@ -86,10 +86,10 @@ public class BSkipLevels extends SkipLevels {
|
||||
for(int i = 0; i < nonNull; i++) {
|
||||
int lp = lps[i];
|
||||
if(lp != 0) {
|
||||
levels[i] = (BSkipLevels) bsl.levelHash.get(new Integer(lp));
|
||||
levels[i] = bsl.levelHash.get(Integer.valueOf(lp));
|
||||
if(levels[i] == null) {
|
||||
levels[i] = new BSkipLevels(bf, lp, bsl);
|
||||
bsl.levelHash.put(new Integer(lp), levels[i]);
|
||||
bsl.levelHash.put(Integer.valueOf(lp), levels[i]);
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
|
@ -44,6 +44,7 @@ import net.metanotion.util.skiplist.*;
|
||||
* first level page (unsigned int)
|
||||
* size (unsigned int)
|
||||
* spans (unsigned int)
|
||||
* levels (unsigned int)
|
||||
*
|
||||
* Always fits on one page.
|
||||
*/
|
||||
@ -52,10 +53,11 @@ public class BSkipList extends SkipList {
|
||||
public int firstSpanPage = 0;
|
||||
public int firstLevelPage = 0;
|
||||
public int skipPage = 0;
|
||||
public BlockFile bf;
|
||||
public final BlockFile bf;
|
||||
private boolean isClosed;
|
||||
|
||||
public HashMap spanHash = new HashMap();
|
||||
public HashMap levelHash = new HashMap();
|
||||
final HashMap<Integer, BSkipSpan> spanHash = new HashMap();
|
||||
final HashMap<Integer, SkipLevels> levelHash = new HashMap();
|
||||
|
||||
private final boolean fileOnly;
|
||||
|
||||
@ -77,6 +79,7 @@ public class BSkipList extends SkipList {
|
||||
firstLevelPage = bf.file.readUnsignedInt();
|
||||
size = bf.file.readUnsignedInt();
|
||||
spans = bf.file.readUnsignedInt();
|
||||
levelCount = bf.file.readUnsignedInt();
|
||||
//System.out.println(size + " " + spans);
|
||||
|
||||
this.fileOnly = fileOnly;
|
||||
@ -91,18 +94,24 @@ public class BSkipList extends SkipList {
|
||||
public void close() {
|
||||
//System.out.println("Closing index " + size + " and " + spans);
|
||||
flush();
|
||||
first = null;
|
||||
stack = null;
|
||||
spanHash.clear();
|
||||
levelHash.clear();
|
||||
isClosed = true;
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
if (isClosed) {
|
||||
BlockFile.log.error("Already closed!! " + this, new Exception());
|
||||
return;
|
||||
}
|
||||
try {
|
||||
BlockFile.pageSeek(bf.file, skipPage);
|
||||
bf.file.writeLong(MAGIC);
|
||||
bf.file.writeInt(firstSpanPage);
|
||||
bf.file.writeInt(firstLevelPage);
|
||||
bf.file.writeInt(size);
|
||||
bf.file.writeInt(spans);
|
||||
bf.file.writeInt(Math.max(0, size));
|
||||
bf.file.writeInt(Math.max(0, spans));
|
||||
bf.file.writeInt(Math.max(0, levelCount));
|
||||
|
||||
} catch (IOException ioe) { throw new RuntimeException("Error writing to database", ioe); }
|
||||
}
|
||||
@ -177,6 +186,7 @@ public class BSkipList extends SkipList {
|
||||
public void bslck(boolean isMeta, boolean fix) {
|
||||
BlockFile.log.warn(" size " + this.size);
|
||||
BlockFile.log.warn(" spans " + this.spans);
|
||||
BlockFile.log.warn(" levels " + this.levelCount);
|
||||
BlockFile.log.warn(" skipPage " + this.skipPage);
|
||||
BlockFile.log.warn(" firstSpanPage " + this.firstSpanPage);
|
||||
BlockFile.log.warn(" firstLevelPage " + this.firstLevelPage);
|
||||
@ -201,4 +211,12 @@ public class BSkipList extends SkipList {
|
||||
if (items != this.size)
|
||||
BlockFile.log.warn("****** size mismatch, header = " + this.size + " actual = " + items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String rv = getClass().getSimpleName() + " page " + skipPage;
|
||||
if (isClosed)
|
||||
rv += " CLOSED";
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
@ -218,7 +218,7 @@ public class BSkipSpan extends SkipSpan {
|
||||
bss.keySer = key;
|
||||
bss.valSer = val;
|
||||
|
||||
bsl.spanHash.put(new Integer(spanPage), bss);
|
||||
bsl.spanHash.put(Integer.valueOf(spanPage), bss);
|
||||
|
||||
BlockFile.pageSeek(bf.file, spanPage);
|
||||
|
||||
@ -308,10 +308,9 @@ public class BSkipSpan extends SkipSpan {
|
||||
this.prev = null;
|
||||
|
||||
BSkipSpan bss = this;
|
||||
BSkipSpan temp;
|
||||
int np = nextPage;
|
||||
while(np != 0) {
|
||||
temp = (BSkipSpan) bsl.spanHash.get(new Integer(np));
|
||||
BSkipSpan temp = bsl.spanHash.get(Integer.valueOf(np));
|
||||
if(temp != null) {
|
||||
bss.next = temp;
|
||||
break;
|
||||
@ -328,7 +327,7 @@ public class BSkipSpan extends SkipSpan {
|
||||
bss = this;
|
||||
np = prevPage;
|
||||
while(np != 0) {
|
||||
temp = (BSkipSpan) bsl.spanHash.get(new Integer(np));
|
||||
BSkipSpan temp = bsl.spanHash.get(Integer.valueOf(np));
|
||||
if(temp != null) {
|
||||
bss.next = temp;
|
||||
break;
|
||||
|
@ -246,7 +246,7 @@ public class IBSkipSpan extends BSkipSpan {
|
||||
IBSkipSpan temp;
|
||||
int np = nextPage;
|
||||
while(np != 0) {
|
||||
temp = (IBSkipSpan) bsl.spanHash.get(new Integer(np));
|
||||
temp = (IBSkipSpan) bsl.spanHash.get(Integer.valueOf(np));
|
||||
if(temp != null) {
|
||||
bss.next = temp;
|
||||
break;
|
||||
@ -264,7 +264,7 @@ public class IBSkipSpan extends BSkipSpan {
|
||||
bss = this;
|
||||
np = prevPage;
|
||||
while(np != 0) {
|
||||
temp = (IBSkipSpan) bsl.spanHash.get(new Integer(np));
|
||||
temp = (IBSkipSpan) bsl.spanHash.get(Integer.valueOf(np));
|
||||
if(temp != null) {
|
||||
bss.next = temp;
|
||||
break;
|
||||
|
@ -187,6 +187,7 @@ public class SkipLevels {
|
||||
}
|
||||
res[1] = null;
|
||||
}
|
||||
sl.delSpan(res[1] != null);
|
||||
}
|
||||
if((bottom.nKeys == 0) && (sl.first != bottom)) { this.killInstance(); }
|
||||
return res;
|
||||
@ -243,6 +244,7 @@ public class SkipLevels {
|
||||
if(levels.length < height)
|
||||
return slvls;
|
||||
}
|
||||
sl.addSpan(height != 0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -32,16 +32,21 @@ import java.util.Random;
|
||||
|
||||
import net.i2p.util.RandomSource;
|
||||
|
||||
import net.metanotion.io.block.BlockFile;
|
||||
//import net.metanotion.io.block.BlockFile;
|
||||
|
||||
public class SkipList {
|
||||
/** the probability of each next higher level */
|
||||
private static final int P = 2;
|
||||
private static final int MIN_SLOTS = 4;
|
||||
// these two are really final
|
||||
protected SkipSpan first;
|
||||
protected SkipLevels stack;
|
||||
// I2P mod
|
||||
public static final Random rng = RandomSource.getInstance();
|
||||
|
||||
public int size=0;
|
||||
public int spans=0;
|
||||
protected int size;
|
||||
protected int spans;
|
||||
protected int levelCount;
|
||||
|
||||
public void flush() { }
|
||||
protected SkipList() { }
|
||||
@ -56,11 +61,34 @@ public class SkipList {
|
||||
first = new SkipSpan(span);
|
||||
stack = new SkipLevels(1, first);
|
||||
spans = 1;
|
||||
levelCount = 1;
|
||||
//rng = new Random(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public int size() { return size; }
|
||||
|
||||
public void addItem() {
|
||||
size++;
|
||||
}
|
||||
|
||||
public void delItem() {
|
||||
if (size > 0)
|
||||
size--;
|
||||
}
|
||||
|
||||
public void addSpan(boolean addLevel) {
|
||||
spans++;
|
||||
if (addLevel)
|
||||
levelCount++;
|
||||
}
|
||||
|
||||
public void delSpan(boolean delLevel) {
|
||||
if (spans > 0)
|
||||
spans--;
|
||||
if (delLevel && levelCount > 0)
|
||||
levelCount--;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return log2(spans), minimum 4
|
||||
*/
|
||||
@ -68,21 +96,21 @@ public class SkipList {
|
||||
int hob = 0, s = spans;
|
||||
while(s > 0) {
|
||||
hob++;
|
||||
s /= 2;
|
||||
s /= P;
|
||||
}
|
||||
return Math.max(hob, 4);
|
||||
return Math.max(hob, MIN_SLOTS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0..maxLevels()
|
||||
* @return 0..maxLevels(), each successive one with probability 1 / P
|
||||
*/
|
||||
public int generateColHeight() {
|
||||
int bits = rng.nextInt();
|
||||
int max = maxLevels();
|
||||
for(int res = 0; res < max; res++) {
|
||||
if (bits % 2 == 0)
|
||||
if (bits % P == 0)
|
||||
return res;
|
||||
bits /= 2;
|
||||
bits /= P;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
@ -93,7 +121,7 @@ public class SkipList {
|
||||
SkipLevels slvls = stack.put(stack.levels.length - 1, key, val, this);
|
||||
if(slvls != null) {
|
||||
// grow our stack
|
||||
BlockFile.log.info("Top level old hgt " + stack.levels.length + " new hgt " + slvls.levels.length);
|
||||
//BlockFile.log.info("Top level old hgt " + stack.levels.length + " new hgt " + slvls.levels.length);
|
||||
SkipLevels[] levels = new SkipLevels[slvls.levels.length];
|
||||
for(int i=0;i < slvls.levels.length; i++) {
|
||||
if(i < stack.levels.length) {
|
||||
|
@ -138,7 +138,6 @@ public class SkipSpan {
|
||||
|
||||
private void split(int loc, Comparable key, Object val, SkipList sl) {
|
||||
SkipSpan right = newInstance(sl);
|
||||
sl.spans++;
|
||||
|
||||
if(this.next != null) { this.next.prev = right; }
|
||||
right.next = this.next;
|
||||
@ -175,7 +174,7 @@ public class SkipSpan {
|
||||
* @return the new span if it caused a split, else null if it went in this span
|
||||
*/
|
||||
private SkipSpan insert(int loc, Comparable key, Object val, SkipList sl) {
|
||||
sl.size++;
|
||||
sl.addItem();
|
||||
if(nKeys == keys.length) {
|
||||
// split.
|
||||
split(loc, key, val, sl);
|
||||
@ -194,7 +193,7 @@ public class SkipSpan {
|
||||
*/
|
||||
public SkipSpan put(Comparable key, Object val, SkipList sl) {
|
||||
if(nKeys == 0) {
|
||||
sl.size++;
|
||||
sl.addItem();
|
||||
keys[0] = key;
|
||||
vals[0] = val;
|
||||
nKeys++;
|
||||
@ -256,9 +255,8 @@ public class SkipSpan {
|
||||
Object o = vals[loc];
|
||||
Object[] res = new Object[2];
|
||||
res[0] = o;
|
||||
sl.size--;
|
||||
sl.delItem();
|
||||
if(nKeys == 1) {
|
||||
if(sl.spans > 1) { sl.spans--; }
|
||||
if((this.prev == null) && (this.next != null)) {
|
||||
res[1] = this.next;
|
||||
// We're the first node in the list... copy the next node over and kill it. See also bottom of SkipLevels.java
|
||||
|
Reference in New Issue
Block a user