package org.wonderdb.core.collection.impl;
/*******************************************************************************
* Copyright 2013 Vilas Athavale
*
* 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 at
*
* 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.
*******************************************************************************/
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.log4j.Logger;
import org.wonderdb.block.Block;
import org.wonderdb.block.BlockManager;
import org.wonderdb.block.IndexBlock;
import org.wonderdb.block.IndexBranchBlock;
import org.wonderdb.block.IndexLeafBlock;
import org.wonderdb.cache.impl.CacheEntryPinner;
import org.wonderdb.file.StorageUtils;
import org.wonderdb.freeblock.FreeBlockFactory;
import org.wonderdb.seralizers.block.SerializedBlockImpl;
import org.wonderdb.serialize.SerializerManager;
import org.wonderdb.serialize.block.BlockSerilizer;
import org.wonderdb.serialize.record.RecordSerializer;
import org.wonderdb.types.BlockPtr;
import org.wonderdb.types.ColumnSerializerMetadata;
import org.wonderdb.types.DBType;
import org.wonderdb.types.SingleBlockPtr;
import org.wonderdb.types.TypeMetadata;
import org.wonderdb.types.record.IndexRecord;
import org.wonderdb.types.record.ObjectRecord;
import org.wonderdb.types.record.Record;
public class SplitFactory {
private static SplitFactory instance = new SplitFactory();
private SplitFactory() {
}
public static SplitFactory getInstance() {
return instance;
}
public boolean isSplitRequired(Block block, int size, TypeMetadata meta) {
int maxBlockSize = StorageUtils.getInstance().getTotalBlockSize(block.getPtr()) - BlockSerilizer.INDEX_BLOCK_HEADER - SerializedBlockImpl.HEADER_SIZE;
if (size >= maxBlockSize) {
return true;
}
return false;
}
private List<List<Record>> split(IndexBlock block, TypeMetadata meta) {
int overhead = BlockSerilizer.INDEX_BLOCK_HEADER + SerializedBlockImpl.HEADER_SIZE;
int maxBlockSize = StorageUtils.getInstance().getTotalBlockSize(block.getPtr()) - overhead;
List<Record> list = block.getData();
List<List<Record>> listOfList = new ArrayList<List<Record>>();
List<Record> currentList = new ArrayList<Record>();
int currentListSize = 0;
listOfList.add(currentList);
TypeMetadata newMeta = meta;
if (block instanceof IndexBranchBlock) {
newMeta = new ColumnSerializerMetadata(SerializerManager.BLOCK_PTR);
}
for (int i = 0; i < list.size(); i++) {
Record st = (Record) list.get(i);
int size = RecordSerializer.getInstance().getRecordSize(st, newMeta);
// currentListSize = currentListSize + size;
if (currentListSize >= maxBlockSize*0.7) {
currentList = new ArrayList<Record>();
currentList.add(st);
listOfList.add(currentList);
currentListSize = size;
} else {
currentList.add(st);
currentListSize = currentListSize + size;
}
}
return listOfList;
}
private void setMaxKey(IndexBlock block, TypeMetadata meta, Set<Object> pinnedBlocks) {
IndexRecord lastRecord = (IndexRecord) block.getData().get(block.getData().size()-1);
DBType column = lastRecord.getColumn();
DBType dt = column;
if (dt instanceof BlockPtr) {
IndexBlock b = (IndexBlock) BlockManager.getInstance().getBlock((BlockPtr) dt, meta, pinnedBlocks);
block.setMaxKey(b.getMaxKey(meta));
} else {
block.setMaxKey(dt);
}
}
public List<IndexBlock> split(IndexBlock block, Set<Block> changedBlocks, Set<Object> pinnedBlocks, TypeMetadata meta) {
List<IndexBlock> retList = new ArrayList<IndexBlock>();
retList.add(block);
boolean branchBlock = block instanceof IndexBranchBlock;
List<List<Record>> splitList = split(block, meta);
block.getData().clear();
block.getData().addAll(splitList.get(0));
setMaxKey(block, meta, pinnedBlocks);
// BlockPtr parentPtr = block.getParent(stack);
if (splitList.size() > 2) {
Logger.getLogger(getClass()).fatal("split more");
}
for (int i = 1; i < splitList.size(); i++) {
IndexBlock tmpBlock = null;
long posn = FreeBlockFactory.getInstance().getFreeBlockPosn(block.getPtr().getFileId());
BlockPtr ptr = new SingleBlockPtr(block.getPtr().getFileId(), posn);
CacheEntryPinner.getInstance().pin(ptr, pinnedBlocks);
if (branchBlock) {
tmpBlock = (IndexBlock) BlockManager.getInstance().createBranchBlock(ptr, pinnedBlocks);
} else {
tmpBlock = (IndexBlock) BlockManager.getInstance().createIndexLefBlock(ptr, pinnedBlocks);
}
CacheEntryPinner.getInstance().pin(tmpBlock.getPtr(), pinnedBlocks);
tmpBlock.getData().addAll(splitList.get(i));
retList.add(tmpBlock);
changedBlocks.add(tmpBlock);
// tmpBlock.setParent(parentPtr);
setMaxKey(tmpBlock, meta, pinnedBlocks);
if (!branchBlock) {
IndexLeafBlock nextBlock = (IndexLeafBlock) BlockManager.getInstance().getBlock(block.getNext(), meta, pinnedBlocks);
if (nextBlock != null) {
nextBlock.setPrev(tmpBlock.getPtr());
changedBlocks.add(nextBlock);
}
tmpBlock.setNext(block.getNext());
block.setNext(tmpBlock.getPtr());
tmpBlock.setPrev(block.getPtr());
} else {
for (int j = 0; j < tmpBlock.getData().size(); j++) {
BlockPtr p = (BlockPtr) ((ObjectRecord) tmpBlock.getData().get(j)).getColumn();
CacheEntryPinner.getInstance().pin(p, pinnedBlocks);
Block b = BlockManager.getInstance().getBlock(p, meta, pinnedBlocks);
b.setParent(tmpBlock.getPtr());
// changedBlocks.add(b);
}
}
}
return retList;
}
}