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.regionserver.wal;
19  
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Set;
26  import java.util.concurrent.atomic.AtomicLong;
27  
28  import org.apache.hadoop.hbase.Cell;
29  import org.apache.hadoop.hbase.CellUtil;
30  import org.apache.hadoop.hbase.HRegionInfo;
31  import org.apache.hadoop.hbase.HTableDescriptor;
32  import org.apache.hadoop.hbase.classification.InterfaceAudience;
33  import org.apache.hadoop.hbase.util.Bytes;
34  import org.apache.hadoop.hbase.util.CollectionUtils;
35  
36  import com.google.common.collect.Sets;
37  
38  import org.apache.hadoop.hbase.wal.WAL.Entry;
39  import org.apache.hadoop.hbase.wal.WALKey;
40  
41  /**
42   * A WAL Entry for {@link FSHLog} implementation.  Immutable.
43   * A subclass of {@link Entry} that carries extra info across the ring buffer such as
44   * region sequence id (we want to use this later, just before we write the WAL to ensure region
45   * edits maintain order).  The extra info added here is not 'serialized' as part of the WALEdit
46   * hence marked 'transient' to underline this fact.  It also adds mechanism so we can wait on
47   * the assign of the region sequence id.  See #stampRegionSequenceId().
48   */
49  @InterfaceAudience.Private
50  class FSWALEntry extends Entry {
51    // The below data members are denoted 'transient' just to highlight these are not persisted;
52    // they are only in memory and held here while passing over the ring buffer.
53    private final transient long sequence;
54    private final transient AtomicLong regionSequenceIdReference;
55    private final transient boolean inMemstore;
56    private final transient HTableDescriptor htd;
57    private final transient HRegionInfo hri;
58    private final transient List<Cell> memstoreCells;
59    private final Set<byte[]> familyNames;
60  
61    FSWALEntry(final long sequence, final WALKey key, final WALEdit edit,
62        final AtomicLong referenceToRegionSequenceId, final boolean inMemstore,
63        final HTableDescriptor htd, final HRegionInfo hri, List<Cell> memstoreCells) {
64      super(key, edit);
65      this.regionSequenceIdReference = referenceToRegionSequenceId;
66      this.inMemstore = inMemstore;
67      this.htd = htd;
68      this.hri = hri;
69      this.sequence = sequence;
70      this.memstoreCells = memstoreCells;
71      if (inMemstore) {
72        // construct familyNames here to reduce the work of log sinker.
73        ArrayList<Cell> cells = this.getEdit().getCells();
74        if (CollectionUtils.isEmpty(cells)) {
75          this.familyNames = Collections.<byte[]> emptySet();
76        } else {
77          Set<byte[]> familySet = Sets.newTreeSet(Bytes.BYTES_COMPARATOR);
78          for (Cell cell : cells) {
79            if (!CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {
80              familySet.add(CellUtil.cloneFamily(cell));
81            }
82          }
83          this.familyNames = Collections.unmodifiableSet(familySet);
84        }
85      } else {
86        this.familyNames = Collections.<byte[]> emptySet();
87      }
88    }
89  
90    public String toString() {
91      return "sequence=" + this.sequence + ", " + super.toString();
92    };
93  
94    boolean isInMemstore() {
95      return this.inMemstore;
96    }
97  
98    HTableDescriptor getHTableDescriptor() {
99      return this.htd;
100   }
101 
102   HRegionInfo getHRegionInfo() {
103     return this.hri;
104   }
105 
106   /**
107    * @return The sequence on the ring buffer when this edit was added.
108    */
109   long getSequence() {
110     return this.sequence;
111   }
112 
113   /**
114    * Stamp this edit with a region edit/sequence id.
115    * Call when safe to do so: i.e. the context is such that the increment on the passed in
116    * {@link #regionSequenceIdReference} is guaranteed aligned w/ how appends are going into the
117    * WAL.  This method works with {@link #getRegionSequenceId()}.  It will block waiting on this
118    * method to be called.
119    * @return The region edit/sequence id we set for this edit.
120    * @throws IOException
121    * @see #getRegionSequenceId()
122    */
123   long stampRegionSequenceId() throws IOException {
124     long regionSequenceId = this.regionSequenceIdReference.incrementAndGet();
125     if (!this.getEdit().isReplay() && !CollectionUtils.isEmpty(memstoreCells)) {
126       for (Cell cell : this.memstoreCells) {
127         CellUtil.setSequenceId(cell, regionSequenceId);
128       }
129     }
130     WALKey key = getKey();
131     key.setLogSeqNum(regionSequenceId);
132     return regionSequenceId;
133   }
134 
135   /**
136    * @return the family names which are effected by this edit.
137    */
138   Set<byte[]> getFamilyNames() {
139     return familyNames;
140   }
141 }