package water.util;
import java.io.IOException;
import java.io.InputStream;
import com.google.common.base.Throwables;
public abstract class RIStream extends InputStream {
public interface ProgressMonitor {
void update(long n);
}
InputStream _is;
ProgressMonitor _pmon;
public final int _retries = 5;
String [] _bk;
private long _off;
boolean _knownSize;
long _expectedSz;
protected RIStream( long off, ProgressMonitor pmon){
_off = off;
}
public final long off(){return _off;}
public final long expectedSz(){
return _knownSize?_expectedSz:-1;
}
public void setExpectedSz(long sz){
_knownSize = true;
_expectedSz = sz;
}
public final void open(){
assert _is == null;
try{
_is = open(_off);
} catch(IOException e){
throw new RuntimeException(e);
}
}
protected abstract InputStream open(long offset) throws IOException;
public void closeQuietly(){
try{close();} catch(Exception e){} // ignore any errors
}
private void try2Recover(int attempt, IOException e) {
if(attempt == _retries) Throwables.propagate(e);
Log.warn("[H2OS3InputStream] Attempt("+attempt + ") to recover from " + e.getMessage() + "), off = " + _off);
try{_is.close();}catch(IOException ex){}
_is = null;
if(attempt > 0) try {Thread.sleep(256 << attempt);}catch(InterruptedException ex){}
open();
return;
}
private void updateOffset(int off) {
if(_knownSize)assert (off + _off) <= _expectedSz;
_off += off;
}
@Override
public boolean markSupported(){
return false;
}
@Override
public void mark(int readLimit){throw new UnsupportedOperationException();}
@Override
public void reset(){throw new UnsupportedOperationException();}
private void checkEof() throws IOException {
if(_knownSize && _off < _expectedSz)
throw new IOException("premature end of file reported, expected " + _expectedSz + " bytes, but got eof after " + _off + " bytes");
}
@Override
public final int available() throws IOException {
int attempts = 0;
while(true){
try {
int res = _is.available();
if(res == 0) checkEof();
return _is.available();
} catch (IOException e) {
try2Recover(attempts++,e);
}
}
}
@Override
public int read() throws IOException {
int attempts = 0;
while(true){
try{
int res = _is.read();
if(res == -1) checkEof();
if(res != -1){
updateOffset(1);
if(_pmon != null)_pmon.update(1);
}
return res;
}catch (IOException e){
try2Recover(attempts++,e);
}
}
}
@Override
public int read(byte [] b) throws IOException {
int attempts = 0;
while(true){
try {
int res = _is.read(b);
if(res == -1) checkEof();
if(res > 0){
updateOffset(res);
if(_pmon != null)_pmon.update(res);
}
return res;
} catch(IOException e) {
try2Recover(attempts++,e);
}
}
}
@Override
public int read(byte [] b, int off, int len) throws IOException {
int attempts = 0;
while(true){
try {
int res = _is.read(b,off,len);
if(res == -1) checkEof();
if(res > 0){
updateOffset(res);
if(_pmon != null)_pmon.update(res);
}
return res;
} catch(IOException e) {
try2Recover(attempts++,e);
}
}
}
@Override
public void close() throws IOException {
if(_is != null){
_is.close();
_is = null;
}
}
@Override
public long skip(long n) throws IOException {
int attempts = 0;
while(true){
try{
long res = _is.skip(n);
if(res > 0){
updateOffset((int)res);
if(_pmon != null)_pmon.update(res);
}
return res;
} catch (IOException e) {
try2Recover(attempts++,e);
}
}
}
}