001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.client;
020
021import java.util.Collections;
022import java.util.Map;
023import java.util.Set;
024import java.util.TreeMap;
025import java.util.TreeSet;
026
027import org.apache.hadoop.hbase.util.Bytes;
028import org.apache.yetus.audience.InterfaceAudience;
029
030import org.apache.hbase.thirdparty.com.google.common.base.Preconditions;
031
032@InterfaceAudience.Public
033public final class TableDescriptorUtils {
034  public final static class TableDescriptorDelta {
035    private final Set<byte[]> columnsAdded;
036    private final Set<byte[]> columnsDeleted;
037    private final Set<byte[]> columnsModified;
038
039    private TableDescriptorDelta(TableDescriptor oldTD, TableDescriptor newTD) {
040      Preconditions.checkNotNull(oldTD);
041      Preconditions.checkNotNull(newTD);
042
043      Map<byte[], ColumnFamilyDescriptor> oldCFs = new TreeMap<>(Bytes.BYTES_COMPARATOR);
044      Set<byte[]> newCFs = new TreeSet<>(Bytes.BYTES_COMPARATOR);
045
046      // CFD -> (name, CFD)
047      for (ColumnFamilyDescriptor cfd : oldTD.getColumnFamilies()) {
048        oldCFs.put(cfd.getName(), cfd);
049      }
050
051      Set<byte[]> added = new TreeSet<>(Bytes.BYTES_COMPARATOR);
052      Set<byte[]> modified = new TreeSet<>(Bytes.BYTES_COMPARATOR);
053
054      for (ColumnFamilyDescriptor cfd : newTD.getColumnFamilies()) {
055        byte[] cfName = cfd.getName();
056        newCFs.add(cfName);
057
058        if (!oldCFs.containsKey(cfName)) {
059          // If column family is in newTD but not oldTD, then it was added
060          added.add(cfName);
061        } else if (!cfd.equals(oldCFs.get(cfName))) {
062          // If column family is in both, but not equal, then it was modified
063          modified.add(cfName);
064        }
065      }
066
067      // If column family is in oldTD, but not in newTD, then it got deleted.
068      Set<byte[]> deleted = oldCFs.keySet();
069      deleted.removeAll(newCFs);
070
071      columnsAdded = Collections.unmodifiableSet(added);
072      columnsDeleted = Collections.unmodifiableSet(deleted);
073      columnsModified = Collections.unmodifiableSet(modified);
074    }
075
076    public Set<byte[]> getColumnsAdded() {
077      return columnsAdded;
078    }
079
080    public Set<byte[]> getColumnsDeleted() {
081      return columnsDeleted;
082    }
083
084    public Set<byte[]> getColumnsModified() {
085      return columnsModified;
086    }
087  }
088
089  private TableDescriptorUtils() { }
090
091  /**
092   * Compares two {@link TableDescriptor} and indicate which columns were added, deleted,
093   * or modified from oldTD to newTD
094   * @return a TableDescriptorDelta that contains the added/deleted/modified column names
095   */
096  public static TableDescriptorDelta computeDelta(TableDescriptor oldTD, TableDescriptor newTD) {
097    return new TableDescriptorDelta(oldTD, newTD);
098  }
099}