Merge branch 'cassandra-3.11' into trunk

Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/e38fddf1
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/e38fddf1
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/e38fddf1

Branch: refs/heads/trunk
Commit: e38fddf19022e9574487e2f8cbf73af27d1afaf6
Parents: 922dbdb 394fb0b
Author: Aleksey Yeschenko <alek...@yeschenko.com>
Authored: Tue Oct 17 11:56:40 2017 +0100
Committer: Aleksey Yeschenko <alek...@yeschenko.com>
Committed: Tue Oct 17 11:58:05 2017 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../org/apache/cassandra/schema/Schema.java     | 17 +++++++++++
 .../cassandra/service/StorageService.java       |  5 +++
 .../cassandra/service/StorageServiceMBean.java  |  2 ++
 .../org/apache/cassandra/tools/NodeProbe.java   |  5 +++
 .../org/apache/cassandra/tools/NodeTool.java    |  1 +
 .../tools/nodetool/ReloadLocalSchema.java       | 32 ++++++++++++++++++++
 7 files changed, 63 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/e38fddf1/CHANGES.txt
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e38fddf1/src/java/org/apache/cassandra/schema/Schema.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/schema/Schema.java
index 6dc63aa,0000000..2319858
mode 100644,000000..100644
--- a/src/java/org/apache/cassandra/schema/Schema.java
+++ b/src/java/org/apache/cassandra/schema/Schema.java
@@@ -1,804 -1,0 +1,821 @@@
 +/*
 + * 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.schema;
 +
 +import java.nio.ByteBuffer;
 +import java.util.*;
 +import java.util.concurrent.CopyOnWriteArrayList;
 +import java.util.stream.Collectors;
 +
 +import com.google.common.collect.ImmutableList;
 +import com.google.common.collect.MapDifference;
 +import com.google.common.collect.Sets;
 +
 +import org.apache.cassandra.config.DatabaseDescriptor;
 +import org.apache.cassandra.cql3.functions.*;
 +import org.apache.cassandra.db.ColumnFamilyStore;
 +import org.apache.cassandra.db.Keyspace;
 +import org.apache.cassandra.db.KeyspaceNotDefinedException;
 +import org.apache.cassandra.db.Mutation;
 +import org.apache.cassandra.db.SystemKeyspace;
 +import org.apache.cassandra.db.commitlog.CommitLog;
 +import org.apache.cassandra.db.compaction.CompactionManager;
 +import org.apache.cassandra.db.marshal.AbstractType;
 +import org.apache.cassandra.db.marshal.UserType;
 +import org.apache.cassandra.exceptions.ConfigurationException;
 +import org.apache.cassandra.exceptions.InvalidRequestException;
 +import org.apache.cassandra.exceptions.UnknownTableException;
 +import org.apache.cassandra.io.sstable.Descriptor;
 +import org.apache.cassandra.locator.LocalStrategy;
 +import org.apache.cassandra.utils.Pair;
 +import org.cliffc.high_scale_lib.NonBlockingHashMap;
 +
 +import static java.lang.String.format;
 +
 +import static com.google.common.collect.Iterables.size;
 +
 +public final class Schema
 +{
 +    public static final Schema instance = new Schema();
 +
 +    private volatile Keyspaces keyspaces = Keyspaces.none();
 +
 +    // UUID -> mutable metadata ref map. We have to update these in place 
every time a table changes.
 +    private final Map<TableId, TableMetadataRef> metadataRefs = new 
NonBlockingHashMap<>();
 +
 +    // (keyspace name, index name) -> mutable metadata ref map. We have to 
update these in place every time an index changes.
 +    private final Map<Pair<String, String>, TableMetadataRef> 
indexMetadataRefs = new NonBlockingHashMap<>();
 +
 +    // Keyspace objects, one per keyspace. Only one instance should ever 
exist for any given keyspace.
 +    private final Map<String, Keyspace> keyspaceInstances = new 
NonBlockingHashMap<>();
 +
 +    private volatile UUID version;
 +
 +    private final List<SchemaChangeListener> changeListeners = new 
CopyOnWriteArrayList<>();
 +
 +    /**
 +     * Initialize empty schema object and load the hardcoded system tables
 +     */
 +    private Schema()
 +    {
 +        if (DatabaseDescriptor.isDaemonInitialized() || 
DatabaseDescriptor.isToolInitialized())
 +        {
 +            load(SchemaKeyspace.metadata());
 +            load(SystemKeyspace.metadata());
 +        }
 +    }
 +
 +    /**
 +     * Validates that the provided keyspace is not one of the system keyspace.
 +     *
 +     * @param keyspace the keyspace name to validate.
 +     *
 +     * @throws InvalidRequestException if {@code keyspace} is the name of a
 +     * system keyspace.
 +     */
 +    public static void validateKeyspaceNotSystem(String keyspace)
 +    {
 +        if (SchemaConstants.isSystemKeyspace(keyspace))
 +            throw new InvalidRequestException(format("%s keyspace is not 
user-modifiable", keyspace));
 +    }
 +
 +    /**
 +     * load keyspace (keyspace) definitions, but do not initialize the 
keyspace instances.
 +     * Schema version may be updated as the result.
 +     */
 +    public void loadFromDisk()
 +    {
 +        loadFromDisk(true);
 +    }
 +
 +    /**
 +     * Load schema definitions from disk.
 +     *
 +     * @param updateVersion true if schema version needs to be updated
 +     */
 +    public void loadFromDisk(boolean updateVersion)
 +    {
 +        load(SchemaKeyspace.fetchNonSystemKeyspaces());
 +        if (updateVersion)
 +            updateVersion();
 +    }
 +
 +    /**
 +     * Load up non-system keyspaces
 +     *
 +     * @param keyspaceDefs The non-system keyspace definitions
 +     */
 +    private void load(Iterable<KeyspaceMetadata> keyspaceDefs)
 +    {
 +        keyspaceDefs.forEach(this::load);
 +    }
 +
 +    /**
 +     * Update (or insert) new keyspace definition
 +     *
 +     * @param ksm The metadata about keyspace
 +     */
 +    synchronized public void load(KeyspaceMetadata ksm)
 +    {
 +        KeyspaceMetadata previous = keyspaces.getNullable(ksm.name);
 +
 +        if (previous == null)
 +            loadNew(ksm);
 +        else
 +            reload(previous, ksm);
 +
 +        keyspaces = keyspaces.withAddedOrUpdated(ksm);
 +    }
 +
 +    private void loadNew(KeyspaceMetadata ksm)
 +    {
 +        ksm.tablesAndViews()
 +           .forEach(metadata -> metadataRefs.put(metadata.id, new 
TableMetadataRef(metadata)));
 +
 +        ksm.tables
 +           .indexTables()
 +           .forEach((name, metadata) -> 
indexMetadataRefs.put(Pair.create(ksm.name, name), new 
TableMetadataRef(metadata)));
 +    }
 +
 +    private void reload(KeyspaceMetadata previous, KeyspaceMetadata updated)
 +    {
 +        Keyspace keyspace = getKeyspaceInstance(updated.name);
 +        if (keyspace != null)
 +            keyspace.setMetadata(updated);
 +
 +        MapDifference<TableId, TableMetadata> tablesDiff = 
previous.tables.diff(updated.tables);
 +        MapDifference<TableId, ViewMetadata> viewsDiff = 
previous.views.diff(updated.views);
 +        MapDifference<String, TableMetadata> indexesDiff = 
previous.tables.indexesDiff(updated.tables);
 +
 +        // clean up after removed entries
 +
 +        tablesDiff.entriesOnlyOnLeft()
 +                  .values()
 +                  .forEach(table -> metadataRefs.remove(table.id));
 +
 +        viewsDiff.entriesOnlyOnLeft()
 +                 .values()
 +                 .forEach(view -> metadataRefs.remove(view.metadata.id));
 +
 +        indexesDiff.entriesOnlyOnLeft()
 +                   .values()
 +                   .forEach(indexTable -> 
indexMetadataRefs.remove(Pair.create(indexTable.keyspace, 
indexTable.indexName().get())));
 +
 +        // load up new entries
 +
 +        tablesDiff.entriesOnlyOnRight()
 +                  .values()
 +                  .forEach(table -> metadataRefs.put(table.id, new 
TableMetadataRef(table)));
 +
 +        viewsDiff.entriesOnlyOnRight()
 +                 .values()
 +                 .forEach(view -> metadataRefs.put(view.metadata.id, new 
TableMetadataRef(view.metadata)));
 +
 +        indexesDiff.entriesOnlyOnRight()
 +                   .values()
 +                   .forEach(indexTable -> 
indexMetadataRefs.put(Pair.create(indexTable.keyspace, 
indexTable.indexName().get()), new TableMetadataRef(indexTable)));
 +
 +        // refresh refs to updated ones
 +
 +        tablesDiff.entriesDiffering()
 +                  .values()
 +                  .forEach(diff -> 
metadataRefs.get(diff.rightValue().id).set(diff.rightValue()));
 +
 +        viewsDiff.entriesDiffering()
 +                 .values()
 +                 .forEach(diff -> 
metadataRefs.get(diff.rightValue().metadata.id).set(diff.rightValue().metadata));
 +
 +        indexesDiff.entriesDiffering()
 +                   .values()
 +                   .stream()
 +                   .map(MapDifference.ValueDifference::rightValue)
 +                   .forEach(indexTable -> 
indexMetadataRefs.get(Pair.create(indexTable.keyspace, 
indexTable.indexName().get())).set(indexTable));
 +    }
 +
 +    public void registerListener(SchemaChangeListener listener)
 +    {
 +        changeListeners.add(listener);
 +    }
 +
 +    @SuppressWarnings("unused")
 +    public void unregisterListener(SchemaChangeListener listener)
 +    {
 +        changeListeners.remove(listener);
 +    }
 +
 +    /**
 +     * Get keyspace instance by name
 +     *
 +     * @param keyspaceName The name of the keyspace
 +     *
 +     * @return Keyspace object or null if keyspace was not found
 +     */
 +    public Keyspace getKeyspaceInstance(String keyspaceName)
 +    {
 +        return keyspaceInstances.get(keyspaceName);
 +    }
 +
 +    public ColumnFamilyStore getColumnFamilyStoreInstance(TableId id)
 +    {
 +        TableMetadata metadata = getTableMetadata(id);
 +        if (metadata == null)
 +            return null;
 +
 +        Keyspace instance = getKeyspaceInstance(metadata.keyspace);
 +        if (instance == null)
 +            return null;
 +
 +        return instance.hasColumnFamilyStore(metadata.id)
 +             ? instance.getColumnFamilyStore(metadata.id)
 +             : null;
 +    }
 +
 +    /**
 +     * Store given Keyspace instance to the schema
 +     *
 +     * @param keyspace The Keyspace instance to store
 +     *
 +     * @throws IllegalArgumentException if Keyspace is already stored
 +     */
 +    public void storeKeyspaceInstance(Keyspace keyspace)
 +    {
 +        if (keyspaceInstances.containsKey(keyspace.getName()))
 +            throw new IllegalArgumentException(String.format("Keyspace %s was 
already initialized.", keyspace.getName()));
 +
 +        keyspaceInstances.put(keyspace.getName(), keyspace);
 +    }
 +
 +    /**
 +     * Remove keyspace from schema
 +     *
 +     * @param keyspaceName The name of the keyspace to remove
 +     *
 +     * @return removed keyspace instance or null if it wasn't found
 +     */
 +    public Keyspace removeKeyspaceInstance(String keyspaceName)
 +    {
 +        return keyspaceInstances.remove(keyspaceName);
 +    }
 +
 +    /**
 +     * Remove keyspace definition from system
 +     *
 +     * @param ksm The keyspace definition to remove
 +     */
 +    synchronized void unload(KeyspaceMetadata ksm)
 +    {
 +        keyspaces = keyspaces.without(ksm.name);
 +
 +        ksm.tablesAndViews()
 +           .forEach(t -> metadataRefs.remove(t.id));
 +
 +        ksm.tables
 +           .indexTables()
 +           .keySet()
 +           .forEach(name -> indexMetadataRefs.remove(Pair.create(ksm.name, 
name)));
 +    }
 +
 +    public int getNumberOfTables()
 +    {
 +        return keyspaces.stream().mapToInt(k -> 
size(k.tablesAndViews())).sum();
 +    }
 +
 +    public ViewMetadata getView(String keyspaceName, String viewName)
 +    {
 +        assert keyspaceName != null;
 +        KeyspaceMetadata ksm = keyspaces.getNullable(keyspaceName);
 +        return (ksm == null) ? null : ksm.views.getNullable(viewName);
 +    }
 +
 +    /**
 +     * Get metadata about keyspace by its name
 +     *
 +     * @param keyspaceName The name of the keyspace
 +     *
 +     * @return The keyspace metadata or null if it wasn't found
 +     */
 +    public KeyspaceMetadata getKeyspaceMetadata(String keyspaceName)
 +    {
 +        assert keyspaceName != null;
 +        return keyspaces.getNullable(keyspaceName);
 +    }
 +
 +    private Set<String> getNonSystemKeyspacesSet()
 +    {
 +        return Sets.difference(keyspaces.names(), 
SchemaConstants.SYSTEM_KEYSPACE_NAMES);
 +    }
 +
 +    /**
 +     * @return collection of the non-system keyspaces (note that this count 
as system only the
 +     * non replicated keyspaces, so keyspace like system_traces which are 
replicated are actually
 +     * returned. See getUserKeyspace() below if you don't want those)
 +     */
 +    public ImmutableList<String> getNonSystemKeyspaces()
 +    {
 +        return ImmutableList.copyOf(getNonSystemKeyspacesSet());
 +    }
 +
 +    /**
 +     * @return a collection of keyspaces that do not use LocalStrategy for 
replication
 +     */
 +    public List<String> getNonLocalStrategyKeyspaces()
 +    {
 +        return keyspaces.stream()
 +                        .filter(keyspace -> keyspace.params.replication.klass 
!= LocalStrategy.class)
 +                        .map(keyspace -> keyspace.name)
 +                        .collect(Collectors.toList());
 +    }
 +
 +    /**
 +     * @return collection of the user defined keyspaces
 +     */
 +    public List<String> getUserKeyspaces()
 +    {
 +        return 
ImmutableList.copyOf(Sets.difference(getNonSystemKeyspacesSet(), 
SchemaConstants.REPLICATED_SYSTEM_KEYSPACE_NAMES));
 +    }
 +
 +    /**
 +     * Get metadata about keyspace inner ColumnFamilies
 +     *
 +     * @param keyspaceName The name of the keyspace
 +     *
 +     * @return metadata about ColumnFamilies the belong to the given keyspace
 +     */
 +    public Iterable<TableMetadata> getTablesAndViews(String keyspaceName)
 +    {
 +        assert keyspaceName != null;
 +        KeyspaceMetadata ksm = keyspaces.getNullable(keyspaceName);
 +        assert ksm != null;
 +        return ksm.tablesAndViews();
 +    }
 +
 +    /**
 +     * @return collection of the all keyspace names registered in the system 
(system and non-system)
 +     */
 +    public Set<String> getKeyspaces()
 +    {
 +        return keyspaces.names();
 +    }
 +
 +    /* TableMetadata/Ref query/control methods */
 +
 +    /**
 +     * Given a keyspace name and table/view name, get the table metadata
 +     * reference. If the keyspace name or table/view name is not present
 +     * this method returns null.
 +     *
 +     * @return TableMetadataRef object or null if it wasn't found
 +     */
 +    public TableMetadataRef getTableMetadataRef(String keyspace, String table)
 +    {
 +        TableMetadata tm = getTableMetadata(keyspace, table);
 +        return tm == null
 +             ? null
 +             : metadataRefs.get(tm.id);
 +    }
 +
 +    public TableMetadataRef getIndexTableMetadataRef(String keyspace, String 
index)
 +    {
 +        return indexMetadataRefs.get(Pair.create(keyspace, index));
 +    }
 +
 +    /**
 +     * Get Table metadata by its identifier
 +     *
 +     * @param id table or view identifier
 +     *
 +     * @return metadata about Table or View
 +     */
 +    public TableMetadataRef getTableMetadataRef(TableId id)
 +    {
 +        return metadataRefs.get(id);
 +    }
 +
 +    public TableMetadataRef getTableMetadataRef(Descriptor descriptor)
 +    {
 +        return getTableMetadataRef(descriptor.ksname, descriptor.cfname);
 +    }
 +
 +    /**
 +     * Given a keyspace name and table name, get the table
 +     * meta data. If the keyspace name or table name is not valid
 +     * this function returns null.
 +     *
 +     * @param keyspace The keyspace name
 +     * @param table The table name
 +     *
 +     * @return TableMetadata object or null if it wasn't found
 +     */
 +    public TableMetadata getTableMetadata(String keyspace, String table)
 +    {
 +        assert keyspace != null;
 +        assert table != null;
 +
 +        KeyspaceMetadata ksm = keyspaces.getNullable(keyspace);
 +        return ksm == null
 +             ? null
 +             : ksm.getTableOrViewNullable(table);
 +    }
 +
 +    public TableMetadata getTableMetadata(TableId id)
 +    {
 +        return keyspaces.getTableOrViewNullable(id);
 +    }
 +
 +    public TableMetadata validateTable(String keyspaceName, String tableName)
 +    {
 +        if (tableName.isEmpty())
 +            throw new InvalidRequestException("non-empty table is required");
 +
 +        KeyspaceMetadata keyspace = keyspaces.getNullable(keyspaceName);
 +        if (keyspace == null)
 +            throw new KeyspaceNotDefinedException(format("keyspace %s does 
not exist", keyspaceName));
 +
 +        TableMetadata metadata = keyspace.getTableOrViewNullable(tableName);
 +        if (metadata == null)
 +            throw new InvalidRequestException(format("table %s does not 
exist", tableName));
 +
 +        return metadata;
 +    }
 +
 +    public TableMetadata getTableMetadata(Descriptor descriptor)
 +    {
 +        return getTableMetadata(descriptor.ksname, descriptor.cfname);
 +    }
 +
 +    /**
 +     * @throws UnknownTableException if the table couldn't be found in the 
metadata
 +     */
 +    public TableMetadata getExistingTableMetadata(TableId id) throws 
UnknownTableException
 +    {
 +        TableMetadata metadata = getTableMetadata(id);
 +        if (metadata != null)
 +            return metadata;
 +
 +        String message =
 +            String.format("Couldn't find table with id %s. If a table was 
just created, this is likely due to the schema"
 +                          + "not being fully propagated.  Please wait for 
schema agreement on table creation.",
 +                          id);
 +        throw new UnknownTableException(message, id);
 +    }
 +
 +    /* Function helpers */
 +
 +    /**
 +     * Get all function overloads with the specified name
 +     *
 +     * @param name fully qualified function name
 +     * @return an empty list if the keyspace or the function name are not 
found;
 +     *         a non-empty collection of {@link Function} otherwise
 +     */
 +    public Collection<Function> getFunctions(FunctionName name)
 +    {
 +        if (!name.hasKeyspace())
 +            throw new IllegalArgumentException(String.format("Function name 
must be fully qualified: got %s", name));
 +
 +        KeyspaceMetadata ksm = getKeyspaceMetadata(name.keyspace);
 +        return ksm == null
 +             ? Collections.emptyList()
 +             : ksm.functions.get(name);
 +    }
 +
 +    /**
 +     * Find the function with the specified name
 +     *
 +     * @param name fully qualified function name
 +     * @param argTypes function argument types
 +     * @return an empty {@link Optional} if the keyspace or the function name 
are not found;
 +     *         a non-empty optional of {@link Function} otherwise
 +     */
 +    public Optional<Function> findFunction(FunctionName name, 
List<AbstractType<?>> argTypes)
 +    {
 +        if (!name.hasKeyspace())
 +            throw new IllegalArgumentException(String.format("Function name 
must be fully quallified: got %s", name));
 +
 +        KeyspaceMetadata ksm = getKeyspaceMetadata(name.keyspace);
 +        return ksm == null
 +             ? Optional.empty()
 +             : ksm.functions.find(name, argTypes);
 +    }
 +
 +    /* Version control */
 +
 +    /**
 +     * @return current schema version
 +     */
 +    public UUID getVersion()
 +    {
 +        return version;
 +    }
 +
 +    /**
 +     * Read schema from system keyspace and calculate MD5 digest of every 
row, resulting digest
 +     * will be converted into UUID which would act as content-based version 
of the schema.
 +     */
 +    public void updateVersion()
 +    {
 +        version = SchemaKeyspace.calculateSchemaDigest();
 +        SystemKeyspace.updateSchemaVersion(version);
 +    }
 +
 +    /*
 +     * Like updateVersion, but also announces via gossip
 +     */
 +    public void updateVersionAndAnnounce()
 +    {
 +        updateVersion();
 +        MigrationManager.passiveAnnounce(version);
 +    }
 +
 +    /**
 +     * Clear all KS/CF metadata and reset version.
 +     */
 +    public synchronized void clear()
 +    {
 +        getNonSystemKeyspaces().forEach(k -> unload(getKeyspaceMetadata(k)));
 +        updateVersionAndAnnounce();
 +    }
 +
++    /*
++     * Reload schema from local disk. Useful if a user made changes to schema 
tables by hand, or has suspicion that
++     * in-memory representation got out of sync somehow with what's on disk.
++     */
++    public synchronized void reloadSchemaAndAnnounceVersion()
++    {
++        Keyspaces before = keyspaces.filter(k -> 
!SchemaConstants.isSystemKeyspace(k.name));
++        Keyspaces after = SchemaKeyspace.fetchNonSystemKeyspaces();
++        merge(before, after);
++        updateVersionAndAnnounce();
++    }
++
 +    /**
 +     * Merge remote schema in form of mutations with local and mutate ks/cf 
metadata objects
 +     * (which also involves fs operations on add/drop ks/cf)
 +     *
 +     * @param mutations the schema changes to apply
 +     *
 +     * @throws ConfigurationException If one of metadata attributes has 
invalid value
 +     */
 +    synchronized void mergeAndAnnounceVersion(Collection<Mutation> mutations)
 +    {
 +        merge(mutations);
 +        updateVersionAndAnnounce();
 +    }
 +
 +    synchronized void merge(Collection<Mutation> mutations)
 +    {
 +        // only compare the keyspaces affected by this set of schema mutations
 +        Set<String> affectedKeyspaces = 
SchemaKeyspace.affectedKeyspaces(mutations);
 +
 +        // fetch the current state of schema for the affected keyspaces only
 +        Keyspaces before = keyspaces.filter(k -> 
affectedKeyspaces.contains(k.name));
 +
 +        // apply the schema mutations
 +        SchemaKeyspace.applyChanges(mutations);
 +
 +        // apply the schema mutations and fetch the new versions of the 
altered keyspaces
 +        Keyspaces after = SchemaKeyspace.fetchKeyspaces(affectedKeyspaces);
 +
++        merge(before, after);
++    }
++
++    private synchronized void merge(Keyspaces before, Keyspaces after)
++    {
 +        MapDifference<String, KeyspaceMetadata> keyspacesDiff = 
before.diff(after);
 +
 +        // dropped keyspaces
 +        
keyspacesDiff.entriesOnlyOnLeft().values().forEach(this::dropKeyspace);
 +
 +        // new keyspaces
 +        
keyspacesDiff.entriesOnlyOnRight().values().forEach(this::createKeyspace);
 +
 +        // updated keyspaces
 +        keyspacesDiff.entriesDiffering().entrySet().forEach(diff -> 
alterKeyspace(diff.getValue().leftValue(), diff.getValue().rightValue()));
 +    }
 +
 +    private void alterKeyspace(KeyspaceMetadata before, KeyspaceMetadata 
after)
 +    {
 +        // calculate the deltas
 +        MapDifference<TableId, TableMetadata> tablesDiff = 
before.tables.diff(after.tables);
 +        MapDifference<TableId, ViewMetadata> viewsDiff = 
before.views.diff(after.views);
 +        MapDifference<ByteBuffer, UserType> typesDiff = 
before.types.diff(after.types);
 +        MapDifference<Pair<FunctionName, List<String>>, UDFunction> udfsDiff 
= before.functions.udfsDiff(after.functions);
 +        MapDifference<Pair<FunctionName, List<String>>, UDAggregate> udasDiff 
= before.functions.udasDiff(after.functions);
 +
 +        // drop tables and views
 +        viewsDiff.entriesOnlyOnLeft().values().forEach(this::dropView);
 +        tablesDiff.entriesOnlyOnLeft().values().forEach(this::dropTable);
 +
 +        load(after);
 +
 +        // add tables and views
 +        tablesDiff.entriesOnlyOnRight().values().forEach(this::createTable);
 +        viewsDiff.entriesOnlyOnRight().values().forEach(this::createView);
 +
 +        // update tables and views
 +        tablesDiff.entriesDiffering().values().forEach(diff -> 
alterTable(diff.rightValue()));
 +        viewsDiff.entriesDiffering().values().forEach(diff -> 
alterView(diff.rightValue()));
 +
 +        // deal with all removed, added, and altered views
 +        Keyspace.open(before.name).viewManager.reload();
 +
 +        // notify on everything dropped
 +        
udasDiff.entriesOnlyOnLeft().values().forEach(this::notifyDropAggregate);
 +        
udfsDiff.entriesOnlyOnLeft().values().forEach(this::notifyDropFunction);
 +        viewsDiff.entriesOnlyOnLeft().values().forEach(this::notifyDropView);
 +        
tablesDiff.entriesOnlyOnLeft().values().forEach(this::notifyDropTable);
 +        typesDiff.entriesOnlyOnLeft().values().forEach(this::notifyDropType);
 +
 +        // notify on everything created
 +        
typesDiff.entriesOnlyOnRight().values().forEach(this::notifyCreateType);
 +        
tablesDiff.entriesOnlyOnRight().values().forEach(this::notifyCreateTable);
 +        
viewsDiff.entriesOnlyOnRight().values().forEach(this::notifyCreateView);
 +        
udfsDiff.entriesOnlyOnRight().values().forEach(this::notifyCreateFunction);
 +        
udasDiff.entriesOnlyOnRight().values().forEach(this::notifyCreateAggregate);
 +
 +        // notify on everything altered
 +        if (!before.params.equals(after.params))
 +            notifyAlterKeyspace(after);
 +        typesDiff.entriesDiffering().values().forEach(diff -> 
notifyAlterType(diff.rightValue()));
 +        tablesDiff.entriesDiffering().values().forEach(diff -> 
notifyAlterTable(diff.leftValue(), diff.rightValue()));
 +        viewsDiff.entriesDiffering().values().forEach(diff -> 
notifyAlterView(diff.leftValue(), diff.rightValue()));
 +        udfsDiff.entriesDiffering().values().forEach(diff -> 
notifyAlterFunction(diff.rightValue()));
 +        udasDiff.entriesDiffering().values().forEach(diff -> 
notifyAlterAggregate(diff.rightValue()));
 +    }
 +
 +    private void createKeyspace(KeyspaceMetadata keyspace)
 +    {
 +        load(keyspace);
 +        Keyspace.open(keyspace.name);
 +
 +        notifyCreateKeyspace(keyspace);
 +        keyspace.types.forEach(this::notifyCreateType);
 +        keyspace.tables.forEach(this::notifyCreateTable);
 +        keyspace.views.forEach(this::notifyCreateView);
 +        keyspace.functions.udfs().forEach(this::notifyCreateFunction);
 +        keyspace.functions.udas().forEach(this::notifyCreateAggregate);
 +    }
 +
 +    private void dropKeyspace(KeyspaceMetadata keyspace)
 +    {
 +        keyspace.views.forEach(this::dropView);
 +        keyspace.tables.forEach(this::dropTable);
 +
 +        // remove the keyspace from the static instances.
 +        Keyspace.clear(keyspace.name);
 +        unload(keyspace);
 +        Keyspace.writeOrder.awaitNewBarrier();
 +
 +        keyspace.functions.udas().forEach(this::notifyDropAggregate);
 +        keyspace.functions.udfs().forEach(this::notifyDropFunction);
 +        keyspace.views.forEach(this::notifyDropView);
 +        keyspace.tables.forEach(this::notifyDropTable);
 +        keyspace.types.forEach(this::notifyDropType);
 +        notifyDropKeyspace(keyspace);
 +    }
 +
 +    private void dropView(ViewMetadata metadata)
 +    {
 +        dropTable(metadata.metadata);
 +    }
 +
 +    private void dropTable(TableMetadata metadata)
 +    {
 +        ColumnFamilyStore cfs = 
Keyspace.open(metadata.keyspace).getColumnFamilyStore(metadata.name);
 +        assert cfs != null;
 +        // make sure all the indexes are dropped, or else.
 +        cfs.indexManager.markAllIndexesRemoved();
 +        
CompactionManager.instance.interruptCompactionFor(Collections.singleton(metadata),
 true);
 +        if (DatabaseDescriptor.isAutoSnapshot())
 +            
cfs.snapshot(Keyspace.getTimestampedSnapshotNameWithPrefix(cfs.name, 
ColumnFamilyStore.SNAPSHOT_DROP_PREFIX));
 +        
CommitLog.instance.forceRecycleAllSegments(Collections.singleton(metadata.id));
 +        Keyspace.open(metadata.keyspace).dropCf(metadata.id);
 +    }
 +
 +    private void createTable(TableMetadata table)
 +    {
 +        Keyspace.open(table.keyspace).initCf(metadataRefs.get(table.id), 
true);
 +    }
 +
 +    private void createView(ViewMetadata view)
 +    {
 +        
Keyspace.open(view.keyspace).initCf(metadataRefs.get(view.metadata.id), true);
 +    }
 +
 +    private void alterTable(TableMetadata updated)
 +    {
 +        
Keyspace.open(updated.keyspace).getColumnFamilyStore(updated.name).reload();
 +    }
 +
 +    private void alterView(ViewMetadata updated)
 +    {
 +        
Keyspace.open(updated.keyspace).getColumnFamilyStore(updated.name).reload();
 +    }
 +
 +    private void notifyCreateKeyspace(KeyspaceMetadata ksm)
 +    {
 +        changeListeners.forEach(l -> l.onCreateKeyspace(ksm.name));
 +    }
 +
 +    private void notifyCreateTable(TableMetadata metadata)
 +    {
 +        changeListeners.forEach(l -> l.onCreateTable(metadata.keyspace, 
metadata.name));
 +    }
 +
 +    private void notifyCreateView(ViewMetadata view)
 +    {
 +        changeListeners.forEach(l -> l.onCreateView(view.keyspace, 
view.name));
 +    }
 +
 +    private void notifyCreateType(UserType ut)
 +    {
 +        changeListeners.forEach(l -> l.onCreateType(ut.keyspace, 
ut.getNameAsString()));
 +    }
 +
 +    private void notifyCreateFunction(UDFunction udf)
 +    {
 +        changeListeners.forEach(l -> l.onCreateFunction(udf.name().keyspace, 
udf.name().name, udf.argTypes()));
 +    }
 +
 +    private void notifyCreateAggregate(UDAggregate udf)
 +    {
 +        changeListeners.forEach(l -> l.onCreateAggregate(udf.name().keyspace, 
udf.name().name, udf.argTypes()));
 +    }
 +
 +    private void notifyAlterKeyspace(KeyspaceMetadata ksm)
 +    {
 +        changeListeners.forEach(l -> l.onAlterKeyspace(ksm.name));
 +    }
 +
 +    private void notifyAlterTable(TableMetadata current, TableMetadata 
updated)
 +    {
 +        boolean changeAffectedPreparedStatements = 
current.changeAffectsPreparedStatements(updated);
 +        changeListeners.forEach(l -> l.onAlterTable(updated.keyspace, 
updated.name, changeAffectedPreparedStatements));
 +    }
 +
 +    private void notifyAlterView(ViewMetadata current, ViewMetadata updated)
 +    {
 +        boolean changeAffectedPreparedStatements = 
current.metadata.changeAffectsPreparedStatements(updated.metadata);
 +        changeListeners.forEach(l ->l.onAlterView(updated.keyspace, 
updated.name, changeAffectedPreparedStatements));
 +    }
 +
 +    private void notifyAlterType(UserType ut)
 +    {
 +        changeListeners.forEach(l -> l.onAlterType(ut.keyspace, 
ut.getNameAsString()));
 +    }
 +
 +    private void notifyAlterFunction(UDFunction udf)
 +    {
 +        changeListeners.forEach(l -> l.onAlterFunction(udf.name().keyspace, 
udf.name().name, udf.argTypes()));
 +    }
 +
 +    private void notifyAlterAggregate(UDAggregate udf)
 +    {
 +        changeListeners.forEach(l -> l.onAlterAggregate(udf.name().keyspace, 
udf.name().name, udf.argTypes()));
 +    }
 +
 +    private void notifyDropKeyspace(KeyspaceMetadata ksm)
 +    {
 +        changeListeners.forEach(l -> l.onDropKeyspace(ksm.name));
 +    }
 +
 +    private void notifyDropTable(TableMetadata metadata)
 +    {
 +        changeListeners.forEach(l -> l.onDropTable(metadata.keyspace, 
metadata.name));
 +    }
 +
 +    private void notifyDropView(ViewMetadata view)
 +    {
 +        changeListeners.forEach(l -> l.onDropView(view.keyspace, view.name));
 +    }
 +
 +    private void notifyDropType(UserType ut)
 +    {
 +        changeListeners.forEach(l -> l.onDropType(ut.keyspace, 
ut.getNameAsString()));
 +    }
 +
 +    private void notifyDropFunction(UDFunction udf)
 +    {
 +        changeListeners.forEach(l -> l.onDropFunction(udf.name().keyspace, 
udf.name().name, udf.argTypes()));
 +    }
 +
 +    private void notifyDropAggregate(UDAggregate udf)
 +    {
 +        changeListeners.forEach(l -> l.onDropAggregate(udf.name().keyspace, 
udf.name().name, udf.argTypes()));
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e38fddf1/src/java/org/apache/cassandra/service/StorageService.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/service/StorageService.java
index 52c645f,2c17fb8..8f28947
--- a/src/java/org/apache/cassandra/service/StorageService.java
+++ b/src/java/org/apache/cassandra/service/StorageService.java
@@@ -4933,6 -5115,11 +4933,11 @@@ public class StorageService extends Not
          MigrationManager.resetLocalSchema();
      }
  
+     public void reloadLocalSchema()
+     {
 -        SchemaKeyspace.reloadSchemaAndAnnounceVersion();
++        Schema.instance.reloadSchemaAndAnnounceVersion();
+     }
+ 
      public void setTraceProbability(double probability)
      {
          this.traceProbability = probability;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e38fddf1/src/java/org/apache/cassandra/service/StorageServiceMBean.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/service/StorageServiceMBean.java
index 28c1b36,7be4224..c4548ae
--- a/src/java/org/apache/cassandra/service/StorageServiceMBean.java
+++ b/src/java/org/apache/cassandra/service/StorageServiceMBean.java
@@@ -578,8 -623,10 +578,10 @@@ public interface StorageServiceMBean ex
  
      public void resetLocalSchema() throws IOException;
  
+     public void reloadLocalSchema();
+ 
      /**
 -     * Enables/Disables tracing for the whole system. Only thrift requests 
can start tracing currently.
 +     * Enables/Disables tracing for the whole system.
       *
       * @param probability
       *            ]0,1[ will enable tracing on a partial number of requests 
with the provided probability. 0 will

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e38fddf1/src/java/org/apache/cassandra/tools/NodeProbe.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e38fddf1/src/java/org/apache/cassandra/tools/NodeTool.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/tools/NodeTool.java
index de89f61,58df080..640cf36
--- a/src/java/org/apache/cassandra/tools/NodeTool.java
+++ b/src/java/org/apache/cassandra/tools/NodeTool.java
@@@ -132,8 -128,10 +132,9 @@@ public class NodeToo
                  EnableBackup.class,
                  DisableBackup.class,
                  ResetLocalSchema.class,
+                 ReloadLocalSchema.class,
                  ReloadTriggers.class,
                  SetCacheKeysToSave.class,
 -                DisableThrift.class,
                  DisableHandoff.class,
                  Drain.class,
                  TruncateHints.class,

http://git-wip-us.apache.org/repos/asf/cassandra/blob/e38fddf1/src/java/org/apache/cassandra/tools/nodetool/ReloadLocalSchema.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/tools/nodetool/ReloadLocalSchema.java
index 0000000,78fbf2d..d4b1c69
mode 000000,100644..100644
--- a/src/java/org/apache/cassandra/tools/nodetool/ReloadLocalSchema.java
+++ b/src/java/org/apache/cassandra/tools/nodetool/ReloadLocalSchema.java
@@@ -1,0 -1,32 +1,32 @@@
+ /*
+  * 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.tools.nodetool;
+ 
 -import io.airlift.command.Command;
++import io.airlift.airline.Command;
+ import org.apache.cassandra.tools.NodeProbe;
+ import org.apache.cassandra.tools.NodeTool.NodeToolCmd;
+ 
+ @Command(name = "reloadlocalschema", description = "Reload local node schema 
from system tables")
+ public class ReloadLocalSchema extends NodeToolCmd
+ {
+     @Override
+     public void execute(NodeProbe probe)
+     {
+         probe.reloadLocalSchema();
+     }
+ }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to