/* * 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.schema; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.database.CacheDataRow; import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtLocalPartition; import org.apache.ignite.internal.processors.cache.distributed.near.GridNearCacheAdapter; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.query.GridQueryProcessor; import org.apache.ignite.internal.util.lang.GridCursor; import org.apache.ignite.internal.util.typedef.internal.S; import java.util.Collection; import static org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtPartitionState.EVICTED; import static org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtPartitionState.OWNING; import static org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtPartitionState.RENTING; /** * Traversor operating all primary and backup partitions of given cache. */ public class SchemaIndexCacheVisitorImpl implements SchemaIndexCacheVisitor { /** Query procssor. */ private final GridQueryProcessor qryProc; /** Cache context. */ private final GridCacheContext cctx; /** Space name. */ private final String spaceName; /** Table name. */ private final String tblName; /** Cancellation token. */ private final SchemaIndexOperationCancellationToken cancel; /** * Constructor. * * @param cctx Cache context. * @param spaceName Space name. * @param tblName Table name. * @param cancel Cancellation token. */ public SchemaIndexCacheVisitorImpl(GridQueryProcessor qryProc, GridCacheContext cctx, String spaceName, String tblName, SchemaIndexOperationCancellationToken cancel) { this.qryProc = qryProc; this.spaceName = spaceName; this.tblName = tblName; this.cancel = cancel; if (cctx.isNear()) cctx = ((GridNearCacheAdapter)cctx.cache()).dht().context(); this.cctx = cctx; } /** {@inheritDoc} */ @Override public void visit(SchemaIndexCacheVisitorClosure clo) throws IgniteCheckedException { assert clo != null; FilteringVisitorClosure filterClo = new FilteringVisitorClosure(clo); Collection<GridDhtLocalPartition> parts = cctx.topology().localPartitions(); for (GridDhtLocalPartition part : parts) processPartition(part, filterClo); } /** * Process partition. * * @param part Partition. * @param clo Index closure. * @throws IgniteCheckedException If failed. */ private void processPartition(GridDhtLocalPartition part, FilteringVisitorClosure clo) throws IgniteCheckedException { checkCancelled(); boolean reserved = false; if (part != null && part.state() != EVICTED) reserved = (part.state() == OWNING || part.state() == RENTING) && part.reserve(); if (!reserved) return; try { GridCursor<? extends CacheDataRow> cursor = part.dataStore().cursor(); while (cursor.next()) { CacheDataRow row = cursor.get(); KeyCacheObject key = row.key(); processKey(key, row.link(), clo); } } finally { part.release(); } } /** * Process single key. * * @param key Key. * @param link Link. * @param clo Closure. * @throws IgniteCheckedException If failed. */ private void processKey(KeyCacheObject key, long link, FilteringVisitorClosure clo) throws IgniteCheckedException { while (true) { try { checkCancelled(); GridCacheEntryEx entry = cctx.cache().entryEx(key); try { entry.updateIndex(clo, link); } finally { cctx.evicts().touch(entry, AffinityTopologyVersion.NONE); } break; } catch (GridCacheEntryRemovedException ignored) { // No-op. } } } /** * Check if visit process is not cancelled. * * @throws IgniteCheckedException If cancelled. */ private void checkCancelled() throws IgniteCheckedException { if (cancel.isCancelled()) throw new IgniteCheckedException("Index creation was cancelled."); } /** {@inheritDoc} */ @Override public String toString() { return S.toString(SchemaIndexCacheVisitorImpl.class, this); } /** * Filtering visitor closure. */ private class FilteringVisitorClosure implements SchemaIndexCacheVisitorClosure { /** Target closure. */ private final SchemaIndexCacheVisitorClosure target; /** * Constructor. * * @param target Target. */ public FilteringVisitorClosure(SchemaIndexCacheVisitorClosure target) { this.target = target; } /** {@inheritDoc} */ @Override public void apply(KeyCacheObject key, int part, CacheObject val, GridCacheVersion ver, long expiration, long link) throws IgniteCheckedException { if (qryProc.belongsToTable(cctx, spaceName, tblName, key, val)) target.apply(key, part, val, ver, expiration, link); } } }