-
Notifications
You must be signed in to change notification settings - Fork 476
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
195 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
package org.jgroups.util; | ||
|
||
import java.io.DataInput; | ||
import java.io.DataOutput; | ||
import java.util.ArrayList; | ||
import java.util.Iterator; | ||
import java.util.List; | ||
import java.util.NoSuchElementException; | ||
|
||
/** | ||
* A list of sequence numbers (seqnos). Seqnos have to be added in ascending order, and can be single seqnos | ||
* or seqno ranges (e.g. [5-10]). This class is unsynchronized. Note that for serialization, we assume that the | ||
* lowest and highest seqno in the list are not more than 2 ^ 31 apart. | ||
* @author Bela Ban | ||
* @since 3.1 | ||
*/ | ||
public class SeqnoList implements Streamable, Iterable<Long> { | ||
protected final List<Seqno> seqnos=new ArrayList<Seqno>(); | ||
|
||
public SeqnoList() { | ||
} | ||
|
||
/** Adds a single seqno */ | ||
public SeqnoList add(long seqno) { | ||
seqnos.add(new Seqno(seqno)); | ||
return this; | ||
} | ||
|
||
public SeqnoList add(long ... seqnos) { | ||
if(seqnos != null) { | ||
for(long seqno: seqnos) | ||
add(seqno); | ||
} | ||
return this; | ||
} | ||
|
||
/** Adds a seqno range */ | ||
public SeqnoList add(long from, long to) { | ||
seqnos.add(new SeqnoRange(from, to)); | ||
return this; | ||
} | ||
|
||
public void writeTo(DataOutput out) throws Exception { | ||
out.writeInt(seqnos.size()); | ||
for(Seqno seqno: seqnos) { | ||
if(seqno instanceof SeqnoRange) { | ||
SeqnoRange range=(SeqnoRange)seqno; | ||
out.writeBoolean(true); | ||
Util.writeLongSequence(range.from, range.to, out); | ||
} | ||
else { | ||
out.writeBoolean(false); | ||
Util.writeLong(seqno.from, out); | ||
} | ||
} | ||
} | ||
|
||
public void readFrom(DataInput in) throws Exception { | ||
int len=in.readInt(); | ||
for(int i=0; i < len; i++) { | ||
if(in.readBoolean()) { | ||
long[] tmp=Util.readLongSequence(in); | ||
seqnos.add(new SeqnoRange(tmp[0], tmp[1])); | ||
} | ||
else { | ||
seqnos.add(new Seqno(Util.readLong(in))); | ||
} | ||
} | ||
} | ||
|
||
public int size() { | ||
int retval=0; | ||
for(Seqno seqno: seqnos) { | ||
if(seqno instanceof SeqnoRange) { | ||
SeqnoRange range=(SeqnoRange)seqno; | ||
retval+=(range.to - range.from +1); | ||
} | ||
else | ||
retval++; | ||
} | ||
|
||
return retval; | ||
} | ||
|
||
public String toString() { | ||
return seqnos.toString(); | ||
} | ||
|
||
public Iterator<Long> iterator() { | ||
return new Iterator<Long>() { | ||
protected int index=0; | ||
protected SeqnoRange range=null; | ||
protected long range_index=-1; | ||
|
||
public boolean hasNext() { | ||
return index +1 <= seqnos.size(); | ||
} | ||
|
||
public Long next() { | ||
if(range != null) { | ||
if(range_index +1 <= range.to) | ||
return range_index++; | ||
else | ||
range=null; | ||
} | ||
if(index >= seqnos.size()) | ||
throw new NoSuchElementException("index " + index + " is >= size " + seqnos.size()); | ||
Seqno next=seqnos.get(index++); | ||
if(next instanceof SeqnoRange) { | ||
range=(SeqnoRange)next; | ||
range_index=range.from; | ||
return range_index; | ||
} | ||
else | ||
return next.from; | ||
} | ||
|
||
public void remove() { // not supported | ||
} | ||
}; | ||
} | ||
|
||
protected static class Seqno { | ||
protected long from; | ||
|
||
public Seqno(long num) { | ||
this.from=num; | ||
} | ||
|
||
public String toString() { | ||
return String.valueOf(from); | ||
} | ||
} | ||
|
||
protected static class SeqnoRange extends Seqno { | ||
protected long to; | ||
|
||
public SeqnoRange(long from, long to) { | ||
super(from); | ||
this.to=to; | ||
if(to < from) | ||
throw new IllegalArgumentException("to (" + to + ") needs to be >= from (" + from + ")"); | ||
} | ||
|
||
public String toString() { | ||
return super.toString() + "-" + to; | ||
} | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
tests/junit-functional/org/jgroups/tests/SeqnoListTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package org.jgroups.tests; | ||
|
||
import org.jgroups.Global; | ||
import org.jgroups.util.SeqnoList; | ||
import org.jgroups.util.Util; | ||
import org.testng.annotations.Test; | ||
|
||
/** | ||
* @author Bela Ban | ||
* @since 3.1 | ||
*/ | ||
@Test(groups=Global.FUNCTIONAL) | ||
public class SeqnoListTest { | ||
|
||
public void testAddition() { | ||
SeqnoList list=new SeqnoList().add(1).add(5,10).add(15); | ||
System.out.println("list = " + list); | ||
assert list.size() == 8; | ||
} | ||
|
||
public void testIteration() { | ||
SeqnoList list=new SeqnoList().add(1).add(5,10).add(15); | ||
System.out.println("list = " + list); | ||
int count=0; | ||
for(long num: list) { | ||
System.out.print(num + " "); | ||
count++; | ||
} | ||
|
||
assert count == list.size(); | ||
} | ||
|
||
public void testSerialization() throws Exception { | ||
SeqnoList list=new SeqnoList().add(1, 10, 50) | ||
.add(100,150).add(152,153).add(200,205).add(300,304,306).add(400,450).add(500); | ||
for(int i=502; i < 550; i+=2) | ||
list.add(i); | ||
|
||
|
||
System.out.println("list.size()=" + list.size() + "\nlist = " + list); | ||
byte[] buf=Util.streamableToByteBuffer(list); | ||
SeqnoList list2=(SeqnoList)Util.streamableFromByteBuffer(SeqnoList.class,buf); | ||
System.out.println("list2.size()=" + list2.size() + "\nlist2 = " + list2); | ||
assert list.size() == list2.size(); | ||
} | ||
} |