* @return <code>true</code> if the source Segment is compacted successfully.
* Otherwise, <code>false</code>.
* @throws IOException if this operation can not be finished properly.
*/
private boolean compact(Segment segment, SegmentIndexBuffer sibSource, Segment segTarget) throws IOException {
Segment segSource = segment;
int segSourceId = segSource.getSegmentId();
int segTargetId = segTarget.getSegmentId();
Chronos c = new Chronos();
if(!segment.canReadFromBuffer() && segment.getLoadFactor() > 0.1) {
segSource = new BufferedSegment(segment, getByteBuffer((int)segment.getInitialSize()));
_log.info("buffering: " + c.tick() + " ms");
}
// Open the segment index buffer for the target segment
SegmentIndexBuffer sibTarget = _dataArray.getSegmentManager().openSegmentIndexBuffer(segTargetId);
long sizeLimit = segTarget.getInitialSize();
long bytesTransferred = 0;
boolean succ = true;
try {
AddressFormat addrFormat = _dataArray._addressFormat;
SegmentIndexBuffer.IndexOffset reuse = new SegmentIndexBuffer.IndexOffset();
for(int i = 0, cnt = sibSource.size(); i < cnt; i++) {
sibSource.get(i, reuse);
int index = reuse.getIndex();
int sibSegPos = reuse.getOffset();
long oldAddress = _dataArray.getAddress(index);
int oldSegPos = addrFormat.getOffset(oldAddress);
if(sibSegPos != oldSegPos) continue;
int oldSegInd = addrFormat.getSegment(oldAddress);
int length = addrFormat.getDataSize(oldAddress);
if (oldSegInd == segSourceId && oldSegPos >= Segment.dataStartPosition) {
if(length == 0) length = segSource.readInt(oldSegPos);
int byteCnt = 4 + length;
long newSegPos = segTarget.getAppendPosition();
long newAddress = addrFormat.composeAddress((int)newSegPos, segTargetId, length);
if(segTarget.getAppendPosition() + byteCnt >= sizeLimit) {
succ = false;
break;
}
// Transfer bytes from source to target
segSource.transferTo(oldSegPos, byteCnt, segTarget);
bytesTransferred += byteCnt;
sibTarget.add(index, (int)newSegPos);
_updateManager.addUpdate(index, byteCnt, newAddress, oldAddress, segTarget);
}
}
// Push whatever left into update queue
_updateManager.endUpdate(segTarget);
_log.info("bytes fastscanned from " + segSource.getSegmentId() + ": " + bytesTransferred + " time: " + c.tick() + " ms");
return succ;
} finally {
if(segSource.getClass() == BufferedSegment.class) {
segSource.close(false);
segSource = null;
}
}
}