Skip to content

Commit

Permalink
Merge pull request archiver-appliance#287 from jacomago/format-storag…
Browse files Browse the repository at this point in the history
…eplugin-code

Format the StoragePlugin related files
  • Loading branch information
jacomago authored Nov 22, 2024
2 parents 6df0781 + 9c3c868 commit 64c782c
Show file tree
Hide file tree
Showing 39 changed files with 2,866 additions and 2,767 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@
* This is a special kind of comparison function meant for a combo binary/linear search function.
* This takes in a byte sequence (perhaps from a PB file) and compares it to the point (timestamp) being sought.
* It then returns one of the enums to direct the direction of search.
* We assume that time is from the left (past) to the right (future).
* We assume that time is from the left (past) to the right (future).
* @author mshankar
*/
public interface CompareEventLine {
enum NextStep {
GO_LEFT,
GO_RIGHT,
STAY_WHERE_YOU_ARE
}
/**
* This is the actual comparison function.
* @param line1 - A full PB line
* @param line2 - A full PB line
* @return NextStep one of the eumuration of NextStep
* @throws IOException  
*/
public NextStep compare(byte[] line1, byte[] line2) throws IOException;
enum NextStep {
GO_LEFT,
GO_RIGHT,
STAY_WHERE_YOU_ARE
}

/**
* This is the actual comparison function.
* @param line1 - A full PB line
* @param line2 - A full PB line
* @return NextStep one of the eumuration of NextStep
* @throws IOException  
*/
public NextStep compare(byte[] line1, byte[] line2) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import java.nio.file.Files;
import java.nio.file.Path;


/**
* This is a variant of binary search that searches for an event in a event stream file.
* We assume a time-sorted PB file separated by unix newlines as outlined in the archiver appliance design doc.
Expand All @@ -31,175 +30,174 @@
* <li>LineByteStream.readLine's after this should give events that satisfy getData's requirements.</li>
* <li>Remember to terminate appropriately</li>
* </ol>
*
*
* @author mshankar
*
*/
public class FileEventStreamSearch {
private static final Logger logger = LogManager.getLogger(FileEventStreamSearch.class);
/**
* Constant use to bound length of searches before giving up.
*/
private static final int MAXITERATIONS = 1000;
/**
* Internally used to indicate the left/lower window for the search
*/
private long min = 0;
/**
* Internally used to indicate the right/upper window for the search
*/
private long max = 0;
/**
* Internally used to the current search point
*/
private long mid = 0;
/**
* Remember the last left/lower bound; this is the requirement for getData when the time t1 is not present exactly in the file.
*/
private long lastgoright = 0;
private Path path;

/**
* Position where we found the value
*/
private long foundPosition = 0;

/**
* PB files often have a header; so we'd want to start after the header.
*/
private long startPosition = 0;


/**
* @param path Path
* @param startPosn a starting position of search PB files
*/
public FileEventStreamSearch(Path path, long startPosn) {
this.path = path;
this.startPosition = startPosn;
}
private static final Logger logger = LogManager.getLogger(FileEventStreamSearch.class);
/**
* Constant use to bound length of searches before giving up.
*/
private static final int MAXITERATIONS = 1000;
/**
* Internally used to indicate the left/lower window for the search
*/
private long min = 0;
/**
* Internally used to indicate the right/upper window for the search
*/
private long max = 0;
/**
* Internally used to the current search point
*/
private long mid = 0;
/**
* Remember the last left/lower bound; this is the requirement for getData when the time t1 is not present exactly in the file.
*/
private long lastgoright = 0;

private Path path;

/**
* Position where we found the value
*/
private long foundPosition = 0;

/**
* PB files often have a header; so we'd want to start after the header.
*/
private long startPosition = 0;

/**
* @param path Path
* @param startPosn a starting position of search PB files
*/
public FileEventStreamSearch(Path path, long startPosn) {
this.path = path;
this.startPosition = startPosn;
}

public long getFoundPosition() {
return foundPosition;
}

/**
* Set the fileChannels position to a point that best satisfies the requirements for getData(t1,...).
* If found (return value is true), the file's position is set such that
* <code>
* LineByteStream lis = new LineByteStream(fchannel);
* lis.seekToFirstNewLine();
* byte[] line = lis.readLine();
* </code>
* starts returning events that satisfy getData's requirements
* @return <code>true</code> or <code>false</code>
* @param dbrtype ArchDBRType the enumeration type
* @param yearSecondTimestamp Search seconds into year
* @throws IOException &emsp;
* @see edu.stanford.slac.archiverappliance.PlainPB.ComparePBEvent
*/
public boolean seekToTime(ArchDBRTypes dbrtype, YearSecondTimestamp yearSecondTimestamp) throws IOException {
ComparePBEvent comparefunction = new ComparePBEvent(dbrtype, yearSecondTimestamp);
return seekToTime(comparefunction);
}

/**
* This should only be used by the unit tests.
* @param comparefunction CompareEventLine
* @return <code>true</code> or <code>false</code>
* @throws IOException when parsing the absolute path
*/
public boolean seekToTime(CompareEventLine comparefunction) throws IOException {
boolean found = binarysearch(comparefunction);
if (found) {
// We found an exact match.
return true;
} else {
// We did not find an exact match.
// However, check to see if the location satisfies s1 <= t1 < s2
if (lastgoright == 0 && startPosition != 0) {
// Skip the header if any specified.
lastgoright = startPosition;
}
try (LineByteStream lis = new LineByteStream(path, lastgoright)) {
long currPosn = lis.getCurrentPosition();
try {
lis.seekToFirstNewLine();
byte[] line1 = lis.readLine();
byte[] line2 = lis.readLine();
if (line1 == null || line2 == null || line1.length == 0 || line2.length == 0) {
// Nope, we did not find anything.
return false;
} else {
CompareEventLine.NextStep test = comparefunction.compare(line1, line2);
// For s1 < t1, the compare function should tell us to go right.
// For s1 == t1, it should tell us to stay where we are.
// for t1 < s2, the compare function should tell us to go left.
if (test == CompareEventLine.NextStep.STAY_WHERE_YOU_ARE) {
// We found a location that satisfies s1 <= t1 < s2
foundPosition = lastgoright;
return true;
} else {
// In this case, we really did not find the event as it is out of range.
return false;
}
}
} catch (IOException ex) {
logger.error("Exception when parsing " + lis.getAbsolutePath() + " near posn " + currPosn, ex);
throw ex;
}
}
}
}

private boolean binarysearch(CompareEventLine comparefunction) throws IOException {
// We bound the binary search to avoid infinite loops.
int maxIterations = MAXITERATIONS;
try {
// Set up binary search.
min = this.startPosition;
max = Files.size(path) - 1;
do {
mid = min + ((max - min) / 2);
// System.out.println("Min: " + min + " Mid: " + mid + " Max: " + max);
try (LineByteStream lis = new LineByteStream(path, mid)) {
lis.seekToFirstNewLine();
byte[] line1 = lis.readLine();
if (line1 == null || line1.length <= 0) {
// Empty line in the PB file - Returning false from search.
return false;
}
byte[] line2 = lis.readLine();

CompareEventLine.NextStep nextStep = comparefunction.compare(line1, line2);
switch (nextStep) {
case GO_LEFT:
max = mid - 1;
break;
case GO_RIGHT:
lastgoright = mid;
min = mid + 1;
break;
case STAY_WHERE_YOU_ARE:
foundPosition = mid;
return true;
default:
logger.error("Compare function returned something unexpeected " + nextStep);
}

public long getFoundPosition() {
return foundPosition;
}


/**
* Set the fileChannels position to a point that best satisfies the requirements for getData(t1,...).
* If found (return value is true), the file's position is set such that
* <code>
* LineByteStream lis = new LineByteStream(fchannel);
* lis.seekToFirstNewLine();
* byte[] line = lis.readLine();
* </code>
* starts returning events that satisfy getData's requirements
* @return <code>true</code> or <code>false</code>
* @param dbrtype ArchDBRType the enumeration type
* @param yearSecondTimestamp Search seconds into year
* @throws IOException &emsp;
* @see edu.stanford.slac.archiverappliance.PlainPB.ComparePBEvent
*/
public boolean seekToTime(ArchDBRTypes dbrtype, YearSecondTimestamp yearSecondTimestamp) throws IOException {
ComparePBEvent comparefunction = new ComparePBEvent(dbrtype, yearSecondTimestamp);
return seekToTime(comparefunction);
}


/**
* This should only be used by the unit tests.
* @param comparefunction CompareEventLine
* @return <code>true</code> or <code>false</code>
* @throws IOException when parsing the absolute path
*/
public boolean seekToTime(CompareEventLine comparefunction) throws IOException {
boolean found = binarysearch(comparefunction);
if(found) {
// We found an exact match.
return true;
} else {
// We did not find an exact match.
// However, check to see if the location satisfies s1 <= t1 < s2
if(lastgoright == 0 && startPosition != 0) {
// Skip the header if any specified.
lastgoright = startPosition;
}
try(LineByteStream lis = new LineByteStream(path, lastgoright)) {
long currPosn = lis.getCurrentPosition();
try {
lis.seekToFirstNewLine();
byte[] line1 = lis.readLine();
byte[] line2 = lis.readLine();
if(line1 == null || line2 == null || line1.length == 0 || line2.length == 0) {
// Nope, we did not find anything.
return false;
} else {
CompareEventLine.NextStep test = comparefunction.compare(line1, line2);
// For s1 < t1, the compare function should tell us to go right.
// For s1 == t1, it should tell us to stay where we are.
// for t1 < s2, the compare function should tell us to go left.
if(test == CompareEventLine.NextStep.STAY_WHERE_YOU_ARE) {
// We found a location that satisfies s1 <= t1 < s2
foundPosition = lastgoright;
return true;
} else {
// In this case, we really did not find the event as it is out of range.
return false;
}
}
} catch(IOException ex) {
logger.error("Exception when parsing " + lis.getAbsolutePath() + " near posn " + currPosn, ex);
throw ex;
}
}
}
}

private boolean binarysearch(CompareEventLine comparefunction) throws IOException {
// We bound the binary search to avoid infinite loops.
int maxIterations = MAXITERATIONS;
try {
// Set up binary search.
min = this.startPosition;
max = Files.size(path)-1;
do {
mid = min + ((max - min)/2);
// System.out.println("Min: " + min + " Mid: " + mid + " Max: " + max);
try(LineByteStream lis = new LineByteStream(path, mid)) {
lis.seekToFirstNewLine();
byte[] line1 = lis.readLine();
if(line1 == null || line1.length <= 0) {
// Empty line in the PB file - Returning false from search.
return false;
}
byte[] line2 = lis.readLine();
maxIterations--;
}
} while ((max > min) && maxIterations > 0);
} catch (Exception ex) {
throw new IOException(
"Exception searching in input stream; min: " + min + " mid: " + mid + " max:" + max, ex);
}

CompareEventLine.NextStep nextStep = comparefunction.compare(line1, line2);
switch(nextStep) {
case GO_LEFT:
max = mid - 1;
break;
case GO_RIGHT:
lastgoright = mid;
min = mid + 1;
break;
case STAY_WHERE_YOU_ARE:
foundPosition = mid;
return true;
default:
logger.error("Compare function returned something unexpeected " + nextStep);
}
if (maxIterations <= 0) {
throw new IOException("Max iterations reached");
}

maxIterations--;
}
} while((max > min) && maxIterations > 0);
} catch(Exception ex) {
throw new IOException("Exception searching in input stream; min: " + min + " mid: " + mid + " max:" + max, ex);
}

if(maxIterations <= 0) {
throw new IOException("Max iterations reached");
}

return false;
}
return false;
}
}
Loading

0 comments on commit 64c782c

Please sign in to comment.