/*
* 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.opt;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
import org.h2.command.ddl.CreateTableData;
import org.h2.engine.Session;
import org.h2.index.BaseIndex;
import org.h2.index.Cursor;
import org.h2.index.Index;
import org.h2.index.IndexCondition;
import org.h2.index.IndexType;
import org.h2.index.SingleRowCursor;
import org.h2.message.DbException;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
import org.h2.table.TableBase;
import org.h2.table.TableFilter;
import org.h2.table.TableType;
import org.h2.value.Value;
import org.h2.value.ValueInt;
import org.jsr166.ConcurrentHashMap8;
/**
* Meta table.
*/
public class GridH2MetaTable extends TableBase {
/** */
private static final int ID = 0;
/** */
private final MetaIndex index;
/** */
private final AtomicLong dataModificationId = new AtomicLong();
/** */
private final Set<Session> fakeExclusiveSet = Collections.newSetFromMap(
new ConcurrentHashMap8<Session,Boolean>());
/**
* @param data Data.
*/
public GridH2MetaTable(CreateTableData data) {
super(data);
ArrayList<Column> cols = data.columns;
assert cols.size() == 4 : cols;
Column id = cols.get(ID);
assert "ID".equals(id.getName()) && id.getType() == Value.INT : cols;
assert id.getColumnId() == ID;
index = new MetaIndex();
}
/** {@inheritDoc} */
@Override public Row getTemplateRow() {
return new MetaRow();
}
/** {@inheritDoc} */
@Override public SearchRow getTemplateSimpleRow(boolean singleColumn) {
if (singleColumn)
return GridH2RowFactory.create((Value)null);
return new MetaRow();
}
/** {@inheritDoc} */
@Override public boolean lock(Session session, boolean exclusive, boolean forceLockEvenInMvcc) {
if (fakeExclusiveSet.contains(session))
return true;
if (exclusive)
fakeExclusiveSet.add(session);
return false;
}
/** {@inheritDoc} */
@Override public void unlock(Session s) {
fakeExclusiveSet.remove(s);
}
/** {@inheritDoc} */
@Override public void close(Session session) {
// No-op.
}
/** {@inheritDoc} */
@Override public Index addIndex(Session session, String indexName, int indexId,
IndexColumn[] cols, IndexType indexType, boolean create, String indexComment) {
assert cols.length == 1 : "len: " + cols.length;
int colId = cols[0].column.getColumnId();
assert colId == ID : "colId: " + colId;
return index;
}
/** {@inheritDoc} */
@Override public void removeRow(Session session, Row row) {
dataModificationId.incrementAndGet();
index.remove(session, row);
}
/** {@inheritDoc} */
@Override public void truncate(Session session) {
dataModificationId.incrementAndGet();
index.truncate(session);
}
/** {@inheritDoc} */
@Override public void addRow(Session session, Row row) {
dataModificationId.incrementAndGet();
index.add(session, row);
}
/** {@inheritDoc} */
@Override public void checkSupportAlter() {
throw DbException.getUnsupportedException("alter");
}
/** {@inheritDoc} */
@Override public TableType getTableType() {
return TableType.SYSTEM_TABLE;
}
/** {@inheritDoc} */
@Override public Index getScanIndex(Session session) {
return index;
}
/** {@inheritDoc} */
@Override public Index getUniqueIndex() {
return index;
}
/** {@inheritDoc} */
@Override public ArrayList<Index> getIndexes() {
return null;
}
/** {@inheritDoc} */
@Override public boolean isLockedExclusively() {
return !fakeExclusiveSet.isEmpty();
}
/** {@inheritDoc} */
@Override public boolean isLockedExclusivelyBy(Session s) {
return fakeExclusiveSet.contains(s);
}
/** {@inheritDoc} */
@Override public long getMaxDataModificationId() {
return dataModificationId.get();
}
/** {@inheritDoc} */
@Override public boolean isDeterministic() {
return false;
}
/** {@inheritDoc} */
@Override public boolean canGetRowCount() {
return true;
}
/** {@inheritDoc} */
@Override public boolean canDrop() {
return false;
}
/** {@inheritDoc} */
@Override public long getRowCount(Session session) {
return index.getRowCount(session);
}
/** {@inheritDoc} */
@Override public long getRowCountApproximation() {
return index.getRowCountApproximation();
}
/** {@inheritDoc} */
@Override public long getDiskSpaceUsed() {
return 0;
}
/** {@inheritDoc} */
@Override public void checkRename() {
throw DbException.getUnsupportedException("rename");
}
/**
* Get value row.
*/
private static class MetaRow extends GridH2Row {
/** */
private Value v0;
/** */
private Value v1;
/** */
private Value v2;
/** */
private Value v3;
/** {@inheritDoc} */
@Override public int getColumnCount() {
return 4;
}
/** {@inheritDoc} */
@Override public Value getValue(int idx) {
switch (idx) {
case 0:
return v0;
case 1:
return v1;
case 2:
return v2;
case 3:
return v3;
default:
throw new IllegalStateException("Index: " + idx);
}
}
/** {@inheritDoc} */
@Override public void setValue(int idx, Value v) {
switch (idx) {
case 0:
v0 = v;
break;
case 1:
v1 = v;
break;
case 2:
v2 = v;
break;
case 3:
v3 = v;
break;
default:
throw new IllegalStateException("Index: " + idx);
}
}
/** {@inheritDoc} */
@Override public long expireTime() {
return 0;
}
}
/**
* Met index.
*/
private static class MetaIndex extends BaseIndex {
/** */
private final ConcurrentMap<ValueInt, GridH2Row> rows = new ConcurrentHashMap8<>();
/** {@inheritDoc} */
@Override public void checkRename() {
throw DbException.getUnsupportedException("rename");
}
/** {@inheritDoc} */
@Override public void close(Session session) {
// No-op.
}
/**
* @param row Row.
* @return ID.
*/
private static ValueInt id(SearchRow row) {
Value id = row.getValue(ID);
assert id != null;
return (ValueInt)id;
}
/** {@inheritDoc} */
@Override public void add(Session session, Row row) {
rows.put(id(row), (GridH2Row)row);
}
/** {@inheritDoc} */
@Override public void remove(Session session, Row row) {
rows.remove(id(row), row);
}
/** {@inheritDoc} */
@Override public Cursor find(Session session, SearchRow first, SearchRow last) {
if (first == null || last == null || !Objects.equals(id(first), id(last)))
return new GridH2Cursor(rows.values().iterator());
return new SingleRowCursor(rows.get(id(first)));
}
/** {@inheritDoc} */
@Override public double getCost(Session session, int[] masks, TableFilter[] filters,
int filter, SortOrder sortOrder, HashSet<Column> cols) {
if ((masks[ID] & IndexCondition.EQUALITY) == IndexCondition.EQUALITY)
return 1;
return 1000 + rows.size();
}
/** {@inheritDoc} */
@Override public void remove(Session session) {
// No-op.
}
/** {@inheritDoc} */
@Override public void truncate(Session session) {
rows.clear();
}
/** {@inheritDoc} */
@Override public boolean canGetFirstOrLast() {
return false;
}
/** {@inheritDoc} */
@Override public Cursor findFirstOrLast(Session session, boolean first) {
throw new UnsupportedOperationException();
}
/** {@inheritDoc} */
@Override public boolean needRebuild() {
return false;
}
/** {@inheritDoc} */
@Override public long getRowCount(Session session) {
return rows.size();
}
/** {@inheritDoc} */
@Override public long getRowCountApproximation() {
return getRowCount(null);
}
/** {@inheritDoc} */
@Override public long getDiskSpaceUsed() {
return 0;
}
}
}