/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* A utility class that implements a number list that keeps track of which
* tokens have arrived by storing their token numbers in the list. It helps
* detect old tokens, out of sequence tokens, and duplicate tokens.
*
* Each element of the list is an interval [a, b]. Its existence in the
* list implies that all token numbers in the range a, a+1, ..., b-1, b
* have arrived. Gaps in arrived token numbers are represented by the
* numbers that fall in between two elements of the list. eg. {[a,b],
* [c,d]} indicates that the token numbers b+1, ..., c-1 have not arrived
* yet.
*
* The maximum number of intervals that we keep track of is
* MAX_INTERVALS. Thus if there are too many gaps, then some of the older
* sequence numbers are deleted from the list. The earliest sequence number
* that exists in the list is the windowStart. The next expected sequence
* number, or expectedNumber, is one greater than the latest sequence
* number in the list.
*
* The list keeps track the first token number that should have arrived
* (initNumber) so that it is able to detect if certain numbers occur after
* the first valid token number but before windowStart. That would happen
* if the number of elements (intervals) exceeds MAX_INTERVALS and some
* initial elements had to be deleted.
*
* The working of the list is optimized for the normal case where the
* tokens arrive in sequence.
*
* @author Mayank Upadhyay
* @since 1.4
*/
public class TokenTracker {
private int initNumber;
private int windowStart;
private int expectedNumber;
this.initNumber = initNumber;
this.windowStart = initNumber;
this.expectedNumber = initNumber;
// Make an entry with one less than the expected first token
}
/**
* Returns the index for the entry into which this number will fit. If
* there is none, it returns the index of the last interval
* which precedes this number. It returns -1 if the number needs to be
* a in a new interval ahead of the whole list.
*/
int i;
// Start from the rear to optimize for the normal case
break;
}
return i;
}
/**
* Sets the sequencing and replay information for the given token
* number.
*
* The following represents the number line with positions of
* initNumber, windowStart, expectedNumber marked on it. Regions in
* between them show the different sequencing and replay state
* possibilites for tokens that fall in there.
*
* (1) windowStart
* initNumber expectedNumber
* | |
* ---|---------------------------|---
*
*
* (2) initNumber windowStart expectedNumber
* | | |
* ---|---------------|--------------|---
*
*
* (3) windowStart
* expectedNumber initNumber
* | |
* ---|---------------------------|---
*
*
* (4) expectedNumber initNumber windowStart
* | | |
* ---|---------------|--------------|---
*
*
*
* (5) windowStart expectedNumber initNumber
* | | |
* ---|---------------|--------------|---
*
*
*
* (This analysis leaves out the possibility that expectedNumber passes
* initNumber after wrapping around. That may be added later.)
*/
boolean gap = false;
boolean old = false;
boolean unsequenced = false;
boolean duplicate = false;
// System.out.println("\n\n==========");
// System.out.println("TokenTracker.getProps(): number=" + number);
// System.out.println(toString());
if (pos != -1)
// Optimize for the expected case:
if (number == expectedNumber) {
} else {
// Next trivial case is to check for duplicate
duplicate = true;
else {
if (expectedNumber >= initNumber) {
// Cases (1) and (2)
if (number > expectedNumber) {
gap = true;
} else if (number >= windowStart) {
unsequenced = true;
} else if (number >= initNumber) {
old = true;
} else {
gap = true;
}
} else {
// Cases (3), (4) and (5)
if (number > expectedNumber) {
if (number < initNumber) {
gap = true;
} else if (windowStart >= initNumber) {
if (number >= windowStart) {
unsequenced = true;
} else
old = true;
} else {
old = true;
}
} else if (windowStart > expectedNumber) {
unsequenced = true;
} else if (number < windowStart) {
old = true;
} else
unsequenced = true;
}
}
}
if (gap)
0, null);
// System.out.println("Leaving with state:");
// System.out.println(toString());
// System.out.println("==========\n");
}
/**
* Adds the number to the list just after the entry that is currently
* at position prevEntryPos. If prevEntryPos is -1, then the number
* will begin a new interval at the front of the list.
*/
boolean appended = false;
boolean prepended = false;
if (prevEntryPos != -1) {
// Can this number simply be added to the previous interval?
appended = true;
}
}
// Now check the interval that follows this number
// Can this number simply be added to the next interval?
if (!appended) {
} else {
// Merge the two entries
// Index of any entry following this gets decremented
if (windowStartIndex > prevEntryPos)
}
prepended = true;
}
}
return;
/*
* At this point we know that the number will start a new interval
* which needs to be added to the list. We might have to recyle an
* older entry in the list.
*/
if (prevEntryPos < windowStartIndex)
windowStartIndex++; // due to the insertion which will happen
} else {
/*
* Delete the entry that marks the start of the current window.
* The marker will automatically point to the next entry in the
* list when this happens. If the current entry is at the end
* of the list then set the marker to the start of the list.
*/
windowStartIndex = 0;
if (prevEntryPos >= oldWindowStartIndex) {
prevEntryPos--; // due to the deletion that just happened
} else {
/*
* If the start of the current window just moved from the
* end of the list to the front of the list, and if the new
* entry will be added to the front of the list, then
* the new entry is the actual window start.
* eg, Consider { [-10, -8], ..., [-6, -3], [3, 9]}. In
* this list, suppose the element [3, 9] is the start of
* the window and has to be deleted to make place to add
* [-12, -12]. The resultant list will be
* {[-12, -12], [-10, -8], ..., [-6, -3]} and the new start
* of the window should be the element [-12, -12], not
* [-10, -8] which succeeded [3, 9] in the old list.
*/
if (oldWindowStartIndex != windowStartIndex) {
// windowStartIndex is 0 at this point
if (prevEntryPos == -1)
// The new entry is going to the front
} else {
// due to the insertion which will happen:
}
}
}
// Finally we are ready to actually add to the list at index
// 'prevEntryPos+1'
}
if (i != 0)
}
}
/**
* An entry in the list that represents the sequence of received
* tokens. Each entry is actaully an interval of numbers, all of which
* have been received.
*/
class Entry {
private int start;
private int end;
}
/**
* Returns -1 if this interval represented by this entry precedes
* the number, 0 if the the number is contained in the interval,
* and -1 if the interval occurs after the number.
*/
return 1;
return -1;
else
return 0;
}
}
}
}
}
}
final int getStart() {
return start;
}
final int getEnd() {
return end;
}
}
}
}