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