package water;
import water.fvec.ChunkUtils;
import water.fvec.NewChunk;
import java.io.IOException;
import java.nio.channels.ByteChannel;
import static water.ExternalFrameUtils.*;
/**
* This class contains methods used on the h2o backend to store incoming data as H2O Frame
*/
final class ExternalFrameWriterBackend {
/**
* Internal method use on the h2o backend side to handle writing to the chunk from non-h2o environment
* @param sock socket channel originating from non-h2o node
* @param ab {@link AutoBuffer} containing information necessary for preparing backend for writing
*/
static void handleWriteToChunk(ByteChannel sock, AutoBuffer ab) throws IOException {
String frameKey = ab.getStr();
byte[] expectedTypes = ab.getA1();
assert expectedTypes != null;
byte[] vecTypes = vecTypesFromExpectedTypes(expectedTypes);
int expectedNumRows = ab.getInt();
int currentRowIdx = 0;
int chunk_id = ab.getInt();
NewChunk[] nchnk = ChunkUtils.createNewChunks(frameKey, vecTypes, chunk_id);
assert nchnk != null;
while (currentRowIdx < expectedNumRows) {
for(int colIdx = 0; colIdx<expectedTypes.length; colIdx++){
switch (expectedTypes[colIdx]) {
case EXPECTED_BOOL: // fall through to byte since BOOL is internally stored in frame as number (byte)
case EXPECTED_BYTE:
store(ab, nchnk[colIdx], ab.get1());
break;
case EXPECTED_CHAR:
store(ab, nchnk[colIdx], ab.get2());
break;
case EXPECTED_SHORT:
store(ab, nchnk[colIdx], ab.get2s());
break;
case EXPECTED_INT:
store(ab, nchnk[colIdx], ab.getInt());
break;
case EXPECTED_TIMESTAMP: // fall through to long since TIMESTAMP is internally stored in frame as long
case EXPECTED_LONG:
store(ab, nchnk[colIdx], ab.get8());
break;
case EXPECTED_FLOAT:
store(nchnk[colIdx], ab.get4f());
break;
case EXPECTED_DOUBLE:
store(nchnk[colIdx], ab.get8d());
break;
case EXPECTED_STRING:
store(ab, nchnk[colIdx], ab.getStr());
break;
default:
throw new IllegalArgumentException("Unknown expected type: " + expectedTypes[colIdx]);
}
}
currentRowIdx++;
}
// close chunks at the end
ChunkUtils.closeNewChunks(nchnk);
// Flag informing sender that all work is done and
// chunks are ready to be finalized.
//
// This also needs to be sent because in the sender we have to
// wait for all chunks to be written to DKV; otherwise we get race during finalizing and
// it happens that we try to finalize frame with chunks not ready yet
AutoBuffer outputAb = new AutoBuffer();
outputAb.put1(ExternalFrameHandler.CONFIRM_WRITING_DONE);
writeToChannel(outputAb, sock);
}
private static void store(AutoBuffer ab, NewChunk chunk, long data){
if(isNA(ab, data)){
chunk.addNA();
}else{
chunk.addNum(data);
}
}
private static void store(NewChunk chunk, double data){
if(isNA(data)){
chunk.addNA();
}else{
chunk.addNum(data);
}
}
private static void store(AutoBuffer ab, NewChunk chunk, String data){
if(isNA(ab, data)){
chunk.addNA();
}else{
chunk.addStr(data);
}
}
}