[bug-65184] Improve performance of POFSMiniStore getBlockAt. Thanks to sits

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1887657 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2021-03-14 23:21:18 +00:00
parent 82b5113ba9
commit 66dee7b4d8
2 changed files with 63 additions and 21 deletions

View File

@ -61,20 +61,25 @@ public class POIFSMiniStore extends BlockStore {
int bigBlockOffset = byteOffset % _filesystem.getBigBlockSize();
// Now locate the data block for it
Iterator<ByteBuffer> it = _mini_stream.getBlockIterator();
Iterator<Integer> it = _mini_stream.getBlockOffsetIterator();
for (int i = 0; i < bigBlockNumber; i++) {
it.next();
}
ByteBuffer dataBlock = it.next();
assert (dataBlock != null);
// Position ourselves, and take a slice
dataBlock.position(
dataBlock.position() + bigBlockOffset
);
ByteBuffer miniBuffer = dataBlock.slice();
miniBuffer.limit(POIFSConstants.SMALL_BLOCK_SIZE);
return miniBuffer;
try {
ByteBuffer dataBlock = _filesystem.getBlockAt(it.next());
assert(dataBlock != null);
// Position ourselves, and take a slice
dataBlock.position(
dataBlock.position() + bigBlockOffset
);
ByteBuffer miniBuffer = dataBlock.slice();
miniBuffer.limit(POIFSConstants.SMALL_BLOCK_SIZE);
return miniBuffer;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**

View File

@ -96,6 +96,15 @@ public class POIFSStream implements Iterable<ByteBuffer>
return new StreamBlockByteBufferIterator(startBlock);
}
Iterator<Integer> getBlockOffsetIterator() {
if(startBlock == POIFSConstants.END_OF_CHAIN) {
throw new IllegalStateException(
"Can't read from a new stream before it has been written to"
);
}
return new StreamBlockOffsetIterator(startBlock);
}
/**
* Updates the contents of the stream to the new
* set of bytes.
@ -140,11 +149,11 @@ public class POIFSStream implements Iterable<ByteBuffer>
/**
* Class that handles a streaming read of one stream
*/
private class StreamBlockByteBufferIterator implements Iterator<ByteBuffer> {
private class StreamBlockOffsetIterator implements Iterator<Integer> {
private final ChainLoopDetector loopDetector;
private int nextBlock;
StreamBlockByteBufferIterator(int firstBlock) {
StreamBlockOffsetIterator(int firstBlock) {
this.nextBlock = firstBlock;
try {
this.loopDetector = blockStore.getChainLoopDetector();
@ -157,19 +166,15 @@ public class POIFSStream implements Iterable<ByteBuffer>
return nextBlock != POIFSConstants.END_OF_CHAIN;
}
public ByteBuffer next() {
public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException("Can't read past the end of the stream");
}
try {
loopDetector.claim(nextBlock);
ByteBuffer data = blockStore.getBlockAt(nextBlock);
nextBlock = blockStore.getNextBlock(nextBlock);
return data;
} catch(IOException e) {
throw new RuntimeException(e);
}
loopDetector.claim(nextBlock);
int currentBlock = nextBlock;
nextBlock = blockStore.getNextBlock(nextBlock);
return currentBlock;
}
public void remove() {
@ -177,6 +182,38 @@ public class POIFSStream implements Iterable<ByteBuffer>
}
}
/**
* Class that handles a streaming read of one stream
*/
private class StreamBlockByteBufferIterator implements Iterator<ByteBuffer> {
private final StreamBlockOffsetIterator offsetIterator;
StreamBlockByteBufferIterator(int firstBlock) {
offsetIterator = new StreamBlockOffsetIterator(firstBlock);
}
public boolean hasNext() {
return offsetIterator.hasNext();
}
public ByteBuffer next() {
if (!hasNext()) {
throw new NoSuchElementException("Can't read past the end of the stream");
}
try {
return blockStore.getBlockAt(offsetIterator.next());
} catch(IOException e) {
throw new RuntimeException(e);
}
}
public void remove() {
throw new UnsupportedOperationException();
}
}
protected class StreamBlockByteBuffer extends OutputStream {
byte[] oneByte = new byte[1];
ByteBuffer buffer;