forked from I2P_Developers/i2p.i2p
Blockfile: Add generics, part 1
This commit is contained in:
@ -105,13 +105,13 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
private String _version = "0";
|
private String _version = "0";
|
||||||
private boolean _needsUpgrade;
|
private boolean _needsUpgrade;
|
||||||
|
|
||||||
private static final Serializer _infoSerializer = new PropertiesSerializer();
|
private static final Serializer<Properties> _infoSerializer = new PropertiesSerializer();
|
||||||
private static final Serializer _stringSerializer = new UTF8StringBytes();
|
private static final Serializer<String> _stringSerializer = new UTF8StringBytes();
|
||||||
private static final Serializer _destSerializerV1 = new DestEntrySerializer();
|
private static final Serializer<DestEntry> _destSerializerV1 = new DestEntrySerializer();
|
||||||
private static final Serializer _destSerializerV4 = new DestEntrySerializerV4();
|
private static final Serializer<DestEntry> _destSerializerV4 = new DestEntrySerializerV4();
|
||||||
// upgrade(), initExisting(), and initNew() will change this to _destSerializerV4
|
// upgrade(), initExisting(), and initNew() will change this to _destSerializerV4
|
||||||
private volatile Serializer _destSerializer = _destSerializerV1;
|
private volatile Serializer<DestEntry> _destSerializer = _destSerializerV1;
|
||||||
private static final Serializer _hashIndexSerializer = new IntBytes();
|
private static final Serializer<Integer> _hashIndexSerializer = new IntBytes();
|
||||||
|
|
||||||
private static final String HOSTS_DB = "hostsdb.blockfile";
|
private static final String HOSTS_DB = "hostsdb.blockfile";
|
||||||
private static final String FALLBACK_LIST = "hosts.txt";
|
private static final String FALLBACK_LIST = "hosts.txt";
|
||||||
@ -1402,14 +1402,13 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
* but if we threw a RuntimeException we would prevent access to entries later in
|
* but if we threw a RuntimeException we would prevent access to entries later in
|
||||||
* the SkipSpan.
|
* the SkipSpan.
|
||||||
*/
|
*/
|
||||||
private static class DestEntrySerializer implements Serializer {
|
private static class DestEntrySerializer implements Serializer<DestEntry> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A format error on the properties is non-fatal (only the properties are lost)
|
* A format error on the properties is non-fatal (only the properties are lost)
|
||||||
* A format error on the destination is fatal
|
* A format error on the destination is fatal
|
||||||
*/
|
*/
|
||||||
public byte[] getBytes(Object o) {
|
public byte[] getBytes(DestEntry de) {
|
||||||
DestEntry de = (DestEntry) o;
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
@ -1429,7 +1428,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** returns null on error */
|
/** returns null on error */
|
||||||
public Object construct(byte[] b) {
|
public DestEntry construct(byte[] b) {
|
||||||
DestEntry rv = new DestEntry();
|
DestEntry rv = new DestEntry();
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(b);
|
ByteArrayInputStream bais = new ByteArrayInputStream(b);
|
||||||
try {
|
try {
|
||||||
@ -1452,10 +1451,9 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
* For multiple destinations per hostname
|
* For multiple destinations per hostname
|
||||||
* @since 0.9.26
|
* @since 0.9.26
|
||||||
*/
|
*/
|
||||||
private static class DestEntrySerializerV4 implements Serializer {
|
private static class DestEntrySerializerV4 implements Serializer<DestEntry> {
|
||||||
|
|
||||||
public byte[] getBytes(Object o) {
|
public byte[] getBytes(DestEntry de) {
|
||||||
DestEntry de = (DestEntry) o;
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
|
||||||
int sz = de.destList != null ? de.destList.size() : 1;
|
int sz = de.destList != null ? de.destList.size() : 1;
|
||||||
try {
|
try {
|
||||||
@ -1487,7 +1485,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** returns null on error */
|
/** returns null on error */
|
||||||
public Object construct(byte[] b) {
|
public DestEntry construct(byte[] b) {
|
||||||
DestEntry rv = new DestEntry();
|
DestEntry rv = new DestEntry();
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(b);
|
ByteArrayInputStream bais = new ByteArrayInputStream(b);
|
||||||
try {
|
try {
|
||||||
|
@ -28,7 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||||||
*/
|
*/
|
||||||
package net.metanotion.io;
|
package net.metanotion.io;
|
||||||
|
|
||||||
public interface Serializer {
|
public interface Serializer<T> {
|
||||||
public byte[] getBytes(Object o);
|
public byte[] getBytes(T o);
|
||||||
public Object construct(byte[] b);
|
public T construct(byte[] b);
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ public class BlockFile implements Closeable {
|
|||||||
/** I2P was the file locked when we opened it? */
|
/** I2P was the file locked when we opened it? */
|
||||||
private final boolean _wasMounted;
|
private final boolean _wasMounted;
|
||||||
|
|
||||||
private final BSkipList metaIndex;
|
private final BSkipList<String, Integer> metaIndex;
|
||||||
private boolean _isClosed;
|
private boolean _isClosed;
|
||||||
/** cached list of free pages, only valid if freListStart > 0 */
|
/** cached list of free pages, only valid if freListStart > 0 */
|
||||||
private FreeListBlock flb;
|
private FreeListBlock flb;
|
||||||
@ -322,7 +322,7 @@ public class BlockFile implements Closeable {
|
|||||||
if (rai.canWrite())
|
if (rai.canWrite())
|
||||||
mount();
|
mount();
|
||||||
|
|
||||||
metaIndex = new BSkipList(spanSize, this, METAINDEX_PAGE, new StringBytes(), new IntBytes());
|
metaIndex = new BSkipList<String, Integer>(spanSize, this, METAINDEX_PAGE, new StringBytes(), new IntBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -442,15 +442,15 @@ public class BlockFile implements Closeable {
|
|||||||
*
|
*
|
||||||
* @return null if not found
|
* @return null if not found
|
||||||
*/
|
*/
|
||||||
public BSkipList getIndex(String name, Serializer key, Serializer val) throws IOException {
|
public <K extends Comparable<? super K>, V> BSkipList<K, V> getIndex(String name, Serializer<K> key, Serializer<V> val) throws IOException {
|
||||||
// added I2P
|
// added I2P
|
||||||
BSkipList bsl = openIndices.get(name);
|
BSkipList<K, V> bsl = (BSkipList<K, V>) openIndices.get(name);
|
||||||
if (bsl != null)
|
if (bsl != null)
|
||||||
return bsl;
|
return bsl;
|
||||||
|
|
||||||
Integer page = (Integer) metaIndex.get(name);
|
Integer page = metaIndex.get(name);
|
||||||
if (page == null) { return null; }
|
if (page == null) { return null; }
|
||||||
bsl = new BSkipList(spanSize, this, page.intValue(), key, val, true);
|
bsl = new BSkipList<K, V>(spanSize, this, page.intValue(), key, val, true);
|
||||||
if (file.canWrite()) {
|
if (file.canWrite()) {
|
||||||
log.info("Checking skiplist " + name + " in blockfile " + file);
|
log.info("Checking skiplist " + name + " in blockfile " + file);
|
||||||
if (bsl.bslck(true, false))
|
if (bsl.bslck(true, false))
|
||||||
@ -468,12 +468,12 @@ public class BlockFile implements Closeable {
|
|||||||
*
|
*
|
||||||
* @throws IOException if already exists or other errors
|
* @throws IOException if already exists or other errors
|
||||||
*/
|
*/
|
||||||
public BSkipList makeIndex(String name, Serializer key, Serializer val) throws IOException {
|
public <K extends Comparable<? super K>, V> BSkipList<K, V> makeIndex(String name, Serializer<K> key, Serializer<V> val) throws IOException {
|
||||||
if(metaIndex.get(name) != null) { throw new IOException("Index already exists"); }
|
if(metaIndex.get(name) != null) { throw new IOException("Index already exists"); }
|
||||||
int page = allocPage();
|
int page = allocPage();
|
||||||
metaIndex.put(name, Integer.valueOf(page));
|
metaIndex.put(name, Integer.valueOf(page));
|
||||||
BSkipList.init(this, page, spanSize);
|
BSkipList.init(this, page, spanSize);
|
||||||
BSkipList bsl = new BSkipList(spanSize, this, page, key, val, true);
|
BSkipList<K, V> bsl = new BSkipList<K, V>(spanSize, this, page, key, val, true);
|
||||||
openIndices.put(name, bsl);
|
openIndices.put(name, bsl);
|
||||||
return bsl;
|
return bsl;
|
||||||
}
|
}
|
||||||
@ -516,24 +516,24 @@ public class BlockFile implements Closeable {
|
|||||||
* @throws IOException if it is open or on errors
|
* @throws IOException if it is open or on errors
|
||||||
* @since 0.9.26
|
* @since 0.9.26
|
||||||
*/
|
*/
|
||||||
public void reformatIndex(String name, Serializer oldKey, Serializer oldVal,
|
public <K extends Comparable<? super K>, V> void reformatIndex(String name, Serializer<K> oldKey, Serializer<V> oldVal,
|
||||||
Serializer newKey, Serializer newVal) throws IOException {
|
Serializer<K> newKey, Serializer<V> newVal) throws IOException {
|
||||||
if (openIndices.containsKey(name))
|
if (openIndices.containsKey(name))
|
||||||
throw new IOException("Cannot reformat open skiplist " + name);
|
throw new IOException("Cannot reformat open skiplist " + name);
|
||||||
BSkipList old = getIndex(name, oldKey, oldVal);
|
BSkipList<K, V> old = getIndex(name, oldKey, oldVal);
|
||||||
if (old == null)
|
if (old == null)
|
||||||
return;
|
return;
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
String tmpName = "---tmp---" + name + "---tmp---";
|
String tmpName = "---tmp---" + name + "---tmp---";
|
||||||
BSkipList tmp = makeIndex(tmpName, newKey, newVal);
|
BSkipList<K, V> tmp = makeIndex(tmpName, newKey, newVal);
|
||||||
|
|
||||||
// It could be much more efficient to do this at the
|
// It could be much more efficient to do this at the
|
||||||
// SkipSpan layer but that's way too hard.
|
// SkipSpan layer but that's way too hard.
|
||||||
final int loop = 32;
|
final int loop = 32;
|
||||||
List<Comparable> keys = new ArrayList<Comparable>(loop);
|
List<K> keys = new ArrayList<K>(loop);
|
||||||
List<Object> vals = new ArrayList<Object>(loop);
|
List<V> vals = new ArrayList<V>(loop);
|
||||||
while (true) {
|
while (true) {
|
||||||
SkipIterator iter = old.iterator();
|
SkipIterator<K, V> iter = old.iterator();
|
||||||
for (int i = 0; iter.hasNext() && i < loop; i++) {
|
for (int i = 0; iter.hasNext() && i < loop; i++) {
|
||||||
keys.add(iter.nextKey());
|
keys.add(iter.nextKey());
|
||||||
vals.add(iter.next());
|
vals.add(iter.next());
|
||||||
@ -555,7 +555,7 @@ public class BlockFile implements Closeable {
|
|||||||
delIndex(name);
|
delIndex(name);
|
||||||
closeIndex(name);
|
closeIndex(name);
|
||||||
closeIndex(tmpName);
|
closeIndex(tmpName);
|
||||||
Integer page = (Integer) metaIndex.get(tmpName);
|
Integer page = metaIndex.get(tmpName);
|
||||||
metaIndex.put(name, page);
|
metaIndex.put(name, page);
|
||||||
metaIndex.remove(tmpName);
|
metaIndex.remove(tmpName);
|
||||||
if (log.shouldWarn())
|
if (log.shouldWarn())
|
||||||
@ -623,9 +623,15 @@ public class BlockFile implements Closeable {
|
|||||||
try {
|
try {
|
||||||
// This uses IdentityBytes, so the value class won't be right, but at least
|
// This uses IdentityBytes, so the value class won't be right, but at least
|
||||||
// it won't fail the out-of-order check
|
// it won't fail the out-of-order check
|
||||||
Serializer keyser = slname.equals("%%__REVERSE__%%") ? new IntBytes() : new UTF8StringBytes();
|
boolean fail;
|
||||||
BSkipList bsl = getIndex(slname, keyser, new IdentityBytes());
|
if (slname.equals("%%__REVERSE__%%")) {
|
||||||
if (bsl == null) {
|
Serializer<Integer> keyser = new IntBytes();
|
||||||
|
fail = getIndex(slname, keyser, new IdentityBytes()) == null;
|
||||||
|
} else {
|
||||||
|
Serializer<String> keyser = new UTF8StringBytes();
|
||||||
|
fail = getIndex(slname, keyser, new IdentityBytes()) == null;
|
||||||
|
}
|
||||||
|
if (fail) {
|
||||||
log.error("Can't find list? " + slname);
|
log.error("Can't find list? " + slname);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -55,13 +55,13 @@ import net.i2p.util.Log;
|
|||||||
*
|
*
|
||||||
* Always fits on one page.
|
* Always fits on one page.
|
||||||
*/
|
*/
|
||||||
public class BSkipLevels extends SkipLevels {
|
public class BSkipLevels<K extends Comparable<? super K>, V> extends SkipLevels<K, V> {
|
||||||
private static final long MAGIC = 0x42534c6576656c73l; // "BSLevels"
|
private static final long MAGIC = 0x42534c6576656c73l; // "BSLevels"
|
||||||
static final int HEADER_LEN = 16;
|
static final int HEADER_LEN = 16;
|
||||||
public final int levelPage;
|
public final int levelPage;
|
||||||
public final int spanPage;
|
public final int spanPage;
|
||||||
public final BlockFile bf;
|
public final BlockFile bf;
|
||||||
private final BSkipList bsl;
|
private final BSkipList<K, V> bsl;
|
||||||
private boolean isKilled;
|
private boolean isKilled;
|
||||||
// the level pages, passed from the constructor to initializeLevels(),
|
// the level pages, passed from the constructor to initializeLevels(),
|
||||||
// NOT kept up to date
|
// NOT kept up to date
|
||||||
@ -73,7 +73,7 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
* after the constructor, unless it's a new empty
|
* after the constructor, unless it's a new empty
|
||||||
* level and init() was previously called.
|
* level and init() was previously called.
|
||||||
*/
|
*/
|
||||||
public BSkipLevels(BlockFile bf, int levelPage, BSkipList bsl) throws IOException {
|
public BSkipLevels(BlockFile bf, int levelPage, BSkipList<K, V> bsl) throws IOException {
|
||||||
this.levelPage = levelPage;
|
this.levelPage = levelPage;
|
||||||
this.bf = bf;
|
this.bf = bf;
|
||||||
this.bsl = bsl;
|
this.bsl = bsl;
|
||||||
@ -97,7 +97,7 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
throw new IOException("No span found in cache???");
|
throw new IOException("No span found in cache???");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.levels = new BSkipLevels[maxLen];
|
this.levels = (BSkipLevels<K, V>[]) new BSkipLevels[maxLen];
|
||||||
if (bf.log.shouldLog(Log.DEBUG))
|
if (bf.log.shouldLog(Log.DEBUG))
|
||||||
bf.log.debug("Reading New BSkipLevels with " + nonNull + " / " + maxLen + " valid levels page " + levelPage +
|
bf.log.debug("Reading New BSkipLevels with " + nonNull + " / " + maxLen + " valid levels page " + levelPage +
|
||||||
" in skiplist " + bsl);
|
" in skiplist " + bsl);
|
||||||
@ -118,14 +118,14 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
* @since 0.9.20
|
* @since 0.9.20
|
||||||
*/
|
*/
|
||||||
public void initializeLevels() {
|
public void initializeLevels() {
|
||||||
List<BSkipLevels> toInit = new ArrayList<BSkipLevels>(32);
|
List<BSkipLevels<K, V>> toInit = new ArrayList<BSkipLevels<K, V>>(32);
|
||||||
List<BSkipLevels> nextInit = new ArrayList<BSkipLevels>(32);
|
List<BSkipLevels<K, V>> nextInit = new ArrayList<BSkipLevels<K, V>>(32);
|
||||||
initializeLevels(toInit);
|
initializeLevels(toInit);
|
||||||
while (!toInit.isEmpty()) {
|
while (!toInit.isEmpty()) {
|
||||||
for (BSkipLevels bsl : toInit) {
|
for (BSkipLevels<K, V> bsl : toInit) {
|
||||||
bsl.initializeLevels(nextInit);
|
bsl.initializeLevels(nextInit);
|
||||||
}
|
}
|
||||||
List<BSkipLevels> tmp = toInit;
|
List<BSkipLevels<K, V>> tmp = toInit;
|
||||||
toInit = nextInit;
|
toInit = nextInit;
|
||||||
nextInit = tmp;
|
nextInit = tmp;
|
||||||
nextInit.clear();
|
nextInit.clear();
|
||||||
@ -139,7 +139,7 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
* @param nextInit out parameter, next levels to initialize
|
* @param nextInit out parameter, next levels to initialize
|
||||||
* @since 0.9.20
|
* @since 0.9.20
|
||||||
*/
|
*/
|
||||||
private void initializeLevels(List<BSkipLevels> nextInit) {
|
private void initializeLevels(List<BSkipLevels<K, V>> nextInit) {
|
||||||
boolean fail = false;
|
boolean fail = false;
|
||||||
for(int i = 0; i < lps.length; i++) {
|
for(int i = 0; i < lps.length; i++) {
|
||||||
int lp = lps[i];
|
int lp = lps[i];
|
||||||
@ -147,7 +147,7 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
levels[i] = bsl.levelHash.get(Integer.valueOf(lp));
|
levels[i] = bsl.levelHash.get(Integer.valueOf(lp));
|
||||||
if(levels[i] == null) {
|
if(levels[i] == null) {
|
||||||
try {
|
try {
|
||||||
BSkipLevels lev = new BSkipLevels(bf, lp, bsl);
|
BSkipLevels<K, V> lev = new BSkipLevels<K, V>(bf, lp, bsl);
|
||||||
levels[i] = lev;
|
levels[i] = lev;
|
||||||
nextInit.add(lev);
|
nextInit.add(lev);
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
@ -158,8 +158,8 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Comparable ourKey = key();
|
K ourKey = key();
|
||||||
Comparable nextKey = levels[i].key();
|
K nextKey = levels[i].key();
|
||||||
if (ourKey != null && nextKey != null &&
|
if (ourKey != null && nextKey != null &&
|
||||||
ourKey.compareTo(nextKey) >= 0) {
|
ourKey.compareTo(nextKey) >= 0) {
|
||||||
bf.log.warn("Corrupt database, level out of order " + this +
|
bf.log.warn("Corrupt database, level out of order " + this +
|
||||||
@ -215,9 +215,9 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bf.file.writeShort(i);
|
bf.file.writeShort(i);
|
||||||
bf.file.writeInt(((BSkipSpan) bottom).page);
|
bf.file.writeInt(((BSkipSpan<K, V>) bottom).page);
|
||||||
for(int j = 0; j < i; j++) {
|
for(int j = 0; j < i; j++) {
|
||||||
bf.file.writeInt(((BSkipLevels) levels[j]).levelPage);
|
bf.file.writeInt(((BSkipLevels<K, V>) levels[j]).levelPage);
|
||||||
}
|
}
|
||||||
} catch (IOException ioe) { throw new RuntimeException("Error writing to database", ioe); }
|
} catch (IOException ioe) { throw new RuntimeException("Error writing to database", ioe); }
|
||||||
}
|
}
|
||||||
@ -236,15 +236,15 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SkipLevels newInstance(int levels, SkipSpan ss, SkipList sl) {
|
public SkipLevels<K, V> newInstance(int levels, SkipSpan<K, V> ss, SkipList<K, V> sl) {
|
||||||
try {
|
try {
|
||||||
BSkipSpan bss = (BSkipSpan) ss;
|
BSkipSpan<K, V> bss = (BSkipSpan<K, V>) ss;
|
||||||
BSkipList bsl = (BSkipList) sl;
|
BSkipList<K, V> bsl = (BSkipList<K, V>) sl;
|
||||||
int page = bf.allocPage();
|
int page = bf.allocPage();
|
||||||
BSkipLevels.init(bf, page, bss.page, levels);
|
BSkipLevels.init(bf, page, bss.page, levels);
|
||||||
if (bf.log.shouldLog(Log.DEBUG))
|
if (bf.log.shouldLog(Log.DEBUG))
|
||||||
bf.log.debug("New BSkipLevels height " + levels + " page " + page);
|
bf.log.debug("New BSkipLevels height " + levels + " page " + page);
|
||||||
return new BSkipLevels(bf, page, bsl);
|
return new BSkipLevels<K, V>(bf, page, bsl);
|
||||||
// do not need to call initLevels() here
|
// do not need to call initLevels() here
|
||||||
} catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); }
|
} catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); }
|
||||||
}
|
}
|
||||||
@ -273,7 +273,7 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
* @since 0.8.8
|
* @since 0.8.8
|
||||||
*/
|
*/
|
||||||
private boolean blvlfix() {
|
private boolean blvlfix() {
|
||||||
TreeSet<SkipLevels> lvls = new TreeSet<SkipLevels>(new LevelComparator());
|
TreeSet<SkipLevels<K, V>> lvls = new TreeSet<SkipLevels<K, V>>(new LevelComparator<K, V>());
|
||||||
if (bf.log.shouldLog(Log.DEBUG))
|
if (bf.log.shouldLog(Log.DEBUG))
|
||||||
bf.log.debug("Starting level search");
|
bf.log.debug("Starting level search");
|
||||||
getAllLevels(this, lvls);
|
getAllLevels(this, lvls);
|
||||||
@ -285,15 +285,15 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
}
|
}
|
||||||
// traverse the levels, back-to-front
|
// traverse the levels, back-to-front
|
||||||
boolean rv = false;
|
boolean rv = false;
|
||||||
SkipLevels after = null;
|
SkipLevels<K, V> after = null;
|
||||||
for (SkipLevels lv : lvls) {
|
for (SkipLevels<K, V> lv : lvls) {
|
||||||
boolean modified = false;
|
boolean modified = false;
|
||||||
if (bf.log.shouldLog(Log.DEBUG))
|
if (bf.log.shouldLog(Log.DEBUG))
|
||||||
bf.log.debug("Checking " + lv.print());
|
bf.log.debug("Checking " + lv.print());
|
||||||
if (after != null) {
|
if (after != null) {
|
||||||
int min = Math.min(after.levels.length, lv.levels.length);
|
int min = Math.min(after.levels.length, lv.levels.length);
|
||||||
for (int i = 0; i < min; i++) {
|
for (int i = 0; i < min; i++) {
|
||||||
SkipLevels cur = lv.levels[i];
|
SkipLevels<K, V> cur = lv.levels[i];
|
||||||
if (cur != after) {
|
if (cur != after) {
|
||||||
if (cur != null)
|
if (cur != null)
|
||||||
bf.log.warn("Level " + i + " was wrong, fixing for " + lv.print());
|
bf.log.warn("Level " + i + " was wrong, fixing for " + lv.print());
|
||||||
@ -331,12 +331,12 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
* @param lvlSet out parameter, the result
|
* @param lvlSet out parameter, the result
|
||||||
* @since 0.8.8
|
* @since 0.8.8
|
||||||
*/
|
*/
|
||||||
private void getAllLevels(SkipLevels l, Set<SkipLevels> lvlSet) {
|
private void getAllLevels(SkipLevels<K, V> l, Set<SkipLevels<K, V>> lvlSet) {
|
||||||
if (bf.log.shouldLog(Log.DEBUG))
|
if (bf.log.shouldLog(Log.DEBUG))
|
||||||
bf.log.debug("GAL " + l.print());
|
bf.log.debug("GAL " + l.print());
|
||||||
// Do level 0 without recursion, on the assumption everything is findable
|
// Do level 0 without recursion, on the assumption everything is findable
|
||||||
// from the root
|
// from the root
|
||||||
SkipLevels cur = l;
|
SkipLevels<K, V> cur = l;
|
||||||
while (cur != null && lvlSet.add(cur)) {
|
while (cur != null && lvlSet.add(cur)) {
|
||||||
if (bf.log.shouldLog(Log.DEBUG))
|
if (bf.log.shouldLog(Log.DEBUG))
|
||||||
bf.log.debug("Adding " + cur.print());
|
bf.log.debug("Adding " + cur.print());
|
||||||
@ -347,7 +347,7 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
// If there were no nulls at level 0 in the middle,
|
// If there were no nulls at level 0 in the middle,
|
||||||
// i.e. there are no problems, this won't find anything
|
// i.e. there are no problems, this won't find anything
|
||||||
for (int i = 1; i < l.levels.length; i++) {
|
for (int i = 1; i < l.levels.length; i++) {
|
||||||
SkipLevels lv = l.levels[i];
|
SkipLevels<K, V> lv = l.levels[i];
|
||||||
if (lv != null && !lvlSet.contains(lv))
|
if (lv != null && !lvlSet.contains(lv))
|
||||||
getAllLevels(lv, lvlSet);
|
getAllLevels(lv, lvlSet);
|
||||||
}
|
}
|
||||||
@ -358,10 +358,10 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
* Sorts in REVERSE order.
|
* Sorts in REVERSE order.
|
||||||
* @since 0.8.8
|
* @since 0.8.8
|
||||||
*/
|
*/
|
||||||
private static class LevelComparator implements Comparator<SkipLevels>, Serializable {
|
private static class LevelComparator<K extends Comparable<? super K>, V> implements Comparator<SkipLevels<K, V>>, Serializable {
|
||||||
public int compare(SkipLevels l, SkipLevels r) {
|
public int compare(SkipLevels<K, V> l, SkipLevels<K, V> r) {
|
||||||
Comparable lk = l.key();
|
K lk = l.key();
|
||||||
Comparable rk = r.key();
|
K rk = r.key();
|
||||||
if (lk == null && rk == null)
|
if (lk == null && rk == null)
|
||||||
return 0;
|
return 0;
|
||||||
if (lk == null)
|
if (lk == null)
|
||||||
@ -378,13 +378,13 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
* This needs work.
|
* This needs work.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean blvlck(boolean fix, int width, SkipLevels[] prevLevels) {
|
public boolean blvlck(boolean fix, int width, SkipLevels<K, V>[] prevLevels) {
|
||||||
bf.log.warn(" Skip level at width " + width);
|
bf.log.warn(" Skip level at width " + width);
|
||||||
bf.log.warn(" levels " + this.levels.length);
|
bf.log.warn(" levels " + this.levels.length);
|
||||||
bf.log.warn(" first key " + this.key());
|
bf.log.warn(" first key " + this.key());
|
||||||
bf.log.warn(" spanPage " + this.spanPage);
|
bf.log.warn(" spanPage " + this.spanPage);
|
||||||
bf.log.warn(" levelPage " + this.levelPage);
|
bf.log.warn(" levelPage " + this.levelPage);
|
||||||
SkipLevels higher = null;
|
SkipLevels<K, V> higher = null;
|
||||||
for (int i = levels.length - 1; i >= 0; i--) {
|
for (int i = levels.length - 1; i >= 0; i--) {
|
||||||
if (levels[i] != null) {
|
if (levels[i] != null) {
|
||||||
bf.log.info(" level " + i + " -> " + levels[i].key() + " ");
|
bf.log.info(" level " + i + " -> " + levels[i].key() + " ");
|
||||||
@ -418,7 +418,7 @@ public class BSkipLevels extends SkipLevels {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
prevLevels = new SkipLevels[levels.length];
|
prevLevels = (SkipLevels<K, V>[]) new SkipLevels[levels.length];
|
||||||
System.arraycopy(levels, 0, prevLevels, 0, levels.length);
|
System.arraycopy(levels, 0, prevLevels, 0, levels.length);
|
||||||
}
|
}
|
||||||
if (levels[0] != null)
|
if (levels[0] != null)
|
||||||
|
@ -51,7 +51,7 @@ import net.i2p.util.Log;
|
|||||||
*
|
*
|
||||||
* Always fits on one page.
|
* Always fits on one page.
|
||||||
*/
|
*/
|
||||||
public class BSkipList extends SkipList implements Closeable {
|
public class BSkipList<K extends Comparable<? super K>, V> extends SkipList<K, V> implements Closeable {
|
||||||
private static final long MAGIC = 0x536b69704c697374l; // "SkipList"
|
private static final long MAGIC = 0x536b69704c697374l; // "SkipList"
|
||||||
public int firstSpanPage = 0;
|
public int firstSpanPage = 0;
|
||||||
public int firstLevelPage = 0;
|
public int firstLevelPage = 0;
|
||||||
@ -59,16 +59,16 @@ public class BSkipList extends SkipList implements Closeable {
|
|||||||
public final BlockFile bf;
|
public final BlockFile bf;
|
||||||
private boolean isClosed;
|
private boolean isClosed;
|
||||||
|
|
||||||
final HashMap<Integer, BSkipSpan> spanHash = new HashMap<Integer, BSkipSpan>();
|
final HashMap<Integer, BSkipSpan<K, V>> spanHash = new HashMap<Integer, BSkipSpan<K, V>>();
|
||||||
final HashMap<Integer, SkipLevels> levelHash = new HashMap<Integer, SkipLevels>();
|
final HashMap<Integer, SkipLevels<K, V>> levelHash = new HashMap<Integer, SkipLevels<K, V>>();
|
||||||
|
|
||||||
private final boolean fileOnly;
|
private final boolean fileOnly;
|
||||||
|
|
||||||
public BSkipList(int spanSize, BlockFile bf, int skipPage, Serializer key, Serializer val) throws IOException {
|
public BSkipList(int spanSize, BlockFile bf, int skipPage, Serializer<K> key, Serializer<V> val) throws IOException {
|
||||||
this(spanSize, bf, skipPage, key, val, false);
|
this(spanSize, bf, skipPage, key, val, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BSkipList(int spanSize, BlockFile bf, int skipPage, Serializer key, Serializer val, boolean fileOnly) throws IOException {
|
public BSkipList(int spanSize, BlockFile bf, int skipPage, Serializer<K> key, Serializer<V> val, boolean fileOnly) throws IOException {
|
||||||
if(spanSize < 1) { throw new RuntimeException("Span size too small"); }
|
if(spanSize < 1) { throw new RuntimeException("Span size too small"); }
|
||||||
|
|
||||||
this.skipPage = skipPage;
|
this.skipPage = skipPage;
|
||||||
@ -89,10 +89,10 @@ public class BSkipList extends SkipList implements Closeable {
|
|||||||
|
|
||||||
this.fileOnly = fileOnly;
|
this.fileOnly = fileOnly;
|
||||||
if (fileOnly)
|
if (fileOnly)
|
||||||
first = new IBSkipSpan(bf, this, firstSpanPage, key, val);
|
first = new IBSkipSpan<K, V>(bf, this, firstSpanPage, key, val);
|
||||||
else
|
else
|
||||||
first = new BSkipSpan(bf, this, firstSpanPage, key, val);
|
first = new BSkipSpan<K, V>(bf, this, firstSpanPage, key, val);
|
||||||
BSkipLevels bstack = new BSkipLevels(bf, firstLevelPage, this);
|
BSkipLevels<K, V> bstack = new BSkipLevels<K, V>(bf, firstLevelPage, this);
|
||||||
bstack.initializeLevels();
|
bstack.initializeLevels();
|
||||||
stack = bstack;
|
stack = bstack;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
@ -199,33 +199,33 @@ public class BSkipList extends SkipList implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SkipIterator iterator() {
|
public SkipIterator<K, V> iterator() {
|
||||||
if (!this.fileOnly)
|
if (!this.fileOnly)
|
||||||
return super.iterator();
|
return super.iterator();
|
||||||
return new IBSkipIterator(first, 0);
|
return new IBSkipIterator<K, V>(first, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SkipIterator min() {
|
public SkipIterator<K, V> min() {
|
||||||
return iterator();
|
return iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SkipIterator max() {
|
public SkipIterator<K, V> max() {
|
||||||
if (!this.fileOnly)
|
if (!this.fileOnly)
|
||||||
return super.max();
|
return super.max();
|
||||||
SkipSpan ss = stack.getEnd();
|
SkipSpan<K, V> ss = stack.getEnd();
|
||||||
return new IBSkipIterator(ss, ss.nKeys - 1);
|
return new IBSkipIterator<K, V>(ss, ss.nKeys - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SkipIterator find(Comparable key) {
|
public SkipIterator<K, V> find(K key) {
|
||||||
if (!this.fileOnly)
|
if (!this.fileOnly)
|
||||||
return super.find(key);
|
return super.find(key);
|
||||||
int[] search = new int[1];
|
int[] search = new int[1];
|
||||||
SkipSpan ss = stack.getSpan(stack.levels.length - 1, key, search);
|
SkipSpan<K, V> ss = stack.getSpan(stack.levels.length - 1, key, search);
|
||||||
if(search[0] < 0) { search[0] = -1 * (search[0] + 1); }
|
if(search[0] < 0) { search[0] = -1 * (search[0] + 1); }
|
||||||
return new IBSkipIterator(ss, search[0]);
|
return new IBSkipIterator<K, V>(ss, search[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,19 +59,19 @@ import net.i2p.util.Log;
|
|||||||
* next overflow page (unsigned int)
|
* next overflow page (unsigned int)
|
||||||
*</pre>
|
*</pre>
|
||||||
*/
|
*/
|
||||||
public class BSkipSpan extends SkipSpan {
|
public class BSkipSpan<K extends Comparable<? super K>, V> extends SkipSpan<K, V> {
|
||||||
protected static final int MAGIC = 0x5370616e; // "Span"
|
protected static final int MAGIC = 0x5370616e; // "Span"
|
||||||
protected static final int HEADER_LEN = 20;
|
protected static final int HEADER_LEN = 20;
|
||||||
public static final int CONT_HEADER_LEN = 8;
|
public static final int CONT_HEADER_LEN = 8;
|
||||||
protected final BlockFile bf;
|
protected final BlockFile bf;
|
||||||
private final BSkipList bsl;
|
private final BSkipList<K, V> bsl;
|
||||||
protected int page;
|
protected int page;
|
||||||
protected int overflowPage;
|
protected int overflowPage;
|
||||||
|
|
||||||
protected int prevPage;
|
protected int prevPage;
|
||||||
protected int nextPage = 0;
|
protected int nextPage = 0;
|
||||||
protected Serializer keySer;
|
protected Serializer<K> keySer;
|
||||||
protected Serializer valSer;
|
protected Serializer<V> valSer;
|
||||||
|
|
||||||
// I2P
|
// I2P
|
||||||
protected int spanSize;
|
protected int spanSize;
|
||||||
@ -88,11 +88,11 @@ public class BSkipSpan extends SkipSpan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SkipSpan newInstance(SkipList sl) {
|
public SkipSpan<K, V> newInstance(SkipList<K, V> sl) {
|
||||||
try {
|
try {
|
||||||
int newPage = bf.allocPage();
|
int newPage = bf.allocPage();
|
||||||
init(bf, newPage, bf.spanSize);
|
init(bf, newPage, bf.spanSize);
|
||||||
return new BSkipSpan(bf, (BSkipList) sl, newPage, keySer, valSer);
|
return new BSkipSpan<K, V>(bf, (BSkipList<K, V>) sl, newPage, keySer, valSer);
|
||||||
} catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); }
|
} catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +237,8 @@ public class BSkipSpan extends SkipSpan {
|
|||||||
//bsl.flush();
|
//bsl.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void load(BSkipSpan bss, BlockFile bf, BSkipList bsl, int spanPage, Serializer key, Serializer val) throws IOException {
|
private static <X extends Comparable<? super X>, Y> void load(BSkipSpan<X, Y> bss, BlockFile bf, BSkipList<X, Y> bsl,
|
||||||
|
int spanPage, Serializer<X> key, Serializer<Y> val) throws IOException {
|
||||||
loadInit(bss, bf, bsl, spanPage, key, val);
|
loadInit(bss, bf, bsl, spanPage, key, val);
|
||||||
bss.loadData();
|
bss.loadData();
|
||||||
}
|
}
|
||||||
@ -246,7 +247,8 @@ public class BSkipSpan extends SkipSpan {
|
|||||||
* I2P - first half of load()
|
* I2P - first half of load()
|
||||||
* Only read the span headers
|
* Only read the span headers
|
||||||
*/
|
*/
|
||||||
protected static void loadInit(BSkipSpan bss, BlockFile bf, BSkipList bsl, int spanPage, Serializer key, Serializer val) throws IOException {
|
protected static <X extends Comparable<? super X>, Y> void loadInit(BSkipSpan<X, Y> bss, BlockFile bf, BSkipList<X, Y> bsl,
|
||||||
|
int spanPage, Serializer<X> key, Serializer<Y> val) throws IOException {
|
||||||
if (bss.isKilled)
|
if (bss.isKilled)
|
||||||
throw new IOException("Already killed!! " + bss);
|
throw new IOException("Already killed!! " + bss);
|
||||||
bss.page = spanPage;
|
bss.page = spanPage;
|
||||||
@ -288,8 +290,8 @@ public class BSkipSpan extends SkipSpan {
|
|||||||
protected void loadData(boolean flushOnError) throws IOException {
|
protected void loadData(boolean flushOnError) throws IOException {
|
||||||
if (isKilled)
|
if (isKilled)
|
||||||
throw new IOException("Already killed!! " + this);
|
throw new IOException("Already killed!! " + this);
|
||||||
this.keys = new Comparable[this.spanSize];
|
this.keys = (K[]) new Comparable[this.spanSize];
|
||||||
this.vals = new Object[this.spanSize];
|
this.vals = (V[]) new Object[this.spanSize];
|
||||||
|
|
||||||
int ksz, vsz;
|
int ksz, vsz;
|
||||||
int curPage = this.page;
|
int curPage = this.page;
|
||||||
@ -327,7 +329,7 @@ public class BSkipSpan extends SkipSpan {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// System.out.println("i=" + i + ", Page " + curPage + ", offset " + pageCounter[0] + " ksz " + ksz + " vsz " + vsz);
|
// System.out.println("i=" + i + ", Page " + curPage + ", offset " + pageCounter[0] + " ksz " + ksz + " vsz " + vsz);
|
||||||
this.keys[i] = (Comparable) this.keySer.construct(k);
|
this.keys[i] = this.keySer.construct(k);
|
||||||
this.vals[i] = this.valSer.construct(v);
|
this.vals[i] = this.valSer.construct(v);
|
||||||
// Drop bad entry without throwing exception
|
// Drop bad entry without throwing exception
|
||||||
if (this.keys[i] == null || this.vals[i] == null) {
|
if (this.keys[i] == null || this.vals[i] == null) {
|
||||||
@ -377,31 +379,31 @@ public class BSkipSpan extends SkipSpan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BSkipSpan(BlockFile bf, BSkipList bsl) {
|
protected BSkipSpan(BlockFile bf, BSkipList<K, V> bsl) {
|
||||||
this.bf = bf;
|
this.bf = bf;
|
||||||
this.bsl = bsl;
|
this.bsl = bsl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BSkipSpan(BlockFile bf, BSkipList bsl, int spanPage, Serializer key, Serializer val) throws IOException {
|
public BSkipSpan(BlockFile bf, BSkipList<K, V> bsl, int spanPage, Serializer<K> key, Serializer<V> val) throws IOException {
|
||||||
this.bf = bf;
|
this.bf = bf;
|
||||||
this.bsl = bsl;
|
this.bsl = bsl;
|
||||||
BSkipSpan.load(this, bf, bsl, spanPage, key, val);
|
BSkipSpan.load(this, bf, bsl, spanPage, key, val);
|
||||||
this.next = null;
|
this.next = null;
|
||||||
this.prev = null;
|
this.prev = null;
|
||||||
|
|
||||||
BSkipSpan bss = this;
|
BSkipSpan<K, V> bss = this;
|
||||||
// findbugs ok (set in load() above)
|
// findbugs ok (set in load() above)
|
||||||
int np = nextPage;
|
int np = nextPage;
|
||||||
while(np != 0) {
|
while(np != 0) {
|
||||||
BSkipSpan temp = bsl.spanHash.get(Integer.valueOf(np));
|
BSkipSpan<K, V> temp = bsl.spanHash.get(Integer.valueOf(np));
|
||||||
if(temp != null) {
|
if(temp != null) {
|
||||||
bss.next = temp;
|
bss.next = temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bss.next = new BSkipSpan(bf, bsl);
|
bss.next = new BSkipSpan<K, V>(bf, bsl);
|
||||||
bss.next.next = null;
|
bss.next.next = null;
|
||||||
bss.next.prev = bss;
|
bss.next.prev = bss;
|
||||||
bss = (BSkipSpan) bss.next;
|
bss = (BSkipSpan<K, V>) bss.next;
|
||||||
|
|
||||||
BSkipSpan.load(bss, bf, bsl, np, key, val);
|
BSkipSpan.load(bss, bf, bsl, np, key, val);
|
||||||
np = bss.nextPage;
|
np = bss.nextPage;
|
||||||
@ -411,15 +413,15 @@ public class BSkipSpan extends SkipSpan {
|
|||||||
bss = this;
|
bss = this;
|
||||||
np = prevPage;
|
np = prevPage;
|
||||||
while(np != 0) {
|
while(np != 0) {
|
||||||
BSkipSpan temp = bsl.spanHash.get(Integer.valueOf(np));
|
BSkipSpan<K, V> temp = bsl.spanHash.get(Integer.valueOf(np));
|
||||||
if(temp != null) {
|
if(temp != null) {
|
||||||
bss.prev = temp;
|
bss.prev = temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bss.prev = new BSkipSpan(bf, bsl);
|
bss.prev = new BSkipSpan<K, V>(bf, bsl);
|
||||||
bss.prev.next = bss;
|
bss.prev.next = bss;
|
||||||
bss.prev.prev = null;
|
bss.prev.prev = null;
|
||||||
bss = (BSkipSpan) bss.prev;
|
bss = (BSkipSpan<K, V>) bss.prev;
|
||||||
|
|
||||||
BSkipSpan.load(bss, bf, bsl, np, key, val);
|
BSkipSpan.load(bss, bf, bsl, np, key, val);
|
||||||
np = bss.prevPage;
|
np = bss.prevPage;
|
||||||
|
@ -41,9 +41,9 @@ import net.metanotion.util.skiplist.SkipSpan;
|
|||||||
If the caller does not iterate all the way through, the last span
|
If the caller does not iterate all the way through, the last span
|
||||||
will remain in memory.
|
will remain in memory.
|
||||||
*/
|
*/
|
||||||
public class IBSkipIterator extends SkipIterator {
|
public class IBSkipIterator<K extends Comparable<? super K>, V> extends SkipIterator<K, V> {
|
||||||
|
|
||||||
public IBSkipIterator(SkipSpan ss, int index) {
|
public IBSkipIterator(SkipSpan<K, V> ss, int index) {
|
||||||
super(ss, index);
|
super(ss, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,8 +53,8 @@ public class IBSkipIterator extends SkipIterator {
|
|||||||
* @throws RuntimeException on IOE
|
* @throws RuntimeException on IOE
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object next() {
|
public V next() {
|
||||||
Object o;
|
V o;
|
||||||
if(index < ss.nKeys) {
|
if(index < ss.nKeys) {
|
||||||
if (ss.vals == null) {
|
if (ss.vals == null) {
|
||||||
try {
|
try {
|
||||||
@ -90,7 +90,7 @@ public class IBSkipIterator extends SkipIterator {
|
|||||||
* @throws RuntimeException on IOE
|
* @throws RuntimeException on IOE
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Comparable nextKey() {
|
public K nextKey() {
|
||||||
if(index < ss.nKeys) {
|
if(index < ss.nKeys) {
|
||||||
if (ss.keys == null) {
|
if (ss.keys == null) {
|
||||||
try {
|
try {
|
||||||
@ -110,7 +110,7 @@ public class IBSkipIterator extends SkipIterator {
|
|||||||
* @throws RuntimeException on IOE
|
* @throws RuntimeException on IOE
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object previous() {
|
public V previous() {
|
||||||
if(index > 0) {
|
if(index > 0) {
|
||||||
index--;
|
index--;
|
||||||
} else if(ss.prev != null) {
|
} else if(ss.prev != null) {
|
||||||
|
@ -54,21 +54,21 @@ import net.i2p.util.Log;
|
|||||||
*
|
*
|
||||||
* @author zzz
|
* @author zzz
|
||||||
*/
|
*/
|
||||||
public class IBSkipSpan extends BSkipSpan {
|
public class IBSkipSpan<K extends Comparable<? super K>, V> extends BSkipSpan<K, V> {
|
||||||
|
|
||||||
private Comparable firstKey;
|
private K firstKey;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SkipSpan newInstance(SkipList sl) {
|
public SkipSpan<K, V> newInstance(SkipList<K, V> sl) {
|
||||||
if (bf.log.shouldLog(Log.DEBUG))
|
if (bf.log.shouldLog(Log.DEBUG))
|
||||||
bf.log.debug("Splitting page " + this.page + " containing " + this.nKeys + '/' + this.spanSize);
|
bf.log.debug("Splitting page " + this.page + " containing " + this.nKeys + '/' + this.spanSize);
|
||||||
try {
|
try {
|
||||||
int newPage = bf.allocPage();
|
int newPage = bf.allocPage();
|
||||||
init(bf, newPage, bf.spanSize);
|
init(bf, newPage, bf.spanSize);
|
||||||
SkipSpan rv = new IBSkipSpan(bf, (BSkipList) sl, newPage, keySer, valSer);
|
SkipSpan<K, V> rv = new IBSkipSpan<K, V>(bf, (BSkipList<K, V>) sl, newPage, keySer, valSer);
|
||||||
// this is called after a split, so we need the data arrays initialized
|
// this is called after a split, so we need the data arrays initialized
|
||||||
rv.keys = new Comparable[bf.spanSize];
|
rv.keys = (K[]) new Comparable[bf.spanSize];
|
||||||
rv.vals = new Object[bf.spanSize];
|
rv.vals = (V[]) new Object[bf.spanSize];
|
||||||
return rv;
|
return rv;
|
||||||
} catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); }
|
} catch (IOException ioe) { throw new RuntimeException("Error creating database page", ioe); }
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
pageCounter[0] +=4;
|
pageCounter[0] +=4;
|
||||||
byte[] k = new byte[ksz];
|
byte[] k = new byte[ksz];
|
||||||
curPage = this.bf.readMultiPageData(k, curPage, pageCounter, curNextPage);
|
curPage = this.bf.readMultiPageData(k, curPage, pageCounter, curNextPage);
|
||||||
this.firstKey = (Comparable) this.keySer.construct(k);
|
this.firstKey = this.keySer.construct(k);
|
||||||
if (this.firstKey == null) {
|
if (this.firstKey == null) {
|
||||||
bf.log.error("Null deserialized first key in page " + curPage);
|
bf.log.error("Null deserialized first key in page " + curPage);
|
||||||
repair(1);
|
repair(1);
|
||||||
@ -160,7 +160,7 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
/**
|
/**
|
||||||
* Linear search through the span in the file for the value.
|
* Linear search through the span in the file for the value.
|
||||||
*/
|
*/
|
||||||
private Object getData(Comparable key) throws IOException {
|
private V getData(K key) throws IOException {
|
||||||
seekData();
|
seekData();
|
||||||
int curPage = this.page;
|
int curPage = this.page;
|
||||||
int[] curNextPage = new int[1];
|
int[] curNextPage = new int[1];
|
||||||
@ -194,7 +194,7 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
//System.out.println("i=" + i + ", Page " + curPage + ", offset " + pageCounter[0] + " ksz " + ksz + " vsz " + vsz);
|
//System.out.println("i=" + i + ", Page " + curPage + ", offset " + pageCounter[0] + " ksz " + ksz + " vsz " + vsz);
|
||||||
Comparable ckey = (Comparable) this.keySer.construct(k);
|
K ckey = this.keySer.construct(k);
|
||||||
if (ckey == null) {
|
if (ckey == null) {
|
||||||
// skip the value and keep going
|
// skip the value and keep going
|
||||||
curPage = this.bf.skipMultiPageBytes(vsz, curPage, pageCounter, curNextPage);
|
curPage = this.bf.skipMultiPageBytes(vsz, curPage, pageCounter, curNextPage);
|
||||||
@ -213,7 +213,7 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
lostEntries(i, curPage);
|
lostEntries(i, curPage);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Object rv = this.valSer.construct(v);
|
V rv = this.valSer.construct(v);
|
||||||
if (rv == null) {
|
if (rv == null) {
|
||||||
bf.log.error("Null deserialized value in entry " + i + " page " + curPage +
|
bf.log.error("Null deserialized value in entry " + i + " page " + curPage +
|
||||||
" key=" + ckey);
|
" key=" + ckey);
|
||||||
@ -252,11 +252,11 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
*****/
|
*****/
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBSkipSpan(BlockFile bf, BSkipList bsl) {
|
private IBSkipSpan(BlockFile bf, BSkipList<K, V> bsl) {
|
||||||
super(bf, bsl);
|
super(bf, bsl);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IBSkipSpan(BlockFile bf, BSkipList bsl, int spanPage, Serializer key, Serializer val) throws IOException {
|
public IBSkipSpan(BlockFile bf, BSkipList<K, V> bsl, int spanPage, Serializer<K> key, Serializer<V> val) throws IOException {
|
||||||
super(bf, bsl);
|
super(bf, bsl);
|
||||||
if (bf.log.shouldLog(Log.DEBUG))
|
if (bf.log.shouldLog(Log.DEBUG))
|
||||||
bf.log.debug("New ibss page " + spanPage);
|
bf.log.debug("New ibss page " + spanPage);
|
||||||
@ -265,24 +265,24 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
this.next = null;
|
this.next = null;
|
||||||
this.prev = null;
|
this.prev = null;
|
||||||
|
|
||||||
IBSkipSpan bss = this;
|
IBSkipSpan<K, V> bss = this;
|
||||||
IBSkipSpan temp;
|
IBSkipSpan<K, V> temp;
|
||||||
int np = nextPage;
|
int np = nextPage;
|
||||||
while(np != 0) {
|
while(np != 0) {
|
||||||
temp = (IBSkipSpan) bsl.spanHash.get(Integer.valueOf(np));
|
temp = (IBSkipSpan<K, V>) bsl.spanHash.get(Integer.valueOf(np));
|
||||||
if(temp != null) {
|
if(temp != null) {
|
||||||
bss.next = temp;
|
bss.next = temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bss.next = new IBSkipSpan(bf, bsl);
|
bss.next = new IBSkipSpan<K, V>(bf, bsl);
|
||||||
bss.next.next = null;
|
bss.next.next = null;
|
||||||
bss.next.prev = bss;
|
bss.next.prev = bss;
|
||||||
Comparable previousFirstKey = bss.firstKey;
|
K previousFirstKey = bss.firstKey;
|
||||||
bss = (IBSkipSpan) bss.next;
|
bss = (IBSkipSpan<K, V>) bss.next;
|
||||||
|
|
||||||
BSkipSpan.loadInit(bss, bf, bsl, np, key, val);
|
BSkipSpan.loadInit(bss, bf, bsl, np, key, val);
|
||||||
bss.loadFirstKey();
|
bss.loadFirstKey();
|
||||||
Comparable nextFirstKey = bss.firstKey;
|
K nextFirstKey = bss.firstKey;
|
||||||
if (previousFirstKey == null || nextFirstKey == null ||
|
if (previousFirstKey == null || nextFirstKey == null ||
|
||||||
previousFirstKey.compareTo(nextFirstKey) >= 0) {
|
previousFirstKey.compareTo(nextFirstKey) >= 0) {
|
||||||
// TODO remove, but if we are at the bottom of a level
|
// TODO remove, but if we are at the bottom of a level
|
||||||
@ -299,20 +299,20 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
bss = this;
|
bss = this;
|
||||||
np = prevPage;
|
np = prevPage;
|
||||||
while(np != 0) {
|
while(np != 0) {
|
||||||
temp = (IBSkipSpan) bsl.spanHash.get(Integer.valueOf(np));
|
temp = (IBSkipSpan<K, V>) bsl.spanHash.get(Integer.valueOf(np));
|
||||||
if(temp != null) {
|
if(temp != null) {
|
||||||
bss.prev = temp;
|
bss.prev = temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
bss.prev = new IBSkipSpan(bf, bsl);
|
bss.prev = new IBSkipSpan<K, V>(bf, bsl);
|
||||||
bss.prev.next = bss;
|
bss.prev.next = bss;
|
||||||
bss.prev.prev = null;
|
bss.prev.prev = null;
|
||||||
Comparable nextFirstKey = bss.firstKey;
|
K nextFirstKey = bss.firstKey;
|
||||||
bss = (IBSkipSpan) bss.prev;
|
bss = (IBSkipSpan<K, V>) bss.prev;
|
||||||
|
|
||||||
BSkipSpan.loadInit(bss, bf, bsl, np, key, val);
|
BSkipSpan.loadInit(bss, bf, bsl, np, key, val);
|
||||||
bss.loadFirstKey();
|
bss.loadFirstKey();
|
||||||
Comparable previousFirstKey = bss.firstKey;
|
K previousFirstKey = bss.firstKey;
|
||||||
if (previousFirstKey == null || nextFirstKey == null ||
|
if (previousFirstKey == null || nextFirstKey == null ||
|
||||||
previousFirstKey.compareTo(nextFirstKey) >= 0) {
|
previousFirstKey.compareTo(nextFirstKey) >= 0) {
|
||||||
// TODO remove, but if we are at the bottom of a level
|
// TODO remove, but if we are at the bottom of a level
|
||||||
@ -330,7 +330,7 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
* Does not call super, we always store first key here
|
* Does not call super, we always store first key here
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Comparable firstKey() {
|
public K firstKey() {
|
||||||
return this.firstKey;
|
return this.firstKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,13 +339,13 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
* This is called only via SkipList.find()
|
* This is called only via SkipList.find()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SkipSpan getSpan(Comparable key, int[] search) {
|
public SkipSpan<K, V> getSpan(K key, int[] search) {
|
||||||
try {
|
try {
|
||||||
seekAndLoadData();
|
seekAndLoadData();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new RuntimeException("Error reading database", ioe);
|
throw new RuntimeException("Error reading database", ioe);
|
||||||
}
|
}
|
||||||
SkipSpan rv = super.getSpan(key, search);
|
SkipSpan<K, V> rv = super.getSpan(key, search);
|
||||||
this.keys = null;
|
this.keys = null;
|
||||||
this.vals = null;
|
this.vals = null;
|
||||||
return rv;
|
return rv;
|
||||||
@ -355,7 +355,7 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
* Linear search if in file, Binary search if in memory
|
* Linear search if in file, Binary search if in memory
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object get(Comparable key) {
|
public V get(K key) {
|
||||||
try {
|
try {
|
||||||
if (nKeys == 0) { return null; }
|
if (nKeys == 0) { return null; }
|
||||||
if (this.next != null && this.next.firstKey().compareTo(key) <= 0)
|
if (this.next != null && this.next.firstKey().compareTo(key) <= 0)
|
||||||
@ -370,13 +370,13 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
* Load whole span from file, do the operation, flush out, then null out in-memory data again.
|
* Load whole span from file, do the operation, flush out, then null out in-memory data again.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SkipSpan put(Comparable key, Object val, SkipList sl) {
|
public SkipSpan<K, V> put(K key, V val, SkipList<K, V> sl) {
|
||||||
try {
|
try {
|
||||||
seekAndLoadData();
|
seekAndLoadData();
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
throw new RuntimeException("Error reading database", ioe);
|
throw new RuntimeException("Error reading database", ioe);
|
||||||
}
|
}
|
||||||
SkipSpan rv = super.put(key, val, sl);
|
SkipSpan<K, V> rv = super.put(key, val, sl);
|
||||||
// flush() nulls out the data
|
// flush() nulls out the data
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
@ -385,7 +385,7 @@ public class IBSkipSpan extends BSkipSpan {
|
|||||||
* Load whole span from file, do the operation, flush out, then null out in-memory data again.
|
* Load whole span from file, do the operation, flush out, then null out in-memory data again.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Object[] remove(Comparable key, SkipList sl) {
|
public Object[] remove(K key, SkipList<K, V> sl) {
|
||||||
if (bf.log.shouldLog(Log.DEBUG))
|
if (bf.log.shouldLog(Log.DEBUG))
|
||||||
bf.log.debug("Remove " + key + " in " + this);
|
bf.log.debug("Remove " + key + " in " + this);
|
||||||
if (nKeys <= 0)
|
if (nKeys <= 0)
|
||||||
|
@ -35,11 +35,11 @@ import net.metanotion.io.Serializer;
|
|||||||
* Will never return null.
|
* Will never return null.
|
||||||
* Added by I2P.
|
* Added by I2P.
|
||||||
*/
|
*/
|
||||||
public class IdentityBytes implements Serializer {
|
public class IdentityBytes implements Serializer<byte[]> {
|
||||||
|
|
||||||
/** @return byte[] */
|
/** @return byte[] */
|
||||||
public byte[] getBytes(Object o) { return (byte[])o; }
|
public byte[] getBytes(byte[] o) { return o; }
|
||||||
|
|
||||||
/** @return b */
|
/** @return b */
|
||||||
public Object construct(byte[] b) { return b; }
|
public byte[] construct(byte[] b) { return b; }
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,10 @@ package net.metanotion.io.data;
|
|||||||
|
|
||||||
import net.metanotion.io.Serializer;
|
import net.metanotion.io.Serializer;
|
||||||
|
|
||||||
public class IntBytes implements Serializer {
|
public class IntBytes implements Serializer<Integer> {
|
||||||
public byte[] getBytes(Object o) {
|
public byte[] getBytes(Integer o) {
|
||||||
byte[] b = new byte[4];
|
byte[] b = new byte[4];
|
||||||
int v = ((Integer) o).intValue();
|
int v = o.intValue();
|
||||||
b[0] = (byte)(0xff & (v >> 24));
|
b[0] = (byte)(0xff & (v >> 24));
|
||||||
b[1] = (byte)(0xff & (v >> 16));
|
b[1] = (byte)(0xff & (v >> 16));
|
||||||
b[2] = (byte)(0xff & (v >> 8));
|
b[2] = (byte)(0xff & (v >> 8));
|
||||||
@ -41,7 +41,7 @@ public class IntBytes implements Serializer {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object construct(byte[] b) {
|
public Integer construct(byte[] b) {
|
||||||
int v = (((b[0] & 0xff) << 24) |
|
int v = (((b[0] & 0xff) << 24) |
|
||||||
((b[1] & 0xff) << 16) |
|
((b[1] & 0xff) << 16) |
|
||||||
((b[2] & 0xff) << 8) |
|
((b[2] & 0xff) << 8) |
|
||||||
|
@ -30,10 +30,10 @@ package net.metanotion.io.data;
|
|||||||
|
|
||||||
import net.metanotion.io.Serializer;
|
import net.metanotion.io.Serializer;
|
||||||
|
|
||||||
public class LongBytes implements Serializer {
|
public class LongBytes implements Serializer<Long> {
|
||||||
public byte[] getBytes(Object o) {
|
public byte[] getBytes(Long o) {
|
||||||
byte[] b = new byte[8];
|
byte[] b = new byte[8];
|
||||||
long v = ((Long) o).longValue();
|
long v = o.longValue();
|
||||||
b[0] = (byte)(0xff & (v >> 56));
|
b[0] = (byte)(0xff & (v >> 56));
|
||||||
b[1] = (byte)(0xff & (v >> 48));
|
b[1] = (byte)(0xff & (v >> 48));
|
||||||
b[2] = (byte)(0xff & (v >> 40));
|
b[2] = (byte)(0xff & (v >> 40));
|
||||||
@ -45,7 +45,7 @@ public class LongBytes implements Serializer {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object construct(byte[] b) {
|
public Long construct(byte[] b) {
|
||||||
long v =(((long)(b[0] & 0xff) << 56) |
|
long v =(((long)(b[0] & 0xff) << 56) |
|
||||||
((long)(b[1] & 0xff) << 48) |
|
((long)(b[1] & 0xff) << 48) |
|
||||||
((long)(b[2] & 0xff) << 40) |
|
((long)(b[2] & 0xff) << 40) |
|
||||||
|
@ -30,7 +30,7 @@ package net.metanotion.io.data;
|
|||||||
|
|
||||||
import net.metanotion.io.Serializer;
|
import net.metanotion.io.Serializer;
|
||||||
|
|
||||||
public class NullBytes implements Serializer {
|
public class NullBytes implements Serializer<Object> {
|
||||||
public byte[] getBytes(Object o) { return null; }
|
public byte[] getBytes(Object o) { return null; }
|
||||||
public Object construct(byte[] b) { return null; }
|
public Object construct(byte[] b) { return null; }
|
||||||
}
|
}
|
||||||
|
@ -32,14 +32,14 @@ import java.io.UnsupportedEncodingException;
|
|||||||
|
|
||||||
import net.metanotion.io.Serializer;
|
import net.metanotion.io.Serializer;
|
||||||
|
|
||||||
public class StringBytes implements Serializer {
|
public class StringBytes implements Serializer<String> {
|
||||||
public byte[] getBytes(Object o) {
|
public byte[] getBytes(String o) {
|
||||||
try {
|
try {
|
||||||
return ((String) o).getBytes("US-ASCII");
|
return o.getBytes("US-ASCII");
|
||||||
} catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); }
|
} catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object construct(byte[] b) {
|
public String construct(byte[] b) {
|
||||||
try {
|
try {
|
||||||
return new String(b, "US-ASCII");
|
return new String(b, "US-ASCII");
|
||||||
} catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); }
|
} catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); }
|
||||||
|
@ -35,14 +35,14 @@ import net.metanotion.io.Serializer;
|
|||||||
/**
|
/**
|
||||||
* Added by I2P
|
* Added by I2P
|
||||||
*/
|
*/
|
||||||
public class UTF8StringBytes implements Serializer {
|
public class UTF8StringBytes implements Serializer<String> {
|
||||||
public byte[] getBytes(Object o) {
|
public byte[] getBytes(String o) {
|
||||||
try {
|
try {
|
||||||
return ((String) o).getBytes("UTF-8");
|
return o.getBytes("UTF-8");
|
||||||
} catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); }
|
} catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object construct(byte[] b) {
|
public String construct(byte[] b) {
|
||||||
try {
|
try {
|
||||||
return new String(b, "UTF-8");
|
return new String(b, "UTF-8");
|
||||||
} catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); }
|
} catch (UnsupportedEncodingException uee) { throw new Error("Unsupported Encoding"); }
|
||||||
|
@ -39,12 +39,13 @@ import java.util.NoSuchElementException;
|
|||||||
To be clear, this is an iterator through the values.
|
To be clear, this is an iterator through the values.
|
||||||
To get the key, call nextKey() BEFORE calling next().
|
To get the key, call nextKey() BEFORE calling next().
|
||||||
*/
|
*/
|
||||||
public class SkipIterator implements ListIterator {
|
public class SkipIterator<K extends Comparable<? super K>, V> implements ListIterator<V> {
|
||||||
protected SkipSpan ss;
|
protected SkipSpan<K, V> ss;
|
||||||
protected int index;
|
protected int index;
|
||||||
|
|
||||||
protected SkipIterator() { }
|
protected SkipIterator() { }
|
||||||
public SkipIterator(SkipSpan ss, int index) {
|
|
||||||
|
public SkipIterator(SkipSpan<K, V> ss, int index) {
|
||||||
if(ss==null) { throw new NullPointerException(); }
|
if(ss==null) { throw new NullPointerException(); }
|
||||||
this.ss = ss;
|
this.ss = ss;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
@ -59,8 +60,8 @@ public class SkipIterator implements ListIterator {
|
|||||||
* @return the next value, and advances the index
|
* @return the next value, and advances the index
|
||||||
* @throws NoSuchElementException
|
* @throws NoSuchElementException
|
||||||
*/
|
*/
|
||||||
public Object next() {
|
public V next() {
|
||||||
Object o;
|
V o;
|
||||||
if(index < ss.nKeys) {
|
if(index < ss.nKeys) {
|
||||||
o = ss.vals[index];
|
o = ss.vals[index];
|
||||||
} else {
|
} else {
|
||||||
@ -83,7 +84,7 @@ public class SkipIterator implements ListIterator {
|
|||||||
* @return the key for which the value will be returned in the subsequent call to next()
|
* @return the key for which the value will be returned in the subsequent call to next()
|
||||||
* @throws NoSuchElementException
|
* @throws NoSuchElementException
|
||||||
*/
|
*/
|
||||||
public Comparable nextKey() {
|
public K nextKey() {
|
||||||
if(index < ss.nKeys) { return ss.keys[index]; }
|
if(index < ss.nKeys) { return ss.keys[index]; }
|
||||||
throw new NoSuchElementException();
|
throw new NoSuchElementException();
|
||||||
}
|
}
|
||||||
@ -98,7 +99,7 @@ public class SkipIterator implements ListIterator {
|
|||||||
* @return the previous value, and decrements the index
|
* @return the previous value, and decrements the index
|
||||||
* @throws NoSuchElementException
|
* @throws NoSuchElementException
|
||||||
*/
|
*/
|
||||||
public Object previous() {
|
public V previous() {
|
||||||
if(index > 0) {
|
if(index > 0) {
|
||||||
index--;
|
index--;
|
||||||
} else if(ss.prev != null) {
|
} else if(ss.prev != null) {
|
||||||
@ -111,9 +112,9 @@ public class SkipIterator implements ListIterator {
|
|||||||
|
|
||||||
|
|
||||||
// Optional methods
|
// Optional methods
|
||||||
public void add(Object o) { throw new UnsupportedOperationException(); }
|
public void add(V o) { throw new UnsupportedOperationException(); }
|
||||||
public void remove() { throw new UnsupportedOperationException(); }
|
public void remove() { throw new UnsupportedOperationException(); }
|
||||||
public void set(Object o) { throw new UnsupportedOperationException(); }
|
public void set(V o) { throw new UnsupportedOperationException(); }
|
||||||
public int nextIndex() { throw new UnsupportedOperationException(); }
|
public int nextIndex() { throw new UnsupportedOperationException(); }
|
||||||
public int previousIndex() { throw new UnsupportedOperationException(); }
|
public int previousIndex() { throw new UnsupportedOperationException(); }
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ import net.metanotion.io.block.BlockFile;
|
|||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
public class SkipLevels implements Flushable {
|
public class SkipLevels<K extends Comparable<? super K>, V> implements Flushable {
|
||||||
/** We can't have more than 2**32 pages */
|
/** We can't have more than 2**32 pages */
|
||||||
public static final int MAX_SIZE = 32;
|
public static final int MAX_SIZE = 32;
|
||||||
|
|
||||||
@ -45,12 +45,15 @@ public class SkipLevels implements Flushable {
|
|||||||
* The "bottom" level is the direct pointer to a SkipSpan.
|
* The "bottom" level is the direct pointer to a SkipSpan.
|
||||||
*/
|
*/
|
||||||
// levels is almost final
|
// levels is almost final
|
||||||
public SkipLevels[] levels;
|
public SkipLevels<K, V>[] levels;
|
||||||
// bottom is final
|
// bottom is final
|
||||||
public SkipSpan bottom;
|
public SkipSpan<K, V> bottom;
|
||||||
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(BlockFile.class);
|
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(BlockFile.class);
|
||||||
|
|
||||||
public SkipLevels newInstance(int levels, SkipSpan ss, SkipList sl) { return new SkipLevels(levels, ss); }
|
public SkipLevels<K, V> newInstance(int levels, SkipSpan<K, V> ss, SkipList<K, V> sl) {
|
||||||
|
return new SkipLevels<K, V>(levels, ss);
|
||||||
|
}
|
||||||
|
|
||||||
public void killInstance() { }
|
public void killInstance() { }
|
||||||
public void flush() { }
|
public void flush() { }
|
||||||
|
|
||||||
@ -59,10 +62,10 @@ public class SkipLevels implements Flushable {
|
|||||||
/*
|
/*
|
||||||
* @throws IllegalArgumentException if size too big or too small
|
* @throws IllegalArgumentException if size too big or too small
|
||||||
*/
|
*/
|
||||||
public SkipLevels(int size, SkipSpan span) {
|
public SkipLevels(int size, SkipSpan<K, V> span) {
|
||||||
if(size < 1 || size > MAX_SIZE)
|
if(size < 1 || size > MAX_SIZE)
|
||||||
throw new IllegalArgumentException("Invalid Level Skip size");
|
throw new IllegalArgumentException("Invalid Level Skip size");
|
||||||
levels = new SkipLevels[size];
|
levels = (SkipLevels<K, V>[]) new SkipLevels[size];
|
||||||
bottom = span;
|
bottom = span;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,14 +95,14 @@ public class SkipLevels implements Flushable {
|
|||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkipSpan getEnd() {
|
public SkipSpan<K, V> getEnd() {
|
||||||
for(int i=(levels.length - 1);i>=0;i--) {
|
for(int i=(levels.length - 1);i>=0;i--) {
|
||||||
if(levels[i] != null) { return levels[i].getEnd(); }
|
if(levels[i] != null) { return levels[i].getEnd(); }
|
||||||
}
|
}
|
||||||
return bottom.getEnd();
|
return bottom.getEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkipSpan getSpan(int start, Comparable key, int[] search) {
|
public SkipSpan<K, V> getSpan(int start, K key, int[] search) {
|
||||||
for(int i=Math.min(start, levels.length - 1);i>=0;i--) {
|
for(int i=Math.min(start, levels.length - 1);i>=0;i--) {
|
||||||
if((levels[i] != null) && (levels[i].key().compareTo(key) <= 0)) {
|
if((levels[i] != null) && (levels[i].key().compareTo(key) <= 0)) {
|
||||||
return levels[i].getSpan(i,key,search);
|
return levels[i].getSpan(i,key,search);
|
||||||
@ -108,9 +111,9 @@ public class SkipLevels implements Flushable {
|
|||||||
return bottom.getSpan(key, search);
|
return bottom.getSpan(key, search);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Comparable key() { return bottom.firstKey(); }
|
public K key() { return bottom.firstKey(); }
|
||||||
|
|
||||||
public Object get(int start, Comparable key) {
|
public V get(int start, K key) {
|
||||||
for(int i=Math.min(start, levels.length - 1);i>=0;i--) {
|
for(int i=Math.min(start, levels.length - 1);i>=0;i--) {
|
||||||
if((levels[i] != null) && (levels[i].key().compareTo(key) <= 0)) {
|
if((levels[i] != null) && (levels[i].key().compareTo(key) <= 0)) {
|
||||||
return levels[i].get(i,key);
|
return levels[i].get(i,key);
|
||||||
@ -126,16 +129,16 @@ public class SkipLevels implements Flushable {
|
|||||||
* and the deleted SkipLevels is taller than this SkipLevels.
|
* and the deleted SkipLevels is taller than this SkipLevels.
|
||||||
* rv is null if no object was removed.
|
* rv is null if no object was removed.
|
||||||
*/
|
*/
|
||||||
public Object[] remove(int start, Comparable key, SkipList sl) {
|
public Object[] remove(int start, K key, SkipList<K, V> sl) {
|
||||||
Object[] res = null;
|
Object[] res = null;
|
||||||
SkipLevels slvls = null;
|
SkipLevels<K, V> slvls = null;
|
||||||
for(int i = Math.min(start, levels.length - 1); i >= 0; i--) {
|
for(int i = Math.min(start, levels.length - 1); i >= 0; i--) {
|
||||||
if(levels[i] != null) {
|
if(levels[i] != null) {
|
||||||
int cmp = levels[i].key().compareTo(key);
|
int cmp = levels[i].key().compareTo(key);
|
||||||
if((cmp < 0) || ((i==0) && (cmp <= 0))) {
|
if((cmp < 0) || ((i==0) && (cmp <= 0))) {
|
||||||
res = levels[i].remove(i, key, sl);
|
res = levels[i].remove(i, key, sl);
|
||||||
if((res != null) && (res[1] != null)) {
|
if((res != null) && (res[1] != null)) {
|
||||||
slvls = (SkipLevels) res[1];
|
slvls = (SkipLevels<K, V>) res[1];
|
||||||
if(levels.length >= slvls.levels.length) {
|
if(levels.length >= slvls.levels.length) {
|
||||||
res[1] = null;
|
res[1] = null;
|
||||||
}
|
}
|
||||||
@ -159,7 +162,7 @@ public class SkipLevels implements Flushable {
|
|||||||
// if the returned SkipSpan was already copied to us
|
// if the returned SkipSpan was already copied to us
|
||||||
boolean isFirst = sl.first == bottom;
|
boolean isFirst = sl.first == bottom;
|
||||||
if (isFirst && levels[0] != null) {
|
if (isFirst && levels[0] != null) {
|
||||||
SkipSpan ssres = (SkipSpan)res[1];
|
SkipSpan<K, V> ssres = (SkipSpan<K, V>)res[1];
|
||||||
if (bottom.firstKey().equals(ssres.firstKey())) {
|
if (bottom.firstKey().equals(ssres.firstKey())) {
|
||||||
// bottom copied the next span to itself
|
// bottom copied the next span to itself
|
||||||
if (_log.shouldLog(Log.INFO)) {
|
if (_log.shouldLog(Log.INFO)) {
|
||||||
@ -171,7 +174,7 @@ public class SkipLevels implements Flushable {
|
|||||||
_log.info("FIXUP TIME");
|
_log.info("FIXUP TIME");
|
||||||
}
|
}
|
||||||
|
|
||||||
SkipLevels replace = levels[0];
|
SkipLevels<K, V> replace = levels[0];
|
||||||
for (int i = 0; i < levels.length; i++) {
|
for (int i = 0; i < levels.length; i++) {
|
||||||
if (levels[i] == null)
|
if (levels[i] == null)
|
||||||
break;
|
break;
|
||||||
@ -213,12 +216,12 @@ public class SkipLevels implements Flushable {
|
|||||||
* and the new level is taller than our level;
|
* and the new level is taller than our level;
|
||||||
* else null if it went in an existing level or the new level is our height or less.
|
* else null if it went in an existing level or the new level is our height or less.
|
||||||
*/
|
*/
|
||||||
public SkipLevels put(int start, Comparable key, Object val, SkipList sl) {
|
public SkipLevels<K, V> put(int start, K key, V val, SkipList<K, V> sl) {
|
||||||
boolean modified = false;
|
boolean modified = false;
|
||||||
for(int i = Math.min(start, levels.length - 1); i >= 0; i--) {
|
for(int i = Math.min(start, levels.length - 1); i >= 0; i--) {
|
||||||
// is key equal to or after the start of the level?
|
// is key equal to or after the start of the level?
|
||||||
if((levels[i] != null) && (levels[i].key().compareTo(key) <= 0)) {
|
if((levels[i] != null) && (levels[i].key().compareTo(key) <= 0)) {
|
||||||
SkipLevels slvls = levels[i].put(i, key, val, sl);
|
SkipLevels<K, V> slvls = levels[i].put(i, key, val, sl);
|
||||||
if(slvls != null) {
|
if(slvls != null) {
|
||||||
for (int j = i + 1; j < Math.min(slvls.levels.length, levels.length); j++) {
|
for (int j = i + 1; j < Math.min(slvls.levels.length, levels.length); j++) {
|
||||||
// he points to where we used to point
|
// he points to where we used to point
|
||||||
@ -243,11 +246,11 @@ public class SkipLevels implements Flushable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SkipSpan ss = bottom.put(key,val,sl);
|
SkipSpan<K, V> ss = bottom.put(key,val,sl);
|
||||||
if(ss!=null) {
|
if(ss!=null) {
|
||||||
int height = sl.generateColHeight();
|
int height = sl.generateColHeight();
|
||||||
if(height != 0) {
|
if(height != 0) {
|
||||||
SkipLevels slvls = this.newInstance(height, ss, sl);
|
SkipLevels<K, V> slvls = this.newInstance(height, ss, sl);
|
||||||
for(int i=0;i<(Math.min(height,levels.length));i++) {
|
for(int i=0;i<(Math.min(height,levels.length));i++) {
|
||||||
// he points to where we used to point
|
// he points to where we used to point
|
||||||
// and we now point to him
|
// and we now point to him
|
||||||
@ -267,6 +270,6 @@ public class SkipLevels implements Flushable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean blvlck(boolean fix) { return false; }
|
public boolean blvlck(boolean fix) { return false; }
|
||||||
public boolean blvlck(boolean fix, int width, SkipLevels[] prevLevels) { return false; }
|
public boolean blvlck(boolean fix, int width, SkipLevels<K, V>[] prevLevels) { return false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,13 +35,13 @@ import net.i2p.util.RandomSource;
|
|||||||
|
|
||||||
//import net.metanotion.io.block.BlockFile;
|
//import net.metanotion.io.block.BlockFile;
|
||||||
|
|
||||||
public class SkipList implements Flushable {
|
public class SkipList<K extends Comparable<? super K>, V> implements Flushable {
|
||||||
/** the probability of each next higher level */
|
/** the probability of each next higher level */
|
||||||
protected static final int P = 2;
|
protected static final int P = 2;
|
||||||
private static final int MIN_SLOTS = 4;
|
private static final int MIN_SLOTS = 4;
|
||||||
// these two are really final
|
// these two are really final
|
||||||
protected SkipSpan first;
|
protected SkipSpan<K, V> first;
|
||||||
protected SkipLevels stack;
|
protected SkipLevels<K, V> stack;
|
||||||
// I2P mod
|
// I2P mod
|
||||||
public static final Random rng = RandomSource.getInstance();
|
public static final Random rng = RandomSource.getInstance();
|
||||||
|
|
||||||
@ -57,8 +57,8 @@ public class SkipList implements Flushable {
|
|||||||
public SkipList(int span) {
|
public SkipList(int span) {
|
||||||
if(span < 1 || span > SkipSpan.MAX_SIZE)
|
if(span < 1 || span > SkipSpan.MAX_SIZE)
|
||||||
throw new IllegalArgumentException("Invalid span size");
|
throw new IllegalArgumentException("Invalid span size");
|
||||||
first = new SkipSpan(span);
|
first = new SkipSpan<K, V>(span);
|
||||||
stack = new SkipLevels(1, first);
|
stack = new SkipLevels<K, V>(1, first);
|
||||||
//rng = new Random(System.currentTimeMillis());
|
//rng = new Random(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,14 +95,14 @@ public class SkipList implements Flushable {
|
|||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(Comparable key, Object val) {
|
public void put(K key, V val) {
|
||||||
if(key == null) { throw new NullPointerException(); }
|
if(key == null) { throw new NullPointerException(); }
|
||||||
if(val == null) { throw new NullPointerException(); }
|
if(val == null) { throw new NullPointerException(); }
|
||||||
SkipLevels slvls = stack.put(stack.levels.length - 1, key, val, this);
|
SkipLevels<K, V> slvls = stack.put(stack.levels.length - 1, key, val, this);
|
||||||
if(slvls != null) {
|
if(slvls != null) {
|
||||||
// grow our stack
|
// 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];
|
SkipLevels<K, V>[] levels = (SkipLevels<K, V>[]) new SkipLevels[slvls.levels.length];
|
||||||
for(int i=0;i < slvls.levels.length; i++) {
|
for(int i=0;i < slvls.levels.length; i++) {
|
||||||
if(i < stack.levels.length) {
|
if(i < stack.levels.length) {
|
||||||
levels[i] = stack.levels[i];
|
levels[i] = stack.levels[i];
|
||||||
@ -116,12 +116,12 @@ public class SkipList implements Flushable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object remove(Comparable key) {
|
public Object remove(K key) {
|
||||||
if(key == null) { throw new NullPointerException(); }
|
if(key == null) { throw new NullPointerException(); }
|
||||||
Object[] res = stack.remove(stack.levels.length - 1, key, this);
|
Object[] res = stack.remove(stack.levels.length - 1, key, this);
|
||||||
if(res != null) {
|
if(res != null) {
|
||||||
if(res[1] != null) {
|
if(res[1] != null) {
|
||||||
SkipLevels slvls = (SkipLevels) res[1];
|
SkipLevels<K, V> slvls = (SkipLevels<K, V>) res[1];
|
||||||
for(int i=0;i < slvls.levels.length; i++) {
|
for(int i=0;i < slvls.levels.length; i++) {
|
||||||
if(stack.levels[i] == slvls) {
|
if(stack.levels[i] == slvls) {
|
||||||
stack.levels[i] = slvls.levels[i];
|
stack.levels[i] = slvls.levels[i];
|
||||||
@ -154,26 +154,26 @@ public class SkipList implements Flushable {
|
|||||||
System.out.println(first.print());
|
System.out.println(first.print());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get(Comparable key) {
|
public V get(K key) {
|
||||||
if(key == null) { throw new NullPointerException(); }
|
if(key == null) { throw new NullPointerException(); }
|
||||||
return stack.get(stack.levels.length - 1, key);
|
return stack.get(stack.levels.length - 1, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkipIterator iterator() { return new SkipIterator(first, 0); }
|
public SkipIterator<K, V> iterator() { return new SkipIterator<K, V>(first, 0); }
|
||||||
|
|
||||||
public SkipIterator min() { return new SkipIterator(first, 0); }
|
public SkipIterator<K, V> min() { return new SkipIterator<K, V>(first, 0); }
|
||||||
|
|
||||||
public SkipIterator max() {
|
public SkipIterator<K, V> max() {
|
||||||
SkipSpan ss = stack.getEnd();
|
SkipSpan<K, V> ss = stack.getEnd();
|
||||||
return new SkipIterator(ss, ss.nKeys - 1);
|
return new SkipIterator<K, V>(ss, ss.nKeys - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return an iterator where nextKey() is the first one greater than or equal to 'key' */
|
/** @return an iterator where nextKey() is the first one greater than or equal to 'key' */
|
||||||
public SkipIterator find(Comparable key) {
|
public SkipIterator<K, V> find(K key) {
|
||||||
int[] search = new int[1];
|
int[] search = new int[1];
|
||||||
SkipSpan ss = stack.getSpan(stack.levels.length - 1, key, search);
|
SkipSpan<K, V> ss = stack.getSpan(stack.levels.length - 1, key, search);
|
||||||
if(search[0] < 0) { search[0] = -1 * (search[0] + 1); }
|
if(search[0] < 0) { search[0] = -1 * (search[0] + 1); }
|
||||||
return new SkipIterator(ss, search[0]);
|
return new SkipIterator<K, V>(ss, search[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,16 +32,16 @@ import java.io.Flushable;
|
|||||||
|
|
||||||
//import net.metanotion.io.block.BlockFile;
|
//import net.metanotion.io.block.BlockFile;
|
||||||
|
|
||||||
public class SkipSpan implements Flushable {
|
public class SkipSpan<K extends Comparable<? super K>, V> implements Flushable {
|
||||||
/** This is actually limited by BlockFile.spanSize which is much smaller */
|
/** This is actually limited by BlockFile.spanSize which is much smaller */
|
||||||
public static final int MAX_SIZE = 256;
|
public static final int MAX_SIZE = 256;
|
||||||
|
|
||||||
public int nKeys = 0;
|
public int nKeys = 0;
|
||||||
public Comparable[] keys;
|
public K[] keys;
|
||||||
public Object[] vals;
|
public V[] vals;
|
||||||
public SkipSpan next, prev;
|
public SkipSpan<K, V> next, prev;
|
||||||
|
|
||||||
public SkipSpan newInstance(SkipList sl) { return new SkipSpan(keys.length); }
|
public SkipSpan<K, V> newInstance(SkipList<K, V> sl) { return new SkipSpan<K, V>(keys.length); }
|
||||||
public void killInstance() { }
|
public void killInstance() { }
|
||||||
public void flush() { }
|
public void flush() { }
|
||||||
|
|
||||||
@ -53,8 +53,8 @@ public class SkipSpan implements Flushable {
|
|||||||
public SkipSpan(int size) {
|
public SkipSpan(int size) {
|
||||||
if(size < 1 || size > MAX_SIZE)
|
if(size < 1 || size > MAX_SIZE)
|
||||||
throw new IllegalArgumentException("Invalid span size " + size);
|
throw new IllegalArgumentException("Invalid span size " + size);
|
||||||
keys = new Comparable[size];
|
keys = (K[]) new Comparable[size];
|
||||||
vals = new Object[size];
|
vals = (V[]) new Object[size];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** dumps all the data from here to the end */
|
/** dumps all the data from here to the end */
|
||||||
@ -70,7 +70,7 @@ public class SkipSpan implements Flushable {
|
|||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int binarySearch(Comparable key) {
|
private int binarySearch(K key) {
|
||||||
int high = nKeys - 1;
|
int high = nKeys - 1;
|
||||||
int low = 0;
|
int low = 0;
|
||||||
int cur;
|
int cur;
|
||||||
@ -89,12 +89,12 @@ public class SkipSpan implements Flushable {
|
|||||||
return (-1 * (low + 1));
|
return (-1 * (low + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkipSpan getEnd() {
|
public SkipSpan<K, V> getEnd() {
|
||||||
if(next == null) { return this; }
|
if(next == null) { return this; }
|
||||||
return next.getEnd();
|
return next.getEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkipSpan getSpan(Comparable key, int[] search) {
|
public SkipSpan<K, V> getSpan(K key, int[] search) {
|
||||||
if(nKeys == 0) {
|
if(nKeys == 0) {
|
||||||
search[0] = -1;
|
search[0] = -1;
|
||||||
return this;
|
return this;
|
||||||
@ -111,7 +111,7 @@ public class SkipSpan implements Flushable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get(Comparable key) {
|
public V get(K key) {
|
||||||
if(nKeys == 0) { return null; }
|
if(nKeys == 0) { return null; }
|
||||||
if(keys[nKeys - 1].compareTo(key) < 0) {
|
if(keys[nKeys - 1].compareTo(key) < 0) {
|
||||||
if(next == null) { return null; }
|
if(next == null) { return null; }
|
||||||
@ -138,8 +138,8 @@ public class SkipSpan implements Flushable {
|
|||||||
nKeys++;
|
nKeys++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void split(int loc, Comparable key, Object val, SkipList sl) {
|
private void split(int loc, K key, V val, SkipList<K, V> sl) {
|
||||||
SkipSpan right = newInstance(sl);
|
SkipSpan<K, V> right = newInstance(sl);
|
||||||
|
|
||||||
if(this.next != null) { this.next.prev = right; }
|
if(this.next != null) { this.next.prev = right; }
|
||||||
right.next = this.next;
|
right.next = this.next;
|
||||||
@ -175,7 +175,7 @@ public class SkipSpan implements Flushable {
|
|||||||
/**
|
/**
|
||||||
* @return the new span if it caused a split, else null if it went in this span
|
* @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) {
|
private SkipSpan<K, V> insert(int loc, K key, V val, SkipList<K, V> sl) {
|
||||||
sl.addItem();
|
sl.addItem();
|
||||||
if(nKeys == keys.length) {
|
if(nKeys == keys.length) {
|
||||||
// split.
|
// split.
|
||||||
@ -193,7 +193,7 @@ public class SkipSpan implements Flushable {
|
|||||||
/**
|
/**
|
||||||
* @return the new span if it caused a split, else null if it went in an existing span
|
* @return the new span if it caused a split, else null if it went in an existing span
|
||||||
*/
|
*/
|
||||||
public SkipSpan put(Comparable key, Object val, SkipList sl) {
|
public SkipSpan<K, V> put(K key, V val, SkipList<K, V> sl) {
|
||||||
if(nKeys == 0) {
|
if(nKeys == 0) {
|
||||||
sl.addItem();
|
sl.addItem();
|
||||||
keys[0] = key;
|
keys[0] = key;
|
||||||
@ -246,7 +246,7 @@ public class SkipSpan implements Flushable {
|
|||||||
* rv[1] is the deleted SkipSpan if the removed object was the last in the SkipSpan.
|
* rv[1] is the deleted SkipSpan if the removed object was the last in the SkipSpan.
|
||||||
* rv is null if no object was removed.
|
* rv is null if no object was removed.
|
||||||
*/
|
*/
|
||||||
public Object[] remove(Comparable key, SkipList sl) {
|
public Object[] remove(K key, SkipList<K, V> sl) {
|
||||||
if(nKeys == 0) { return null; }
|
if(nKeys == 0) { return null; }
|
||||||
if(keys[nKeys - 1].compareTo(key) < 0) {
|
if(keys[nKeys - 1].compareTo(key) < 0) {
|
||||||
if(next == null) { return null; }
|
if(next == null) { return null; }
|
||||||
@ -270,7 +270,7 @@ public class SkipSpan implements Flushable {
|
|||||||
nKeys = next.nKeys;
|
nKeys = next.nKeys;
|
||||||
//BlockFile.log.error("Killing next span " + next + ") and copying to this span " + this + " in remove of " + key);
|
//BlockFile.log.error("Killing next span " + next + ") and copying to this span " + this + " in remove of " + key);
|
||||||
// Make us point to next.next and him point back to us
|
// Make us point to next.next and him point back to us
|
||||||
SkipSpan nn = next.next;
|
SkipSpan<K, V> nn = next.next;
|
||||||
next.killInstance();
|
next.killInstance();
|
||||||
if (nn != null) {
|
if (nn != null) {
|
||||||
nn.prev = this;
|
nn.prev = this;
|
||||||
@ -311,7 +311,7 @@ public class SkipSpan implements Flushable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** I2P */
|
/** I2P */
|
||||||
public Comparable firstKey() {
|
public K firstKey() {
|
||||||
return keys[0];
|
return keys[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user