- Use new UTF8StringBytes

- Track number of SkipLevels in a SkipList
- More double-checks
- Cleanups, logging, generics
This commit is contained in:
zzz
2011-03-27 22:19:50 +00:00
parent bc231b51b5
commit b7b7283ff9
8 changed files with 78 additions and 54 deletions

View File

@ -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.

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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) {

View File

@ -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