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.replication.regionserver;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021import static org.junit.jupiter.api.Assertions.fail;
022
023import java.io.IOException;
024import java.util.ArrayList;
025import java.util.Collections;
026import java.util.HashMap;
027import java.util.HashSet;
028import java.util.Iterator;
029import java.util.List;
030import java.util.Map;
031import java.util.Random;
032import java.util.Set;
033import java.util.concurrent.ThreadLocalRandom;
034import java.util.concurrent.atomic.AtomicBoolean;
035import org.apache.hadoop.conf.Configuration;
036import org.apache.hadoop.fs.FileSystem;
037import org.apache.hadoop.fs.FileUtil;
038import org.apache.hadoop.fs.Path;
039import org.apache.hadoop.hbase.ExtendedCell;
040import org.apache.hadoop.hbase.HBaseTestingUtil;
041import org.apache.hadoop.hbase.HConstants;
042import org.apache.hadoop.hbase.KeyValue;
043import org.apache.hadoop.hbase.PrivateCellUtil;
044import org.apache.hadoop.hbase.Stoppable;
045import org.apache.hadoop.hbase.TableName;
046import org.apache.hadoop.hbase.TableNotFoundException;
047import org.apache.hadoop.hbase.client.Admin;
048import org.apache.hadoop.hbase.client.Connection;
049import org.apache.hadoop.hbase.client.ConnectionFactory;
050import org.apache.hadoop.hbase.client.Get;
051import org.apache.hadoop.hbase.client.RegionInfo;
052import org.apache.hadoop.hbase.client.RegionLocator;
053import org.apache.hadoop.hbase.client.Result;
054import org.apache.hadoop.hbase.client.ResultScanner;
055import org.apache.hadoop.hbase.client.RetriesExhaustedException;
056import org.apache.hadoop.hbase.client.Scan;
057import org.apache.hadoop.hbase.client.Table;
058import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost;
059import org.apache.hadoop.hbase.testclassification.LargeTests;
060import org.apache.hadoop.hbase.testclassification.ReplicationTests;
061import org.apache.hadoop.hbase.util.Bytes;
062import org.apache.hadoop.hbase.util.CommonFSUtils;
063import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
064import org.apache.hadoop.hbase.util.HFileTestUtil;
065import org.apache.hadoop.hbase.wal.WALEditInternalHelper;
066import org.junit.jupiter.api.AfterAll;
067import org.junit.jupiter.api.BeforeAll;
068import org.junit.jupiter.api.BeforeEach;
069import org.junit.jupiter.api.Tag;
070import org.junit.jupiter.api.Test;
071import org.slf4j.Logger;
072import org.slf4j.LoggerFactory;
073
074import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
075
076import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
077import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos.WALEntry;
078import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.UUID;
079import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos;
080import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.WALKey;
081
082@Tag(ReplicationTests.TAG)
083@Tag(LargeTests.TAG)
084public class TestReplicationSink {
085
086  private static final Logger LOG = LoggerFactory.getLogger(TestReplicationSink.class);
087  private static final int BATCH_SIZE = 10;
088
089  protected final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
090
091  protected static ReplicationSink SINK;
092
093  protected static final TableName TABLE_NAME1 = TableName.valueOf("table1");
094  protected static final TableName TABLE_NAME2 = TableName.valueOf("table2");
095
096  protected static final byte[] FAM_NAME1 = Bytes.toBytes("info1");
097  protected static final byte[] FAM_NAME2 = Bytes.toBytes("info2");
098
099  protected static Table table1;
100  protected static Stoppable STOPPABLE = new Stoppable() {
101    final AtomicBoolean stop = new AtomicBoolean(false);
102
103    @Override
104    public boolean isStopped() {
105      return this.stop.get();
106    }
107
108    @Override
109    public void stop(String why) {
110      LOG.info("STOPPING BECAUSE: " + why);
111      this.stop.set(true);
112    }
113
114  };
115
116  protected static Table table2;
117  protected static String baseNamespaceDir;
118  protected static String hfileArchiveDir;
119  protected static String replicationClusterId;
120
121  @BeforeAll
122  public static void setUpBeforeClass() throws Exception {
123    TEST_UTIL.getConfiguration().set("hbase.replication.source.fs.conf.provider",
124      TestSourceFSConfigurationProvider.class.getCanonicalName());
125    TEST_UTIL.startMiniCluster(3);
126    RegionServerCoprocessorHost rsCpHost =
127      TEST_UTIL.getMiniHBaseCluster().getRegionServer(0).getRegionServerCoprocessorHost();
128    SINK = new ReplicationSink(new Configuration(TEST_UTIL.getConfiguration()), rsCpHost);
129    table1 = TEST_UTIL.createTable(TABLE_NAME1, FAM_NAME1);
130    table2 = TEST_UTIL.createTable(TABLE_NAME2, FAM_NAME2);
131    Path rootDir = CommonFSUtils.getRootDir(TEST_UTIL.getConfiguration());
132    baseNamespaceDir = new Path(rootDir, new Path(HConstants.BASE_NAMESPACE_DIR)).toString();
133    hfileArchiveDir = new Path(rootDir, new Path(HConstants.HFILE_ARCHIVE_DIRECTORY)).toString();
134    replicationClusterId = "12345";
135  }
136
137  @AfterAll
138  public static void tearDownAfterClass() throws Exception {
139    STOPPABLE.stop("Shutting down");
140    TEST_UTIL.shutdownMiniCluster();
141  }
142
143  @BeforeEach
144  public void setUp() throws Exception {
145    table1 = TEST_UTIL.deleteTableData(TABLE_NAME1);
146    table2 = TEST_UTIL.deleteTableData(TABLE_NAME2);
147  }
148
149  /**
150   * Insert a whole batch of entries
151   */
152  @Test
153  public void testBatchSink() throws Exception {
154    List<WALEntry> entries = new ArrayList<>(BATCH_SIZE);
155    List<ExtendedCell> cells = new ArrayList<>();
156    for (int i = 0; i < BATCH_SIZE; i++) {
157      entries.add(createEntry(TABLE_NAME1, i, KeyValue.Type.Put, cells));
158    }
159    SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
160      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
161    Scan scan = new Scan();
162    ResultScanner scanRes = table1.getScanner(scan);
163    assertEquals(BATCH_SIZE, scanRes.next(BATCH_SIZE).length);
164  }
165
166  /**
167   * Insert a mix of puts and deletes
168   */
169  @Test
170  public void testMixedPutDelete() throws Exception {
171    List<WALEntry> entries = new ArrayList<>(BATCH_SIZE / 2);
172    List<ExtendedCell> cells = new ArrayList<>();
173    for (int i = 0; i < BATCH_SIZE / 2; i++) {
174      entries.add(createEntry(TABLE_NAME1, i, KeyValue.Type.Put, cells));
175    }
176    SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells),
177      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
178
179    entries = new ArrayList<>(BATCH_SIZE);
180    cells = new ArrayList<>();
181    for (int i = 0; i < BATCH_SIZE; i++) {
182      entries.add(createEntry(TABLE_NAME1, i,
183        i % 2 != 0 ? KeyValue.Type.Put : KeyValue.Type.DeleteColumn, cells));
184    }
185
186    SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
187      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
188    Scan scan = new Scan();
189    ResultScanner scanRes = table1.getScanner(scan);
190    assertEquals(BATCH_SIZE / 2, scanRes.next(BATCH_SIZE).length);
191  }
192
193  @Test
194  public void testLargeEditsPutDelete() throws Exception {
195    List<WALEntry> entries = new ArrayList<>();
196    List<ExtendedCell> cells = new ArrayList<>();
197    for (int i = 0; i < 5510; i++) {
198      entries.add(createEntry(TABLE_NAME1, i, KeyValue.Type.Put, cells));
199    }
200    SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells),
201      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
202
203    ResultScanner resultScanner = table1.getScanner(new Scan());
204    int totalRows = 0;
205    while (resultScanner.next() != null) {
206      totalRows++;
207    }
208    assertEquals(5510, totalRows);
209
210    entries = new ArrayList<>();
211    cells = new ArrayList<>();
212    for (int i = 0; i < 11000; i++) {
213      entries.add(createEntry(TABLE_NAME1, i,
214        i % 2 != 0 ? KeyValue.Type.Put : KeyValue.Type.DeleteColumn, cells));
215    }
216    SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells),
217      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
218    resultScanner = table1.getScanner(new Scan());
219    totalRows = 0;
220    while (resultScanner.next() != null) {
221      totalRows++;
222    }
223    assertEquals(5500, totalRows);
224  }
225
226  /**
227   * Insert to 2 different tables
228   */
229  @Test
230  public void testMixedPutTables() throws Exception {
231    List<WALEntry> entries = new ArrayList<>(BATCH_SIZE / 2);
232    List<ExtendedCell> cells = new ArrayList<>();
233    for (int i = 0; i < BATCH_SIZE; i++) {
234      entries.add(createEntry(i % 2 == 0 ? TABLE_NAME2 : TABLE_NAME1, i, KeyValue.Type.Put, cells));
235    }
236
237    SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
238      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
239    Scan scan = new Scan();
240    ResultScanner scanRes = table2.getScanner(scan);
241    for (Result res : scanRes) {
242      assertEquals(0, Bytes.toInt(res.getRow()) % 2);
243    }
244    scanRes = table1.getScanner(scan);
245    for (Result res : scanRes) {
246      assertEquals(1, Bytes.toInt(res.getRow()) % 2);
247    }
248  }
249
250  /**
251   * Insert then do different types of deletes
252   */
253  @Test
254  public void testMixedDeletes() throws Exception {
255    List<WALEntry> entries = new ArrayList<>(3);
256    List<ExtendedCell> cells = new ArrayList<>();
257    for (int i = 0; i < 3; i++) {
258      entries.add(createEntry(TABLE_NAME1, i, KeyValue.Type.Put, cells));
259    }
260    SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
261      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
262    entries = new ArrayList<>(3);
263    cells = new ArrayList<>();
264    entries.add(createEntry(TABLE_NAME1, 0, KeyValue.Type.DeleteColumn, cells));
265    entries.add(createEntry(TABLE_NAME1, 1, KeyValue.Type.DeleteFamily, cells));
266    entries.add(createEntry(TABLE_NAME1, 2, KeyValue.Type.DeleteColumn, cells));
267
268    SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
269      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
270
271    Scan scan = new Scan();
272    ResultScanner scanRes = table1.getScanner(scan);
273    assertEquals(0, scanRes.next(3).length);
274  }
275
276  /**
277   * Puts are buffered, but this tests when a delete (not-buffered) is applied before the actual Put
278   * that creates it.
279   */
280  @Test
281  public void testApplyDeleteBeforePut() throws Exception {
282    List<WALEntry> entries = new ArrayList<>(5);
283    List<ExtendedCell> cells = new ArrayList<>();
284    for (int i = 0; i < 2; i++) {
285      entries.add(createEntry(TABLE_NAME1, i, KeyValue.Type.Put, cells));
286    }
287    entries.add(createEntry(TABLE_NAME1, 1, KeyValue.Type.DeleteFamily, cells));
288    for (int i = 3; i < 5; i++) {
289      entries.add(createEntry(TABLE_NAME1, i, KeyValue.Type.Put, cells));
290    }
291    SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
292      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
293    Get get = new Get(Bytes.toBytes(1));
294    Result res = table1.get(get);
295    assertEquals(0, res.size());
296  }
297
298  @Test
299  public void testRethrowRetriesExhaustedException() throws Exception {
300    TableName notExistTable = TableName.valueOf("notExistTable");
301    List<WALEntry> entries = new ArrayList<>();
302    List<ExtendedCell> cells = new ArrayList<>();
303    for (int i = 0; i < 10; i++) {
304      entries.add(createEntry(notExistTable, i, KeyValue.Type.Put, cells));
305    }
306    try {
307      SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
308        replicationClusterId, baseNamespaceDir, hfileArchiveDir);
309      fail("Should re-throw TableNotFoundException.");
310    } catch (TableNotFoundException e) {
311    }
312    entries.clear();
313    cells.clear();
314    for (int i = 0; i < 10; i++) {
315      entries.add(createEntry(TABLE_NAME1, i, KeyValue.Type.Put, cells));
316    }
317    try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) {
318      try (Admin admin = conn.getAdmin()) {
319        admin.disableTable(TABLE_NAME1);
320        try {
321          SINK.replicateEntries(entries,
322            PrivateCellUtil.createExtendedCellScanner(cells.iterator()), replicationClusterId,
323            baseNamespaceDir, hfileArchiveDir);
324          fail("Should re-throw RetriesExhaustedWithDetailsException.");
325        } catch (RetriesExhaustedException e) {
326        } finally {
327          admin.enableTable(TABLE_NAME1);
328        }
329      }
330    }
331  }
332
333  /**
334   * Test replicateEntries with a bulk load entry for 25 HFiles
335   */
336  @Test
337  public void testReplicateEntriesForHFiles() throws Exception {
338    Path dir = TEST_UTIL.getDataTestDirOnTestFS("testReplicateEntries");
339    Path familyDir = new Path(dir, Bytes.toString(FAM_NAME1));
340    int numRows = 10;
341    List<Path> p = new ArrayList<>(1);
342    final String hfilePrefix = "hfile-";
343
344    // 1. Generate 25 hfile ranges
345    Random rand = ThreadLocalRandom.current();
346    Set<Integer> numbers = new HashSet<>();
347    while (numbers.size() < 50) {
348      numbers.add(rand.nextInt(1000));
349    }
350    List<Integer> numberList = new ArrayList<>(numbers);
351    Collections.sort(numberList);
352    Map<String, Long> storeFilesSize = new HashMap<>(1);
353
354    // 2. Create 25 hfiles
355    Configuration conf = TEST_UTIL.getConfiguration();
356    FileSystem fs = dir.getFileSystem(conf);
357    Iterator<Integer> numbersItr = numberList.iterator();
358    for (int i = 0; i < 25; i++) {
359      Path hfilePath = new Path(familyDir, hfilePrefix + i);
360      HFileTestUtil.createHFile(conf, fs, hfilePath, FAM_NAME1, FAM_NAME1,
361        Bytes.toBytes(numbersItr.next()), Bytes.toBytes(numbersItr.next()), numRows);
362      p.add(hfilePath);
363      storeFilesSize.put(hfilePath.getName(), fs.getFileStatus(hfilePath).getLen());
364    }
365
366    // 3. Create a BulkLoadDescriptor and a WALEdit
367    Map<byte[], List<Path>> storeFiles = new HashMap<>(1);
368    storeFiles.put(FAM_NAME1, p);
369    org.apache.hadoop.hbase.wal.WALEdit edit = null;
370    WALProtos.BulkLoadDescriptor loadDescriptor = null;
371
372    try (Connection c = ConnectionFactory.createConnection(conf);
373      RegionLocator l = c.getRegionLocator(TABLE_NAME1)) {
374      RegionInfo regionInfo = l.getAllRegionLocations().get(0).getRegion();
375      loadDescriptor = ProtobufUtil.toBulkLoadDescriptor(TABLE_NAME1,
376        UnsafeByteOperations.unsafeWrap(regionInfo.getEncodedNameAsBytes()), storeFiles,
377        storeFilesSize, 1);
378      edit = org.apache.hadoop.hbase.wal.WALEdit.createBulkLoadEvent(regionInfo, loadDescriptor);
379    }
380    List<WALEntry> entries = new ArrayList<>(1);
381
382    // 4. Create a WALEntryBuilder
383    WALEntry.Builder builder = createWALEntryBuilder(TABLE_NAME1);
384
385    // 5. Copy the hfile to the path as it is in reality
386    for (int i = 0; i < 25; i++) {
387      String pathToHfileFromNS = new StringBuilder(100).append(TABLE_NAME1.getNamespaceAsString())
388        .append(Path.SEPARATOR).append(Bytes.toString(TABLE_NAME1.getName())).append(Path.SEPARATOR)
389        .append(Bytes.toString(loadDescriptor.getEncodedRegionName().toByteArray()))
390        .append(Path.SEPARATOR).append(Bytes.toString(FAM_NAME1)).append(Path.SEPARATOR)
391        .append(hfilePrefix + i).toString();
392      String dst = baseNamespaceDir + Path.SEPARATOR + pathToHfileFromNS;
393      Path dstPath = new Path(dst);
394      FileUtil.copy(fs, p.get(0), fs, dstPath, false, conf);
395    }
396
397    entries.add(builder.build());
398    try (ResultScanner scanner = table1.getScanner(new Scan())) {
399      // 6. Assert no existing data in table
400      assertEquals(0, scanner.next(numRows).length);
401    }
402    // 7. Replicate the bulk loaded entry
403    SINK.replicateEntries(entries,
404      PrivateCellUtil
405        .createExtendedCellScanner(WALEditInternalHelper.getExtendedCells(edit).iterator()),
406      replicationClusterId, baseNamespaceDir, hfileArchiveDir);
407    try (ResultScanner scanner = table1.getScanner(new Scan())) {
408      // 8. Assert data is replicated
409      assertEquals(numRows, scanner.next(numRows).length);
410    }
411    // Clean up the created hfiles or it will mess up subsequent tests
412  }
413
414  /**
415   * Test failure metrics produced for failed replication edits
416   */
417  @Test
418  public void testFailedReplicationSinkMetrics() throws IOException {
419    long initialFailedBatches = SINK.getSinkMetrics().getFailedBatches();
420    long errorCount = 0L;
421    List<WALEntry> entries = new ArrayList<>(BATCH_SIZE);
422    List<ExtendedCell> cells = new ArrayList<>();
423    for (int i = 0; i < BATCH_SIZE; i++) {
424      entries.add(createEntry(TABLE_NAME1, i, KeyValue.Type.Put, cells));
425    }
426    cells.clear(); // cause IndexOutOfBoundsException
427    try {
428      SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
429        replicationClusterId, baseNamespaceDir, hfileArchiveDir);
430      fail("Should re-throw ArrayIndexOutOfBoundsException.");
431    } catch (ArrayIndexOutOfBoundsException e) {
432      errorCount++;
433      assertEquals(initialFailedBatches + errorCount, SINK.getSinkMetrics().getFailedBatches());
434    }
435
436    entries.clear();
437    cells.clear();
438    TableName notExistTable = TableName.valueOf("notExistTable"); // cause TableNotFoundException
439    for (int i = 0; i < BATCH_SIZE; i++) {
440      entries.add(createEntry(notExistTable, i, KeyValue.Type.Put, cells));
441    }
442    try {
443      SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
444        replicationClusterId, baseNamespaceDir, hfileArchiveDir);
445      fail("Should re-throw TableNotFoundException.");
446    } catch (TableNotFoundException e) {
447      errorCount++;
448      assertEquals(initialFailedBatches + errorCount, SINK.getSinkMetrics().getFailedBatches());
449    }
450
451    entries.clear();
452    cells.clear();
453    for (int i = 0; i < BATCH_SIZE; i++) {
454      entries.add(createEntry(TABLE_NAME1, i, KeyValue.Type.Put, cells));
455    }
456    // cause IOException in batch()
457    try (Connection conn = ConnectionFactory.createConnection(TEST_UTIL.getConfiguration())) {
458      try (Admin admin = conn.getAdmin()) {
459        admin.disableTable(TABLE_NAME1);
460        try {
461          SINK.replicateEntries(entries,
462            PrivateCellUtil.createExtendedCellScanner(cells.iterator()), replicationClusterId,
463            baseNamespaceDir, hfileArchiveDir);
464          fail("Should re-throw IOException.");
465        } catch (IOException e) {
466          errorCount++;
467          assertEquals(initialFailedBatches + errorCount, SINK.getSinkMetrics().getFailedBatches());
468        } finally {
469          admin.enableTable(TABLE_NAME1);
470        }
471      }
472    }
473  }
474
475  private WALEntry createEntry(TableName table, int row, KeyValue.Type type,
476    List<ExtendedCell> cells) {
477    byte[] fam = table.equals(TABLE_NAME1) ? FAM_NAME1 : FAM_NAME2;
478    byte[] rowBytes = Bytes.toBytes(row);
479    // Just make sure we don't get the same ts for two consecutive rows with
480    // same key
481    try {
482      Thread.sleep(1);
483    } catch (InterruptedException e) {
484      LOG.info("Was interrupted while sleep, meh", e);
485    }
486    final long now = EnvironmentEdgeManager.currentTime();
487    KeyValue kv = null;
488    if (type.getCode() == KeyValue.Type.Put.getCode()) {
489      kv = new KeyValue(rowBytes, fam, fam, now, KeyValue.Type.Put, Bytes.toBytes(row));
490    } else if (type.getCode() == KeyValue.Type.DeleteColumn.getCode()) {
491      kv = new KeyValue(rowBytes, fam, fam, now, KeyValue.Type.DeleteColumn);
492    } else if (type.getCode() == KeyValue.Type.DeleteFamily.getCode()) {
493      kv = new KeyValue(rowBytes, fam, null, now, KeyValue.Type.DeleteFamily);
494    }
495    WALEntry.Builder builder = createWALEntryBuilder(table);
496    cells.add(kv);
497
498    return builder.build();
499  }
500
501  public static WALEntry.Builder createWALEntryBuilder(TableName table) {
502    WALEntry.Builder builder = WALEntry.newBuilder();
503    builder.setAssociatedCellCount(1);
504    WALKey.Builder keyBuilder = WALKey.newBuilder();
505    UUID.Builder uuidBuilder = UUID.newBuilder();
506    uuidBuilder.setLeastSigBits(HConstants.DEFAULT_CLUSTER_ID.getLeastSignificantBits());
507    uuidBuilder.setMostSigBits(HConstants.DEFAULT_CLUSTER_ID.getMostSignificantBits());
508    keyBuilder.setClusterId(uuidBuilder.build());
509    keyBuilder.setTableName(UnsafeByteOperations.unsafeWrap(table.getName()));
510    keyBuilder.setWriteTime(EnvironmentEdgeManager.currentTime());
511    keyBuilder.setEncodedRegionName(UnsafeByteOperations.unsafeWrap(HConstants.EMPTY_BYTE_ARRAY));
512    keyBuilder.setLogSequenceNumber(-1);
513    builder.setKey(keyBuilder.build());
514    return builder;
515  }
516}