View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.catalog;
19  
20  import java.io.IOException;
21  import java.io.InterruptedIOException;
22  import java.net.ConnectException;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.classification.InterfaceAudience;
29  import org.apache.hadoop.hbase.DoNotRetryIOException;
30  import org.apache.hadoop.hbase.HConstants;
31  import org.apache.hadoop.hbase.HRegionInfo;
32  import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException;
33  import org.apache.hadoop.hbase.ServerName;
34  import org.apache.hadoop.hbase.client.Delete;
35  import org.apache.hadoop.hbase.client.HTable;
36  import org.apache.hadoop.hbase.client.Mutation;
37  import org.apache.hadoop.hbase.client.Put;
38  import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel;
39  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
40  import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType;
41  import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MultiRowMutationService;
42  import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos.MutateRowsRequest;
43  import org.apache.hadoop.hbase.util.Bytes;
44  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
45  
46  import com.google.protobuf.ServiceException;
47  
48  /**
49   * Writes region and assignment information to <code>hbase:meta</code>.
50   * TODO: Put MetaReader and MetaEditor together; doesn't make sense having
51   * them distinct. see HBASE-3475.
52   */
53  @InterfaceAudience.Private
54  public class MetaEditor {
55    // TODO: Strip CatalogTracker from this class.  Its all over and in the end
56    // its only used to get its Configuration so we can get associated
57    // Connection.
58    private static final Log LOG = LogFactory.getLog(MetaEditor.class);
59  
60    /**
61     * Generates and returns a Put containing the region into for the catalog table
62     */
63    public static Put makePutFromRegionInfo(HRegionInfo regionInfo)
64    throws IOException {
65      return makePutFromRegionInfo(regionInfo, HConstants.LATEST_TIMESTAMP);
66    }
67  
68    /**
69     * Generates and returns a Put containing the region into for the catalog table
70     */
71    public static Put makePutFromRegionInfo(HRegionInfo regionInfo, long ts)
72    throws IOException {
73      Put put = new Put(regionInfo.getRegionName(), ts);
74      addRegionInfo(put, regionInfo);
75      return put;
76    }
77  
78    /**
79     * Generates and returns a Delete containing the region info for the catalog
80     * table
81     */
82    public static Delete makeDeleteFromRegionInfo(HRegionInfo regionInfo) {
83      if (regionInfo == null) {
84        throw new IllegalArgumentException("Can't make a delete for null region");
85      }
86      Delete delete = new Delete(regionInfo.getRegionName());
87      return delete;
88    }
89  
90    /**
91     * Adds split daughters to the Put
92     */
93    public static Put addDaughtersToPut(Put put, HRegionInfo splitA, HRegionInfo splitB) {
94      if (splitA != null) {
95        put.addImmutable(
96            HConstants.CATALOG_FAMILY, HConstants.SPLITA_QUALIFIER, splitA.toByteArray());
97      }
98      if (splitB != null) {
99        put.addImmutable(
100           HConstants.CATALOG_FAMILY, HConstants.SPLITB_QUALIFIER, splitB.toByteArray());
101     }
102     return put;
103   }
104 
105   /**
106    * Put the passed <code>p</code> to the <code>hbase:meta</code> table.
107    * @param ct CatalogTracker on whose back we will ride the edit.
108    * @param p Put to add to hbase:meta
109    * @throws IOException
110    */
111   static void putToMetaTable(final CatalogTracker ct, final Put p)
112   throws IOException {
113     put(MetaReader.getMetaHTable(ct), p);
114   }
115 
116   /**
117    * Put the passed <code>p</code> to a catalog table.
118    * @param ct CatalogTracker on whose back we will ride the edit.
119    * @param p Put to add
120    * @throws IOException
121    */
122   static void putToCatalogTable(final CatalogTracker ct, final Put p)
123   throws IOException {
124     put(MetaReader.getCatalogHTable(ct), p);
125   }
126 
127   /**
128    * @param t Table to use (will be closed when done).
129    * @param p
130    * @throws IOException
131    */
132   private static void put(final HTable t, final Put p) throws IOException {
133     try {
134       t.put(p);
135     } finally {
136       t.close();
137     }
138   }
139 
140   /**
141    * Put the passed <code>ps</code> to the <code>hbase:meta</code> table.
142    * @param ct CatalogTracker on whose back we will ride the edit.
143    * @param ps Put to add to hbase:meta
144    * @throws IOException
145    */
146   public static void putsToMetaTable(final CatalogTracker ct, final List<Put> ps)
147   throws IOException {
148     HTable t = MetaReader.getMetaHTable(ct);
149     try {
150       t.put(ps);
151     } finally {
152       t.close();
153     }
154   }
155 
156   /**
157    * Delete the passed <code>d</code> from the <code>hbase:meta</code> table.
158    * @param ct CatalogTracker on whose back we will ride the edit.
159    * @param d Delete to add to hbase:meta
160    * @throws IOException
161    */
162   static void deleteFromMetaTable(final CatalogTracker ct, final Delete d)
163       throws IOException {
164     List<Delete> dels = new ArrayList<Delete>(1);
165     dels.add(d);
166     deleteFromMetaTable(ct, dels);
167   }
168 
169   /**
170    * Delete the passed <code>deletes</code> from the <code>hbase:meta</code> table.
171    * @param ct CatalogTracker on whose back we will ride the edit.
172    * @param deletes Deletes to add to hbase:meta  This list should support #remove.
173    * @throws IOException
174    */
175   public static void deleteFromMetaTable(final CatalogTracker ct, final List<Delete> deletes)
176       throws IOException {
177     HTable t = MetaReader.getMetaHTable(ct);
178     try {
179       t.delete(deletes);
180     } finally {
181       t.close();
182     }
183   }
184 
185   /**
186    * Execute the passed <code>mutations</code> against <code>hbase:meta</code> table.
187    * @param ct CatalogTracker on whose back we will ride the edit.
188    * @param mutations Puts and Deletes to execute on hbase:meta
189    * @throws IOException
190    */
191   public static void mutateMetaTable(final CatalogTracker ct, final List<Mutation> mutations)
192       throws IOException {
193     HTable t = MetaReader.getMetaHTable(ct);
194     try {
195       t.batch(mutations);
196     } catch (InterruptedException e) {
197       InterruptedIOException ie = new InterruptedIOException(e.getMessage());
198       ie.initCause(e);
199       throw ie;
200     } finally {
201       t.close();
202     }
203   }
204 
205   /**
206    * Adds a hbase:meta row for the specified new region.
207    * @param regionInfo region information
208    * @throws IOException if problem connecting or updating meta
209    */
210   public static void addRegionToMeta(CatalogTracker catalogTracker,
211       HRegionInfo regionInfo)
212   throws IOException {
213     putToMetaTable(catalogTracker, makePutFromRegionInfo(regionInfo));
214     LOG.info("Added " + regionInfo.getRegionNameAsString());
215   }
216 
217   /**
218    * Adds a hbase:meta row for the specified new region to the given catalog table. The
219    * HTable is not flushed or closed.
220    * @param meta the HTable for META
221    * @param regionInfo region information
222    * @throws IOException if problem connecting or updating meta
223    */
224   public static void addRegionToMeta(HTable meta, HRegionInfo regionInfo) throws IOException {
225     addRegionToMeta(meta, regionInfo, null, null);
226   }
227 
228   /**
229    * Adds a (single) hbase:meta row for the specified new region and its daughters. Note that this does
230    * not add its daughter's as different rows, but adds information about the daughters
231    * in the same row as the parent. Use
232    * {@link #splitRegion(CatalogTracker, HRegionInfo, HRegionInfo, HRegionInfo, ServerName)}
233    * if you want to do that.
234    * @param meta the HTable for META
235    * @param regionInfo region information
236    * @param splitA first split daughter of the parent regionInfo
237    * @param splitB second split daughter of the parent regionInfo
238    * @throws IOException if problem connecting or updating meta
239    */
240   public static void addRegionToMeta(HTable meta, HRegionInfo regionInfo,
241       HRegionInfo splitA, HRegionInfo splitB) throws IOException {
242     Put put = makePutFromRegionInfo(regionInfo);
243     addDaughtersToPut(put, splitA, splitB);
244     meta.put(put);
245     if (LOG.isDebugEnabled()) {
246       LOG.debug("Added " + regionInfo.getRegionNameAsString());
247     }
248   }
249 
250   /**
251    * Adds a (single) hbase:meta row for the specified new region and its daughters. Note that this does
252    * not add its daughter's as different rows, but adds information about the daughters
253    * in the same row as the parent. Use
254    * {@link #splitRegion(CatalogTracker, HRegionInfo, HRegionInfo, HRegionInfo, ServerName)}
255    * if you want to do that.
256    * @param catalogTracker CatalogTracker on whose back we will ride the edit.
257    * @param regionInfo region information
258    * @param splitA first split daughter of the parent regionInfo
259    * @param splitB second split daughter of the parent regionInfo
260    * @throws IOException if problem connecting or updating meta
261    */
262   public static void addRegionToMeta(CatalogTracker catalogTracker, HRegionInfo regionInfo,
263       HRegionInfo splitA, HRegionInfo splitB) throws IOException {
264     HTable meta = MetaReader.getMetaHTable(catalogTracker);
265     try {
266       addRegionToMeta(meta, regionInfo, splitA, splitB);
267     } finally {
268       meta.close();
269     }
270   }
271 
272   /**
273    * Adds a hbase:meta row for each of the specified new regions.
274    * @param catalogTracker CatalogTracker
275    * @param regionInfos region information list
276    * @throws IOException if problem connecting or updating meta
277    */
278   public static void addRegionsToMeta(CatalogTracker catalogTracker,
279       List<HRegionInfo> regionInfos)
280   throws IOException {
281     addRegionsToMeta(catalogTracker, regionInfos, HConstants.LATEST_TIMESTAMP);
282   }
283 
284   /**
285    * Adds a hbase:meta row for each of the specified new regions.
286    * @param catalogTracker CatalogTracker
287    * @param regionInfos region information list
288    * @param ts desired timestamp
289    * @throws IOException if problem connecting or updating meta
290    */
291   public static void addRegionsToMeta(CatalogTracker catalogTracker,
292       List<HRegionInfo> regionInfos, long ts)
293   throws IOException {
294     List<Put> puts = new ArrayList<Put>();
295     for (HRegionInfo regionInfo : regionInfos) {
296       puts.add(makePutFromRegionInfo(regionInfo, ts));
297     }
298     putsToMetaTable(catalogTracker, puts);
299     LOG.info("Added " + puts.size());
300   }
301 
302   /**
303    * Adds a daughter region entry to meta.
304    * @param regionInfo the region to put
305    * @param sn the location of the region
306    * @param openSeqNum the latest sequence number obtained when the region was open
307    */
308   public static void addDaughter(final CatalogTracker catalogTracker,
309       final HRegionInfo regionInfo, final ServerName sn, final long openSeqNum)
310   throws NotAllMetaRegionsOnlineException, IOException {
311     Put put = new Put(regionInfo.getRegionName());
312     addRegionInfo(put, regionInfo);
313     if (sn != null) {
314       addLocation(put, sn, openSeqNum);
315     }
316     putToMetaTable(catalogTracker, put);
317     LOG.info("Added daughter " + regionInfo.getEncodedName() +
318       (sn == null? ", serverName=null": ", serverName=" + sn.toString()));
319   }
320 
321   /**
322    * Merge the two regions into one in an atomic operation. Deletes the two
323    * merging regions in hbase:meta and adds the merged region with the information of
324    * two merging regions.
325    * @param catalogTracker the catalog tracker
326    * @param mergedRegion the merged region
327    * @param regionA
328    * @param regionB
329    * @param sn the location of the region
330    * @throws IOException
331    */
332   public static void mergeRegions(final CatalogTracker catalogTracker,
333       HRegionInfo mergedRegion, HRegionInfo regionA, HRegionInfo regionB,
334       ServerName sn) throws IOException {
335     HTable meta = MetaReader.getMetaHTable(catalogTracker);
336     try {
337       HRegionInfo copyOfMerged = new HRegionInfo(mergedRegion);
338 
339       // Put for parent
340       Put putOfMerged = makePutFromRegionInfo(copyOfMerged);
341       putOfMerged.addImmutable(HConstants.CATALOG_FAMILY, HConstants.MERGEA_QUALIFIER,
342           regionA.toByteArray());
343       putOfMerged.addImmutable(HConstants.CATALOG_FAMILY, HConstants.MERGEB_QUALIFIER,
344           regionB.toByteArray());
345 
346       // Deletes for merging regions
347       Delete deleteA = makeDeleteFromRegionInfo(regionA);
348       Delete deleteB = makeDeleteFromRegionInfo(regionB);
349 
350       // The merged is a new region, openSeqNum = 1 is fine.
351       addLocation(putOfMerged, sn, 1);
352 
353       byte[] tableRow = Bytes.toBytes(mergedRegion.getRegionNameAsString()
354           + HConstants.DELIMITER);
355       multiMutate(meta, tableRow, putOfMerged, deleteA, deleteB);
356     } finally {
357       meta.close();
358     }
359   }
360 
361   /**
362    * Splits the region into two in an atomic operation. Offlines the parent
363    * region with the information that it is split into two, and also adds
364    * the daughter regions. Does not add the location information to the daughter
365    * regions since they are not open yet.
366    * @param catalogTracker the catalog tracker
367    * @param parent the parent region which is split
368    * @param splitA Split daughter region A
369    * @param splitB Split daughter region A
370    * @param sn the location of the region
371    */
372   public static void splitRegion(final CatalogTracker catalogTracker,
373       HRegionInfo parent, HRegionInfo splitA, HRegionInfo splitB,
374       ServerName sn) throws IOException {
375     HTable meta = MetaReader.getMetaHTable(catalogTracker);
376     try {
377       HRegionInfo copyOfParent = new HRegionInfo(parent);
378       copyOfParent.setOffline(true);
379       copyOfParent.setSplit(true);
380 
381       //Put for parent
382       Put putParent = makePutFromRegionInfo(copyOfParent);
383       addDaughtersToPut(putParent, splitA, splitB);
384 
385       //Puts for daughters
386       Put putA = makePutFromRegionInfo(splitA);
387       Put putB = makePutFromRegionInfo(splitB);
388 
389       addLocation(putA, sn, 1); //these are new regions, openSeqNum = 1 is fine.
390       addLocation(putB, sn, 1);
391 
392       byte[] tableRow = Bytes.toBytes(parent.getRegionNameAsString() + HConstants.DELIMITER);
393       multiMutate(meta, tableRow, putParent, putA, putB);
394     } finally {
395       meta.close();
396     }
397   }
398 
399   /**
400    * Performs an atomic multi-Mutate operation against the given table.
401    */
402   private static void multiMutate(HTable table, byte[] row, Mutation... mutations) throws IOException {
403     CoprocessorRpcChannel channel = table.coprocessorService(row);
404     MutateRowsRequest.Builder mmrBuilder = MutateRowsRequest.newBuilder();
405     for (Mutation mutation : mutations) {
406       if (mutation instanceof Put) {
407         mmrBuilder.addMutationRequest(ProtobufUtil.toMutation(MutationType.PUT, mutation));
408       } else if (mutation instanceof Delete) {
409         mmrBuilder.addMutationRequest(ProtobufUtil.toMutation(MutationType.DELETE, mutation));
410       } else {
411         throw new DoNotRetryIOException("multi in MetaEditor doesn't support "
412             + mutation.getClass().getName());
413       }
414     }
415 
416     MultiRowMutationService.BlockingInterface service =
417         MultiRowMutationService.newBlockingStub(channel);
418     try {
419       service.mutateRows(null, mmrBuilder.build());
420     } catch (ServiceException ex) {
421       ProtobufUtil.toIOException(ex);
422     }
423   }
424 
425 
426   /**
427    * Updates the location of the specified hbase:meta region in ROOT to be the
428    * specified server hostname and startcode.
429    * <p>
430    * Uses passed catalog tracker to get a connection to the server hosting
431    * ROOT and makes edits to that region.
432    *
433    * @param catalogTracker catalog tracker
434    * @param regionInfo region to update location of
435    * @param sn Server name
436    * @param openSeqNum the latest sequence number obtained when the region was open
437    * @throws IOException
438    * @throws ConnectException Usually because the regionserver carrying hbase:meta
439    * is down.
440    * @throws NullPointerException Because no -ROOT- server connection
441    */
442   public static void updateMetaLocation(CatalogTracker catalogTracker,
443       HRegionInfo regionInfo, ServerName sn, long openSeqNum)
444   throws IOException, ConnectException {
445     updateLocation(catalogTracker, regionInfo, sn, openSeqNum);
446   }
447 
448   /**
449    * Updates the location of the specified region in hbase:meta to be the specified
450    * server hostname and startcode.
451    * <p>
452    * Uses passed catalog tracker to get a connection to the server hosting
453    * hbase:meta and makes edits to that region.
454    *
455    * @param catalogTracker catalog tracker
456    * @param regionInfo region to update location of
457    * @param sn Server name
458    * @throws IOException
459    */
460   public static void updateRegionLocation(CatalogTracker catalogTracker,
461       HRegionInfo regionInfo, ServerName sn, long updateSeqNum)
462   throws IOException {
463     updateLocation(catalogTracker, regionInfo, sn, updateSeqNum);
464   }
465 
466   /**
467    * Updates the location of the specified region to be the specified server.
468    * <p>
469    * Connects to the specified server which should be hosting the specified
470    * catalog region name to perform the edit.
471    *
472    * @param catalogTracker
473    * @param regionInfo region to update location of
474    * @param sn Server name
475    * @param openSeqNum the latest sequence number obtained when the region was open
476    * @throws IOException In particular could throw {@link java.net.ConnectException}
477    * if the server is down on other end.
478    */
479   private static void updateLocation(final CatalogTracker catalogTracker,
480       HRegionInfo regionInfo, ServerName sn, long openSeqNum)
481   throws IOException {
482     Put put = new Put(regionInfo.getRegionName());
483     addLocation(put, sn, openSeqNum);
484     putToCatalogTable(catalogTracker, put);
485     LOG.info("Updated row " + regionInfo.getRegionNameAsString() +
486       " with server=" + sn);
487   }
488 
489   /**
490    * Deletes the specified region from META.
491    * @param catalogTracker
492    * @param regionInfo region to be deleted from META
493    * @throws IOException
494    */
495   public static void deleteRegion(CatalogTracker catalogTracker,
496       HRegionInfo regionInfo)
497   throws IOException {
498     Delete delete = new Delete(regionInfo.getRegionName());
499     deleteFromMetaTable(catalogTracker, delete);
500     LOG.info("Deleted " + regionInfo.getRegionNameAsString());
501   }
502 
503   /**
504    * Deletes the specified regions from META.
505    * @param catalogTracker
506    * @param regionsInfo list of regions to be deleted from META
507    * @throws IOException
508    */
509   public static void deleteRegions(CatalogTracker catalogTracker,
510       List<HRegionInfo> regionsInfo) throws IOException {
511     deleteRegions(catalogTracker, regionsInfo, HConstants.LATEST_TIMESTAMP);
512   }
513 
514   /**
515    * Deletes the specified regions from META.
516    * @param catalogTracker
517    * @param regionsInfo list of regions to be deleted from META
518    * @param ts desired timestamp
519    * @throws IOException
520    */
521   public static void deleteRegions(CatalogTracker catalogTracker,
522       List<HRegionInfo> regionsInfo, long ts) throws IOException {
523     List<Delete> deletes = new ArrayList<Delete>(regionsInfo.size());
524     for (HRegionInfo hri: regionsInfo) {
525       deletes.add(new Delete(hri.getRegionName(), ts));
526     }
527     deleteFromMetaTable(catalogTracker, deletes);
528     LOG.info("Deleted " + regionsInfo);
529   }
530 
531   /**
532    * Adds and Removes the specified regions from hbase:meta
533    * @param catalogTracker
534    * @param regionsToRemove list of regions to be deleted from META
535    * @param regionsToAdd list of regions to be added to META
536    * @throws IOException
537    */
538   public static void mutateRegions(CatalogTracker catalogTracker,
539       final List<HRegionInfo> regionsToRemove, final List<HRegionInfo> regionsToAdd)
540       throws IOException {
541     List<Mutation> mutation = new ArrayList<Mutation>();
542     if (regionsToRemove != null) {
543       for (HRegionInfo hri: regionsToRemove) {
544         mutation.add(new Delete(hri.getRegionName()));
545       }
546     }
547     if (regionsToAdd != null) {
548       for (HRegionInfo hri: regionsToAdd) {
549         mutation.add(makePutFromRegionInfo(hri));
550       }
551     }
552     mutateMetaTable(catalogTracker, mutation);
553     if (regionsToRemove != null && regionsToRemove.size() > 0) {
554       LOG.debug("Deleted " + regionsToRemove);
555     }
556     if (regionsToAdd != null && regionsToAdd.size() > 0) {
557       LOG.debug("Added " + regionsToAdd);
558     }
559   }
560 
561   /**
562    * Overwrites the specified regions from hbase:meta
563    * @param catalogTracker
564    * @param regionInfos list of regions to be added to META
565    * @throws IOException
566    */
567   public static void overwriteRegions(CatalogTracker catalogTracker,
568       List<HRegionInfo> regionInfos) throws IOException {
569     // use master time for delete marker and the Put
570     long now = EnvironmentEdgeManager.currentTimeMillis();
571     deleteRegions(catalogTracker, regionInfos, now);
572     // Why sleep? This is the easiest way to ensure that the previous deletes does not
573     // eclipse the following puts, that might happen in the same ts from the server.
574     // See HBASE-9906, and HBASE-9879. Once either HBASE-9879, HBASE-8770 is fixed,
575     // or HBASE-9905 is fixed and meta uses seqIds, we do not need the sleep.
576     //
577     // HBASE-13875 uses master timestamp for the mutations. The 20ms sleep is not needed
578     addRegionsToMeta(catalogTracker, regionInfos, now+1);
579     LOG.info("Overwritten " + regionInfos);
580   }
581 
582   /**
583    * Deletes merge qualifiers for the specified merged region.
584    * @param catalogTracker
585    * @param mergedRegion
586    * @throws IOException
587    */
588   public static void deleteMergeQualifiers(CatalogTracker catalogTracker,
589       final HRegionInfo mergedRegion) throws IOException {
590     Delete delete = new Delete(mergedRegion.getRegionName());
591     delete.deleteColumns(HConstants.CATALOG_FAMILY, HConstants.MERGEA_QUALIFIER);
592     delete.deleteColumns(HConstants.CATALOG_FAMILY, HConstants.MERGEB_QUALIFIER);
593     deleteFromMetaTable(catalogTracker, delete);
594     LOG.info("Deleted references in merged region "
595         + mergedRegion.getRegionNameAsString() + ", qualifier="
596         + Bytes.toStringBinary(HConstants.MERGEA_QUALIFIER) + " and qualifier="
597         + Bytes.toStringBinary(HConstants.MERGEB_QUALIFIER));
598   }
599 
600   private static Put addRegionInfo(final Put p, final HRegionInfo hri)
601   throws IOException {
602     p.addImmutable(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER,
603         hri.toByteArray());
604     return p;
605   }
606 
607   private static Put addLocation(final Put p, final ServerName sn, long openSeqNum) {
608     // using regionserver's local time as the timestamp of Put.
609     // See: HBASE-11536
610     long now = EnvironmentEdgeManager.currentTimeMillis();
611     p.addImmutable(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER, now,
612       Bytes.toBytes(sn.getHostAndPort()));
613     p.addImmutable(HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER, now,
614       Bytes.toBytes(sn.getStartcode()));
615     p.addImmutable(HConstants.CATALOG_FAMILY, HConstants.SEQNUM_QUALIFIER, now,
616         Bytes.toBytes(openSeqNum));
617     return p;
618   }
619 }