org.apache.cassandra.io.sstable.Descriptor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cassandra-all Show documentation
Show all versions of cassandra-all Show documentation
The Apache Cassandra Project develops a highly scalable second-generation distributed database, bringing together Dynamo's fully distributed design and Bigtable's ColumnFamily-based data model.
/*
* 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;
import java.io.File;
import java.util.StringTokenizer;
import com.google.common.base.Objects;
import org.apache.cassandra.io.sstable.metadata.IMetadataSerializer;
import org.apache.cassandra.io.sstable.metadata.LegacyMetadataSerializer;
import org.apache.cassandra.io.sstable.metadata.MetadataSerializer;
import org.apache.cassandra.utils.Pair;
import static org.apache.cassandra.io.sstable.Component.separator;
/**
* A SSTable is described by the keyspace and column family it contains data
* for, a generation (where higher generations contain more recent data) and
* an alphabetic version string.
*
* A descriptor can be marked as temporary, which influences generated filenames.
*/
public class Descriptor
{
// versions are denoted as [major][minor]. Minor versions must be forward-compatible:
// new fields are allowed in e.g. the metadata component, but fields can't be removed
// or have their size changed.
//
// Minor versions were introduced with version "hb" for Cassandra 1.0.3; prior to that,
// we always incremented the major version.
public static class Version
{
// This needs to be at the begining for initialization sake
public static final String current_version = "ka";
// ja (2.0.0): super columns are serialized as composites (note that there is no real format change,
// this is mostly a marker to know if we should expect super columns or not. We do need
// a major version bump however, because we should not allow streaming of super columns
// into this new format)
// tracks max local deletiontime in sstable metadata
// records bloom_filter_fp_chance in metadata component
// remove data size and column count from data file (CASSANDRA-4180)
// tracks max/min column values (according to comparator)
// jb (2.0.1): switch from crc32 to adler32 for compression checksums
// checksum the compressed data
// ka (2.1.0): new Statistics.db file format
// index summaries can be downsampled and the sampling level is persisted
// switch uncompressed checksums to adler32
// tracks presense of legacy (local and remote) counter shards
public static final Version CURRENT = new Version(current_version);
private final String version;
public final boolean isLatestVersion;
public final boolean hasPostCompressionAdlerChecksums;
public final boolean hasSamplingLevel;
public final boolean newStatsFile;
public final boolean hasAllAdlerChecksums;
public final boolean hasRepairedAt;
public final boolean tracksLegacyCounterShards;
public Version(String version)
{
this.version = version;
isLatestVersion = version.compareTo(current_version) == 0;
hasPostCompressionAdlerChecksums = version.compareTo("jb") >= 0;
hasSamplingLevel = version.compareTo("ka") >= 0;
newStatsFile = version.compareTo("ka") >= 0;
hasAllAdlerChecksums = version.compareTo("ka") >= 0;
hasRepairedAt = version.compareTo("ka") >= 0;
tracksLegacyCounterShards = version.compareTo("ka") >= 0;
}
/**
* @param ver SSTable version
* @return True if the given version string matches the format.
* @see #version
*/
static boolean validate(String ver)
{
return ver != null && ver.matches("[a-z]+");
}
public boolean isCompatible()
{
return version.compareTo("ja") >= 0 && version.charAt(0) <= CURRENT.version.charAt(0);
}
@Override
public String toString()
{
return version;
}
@Override
public boolean equals(Object o)
{
return o == this || o instanceof Version && version.equals(((Version) o).version);
}
@Override
public int hashCode()
{
return version.hashCode();
}
}
public static enum Type
{
TEMP("tmp", true), TEMPLINK("tmplink", true), FINAL(null, false);
public final boolean isTemporary;
public final String marker;
Type(String marker, boolean isTemporary)
{
this.isTemporary = isTemporary;
this.marker = marker;
}
}
public final File directory;
/** version has the following format: [a-z]+
*/
public final Version version;
public final String ksname;
public final String cfname;
public final int generation;
public final Type type;
private final int hashCode;
/**
* A descriptor that assumes CURRENT_VERSION.
*/
public Descriptor(File directory, String ksname, String cfname, int generation, Type temp)
{
this(Version.CURRENT, directory, ksname, cfname, generation, temp);
}
public Descriptor(String version, File directory, String ksname, String cfname, int generation, Type temp)
{
this(new Version(version), directory, ksname, cfname, generation, temp);
}
public Descriptor(Version version, File directory, String ksname, String cfname, int generation, Type temp)
{
assert version != null && directory != null && ksname != null && cfname != null;
this.version = version;
this.directory = directory;
this.ksname = ksname;
this.cfname = cfname;
this.generation = generation;
type = temp;
hashCode = Objects.hashCode(directory, generation, ksname, cfname, temp);
}
public Descriptor withGeneration(int newGeneration)
{
return new Descriptor(version, directory, ksname, cfname, newGeneration, type);
}
public String filenameFor(Component component)
{
return filenameFor(component.name());
}
public String baseFilename()
{
StringBuilder buff = new StringBuilder();
buff.append(directory).append(File.separatorChar);
appendFileName(buff);
return buff.toString();
}
private void appendFileName(StringBuilder buff)
{
buff.append(ksname).append(separator);
buff.append(cfname).append(separator);
if (type.isTemporary)
buff.append(type.marker).append(separator);
buff.append(version).append(separator);
buff.append(generation);
}
public String relativeFilenameFor(Component component)
{
final StringBuilder buff = new StringBuilder();
appendFileName(buff);
buff.append(separator).append(component.name());
return buff.toString();
}
/**
* @param suffix A component suffix, such as 'Data.db'/'Index.db'/etc
* @return A filename for this descriptor with the given suffix.
*/
public String filenameFor(String suffix)
{
return baseFilename() + separator + suffix;
}
/**
* @see #fromFilename(File directory, String name)
* @param filename The SSTable filename
* @return Descriptor of the SSTable initialized from filename
*/
public static Descriptor fromFilename(String filename)
{
File file = new File(filename);
return fromFilename(file.getParentFile(), file.getName(), false).left;
}
public static Descriptor fromFilename(String filename, boolean skipComponent)
{
File file = new File(filename);
return fromFilename(file.getParentFile(), file.getName(), skipComponent).left;
}
public static Pair fromFilename(File directory, String name)
{
return fromFilename(directory, name, false);
}
/**
* Filename of the form "--[tmp-][-]-"
*
* @param directory The directory of the SSTable files
* @param name The name of the SSTable file
* @param skipComponent true if the name param should not be parsed for a component tag
*
* @return A Descriptor for the SSTable, and the Component remainder.
*/
public static Pair fromFilename(File directory, String name, boolean skipComponent)
{
// tokenize the filename
StringTokenizer st = new StringTokenizer(name, String.valueOf(separator));
String nexttok;
// all filenames must start with keyspace and column family
String ksname = st.nextToken();
String cfname = st.nextToken();
// optional temporary marker
nexttok = st.nextToken();
Type type = Type.FINAL;
if (nexttok.equals(Type.TEMP.marker))
{
type = Type.TEMP;
nexttok = st.nextToken();
}
else if (nexttok.equals(Type.TEMPLINK.marker))
{
type = Type.TEMPLINK;
nexttok = st.nextToken();
}
if (!Version.validate(nexttok))
throw new UnsupportedOperationException("SSTable " + name + " is too old to open. Upgrade to 2.0 first, and run upgradesstables");
Version version = new Version(nexttok);
nexttok = st.nextToken();
int generation = Integer.parseInt(nexttok);
// component suffix
String component = null;
if (!skipComponent)
component = st.nextToken();
directory = directory != null ? directory : new File(".");
return Pair.create(new Descriptor(version, directory, ksname, cfname, generation, type), component);
}
/**
* @param type temporary flag
* @return A clone of this descriptor with the given 'temporary' status.
*/
public Descriptor asType(Type type)
{
return new Descriptor(version, directory, ksname, cfname, generation, type);
}
public IMetadataSerializer getMetadataSerializer()
{
if (version.newStatsFile)
return new MetadataSerializer();
else
return new LegacyMetadataSerializer();
}
/**
* @return true if the current Cassandra version can read the given sstable version
*/
public boolean isCompatible()
{
return version.isCompatible();
}
@Override
public String toString()
{
return baseFilename();
}
@Override
public boolean equals(Object o)
{
if (o == this)
return true;
if (!(o instanceof Descriptor))
return false;
Descriptor that = (Descriptor)o;
return that.directory.equals(this.directory)
&& that.generation == this.generation
&& that.ksname.equals(this.ksname)
&& that.cfname.equals(this.cfname)
&& that.type == this.type;
}
@Override
public int hashCode()
{
return hashCode;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy