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.Set;
25  
26  import org.apache.hadoop.hbase.Cell;
27  import org.apache.hadoop.hbase.CellUtil;
28  import org.apache.hadoop.hbase.HRegionInfo;
29  import org.apache.hadoop.hbase.HTableDescriptor;
30  import org.apache.hadoop.hbase.classification.InterfaceAudience;
31  import org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl;
32  import org.apache.hadoop.hbase.util.Bytes;
33  import org.apache.hadoop.hbase.util.CollectionUtils;
34  
35  import com.google.common.collect.Sets;
36  
37  import org.apache.hadoop.hbase.wal.WAL.Entry;
38  import org.apache.hadoop.hbase.wal.WALKey;
39  
40  /**
41   * A WAL Entry for {@link FSHLog} implementation.  Immutable.
42   * A subclass of {@link Entry} that carries extra info across the ring buffer such as
43   * region sequence id (we want to use this later, just before we write the WAL to ensure region
44   * edits maintain order).  The extra info added here is not 'serialized' as part of the WALEdit
45   * hence marked 'transient' to underline this fact.  It also adds mechanism so we can wait on
46   * the assign of the region sequence id.  See #stampRegionSequenceId().
47   */
48  @InterfaceAudience.Private
49  class FSWALEntry extends Entry {
50    // The below data members are denoted 'transient' just to highlight these are not persisted;
51    // they are only in memory and held here while passing over the ring buffer.
52    private final transient long sequence;
53    private final transient boolean inMemstore;
54    private final transient HTableDescriptor htd;
55    private final transient HRegionInfo hri;
56    private final Set<byte[]> familyNames;
57  
58    FSWALEntry(final long sequence, final WALKey key, final WALEdit edit,
59        final HTableDescriptor htd, final HRegionInfo hri, final boolean inMemstore) {
60      super(key, edit);
61      this.inMemstore = inMemstore;
62      this.htd = htd;
63      this.hri = hri;
64      this.sequence = sequence;
65      if (inMemstore) {
66        // construct familyNames here to reduce the work of log sinker.
67        ArrayList<Cell> cells = this.getEdit().getCells();
68        if (CollectionUtils.isEmpty(cells)) {
69          this.familyNames = Collections.<byte[]> emptySet();
70        } else {
71          Set<byte[]> familySet = Sets.newTreeSet(Bytes.BYTES_COMPARATOR);
72          for (Cell cell : cells) {
73            if (!CellUtil.matchingFamily(cell, WALEdit.METAFAMILY)) {
74              familySet.add(CellUtil.cloneFamily(cell));
75            }
76          }
77          this.familyNames = Collections.unmodifiableSet(familySet);
78        }
79      } else {
80        this.familyNames = Collections.<byte[]> emptySet();
81      }
82    }
83  
84    public String toString() {
85      return "sequence=" + this.sequence + ", " + super.toString();
86    };
87  
88    boolean isInMemstore() {
89      return this.inMemstore;
90    }
91  
92    HTableDescriptor getHTableDescriptor() {
93      return this.htd;
94    }
95  
96    HRegionInfo getHRegionInfo() {
97      return this.hri;
98    }
99  
100   /**
101    * @return The sequence on the ring buffer when this edit was added.
102    */
103   long getSequence() {
104     return this.sequence;
105   }
106 
107   /**
108    * Here is where a WAL edit gets its sequenceid.
109    * @return The sequenceid we stamped on this edit.
110    * @throws IOException
111    */
112   long stampRegionSequenceId() throws IOException {
113     long regionSequenceId = WALKey.NO_SEQUENCE_ID;
114     MultiVersionConcurrencyControl mvcc = getKey().getMvcc();
115     MultiVersionConcurrencyControl.WriteEntry we = null;
116 
117     if (mvcc != null) {
118       we = mvcc.begin();
119       regionSequenceId = we.getWriteNumber();
120     }
121 
122     if (!this.getEdit().isReplay() && inMemstore) {
123       for (Cell c:getEdit().getCells()) {
124         CellUtil.setSequenceId(c, regionSequenceId);
125       }
126     }
127 
128     // This has to stay in this order
129     WALKey key = getKey();
130     key.setLogSeqNum(regionSequenceId);
131     key.setWriteEntry(we);
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 }