blob: 9a30647899441bd128177ae04a7ed1be951858fd [file] [log] [blame]
/*
* Copyright 2009-2010 by The Regents of the University of California
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may obtain a copy of the License from
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.uci.ics.pregelix.dataflow.util;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import edu.uci.ics.hyracks.api.comm.IFrameTupleAccessor;
import edu.uci.ics.hyracks.api.context.IHyracksTaskContext;
import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
import edu.uci.ics.hyracks.dataflow.common.comm.io.ArrayTupleBuilder;
import edu.uci.ics.hyracks.dataflow.common.comm.io.FrameTupleAppender;
import edu.uci.ics.hyracks.dataflow.common.data.accessors.FrameTupleReference;
import edu.uci.ics.hyracks.storage.am.common.api.ITreeIndexAccessor;
import edu.uci.ics.hyracks.storage.am.common.api.IndexException;
/**
* The buffer to hold updates.
* We do a batch update for the B-tree during index search and join so that
* avoid to open/close cursors frequently.
*/
public class UpdateBuffer {
private int currentInUse = 0;
private final int pageLimit;
private final List<ByteBuffer> buffers = new ArrayList<ByteBuffer>();
private final FrameTupleAppender appender;
private final IHyracksTaskContext ctx;
private final FrameTupleReference tuple = new FrameTupleReference();
private final int frameSize;
private IFrameTupleAccessor fta;
public UpdateBuffer(int numPages, IHyracksTaskContext ctx, int fieldCount) {
this.appender = new FrameTupleAppender(ctx.getFrameSize());
ByteBuffer buffer = ctx.allocateFrame();
this.buffers.add(buffer);
this.appender.reset(buffer, true);
this.pageLimit = numPages;
this.ctx = ctx;
this.frameSize = ctx.getFrameSize();
this.fta = new UpdateBufferTupleAccessor(frameSize, fieldCount);
}
public UpdateBuffer(IHyracksTaskContext ctx, int fieldCount) {
//by default, the update buffer has 1000 pages
this(1000, ctx, fieldCount);
}
public void setFieldCount(int fieldCount) {
if (fta.getFieldCount() != fieldCount) {
this.fta = new UpdateBufferTupleAccessor(frameSize, fieldCount);
}
}
public boolean appendTuple(ArrayTupleBuilder tb) throws HyracksDataException {
if (!appender.append(tb.getFieldEndOffsets(), tb.getByteArray(), 0, tb.getSize())) {
if (currentInUse + 1 < pageLimit) {
// move to the new buffer
currentInUse++;
allocate(currentInUse);
ByteBuffer buffer = buffers.get(currentInUse);
appender.reset(buffer, true);
if (!appender.append(tb.getFieldEndOffsets(), tb.getByteArray(), 0, tb.getSize())) {
throw new HyracksDataException("tuple cannot be appended to a new frame!");
}
return true;
} else {
return false;
}
} else {
return true;
}
}
public void updateBTree(ITreeIndexAccessor bta) throws HyracksDataException, IndexException {
// batch update
for (int i = 0; i <= currentInUse; i++) {
ByteBuffer buffer = buffers.get(i);
fta.reset(buffer);
for (int j = 0; j < fta.getTupleCount(); j++) {
tuple.reset(fta, j);
bta.update(tuple);
}
}
//cleanup the buffer
currentInUse = 0;
ByteBuffer buffer = buffers.get(0);
appender.reset(buffer, true);
}
private void allocate(int index) {
if (index >= buffers.size()) {
buffers.add(ctx.allocateFrame());
}
}
}