/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ package org.apache.ignite.internal.processors.query.h2.database; import java.util.Comparator; import java.util.List; import java.util.concurrent.atomic.AtomicLong; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.pagemem.PageMemory; import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager; import org.apache.ignite.internal.processors.cache.database.tree.BPlusTree; import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusIO; import org.apache.ignite.internal.processors.cache.database.tree.io.BPlusMetaIO; import org.apache.ignite.internal.processors.cache.database.tree.reuse.ReuseList; import org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasInnerIO; import org.apache.ignite.internal.processors.query.h2.database.io.H2ExtrasLeafIO; import org.apache.ignite.internal.processors.query.h2.opt.GridH2Row; import org.apache.ignite.internal.util.typedef.internal.U; import org.h2.result.SearchRow; import org.h2.table.IndexColumn; import org.h2.value.Value; /** */ public abstract class H2Tree extends BPlusTree<SearchRow, GridH2Row> { /** */ private final H2RowFactory rowStore; /** */ private final int inlineSize; /** */ private final List<InlineIndexHelper> inlineIdxs; /** */ private final IndexColumn[] cols; /** */ private final int[] columnIds; /** */ private final Comparator<Value> comp = new Comparator<Value>() { @Override public int compare(Value o1, Value o2) { return compareValues(o1, o2); } }; /** * @param name Tree name. * @param reuseList Reuse list. * @param cacheId Cache ID. * @param pageMem Page memory. * @param wal Write ahead log manager. * @param rowStore Row data store. * @param metaPageId Meta page ID. * @param initNew Initialize new index. * @throws IgniteCheckedException If failed. */ protected H2Tree( String name, ReuseList reuseList, int cacheId, PageMemory pageMem, IgniteWriteAheadLogManager wal, AtomicLong globalRmvId, H2RowFactory rowStore, long metaPageId, boolean initNew, IndexColumn[] cols, List<InlineIndexHelper> inlineIdxs, int inlineSize ) throws IgniteCheckedException { super(name, cacheId, pageMem, wal, globalRmvId, metaPageId, reuseList); if (!initNew) { // Page is ready - read inline size from it. inlineSize = getMetaInlineSize(); } this.inlineSize = inlineSize; assert rowStore != null; this.rowStore = rowStore; this.inlineIdxs = inlineIdxs; this.cols = cols; this.columnIds = new int[cols.length]; for (int i = 0; i < cols.length; i++) columnIds[i] = cols[i].column.getColumnId(); setIos(H2ExtrasInnerIO.getVersions(inlineSize), H2ExtrasLeafIO.getVersions(inlineSize)); initTree(initNew, inlineSize); } /** * @return Row store. */ public H2RowFactory getRowFactory() { return rowStore; } /** {@inheritDoc} */ @Override protected GridH2Row getRow(BPlusIO<SearchRow> io, long pageAddr, int idx, Object ignore) throws IgniteCheckedException { return (GridH2Row)io.getLookupRow(this, pageAddr, idx); } /** * @return Inline size. */ public int inlineSize() { return inlineSize; } /** * @return Inline size. * @throws IgniteCheckedException If failed. */ private int getMetaInlineSize() throws IgniteCheckedException { final long metaPage = acquirePage(metaPageId); try { long pageAddr = readLock(metaPageId, metaPage); // Meta can't be removed. assert pageAddr != 0 : "Failed to read lock meta page [metaPageId=" + U.hexLong(metaPageId) + ']'; try { BPlusMetaIO io = BPlusMetaIO.VERSIONS.forPage(pageAddr); return io.getInlineSize(pageAddr); } finally { readUnlock(metaPageId, metaPage, pageAddr); } } finally { releasePage(metaPageId, metaPage); } } /** {@inheritDoc} */ @Override protected int compare(BPlusIO<SearchRow> io, long pageAddr, int idx, SearchRow row) throws IgniteCheckedException { if (inlineSize() == 0) return compareRows(getRow(io, pageAddr, idx), row); else { int off = io.offset(idx); int fieldOff = 0; int lastIdxUsed = 0; for (int i = 0; i < inlineIdxs.size(); i++) { InlineIndexHelper inlineIdx = inlineIdxs.get(i); Value v2 = row.getValue(inlineIdx.columnIndex()); if (v2 == null) return 0; int c = inlineIdx.compare(pageAddr, off + fieldOff, inlineSize() - fieldOff, v2, comp); if (c == -2) break; lastIdxUsed++; if (c != 0) return c; fieldOff += inlineIdx.fullSize(pageAddr, off + fieldOff); if (fieldOff > inlineSize()) break; } if (lastIdxUsed == cols.length) return 0; SearchRow rowData = getRow(io, pageAddr, idx); for (int i = lastIdxUsed, len = cols.length; i < len; i++) { IndexColumn col = cols[i]; int idx0 = col.column.getColumnId(); Value v2 = row.getValue(idx0); if (v2 == null) { // Can't compare further. return 0; } Value v1 = rowData.getValue(idx0); int c = compareValues(v1, v2); if (c != 0) return InlineIndexHelper.fixSort(c, col.sortType); } return 0; } } /** * Compare two rows. * * @param r1 Row 1. * @param r2 Row 2. * @return Compare result. */ private int compareRows(GridH2Row r1, SearchRow r2) { if (r1 == r2) return 0; for (int i = 0, len = cols.length; i < len; i++) { int idx = columnIds[i]; Value v1 = r1.getValue(idx); Value v2 = r2.getValue(idx); if (v1 == null || v2 == null) { // can't compare further return 0; } int c = compareValues(v1, v2); if (c != 0) return InlineIndexHelper.fixSort(c, cols[i].sortType); } return 0; } /** Compares two Values. */ public abstract int compareValues(Value v1, Value v2); }