class ColumnPage extends Page {

    private final AtomicInteger memory = new AtomicInteger(0);
    private ByteBuffer buff;

    ColumnPage(BTreeMap<?, ?> map) {
        super(map);
    }

    @Override
    public int getMemory() {
        return memory.get();
    }

    @Override
    public void read(ByteBuffer buff, int chunkId, int offset, int expectedPageLength) {
        int start = buff.position();
        int pageLength = buff.getInt();
        checkPageLength(chunkId, pageLength, expectedPageLength);

        readCheckValue(buff, chunkId, offset, pageLength);
        buff.get(); // page type;
        int compressType = buff.get();

        // 解压完之后就结束了，因为还不知道具体的行，所以延迟对列进行反序列化
        this.buff = expandPage(buff, compressType, start, pageLength);
    }

    // 在read方法中已经把buff读出来了，这里只是把字段从buff中解析出来
    void readColumn(Object[] values, int columnIndex) {
        int memory = 0;
        ByteBuffer buff = this.buff.slice(); // 要支持多线程同时读，所以直接用slice
        StorageDataType valueType = map.getValueType();
        for (int row = 0, rowCount = values.length; row < rowCount; row++) {
            valueType.readColumn(buff, values[row], columnIndex);
            memory += valueType.getMemory(values[row], columnIndex);
        }
        if (this.memory.compareAndSet(0, memory)) {
            // buff内存大小在getOrReadPage中加了，这里只加列占用的内存大小
            map.getBTreeStorage().getBTreeGC().addUsedMemory(memory);
        }
    }

    long write(Chunk chunk, DataBuffer buff, Object[] values, int columnIndex) {<FILL_FUNCTION_BODY>}
}

        PageInfo pInfoOld = getRef().getPageInfo();
        beforeWrite(pInfoOld);
        int start = buff.position();
        int type = PageUtils.PAGE_TYPE_COLUMN;
        buff.putInt(0); // 回填pageLength

        StorageDataType valueType = map.getValueType();
        int checkPos = buff.position();
        buff.putShort((short) 0);
        buff.put((byte) type);
        int compressTypePos = buff.position();
        int compressType = 0;
        buff.put((byte) compressType); // 调用compressPage时会回填
        int compressStart = buff.position();
        for (int row = 0, rowCount = values.length; row < rowCount; row++) {
            valueType.writeColumn(buff, values[row], columnIndex);
        }
        compressPage(buff, compressStart, compressType, compressTypePos);
        int pageLength = buff.position() - start;
        buff.putInt(start, pageLength);

        writeCheckValue(buff, chunk, start, pageLength, checkPos);
        return updateChunkAndPage(pInfoOld, chunk, start, pageLength, type);
    
<methods>public int binarySearch(java.lang.Object) ,public com.lealone.storage.aose.btree.page.Page copy() ,public com.lealone.storage.aose.btree.page.Page copyAndInsertLeaf(int, java.lang.Object, java.lang.Object) ,public static com.lealone.storage.aose.btree.page.Page create(BTreeMap<?,?>, int) ,public com.lealone.storage.aose.btree.page.Page getChildPage(int) ,public com.lealone.storage.aose.btree.page.PageReference getChildPageReference(int) ,public com.lealone.storage.aose.btree.page.PageReference[] getChildren() ,public java.lang.Object getKey(int) ,public int getKeyCount() ,public int getMemory() ,public int getPageIndex(java.lang.Object) ,public long getPos() ,public int getRawChildPageCount() ,public com.lealone.storage.aose.btree.page.PageReference getRef() ,public java.lang.Object getValue(int) ,public java.lang.Object getValue(int, int[]) ,public java.lang.Object getValue(int, boolean) ,public com.lealone.storage.aose.btree.page.Page gotoLeafPage(java.lang.Object) ,public boolean isEmpty() ,public boolean isLeaf() ,public boolean isNode() ,public void markDirty() ,public void markDirtyBottomUp() ,public void read(java.nio.ByteBuffer, int, int, int) ,public void remove(int) ,public void setRef(com.lealone.storage.aose.btree.page.PageReference) ,public java.lang.Object setValue(int, java.lang.Object) ,public long writeUnsavedRecursive(com.lealone.storage.aose.btree.page.PageInfo, com.lealone.storage.aose.btree.chunk.Chunk, com.lealone.db.DataBuffer) <variables>public static final boolean ASSERT,protected final non-sealed BTreeMap<?,?> map,private com.lealone.storage.aose.btree.page.PageReference ref