package water.fvec; import java.util.Arrays; import java.io.InputStream; import water.*; import water.util.Log; /** Build a Vec by reading from an InputStream */ public class UploadFileVec extends FileVec { int _nchunks; protected UploadFileVec(Key key) { super(key,-1,Value.ICE); } @Override public boolean writable() { return _len==-1; } public void addAndCloseChunk(Chunk c, Futures fs) { assert _len==-1; // Not closed assert (c._vec == null); // Don't try to re-purpose a chunk. c._vec = this; // Attach chunk to this vec. DKV.put(chunkKey(_nchunks++),c,fs); // Write updated chunk back into K/V } // Close, and possible replace the prior chunk with a new, larger Chunk public void close(C1NChunk c, int cidx, Futures fs) { assert _len==-1; // Not closed c._vec = this; // Attach chunk to this vec. DKV.put(chunkKey(cidx),c,fs); // Write updated chunk back into K/V _len = ((_nchunks-1L)<<H2O.LOG_CHK)+c._len; } @Override public Value chunkIdx( int cidx ) { Value val = DKV.get(chunkKey(cidx)); assert checkMissing(cidx,val); return val; } // --------------------------------------------------------------------------- // Store a file (byte by byte) into a frame. // This file will generally come from a POST through the REST interface. // --------------------------------------------------------------------------- static public Key readPut(String keyname, InputStream is) throws Exception { return readPut(Key.make(keyname), is); } static public Key readPut(Key k, InputStream is) throws Exception { readPut(k,is,new Futures()).blockForPending(); return k; } static private Futures readPut(Key key, InputStream is, final Futures fs) throws Exception { Log.info("Reading byte InputStream into Frame:"); Log.info(" frameKey: " + key.toString()); Key newVecKey = Vec.newKey(); try { new Frame(key,new String[0],new Vec[0]).delete_and_lock(null); UploadFileVec uv = new UploadFileVec(newVecKey); assert uv.writable(); byte prev[] = null; byte bytebuf[] = new byte[FileVec.CHUNK_SZ]; int bytesInChunkSoFar = 0; while (true) { int rv = is.read(bytebuf, bytesInChunkSoFar, FileVec.CHUNK_SZ - bytesInChunkSoFar); if (rv < 0) break; bytesInChunkSoFar += rv; if( bytesInChunkSoFar == FileVec.CHUNK_SZ ) { // Write full chunk of size FileVec.CHUNK_SZ. C1NChunk c = new C1NChunk(bytebuf); uv.addAndCloseChunk(c, fs); prev = bytebuf; bytebuf = new byte[FileVec.CHUNK_SZ]; bytesInChunkSoFar = 0; } } // Add last bytes onto last chunk, which may be bigger than CHUNK_SZ. if( prev==null ) { // No chunks at all uv._nchunks++; // Put a 1st chunk uv.close(new C1NChunk(Arrays.copyOf(bytebuf,bytesInChunkSoFar)),0,fs); } else if (bytesInChunkSoFar != 0 ) { byte buf2[] = Arrays.copyOf(prev,bytesInChunkSoFar+prev.length); System.arraycopy(bytebuf,0,buf2,prev.length,bytesInChunkSoFar); uv.close(new C1NChunk(buf2),uv._nchunks-1,fs); } Log.info(" totalFrames: " + 1); Log.info(" totalVecs: " + 1); Log.info(" totalChunks: " + uv.nChunks()); Log.info(" totalBytes: " + uv.length()); DKV.put(newVecKey, uv, fs); String[] sarr = {"bytes"}; Vec[] varr = {uv}; Frame f = new Frame(key,sarr, varr); f.unlock(null); Log.info(" Success."); } catch (Exception e) { // Clean up and do not leak keys. Log.err("Exception caught in Frame::readPut; attempting to clean up the new frame and vector"); Log.err(e); Lockable.delete(key); DKV.remove(newVecKey); Log.err("Frame::readPut cleaned up new frame and vector successfully"); throw e; } return fs; } }