/** * 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.hadoop.hbase.replication; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.regionserver.wal.WALEdit; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.wal.WAL.Entry; import com.google.common.base.Predicate; /** * Filter a WAL Entry by namespaces and table-cfs config in the peer. It first filter entry * by namespaces config, then filter entry by table-cfs config. * * 1. Set a namespace in peer config means that all tables in this namespace will be replicated. * 2. If the namespaces config is null, then the table-cfs config decide which table's edit * can be replicated. If the table-cfs config is null, then the namespaces config decide * which table's edit can be replicated. */ @InterfaceAudience.Private public class NamespaceTableCfWALEntryFilter implements WALEntryFilter, WALCellFilter { private static final Log LOG = LogFactory.getLog(NamespaceTableCfWALEntryFilter.class); private final ReplicationPeer peer; private BulkLoadCellFilter bulkLoadFilter = new BulkLoadCellFilter(); public NamespaceTableCfWALEntryFilter(ReplicationPeer peer) { this.peer = peer; } @Override public Entry filter(Entry entry) { TableName tabName = entry.getKey().getTablename(); String namespace = tabName.getNamespaceAsString(); Set<String> namespaces = this.peer.getNamespaces(); Map<TableName, List<String>> tableCFs = getTableCfs(); // If null means user has explicitly not configured any namespaces and table CFs // so all the tables data are applicable for replication if (namespaces == null && tableCFs == null) { return entry; } // First filter by namespaces config // If table's namespace in peer config, all the tables data are applicable for replication if (namespaces != null && namespaces.contains(namespace)) { return entry; } // Then filter by table-cfs config // return null(prevent replicating) if logKey's table isn't in this peer's // replicaable namespace list and table list if (tableCFs == null || !tableCFs.containsKey(tabName)) { return null; } return entry; } @Override public Cell filterCell(final Entry entry, Cell cell) { final Map<TableName, List<String>> tableCfs = getTableCfs(); if (tableCfs == null) return cell; TableName tabName = entry.getKey().getTablename(); List<String> cfs = tableCfs.get(tabName); // ignore(remove) kv if its cf isn't in the replicable cf list // (empty cfs means all cfs of this table are replicable) if (CellUtil.matchingColumn(cell, WALEdit.METAFAMILY, WALEdit.BULK_LOAD)) { cell = bulkLoadFilter.filterCell(cell, new Predicate<byte[]>() { @Override public boolean apply(byte[] fam) { if (tableCfs != null) { List<String> cfs = tableCfs.get(entry.getKey().getTablename()); if (cfs != null && !cfs.contains(Bytes.toString(fam))) { return true; } } return false; } }); } else { if ((cfs != null) && !cfs.contains( Bytes.toString(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()))) { return null; } } return cell; } Map<TableName, List<String>> getTableCfs() { Map<TableName, List<String>> tableCFs = null; try { tableCFs = this.peer.getTableCFs(); } catch (IllegalArgumentException e) { LOG.error("should not happen: can't get tableCFs for peer " + peer.getId() + ", degenerate as if it's not configured by keeping tableCFs==null"); } return tableCFs; } }