package org.wonderdb.serialize.record; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.jboss.netty.buffer.ChannelBuffer; import org.wonderdb.cache.impl.CacheEntryPinner; import org.wonderdb.helper.LazyExtendedSpaceProvider; import org.wonderdb.serialize.ColumnSerializer; import org.wonderdb.serialize.Serializer; import org.wonderdb.serialize.SerializerManager; import org.wonderdb.types.BlockPtr; import org.wonderdb.types.ColumnSerializerMetadata; import org.wonderdb.types.DBType; import org.wonderdb.types.Extended; import org.wonderdb.types.TableRecordMetadata; import org.wonderdb.types.TypeMetadata; import org.wonderdb.types.record.ExtendedTableRecord; import org.wonderdb.types.record.RecordHeader; import org.wonderdb.types.record.TableRecord; public class TableRecordSerializer { public static TableRecordSerializer instance = new TableRecordSerializer(); private TableRecordSerializer() { } public static TableRecordSerializer getInstance() { return instance; } public TableRecord readMinimum(ChannelBuffer buffer, TypeMetadata meta) { RecordHeader header = RecordHeaderSerializer.getInstance().getHeader(buffer); TableRecord record = null; if (header.isExtended()) { BlockPtr ptr = (BlockPtr) Serializer.getInstance().getObject(SerializerManager.BLOCK_PTR, buffer, meta); List<BlockPtr> extendedPtrs = new ArrayList<BlockPtr>(); extendedPtrs.add(ptr); record = new ExtendedTableRecord(new HashMap<Integer, DBType>(), extendedPtrs); return record; } record = new TableRecord(null); readMinimumColumns(record, buffer, meta); return record; } private void readMinimumColumns(TableRecord record, ChannelBuffer buffer, TypeMetadata meta) { TableRecordMetadata trsb = (TableRecordMetadata) meta; int size = buffer.readInt(); Map<Integer, DBType> map = new HashMap<Integer, DBType>(size); for (int i = 0; i < size; i++) { int columnId = buffer.readInt(); ColumnSerializerMetadata csm = new ColumnSerializerMetadata(trsb.getColumnIdTypeMap().get(columnId)); DBType column = ColumnSerializer.getInstance().readMinimum(buffer, csm); map.put(columnId, column); } record.setColumnMap(map); } public void readFull(TableRecord record, TypeMetadata meta) { ChannelBuffer buf = null; Set<Object> pinnedBlocks = new HashSet<Object>(); try { if (record instanceof Extended) { buf = LazyExtendedSpaceProvider.getInstance().provideSpaceToRead(((Extended) record).getPtrList(), pinnedBlocks); } else { throw new RuntimeException("readFull is not required for non extended columns"); } readMinimumColumns(record, buf, meta); } finally { CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks); } } public int getFullSize(TableRecord record, TypeMetadata meta) { int size = 1 + Integer.SIZE/8 + 9; TableRecordMetadata trsm = (TableRecordMetadata) meta; Map<Integer, Integer> map = trsm.getColumnIdTypeMap(); Iterator<Integer> iter = record.getColumnMap().keySet().iterator(); while (iter.hasNext()) { int id = iter.next(); int type = map.get(id); DBType column = record.getColumnMap().get(id); size = size + Integer.SIZE/8 + ColumnSerializer.getInstance().getObjectSize(column, new ColumnSerializerMetadata(type)); } return size; } public int getObjectBlockSize(TableRecord record, TypeMetadata meta) { if (record instanceof Extended) { return 9+1; } return getFullSize(record, meta); } public void serializeExtended(byte fileId, TableRecord record, int blockSize, TypeMetadata meta, Set<Object> pinnedBlocks) { int size = getFullSize(record, meta); int blocksRequired = getExtraBlocksRequired(size, blockSize); List<BlockPtr> list = record instanceof Extended ? ((Extended) record).getPtrList() : new ArrayList<BlockPtr>(); ChannelBuffer buf = LazyExtendedSpaceProvider.getInstance().provideSpaceToWrite(fileId, list, blocksRequired, pinnedBlocks); RecordHeader header = new RecordHeader(); if (blocksRequired > 0) { header.setExtended(true); } writeTableRecord(record, buf, meta); } public void serializeMinimum(TableRecord record, ChannelBuffer buffer, TypeMetadata meta) { RecordHeader header = new RecordHeader(); header.setExtended(record instanceof Extended); RecordHeaderSerializer.getInstance().serialize(header, buffer); if (record instanceof Extended) { Serializer.getInstance().serialize(SerializerManager.BLOCK_PTR, ((Extended) record).getPtrList().get(0), buffer, meta); } else { writeMinimum(record, buffer, meta); } } private void writeMinimum(TableRecord record, ChannelBuffer buffer, TypeMetadata meta) { if (record instanceof Extended) { Serializer.getInstance().serialize(SerializerManager.BLOCK_PTR, ((Extended) record).getPtrList().get(0), buffer, meta); return; } else { writeTableRecord(record, buffer, meta); } } private void writeTableRecord(TableRecord record, ChannelBuffer buffer, TypeMetadata meta) { Map<Integer, Integer> map = ((TableRecordMetadata) meta).getColumnIdTypeMap(); Map<Integer, DBType> columnMap = ((TableRecord) record).getColumnMap(); buffer.writeInt(columnMap.size()); Iterator<Integer> iter = columnMap.keySet().iterator(); while (iter.hasNext()) { int colId = iter.next(); buffer.writeInt(colId); DBType column = columnMap.get(colId); ColumnSerializerMetadata csm = new ColumnSerializerMetadata(map.get(colId)); ColumnSerializer.getInstance().serializeMinimum(column, buffer, csm); } } private int getExtraBlocksRequired(int requiredSize, int maxSize) { int mSize = maxSize -10; int retSize = requiredSize/mSize; int balance = requiredSize%mSize; return balance > 0 ? retSize + 1 : retSize; } public int getObjectSize(DBType object, TypeMetadata meta) { if (object instanceof Extended) { return 9; } return getFullSize((TableRecord) object, meta); } }