📄 streamfilecontainer.java
字号:
* prop.getProperty("derby.storage.streamFileBufferSize"); * } * * @param prop Property list to fill in. * * @exception StandardException Standard exception policy. **/ public void getContainerProperties(Properties prop) throws StandardException { AccessFactory af = (AccessFactory) Monitor.getServiceModule(dataFactory, AccessFactory.MODULE); TransactionController tc = (af == null) ? null : af.getTransaction( ContextService.getFactory().getCurrentContextManager()); bufferSize = PropertyUtil.getServiceInt(tc, prop, RawStoreFactory.STREAM_FILE_BUFFER_SIZE_PARAMETER, RawStoreFactory.STREAM_FILE_BUFFER_SIZE_MINIMUM, RawStoreFactory.STREAM_FILE_BUFFER_SIZE_MAXIMUM, RawStoreFactory.STREAM_FILE_BUFFER_SIZE_DEFAULT); } /** * Request the container key associated with the stream container. **/ public ContainerKey getIdentity() { return this.identity; } /** * Can I use this container? * <p> * This method always return true right now. * In the future when there are different uses for this container, * we may need to add qualifications for this. * * @exception StandardException Standard exception policy. **/ protected boolean use(StreamContainerHandle handle) throws StandardException { return true; } /** * load data into this container. * <p> * populate the stream container with data in the rowSource * <p> * * @param rowSource The row source to get rows to load into this container. * * @exception StandardException Standard exception policy. **/ public void load(RowSource rowSource) throws StandardException { // use this output stream to buffer rows before inserting into file. out = new DynamicByteArrayOutputStream(bufferSize); logicalDataOut = new FormatIdOutputStream(out); boolean encrypted = dataFactory.databaseEncrypted(); // reserve the first dataFactory.getEncryptionBlockSize() - 1 bytes, if the database is // encrypted These reserved bytes will be used to pad the byte array if // it is not dataFactory.getEncryptionBlockSize() aligned. if (encrypted) { if (zeroBytes == null) zeroBytes = new byte[dataFactory.getEncryptionBlockSize() - 1]; out.write(zeroBytes, 0, dataFactory.getEncryptionBlockSize() - 1); } try { fileOut = privGetOutputStream(file); FormatableBitSet validColumns = rowSource.getValidColumns(); Object[] row = rowSource.getNextRowFromRowSource(); int numberFields = 0; if (validColumns != null) { for (int i = validColumns.getLength() - 1; i >= 0; i--) { if (validColumns.isSet(i)) { numberFields = i + 1; break; } } } else { numberFields = row.length; } // make the record header to have 0 record id recordHeader = new StoredRecordHeader(0, numberFields); // write the record header once for all the rows, directly to the // beginning of the file. int rhLen = recordHeader.write(out); int validColumnsSize = validColumns == null ? 0 : validColumns.getLength(); while (row != null) { int arrayPosition = -1; for (int i = 0; i < numberFields; i++) { // write each column out if (validColumns == null) { arrayPosition++; Object column = row[arrayPosition]; writeColumn(column); } else { if (validColumnsSize > i && validColumns.isSet(i)) { arrayPosition++; Object column = row[arrayPosition]; writeColumn(column); } else { // it is a non-existent column writeColumn(null); } } // put the buffer onto the page, only if it exceeded the // original buffer size or it has less than 100 bytes left // in the buffer if ((out.getUsed() >= bufferSize) || ((bufferSize - out.getUsed()) < MIN_BUFFER_SIZE)) { writeToFile(); } } // get the next row and its valid columns from the rowSource row = rowSource.getNextRowFromRowSource(); } // Write the buffer to the file if there is something in the output // buffer. Remember we pad the output buffer with // dataFactory.getEncryptionBlockSize() - 1 if this is an encypted database if (encrypted) { if (out.getUsed() > (dataFactory.getEncryptionBlockSize() - 1)) writeToFile(); } else if (out.getUsed() > 0) { writeToFile(); } } catch (IOException ioe) { // handle IO error... throw StandardException.newException( SQLState.DATA_UNEXPECTED_EXCEPTION, ioe); } finally { close(); } } /* */ /** * Write the buffer to the file. * <p> * If the database is encrypted, the dataFactory.getEncryptionBlockSize() - 1 reserved bytes will * be used to pad the byte array to be dataFactory.getEncryptionBlockSize() * aligned. Before the bytes are encrypted and written to the file stream, * the actual length of the byte array is written out as a compressed * integer. This number will be used when decrypting the data. * * If the database is not encrypted, then, we don't reserve the bytes * upfront, and we simple just write the bytes out to the file stream. * * @exception StandardException Standard exception policy. **/ private void writeToFile() throws StandardException { try { if (dataFactory.databaseEncrypted()) { // if db is encrypted, // use the first ENCRYPTION_ALIGN bytes for padding. // int realLen = out.getUsed() - (dataFactory.getEncryptionBlockSize() - 1); int tail = realLen % dataFactory.getEncryptionBlockSize(); int padding = (tail == 0) ? 0 : (dataFactory.getEncryptionBlockSize() - tail); int startByte = (tail == 0) ? (dataFactory.getEncryptionBlockSize() - 1) : (tail - 1); int encryptedLen = realLen + padding; // there is nothing to write, just the encryption padding if (realLen <= 0) return; if (ciphertext == null) { ciphertext = new byte[encryptedLen]; } else { if (ciphertext.length < encryptedLen) ciphertext = new byte[encryptedLen]; } dataFactory.encrypt( out.getByteArray(), startByte, encryptedLen, ciphertext, 0); // write out the actual length, then the encrypted bytes. CompressedNumber.writeInt(fileOut, realLen); dataFactory.writeInProgress(); try { fileOut.write(ciphertext, 0, encryptedLen); } finally { dataFactory.writeFinished(); } // reset the dynamic buffer out.reset(); // reserve bytes if database is encrypted. if (dataFactory.databaseEncrypted()) { if (zeroBytes == null) zeroBytes = new byte[dataFactory.getEncryptionBlockSize() - 1]; out.write(zeroBytes, 0, dataFactory.getEncryptionBlockSize() - 1); } } else { // nothing to write if (out.getUsed() == 0) return; dataFactory.writeInProgress(); try { fileOut.write(out.getByteArray(), 0, out.getUsed()); } finally { dataFactory.writeFinished(); } // reset the dynamic buffer out.reset(); } } catch (IOException ioe) { throw StandardException.newException( SQLState.DATA_UNEXPECTED_EXCEPTION, ioe); } } private void writeColumn(Object column) throws StandardException, IOException { int fieldStatus = FIELD_STATUS; if (column == null) { // just write a non-existent header. fieldStatus = StoredFieldHeader.setNonexistent(fieldStatus); StoredFieldHeader.write(out, fieldStatus, 0, LARGE_SLOT_SIZE); return; } // if the column is a null column, write the field header now. if (column instanceof Storable) { Storable sColumn = (Storable) column; if (sColumn.isNull()) { fieldStatus = StoredFieldHeader.setNull(fieldStatus, true); StoredFieldHeader.write(out, fieldStatus, 0, LARGE_SLOT_SIZE); return; } } int beginPosition = out.getPosition(); int fieldDataLength = 0; // write out the header, mostly to reserve the space StoredFieldHeader.write( out, fieldStatus, fieldDataLength, LARGE_SLOT_SIZE); if (column instanceof StreamStorable) { if (((StreamStorable) column).returnStream() != null) { column = (InputStream) ((StreamStorable) column).returnStream(); } } if (column instanceof InputStream) { InputStream inColumn = (InputStream) column; int bufferLen = inColumn.available(); byte[] bufData = new byte[bufferLen]; do { int lenRead = inColumn.read(bufData, bufferLen, 0); if (lenRead != -1) { fieldDataLength += lenRead; out.write(bufData, lenRead, 0); } else { break; } } while (true); } else if (column instanceof Storable) { Storable sColumn = (Storable) column; // write field data to the stream, we already handled the null case sColumn.writeExternal(logicalDataOut); fieldDataLength = out.getPosition() - beginPosition - FIELD_HEADER_SIZE; } else { // Serializable/Externalizable/Formattable // all look the same at this point. logicalDataOut.writeObject(column); fieldDataLength = out.getPosition() - beginPosition - FIELD_HEADER_SIZE; } // Now we go back to update the fieldDataLength in the field header int endPosition = out.getPosition(); out.setPosition(beginPosition); StoredFieldHeader.write( out, fieldStatus, fieldDataLength, LARGE_SLOT_SIZE); // set position to the end of the field if (!StoredFieldHeader.isNull(fieldStatus)) out.setPosition(endPosition); } public boolean fetchNext(Object[] row) throws StandardException { boolean inUserCode = false; int columnId = 0; try
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -