/* * 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.jena.sparql.core.mem; import static java.lang.ThreadLocal.withInitial; import java.util.concurrent.atomic.AtomicReference; import org.apache.jena.atlas.lib.tuple.TupleMap; import org.apache.jena.graph.Node; import org.apache.jena.query.ReadWrite; import org.slf4j.Logger; /** * A partial implementation of {@link TupleTable} that contains some common state management. * * @param <TupleMapType> the type of the internal structure holding table data * @param <TupleType> the type of tuple in which a subclass of this class transacts * @param <ConsumerType> a type of consumer that can accept as many elements as exist in {@code TupleType} */ public abstract class PMapTupleTable<TupleMapType, TupleType, ConsumerType> extends OrderedTupleTable<TupleType, ConsumerType> implements TupleTable<TupleType> { /** * This method should always return the same value, but note that the same value may not necessarily be the same * instance. * * @return a value to which to initialize the master table data. */ protected abstract TupleMapType initial(); private final AtomicReference<TupleMapType> master = new AtomicReference<>(initial()); /** * We use an {@link AtomicReference} to the internal structure that holds our table data to be able to swap * transactional versions of the data with the shared version atomically. */ protected AtomicReference<TupleMapType> master() { return master; } private final ThreadLocal<TupleMapType> local = withInitial(()->null); /** * @return a thread-local transactional reference to the internal table structure */ protected ThreadLocal<TupleMapType> local() { return local; } private final String tableName; /** * @param n a name for this table */ public PMapTupleTable(final String n, final TupleMap order) { super(order); this.tableName = n; } protected abstract Logger log(); /** * Logs to DEBUG prepending the table name in order to distinguish amongst different indexes */ protected void debug(final String msg, final Object... values) { if ( log().isDebugEnabled() ) log().debug(tableName + ": " + msg, values); } /** * {@link #local} is initialized via {@link #initial()} */ @Override public void begin(final ReadWrite rw) { local.set(master().get()); } @Override public void end() { debug("Abandoning transactional reference."); local.remove(); } @Override public void commit() { debug("Swapping transactional reference in for shared reference"); master().set(local.get()); end(); } @Override public void clear() { local().set(initial()); } protected boolean isConcrete(final Node n) { return n != null && n.isConcrete(); } }