Addressbook: Use new NamingService API methods in action handling

- Refactor HostTxtEntry to consolidate properties writing
- More HostTxtEntry tests
- Start of 'remove' entry handling
Blockfile: Cleanup unused code
- Add Iterable interface to SkipList
This commit is contained in:
zzz
2016-04-21 14:37:38 +00:00
parent 34e390909e
commit 4f262f6140
6 changed files with 159 additions and 197 deletions

View File

@ -254,10 +254,10 @@ public class Daemon {
} }
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME); String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (poldname != null) { if (poldname != null) {
Destination pod = router.lookup(poldname); List<Destination> pod = router.lookupAll(poldname);
if (pod == null) { if (pod == null) {
// we didn't have the old one, so we'll add the new one // we didn't have the old one, so we'll add the new one
} else if (pod.equals(dest)) { } else if (pod.contains(dest)) {
// checks out, so we'll add the new one // checks out, so we'll add the new one
} else { } else {
// mismatch, disallow // mismatch, disallow
@ -297,10 +297,10 @@ public class Daemon {
continue; continue;
} }
Destination pod = new Destination(polddest); Destination pod = new Destination(polddest);
Destination pod2 = router.lookup(poldname); List<Destination> pod2 = router.lookupAll(poldname);
if (pod2 == null) { if (pod2 == null) {
// we didn't have the old name // we didn't have the old name
} else if (pod.equals(pod2)) { } else if (pod2.contains(pod)) {
// checks out, so verify the inner sig // checks out, so verify the inner sig
if (!he.hasValidInnerSig()) { if (!he.hasValidInnerSig()) {
if (log != null) if (log != null)
@ -330,6 +330,8 @@ public class Daemon {
} }
} else if (action.equals(HostTxtEntry.ACTION_CHANGEDEST)) { } else if (action.equals(HostTxtEntry.ACTION_CHANGEDEST)) {
// change destination on an existing entry // change destination on an existing entry
// This removes all previous destinations under that hostname,
// is this what we want?
String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST); String polddest = hprops.getProperty(HostTxtEntry.PROP_OLDDEST);
if (polddest != null) { if (polddest != null) {
Destination pod = new Destination(polddest); Destination pod = new Destination(polddest);
@ -369,20 +371,22 @@ public class Daemon {
} }
} else if (action.equals(HostTxtEntry.ACTION_CHANGENAME)) { } else if (action.equals(HostTxtEntry.ACTION_CHANGENAME)) {
// Delete old name, replace with new // Delete old name, replace with new
// This removes all previous destinations under that hostname,
// is this what we want?
if (isKnown) { if (isKnown) {
old++; old++;
continue; continue;
} }
String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME); String poldname = hprops.getProperty(HostTxtEntry.PROP_OLDNAME);
if (poldname != null) { if (poldname != null) {
Destination pod = router.lookup(poldname); List<Destination> pod = router.lookupAll(poldname);
if (pod == null) { if (pod == null) {
// we didn't have the old name // we didn't have the old name
} else if (pod.equals(dest)) { } else if (pod.contains(dest)) {
// checks out, so we'll delete it // checks out, so we'll delete it
if (knownNames != null) if (knownNames != null)
knownNames.remove(poldname); knownNames.remove(poldname);
boolean success = router.remove(poldname); boolean success = router.remove(poldname, dest);
if (success) if (success)
deleted++; deleted++;
if (log != null) { if (log != null) {
@ -399,7 +403,7 @@ public class Daemon {
if (published != null) { if (published != null) {
if (publishedNS == null) if (publishedNS == null)
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath()); publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
success = publishedNS.remove(poldname); success = publishedNS.remove(poldname, dest);
if (log != null && !success) if (log != null && !success)
log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname); log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname);
} }
@ -431,11 +435,11 @@ public class Daemon {
String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME); String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
if (polddest != null && poldname != null) { if (polddest != null && poldname != null) {
Destination pod = new Destination(polddest); Destination pod = new Destination(polddest);
Destination pod2 = router.lookup(poldname); List<Destination> pod2 = router.lookupAll(poldname);
if (pod.equals(pod2)) { if (pod2 != null && pod2.contains(pod)) {
if (knownNames != null) if (knownNames != null && pod2.size() == 1)
knownNames.remove(poldname); knownNames.remove(poldname);
boolean success = router.remove(poldname); boolean success = router.remove(poldname, pod);
if (success) if (success)
deleted++; deleted++;
if (log != null) { if (log != null) {
@ -452,7 +456,7 @@ public class Daemon {
if (published != null) { if (published != null) {
if (publishedNS == null) if (publishedNS == null)
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath()); publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
success = publishedNS.remove(poldname); success = publishedNS.remove(poldname, pod);
if (log != null && !success) if (log != null && !success)
log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname); log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname);
} }
@ -485,11 +489,11 @@ public class Daemon {
Destination pod = new Destination(polddest); Destination pod = new Destination(polddest);
String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME); String poldname = hprops.getProperty(HostTxtEntry.PROP_NAME);
if (poldname != null) { if (poldname != null) {
Destination pod2 = router.lookup(poldname); List<Destination> pod2 = router.lookupAll(poldname);
if (pod.equals(pod2)) { if (pod2 != null && pod2.contains(pod)) {
if (knownNames != null) if (knownNames != null)
knownNames.remove(poldname); knownNames.remove(poldname);
boolean success = router.remove(poldname); boolean success = router.remove(poldname, pod);
if (success) if (success)
deleted++; deleted++;
if (log != null) { if (log != null) {
@ -506,7 +510,7 @@ public class Daemon {
if (published != null) { if (published != null) {
if (publishedNS == null) if (publishedNS == null)
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath()); publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
success = publishedNS.remove(poldname); success = publishedNS.remove(poldname, pod);
if (log != null && !success) if (log != null && !success)
log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname); log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + poldname);
} }
@ -530,12 +534,12 @@ public class Daemon {
break; break;
rev2 = rev; rev2 = rev;
// forward check in case hash collision or something // forward check in case hash collision or something
Destination fwd = router.lookup(rev); List<Destination> fwd = router.lookupAll(rev);
if (!pod.equals(fwd)) if (!fwd.contains(pod))
break; // can't go around again, fail break; // can't go around again, fail
if (knownNames != null) if (knownNames != null)
knownNames.remove(rev); knownNames.remove(rev);
boolean success = router.remove(rev); boolean success = router.remove(rev, pod);
if (success) if (success)
deleted++; deleted++;
if (log != null) { if (log != null) {
@ -552,7 +556,7 @@ public class Daemon {
if (published != null) { if (published != null) {
if (publishedNS == null) if (publishedNS == null)
publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath()); publishedNS = new SingleFileNamingService(I2PAppContext.getGlobalContext(), published.getAbsolutePath());
success = publishedNS.remove(rev); success = publishedNS.remove(rev, pod);
if (log != null && !success) if (log != null && !success)
log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + rev); log.append("Remove from published address book " + published.getAbsolutePath() + " failed for " + rev);
} }

View File

@ -2,6 +2,8 @@ package net.i2p.addressbook;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map; import java.util.Map;
import net.i2p.crypto.DSAEngine; import net.i2p.crypto.DSAEngine;
@ -17,8 +19,10 @@ import net.i2p.util.OrderedProperties;
import java.io.File; import java.io.File;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.StringWriter; import java.io.StringWriter;
import net.i2p.data.Base32;
import net.i2p.data.PrivateKeyFile; import net.i2p.data.PrivateKeyFile;
import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPrivateKey;
import net.i2p.util.RandomSource;
/** /**
@ -97,7 +101,7 @@ class HostTxtEntry {
* @param line part after the #! * @param line part after the #!
* @throws IllegalArgumentException on dup key and other errors * @throws IllegalArgumentException on dup key and other errors
*/ */
private OrderedProperties parseProps(String line) throws IllegalArgumentException { private static OrderedProperties parseProps(String line) throws IllegalArgumentException {
line = line.trim(); line = line.trim();
OrderedProperties rv = new OrderedProperties(); OrderedProperties rv = new OrderedProperties();
String[] entries = DataHelper.split(line, "#"); String[] entries = DataHelper.split(line, "#");
@ -115,29 +119,60 @@ class HostTxtEntry {
return rv; return rv;
} }
/**
* Write as a standard line name=dest[#!k1=v1#k2=v2...]
* Includes newline.
*/
public void write(BufferedWriter out) throws IOException { public void write(BufferedWriter out) throws IOException {
out.write(name); out.write(name);
out.write(KV_SEPARATOR); out.write(KV_SEPARATOR);
out.write(dest); out.write(dest);
if (props != null && props.size() > 0) { writeProps(out, false, false);
boolean started = false;
for (Map.Entry<Object, Object> e : props.entrySet()) {
if (started) {
out.write(PROP_SEPARATOR);
} else {
started = true;
out.write(PROPS_SEPARATOR);
}
String k = (String) e.getKey();
String v = (String) e.getValue();
out.write(k);
out.write(KV_SEPARATOR);
out.write(v);
}
}
out.newLine(); out.newLine();
} }
/**
* Write as a "remove" line #!olddest=dest#oldname=name#k1=v1#k2=v2...]
* Includes newline.
* Must have been constructed with non-null properties.
*/
public void writeRemove(BufferedWriter out) throws IOException {
if (props == null)
throw new IllegalStateException();
props.setProperty(PROP_OLDNAME, name);
props.setProperty(PROP_OLDDEST, dest);
writeProps(out, false, false);
out.newLine();
props.remove(PROP_OLDNAME);
props.remove(PROP_OLDDEST);
}
/**
* Write the props part (if any) only, without newline
*/
private void writeProps(Writer out, boolean omitSig, boolean omitOldSig) throws IOException {
if (props == null)
return;
boolean started = false;
for (Map.Entry<Object, Object> e : props.entrySet()) {
String k = (String) e.getKey();
if (omitSig && k.equals(PROP_SIG))
continue;
if (omitOldSig && k.equals(PROP_OLDSIG))
continue;
if (started) {
out.write(PROP_SEPARATOR);
} else {
started = true;
out.write(PROPS_SEPARATOR);
}
String v = (String) e.getValue();
out.write(k);
out.write(KV_SEPARATOR);
out.write(v);
}
}
/** /**
* Verify with the dest public key using the "sig" property * Verify with the dest public key using the "sig" property
*/ */
@ -146,34 +181,19 @@ class HostTxtEntry {
return false; return false;
if (!isValidated) { if (!isValidated) {
isValidated = true; isValidated = true;
StringBuilder buf = new StringBuilder(1024); StringWriter buf = new StringWriter(1024);
String sig = null; String sig = props.getProperty(PROP_SIG);
if (sig == null)
return false;
buf.append(name); buf.append(name);
buf.append(KV_SEPARATOR); buf.append(KV_SEPARATOR);
buf.append(dest); buf.append(dest);
boolean started = false; try {
for (Map.Entry<Object, Object> e : props.entrySet()) { writeProps(buf, true, false);
String k = (String) e.getKey(); } catch (IOException ioe) {
String v = (String) e.getValue(); // won't happen
if (k.equals(PROP_SIG)) {
if (sig != null)
return false;
sig = v;
// remove from the written data
continue;
}
if (started) {
buf.append(PROP_SEPARATOR);
} else {
started = true;
buf.append(PROPS_SEPARATOR);
}
buf.append(k);
buf.append(KV_SEPARATOR);
buf.append(v);
}
if (sig == null)
return false; return false;
}
byte[] sdata = Base64.decode(sig); byte[] sdata = Base64.decode(sig);
if (sdata == null) if (sdata == null)
return false; return false;
@ -207,43 +227,20 @@ class HostTxtEntry {
boolean rv = false; boolean rv = false;
// don't cache result // don't cache result
if (true) { if (true) {
StringBuilder buf = new StringBuilder(1024); StringWriter buf = new StringWriter(1024);
String sig = null; String sig = props.getProperty(PROP_OLDSIG);
String olddest = null; String olddest = props.getProperty(PROP_OLDDEST);
if (sig == null || olddest == null)
return false;
buf.append(name); buf.append(name);
buf.append(KV_SEPARATOR); buf.append(KV_SEPARATOR);
buf.append(dest); buf.append(dest);
boolean started = false; try {
for (Map.Entry<Object, Object> e : props.entrySet()) { writeProps(buf, true, true);
String k = (String) e.getKey(); } catch (IOException ioe) {
String v = (String) e.getValue(); // won't happen
if (k.equals(PROP_SIG)) {
continue;
}
if (k.equals(PROP_OLDSIG)) {
if (sig != null)
return false;
sig = v;
// remove from the written data
continue;
}
if (k.equals(PROP_OLDDEST)) {
if (olddest != null)
return false;
olddest = v;
}
if (started) {
buf.append(PROP_SEPARATOR);
} else {
started = true;
buf.append(PROPS_SEPARATOR);
}
buf.append(k);
buf.append(KV_SEPARATOR);
buf.append(v);
}
if (sig == null || olddest == null)
return false; return false;
}
byte[] sdata = Base64.decode(sig); byte[] sdata = Base64.decode(sig);
if (sdata == null) if (sdata == null)
return false; return false;
@ -309,25 +306,16 @@ class HostTxtEntry {
private void signIt(SigningPrivateKey spk, String sigprop) { private void signIt(SigningPrivateKey spk, String sigprop) {
if (props == null) if (props == null)
throw new IllegalStateException(); throw new IllegalStateException();
StringBuilder buf = new StringBuilder(1024); if (props.containsKey(sigprop))
throw new IllegalStateException();
StringWriter buf = new StringWriter(1024);
buf.append(name); buf.append(name);
buf.append(KV_SEPARATOR); buf.append(KV_SEPARATOR);
buf.append(dest); buf.append(dest);
boolean started = false; try {
for (Map.Entry<Object, Object> e : props.entrySet()) { writeProps(buf, false, false);
String k = (String) e.getKey(); } catch (IOException ioe) {
String v = (String) e.getValue(); throw new IllegalStateException(ioe);
if (k.equals(sigprop))
throw new IllegalStateException();
if (started) {
buf.append(PROP_SEPARATOR);
} else {
started = true;
buf.append(PROPS_SEPARATOR);
}
buf.append(k);
buf.append(KV_SEPARATOR);
buf.append(v);
} }
Signature s = DSAEngine.getInstance().sign(DataHelper.getUTF8(buf.toString()), spk); Signature s = DSAEngine.getInstance().sign(DataHelper.getUTF8(buf.toString()), spk);
if (s == null) if (s == null)
@ -336,34 +324,54 @@ class HostTxtEntry {
} }
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
int astart = 0;
if (args.length > 0 && args[0].equals("-i"))
astart++;
OrderedProperties props = new OrderedProperties();
for (int i = astart; i < args.length; i++) {
int eq = args[i].indexOf("=");
props.setProperty(args[i].substring(0, eq), args[i].substring(eq + 1));
}
props.setProperty("zzzz", "zzzzzzzzzzzzzzz");
// outer // outer
File f = new File("tmp-eepPriv.dat"); File f = new File("tmp-eepPriv.dat");
// inner
File f2 = new File("tmp-eepPriv2.dat");
PrivateKeyFile pkf = new PrivateKeyFile(f); PrivateKeyFile pkf = new PrivateKeyFile(f);
PrivateKeyFile pkf2 = new PrivateKeyFile(f2);
pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519); pkf.createIfAbsent(SigType.EdDSA_SHA512_Ed25519);
pkf2.createIfAbsent(SigType.DSA_SHA1); f.delete();
OrderedProperties props = new OrderedProperties(); PrivateKeyFile pkf2;
props.setProperty("c", "ccccccccccc"); if (astart != 0) {
props.setProperty("a", "aaaa"); // inner
props.setProperty(PROP_OLDDEST, pkf2.getDestination().toBase64()); File f2 = new File("tmp-eepPriv2.dat");
HostTxtEntry he = new HostTxtEntry("foo.i2p", pkf.getDestination().toBase64(), props); pkf2 = new PrivateKeyFile(f2);
pkf2.createIfAbsent(SigType.DSA_SHA1);
f2.delete();
props.setProperty(PROP_OLDDEST, pkf2.getDestination().toBase64());
} else {
pkf2 = null;
}
byte[] rand = new byte[5];
RandomSource.getInstance().nextBytes(rand);
String host = Base32.encode(rand) + ".i2p";
HostTxtEntry he = new HostTxtEntry(host, pkf.getDestination().toBase64(), props);
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out)); BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));
out.write("Before signing:\n"); //out.write("Before signing:\n");
he.write(out); //he.write(out);
out.flush(); //out.flush();
SigningPrivateKey priv = pkf.getSigningPrivKey(); SigningPrivateKey priv = pkf.getSigningPrivKey();
SigningPrivateKey priv2 = pkf2.getSigningPrivKey(); if (astart != 0) {
he.signInner(priv2); SigningPrivateKey priv2 = pkf2.getSigningPrivKey();
out.write("After signing inner:\n"); he.signInner(priv2);
he.write(out); //out.write("After signing inner:\n");
//he.write(out);
}
he.sign(priv); he.sign(priv);
out.write("After signing:\n"); //out.write("After signing:\n");
he.write(out); he.write(out);
out.flush(); out.flush();
System.out.println("Orig has valid inner sig? " + he.hasValidInnerSig()); if (astart > 0 && !he.hasValidInnerSig())
System.out.println("Orig has valid sig? " + he.hasValidSig()); throw new IllegalStateException("Inner fail 1");
if (!he.hasValidSig())
throw new IllegalStateException("Outer fail 1");
// now create 2nd, read in // now create 2nd, read in
StringWriter sw = new StringWriter(1024); StringWriter sw = new StringWriter(1024);
BufferedWriter buf = new BufferedWriter(sw); BufferedWriter buf = new BufferedWriter(sw);
@ -371,10 +379,12 @@ class HostTxtEntry {
buf.flush(); buf.flush();
String line = sw.toString(); String line = sw.toString();
line = line.substring(line.indexOf(PROPS_SEPARATOR) + 2); line = line.substring(line.indexOf(PROPS_SEPARATOR) + 2);
HostTxtEntry he2 = new HostTxtEntry("foo.i2p", pkf.getDestination().toBase64(), line); HostTxtEntry he2 = new HostTxtEntry(host, pkf.getDestination().toBase64(), line);
System.out.println("Dupl. has valid inner sig? " + he2.hasValidInnerSig()); if (astart > 0 && !he2.hasValidInnerSig())
System.out.println("Dupl. has valid sig? " + he2.hasValidSig()); throw new IllegalStateException("Inner fail 2");
f.delete(); if (!he2.hasValidSig())
f2.delete(); throw new IllegalStateException("Outer fail 2");
//out.write("Test passed\n");
//out.flush();
} }
} }

View File

@ -217,7 +217,10 @@ class HostTxtParser {
for (HostTxtEntry e : map.values()) { for (HostTxtEntry e : map.values()) {
System.out.println("Host: " + e.getName() + System.out.println("Host: " + e.getName() +
"\nDest: " + e.getDest() + "\nDest: " + e.getDest() +
"\nValid? " + e.hasValidSig()); "\nAction: " + (e.getProps() != null ? e.getProps().getProperty("action") : "(none)") +
"\nValid Inner? " + e.hasValidInnerSig() +
"\nValid? " + e.hasValidSig() +
'\n');
} }
} }

View File

@ -206,6 +206,7 @@ public class BSkipList<K extends Comparable<? super K>, V> extends SkipList<K, V
return new IBSkipIterator<K, V>(first, 0); return new IBSkipIterator<K, V>(first, 0);
} }
/****
@Override @Override
public SkipIterator<K, V> min() { public SkipIterator<K, V> min() {
return iterator(); return iterator();
@ -218,6 +219,7 @@ public class BSkipList<K extends Comparable<? super K>, V> extends SkipList<K, V
SkipSpan<K, V> ss = stack.getEnd(); SkipSpan<K, V> ss = stack.getEnd();
return new IBSkipIterator<K, V>(ss, ss.nKeys - 1); return new IBSkipIterator<K, V>(ss, ss.nKeys - 1);
} }
****/
@Override @Override
public SkipIterator<K, V> find(K key) { public SkipIterator<K, V> find(K key) {

View File

@ -1,59 +0,0 @@
/*
Copyright (c) 2006, Matthew Estes
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Metanotion Software nor the names of its
contributors may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.metanotion.io.data;
import net.metanotion.io.Serializer;
public class LongBytes implements Serializer<Long> {
public byte[] getBytes(Long o) {
byte[] b = new byte[8];
long v = o.longValue();
b[0] = (byte)(0xff & (v >> 56));
b[1] = (byte)(0xff & (v >> 48));
b[2] = (byte)(0xff & (v >> 40));
b[3] = (byte)(0xff & (v >> 32));
b[4] = (byte)(0xff & (v >> 24));
b[5] = (byte)(0xff & (v >> 16));
b[6] = (byte)(0xff & (v >> 8));
b[7] = (byte)(0xff & v);
return b;
}
public Long construct(byte[] b) {
long v =(((long)(b[0] & 0xff) << 56) |
((long)(b[1] & 0xff) << 48) |
((long)(b[2] & 0xff) << 40) |
((long)(b[3] & 0xff) << 32) |
((long)(b[4] & 0xff) << 24) |
((long)(b[5] & 0xff) << 16) |
((long)(b[6] & 0xff) << 8) |
(b[7] & 0xff));
return Long.valueOf(v);
}
}

View File

@ -35,7 +35,7 @@ import net.i2p.util.RandomSource;
//import net.metanotion.io.block.BlockFile; //import net.metanotion.io.block.BlockFile;
public class SkipList<K extends Comparable<? super K>, V> implements Flushable { public class SkipList<K extends Comparable<? super K>, V> implements Flushable, Iterable<V> {
/** 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;
@ -151,6 +151,7 @@ public class SkipList<K extends Comparable<? super K>, V> implements Flushable {
* dumps all the data * dumps all the data
* @deprecated goes to System.out * @deprecated goes to System.out
*/ */
@Deprecated
public void print() { public void print() {
System.out.println("List size " + size); System.out.println("List size " + size);
System.out.println(first.print()); System.out.println(first.print());
@ -163,12 +164,14 @@ public class SkipList<K extends Comparable<? super K>, V> implements Flushable {
public SkipIterator<K, V> iterator() { return new SkipIterator<K, V>(first, 0); } public SkipIterator<K, V> iterator() { return new SkipIterator<K, V>(first, 0); }
/****
public SkipIterator<K, V> min() { return new SkipIterator<K, V>(first, 0); } public SkipIterator<K, V> min() { return new SkipIterator<K, V>(first, 0); }
public SkipIterator<K, V> max() { public SkipIterator<K, V> max() {
SkipSpan<K, V> ss = stack.getEnd(); SkipSpan<K, V> ss = stack.getEnd();
return new SkipIterator<K, V>(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<K, V> find(K key) { public SkipIterator<K, V> find(K key) {
@ -178,7 +181,6 @@ public class SkipList<K extends Comparable<? super K>, V> implements Flushable {
return new SkipIterator<K, V>(ss, search[0]); return new SkipIterator<K, V>(ss, search[0]);
} }
// Levels adjusted to guarantee O(log n) search // Levels adjusted to guarantee O(log n) search
// This is expensive proportional to the number of spans. // This is expensive proportional to the number of spans.
public void balance() { public void balance() {