blob: aedd860922e11479eb1ccf8a00c36f6a15b28037 [file] [log] [blame]
/*
* 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.cassandra.io.sstable.format;
import java.io.IOException;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.cache.ChunkCache;
import org.apache.cassandra.io.sstable.Component;
import org.apache.cassandra.io.sstable.CorruptSSTableException;
import org.apache.cassandra.io.sstable.Descriptor;
import org.apache.cassandra.io.sstable.IOOptions;
import org.apache.cassandra.io.sstable.KeyReader;
import org.apache.cassandra.io.sstable.SSTable;
import org.apache.cassandra.io.sstable.format.SSTableFormat.Components;
import org.apache.cassandra.io.sstable.metadata.ValidationMetadata;
import org.apache.cassandra.metrics.TableMetrics;
import org.apache.cassandra.schema.Schema;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.schema.TableMetadataRef;
import org.apache.cassandra.utils.Clock;
import org.apache.cassandra.utils.JVMStabilityInspector;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.cassandra.db.Directories.SECONDARY_INDEX_NAME_SEPARATOR;
import static org.apache.cassandra.io.sstable.format.SSTableReader.OpenReason.NORMAL;
public abstract class SSTableReaderLoadingBuilder<R extends SSTableReader, B extends SSTableReader.Builder<R, B>>
{
private final static Logger logger = LoggerFactory.getLogger(SSTableReaderLoadingBuilder.class);
protected final Descriptor descriptor;
protected final Set<Component> components;
protected final TableMetadataRef tableMetadataRef;
protected final IOOptions ioOptions;
protected final ChunkCache chunkCache;
public SSTableReaderLoadingBuilder(SSTable.Builder<?, ?> builder)
{
this.descriptor = builder.descriptor;
this.components = builder.getComponents() != null ? ImmutableSet.copyOf(builder.getComponents()) : TOCComponent.loadOrCreate(this.descriptor);
this.tableMetadataRef = builder.getTableMetadataRef() != null ? builder.getTableMetadataRef() : resolveTableMetadataRef();
this.ioOptions = builder.getIOOptions() != null ? builder.getIOOptions() : IOOptions.fromDatabaseDescriptor();
this.chunkCache = builder.getChunkCache() != null ? builder.getChunkCache() : ChunkCache.instance;
checkNotNull(this.components);
checkNotNull(this.tableMetadataRef);
}
public R build(SSTable.Owner owner, boolean validate, boolean online)
{
checkArgument(components.contains(Components.DATA), "Data component is missing for sstable %s", descriptor);
if (validate)
checkArgument(this.components.containsAll(descriptor.getFormat().primaryComponents()), "Some required components (%s) are missing for sstable %s", Sets.difference(descriptor.getFormat().primaryComponents(), this.components), descriptor);
B builder = (B) descriptor.getFormat().getReaderFactory().builder(descriptor);
builder.setOpenReason(NORMAL);
builder.setMaxDataAge(Clock.Global.currentTimeMillis());
builder.setTableMetadataRef(tableMetadataRef);
builder.setComponents(components);
R reader = null;
try
{
CompressionInfoComponent.verifyCompressionInfoExistenceIfApplicable(descriptor, builder.getComponents());
long t0 = Clock.Global.currentTimeMillis();
openComponents(builder, owner, validate, online);
if (logger.isTraceEnabled())
logger.trace("SSTable {} loaded in {}ms", descriptor, Clock.Global.currentTimeMillis() - t0);
reader = builder.build(owner, validate, online);
return reader;
}
catch (RuntimeException | IOException | Error ex)
{
if (reader != null)
reader.selfRef().release();
JVMStabilityInspector.inspectThrowable(ex);
if (ex instanceof CorruptSSTableException)
throw (CorruptSSTableException) ex;
throw new CorruptSSTableException(ex, descriptor.baseFile());
}
}
public abstract KeyReader buildKeyReader(TableMetrics tableMetrics) throws IOException;
protected abstract void openComponents(B builder, SSTable.Owner owner, boolean validate, boolean online) throws IOException;
/**
* Check if sstable is created using same partitioner.
* Partitioner can be null, which indicates older version of sstable or no stats available.
* In that case, we skip the check.
*/
protected void validatePartitioner(TableMetadata metadata, ValidationMetadata validationMetadata)
{
String partitionerName = metadata.partitioner.getClass().getCanonicalName();
if (validationMetadata != null && !partitionerName.equals(validationMetadata.partitioner))
{
throw new CorruptSSTableException(new IOException(String.format("Cannot open %s; partitioner %s does not match system partitioner %s. " +
"Note that the default partitioner starting with Cassandra 1.2 is Murmur3Partitioner, " +
"so you will need to edit that to match your old partitioner if upgrading.",
descriptor, validationMetadata.partitioner, partitionerName)),
descriptor.fileFor(Components.STATS));
}
}
private TableMetadataRef resolveTableMetadataRef()
{
TableMetadataRef metadata;
if (descriptor.cfname.contains(SECONDARY_INDEX_NAME_SEPARATOR))
{
int i = descriptor.cfname.indexOf(SECONDARY_INDEX_NAME_SEPARATOR);
String indexName = descriptor.cfname.substring(i + 1);
metadata = Schema.instance.getIndexTableMetadataRef(descriptor.ksname, indexName);
if (metadata == null)
throw new AssertionError("Could not find index metadata for index cf " + i);
}
else
{
metadata = Schema.instance.getTableMetadataRef(descriptor.ksname, descriptor.cfname);
}
return metadata;
}
}