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.regionserver.wal; 019 020import java.io.IOException; 021import java.util.Collections; 022import java.util.List; 023import java.util.Set; 024import java.util.TreeSet; 025import org.apache.hadoop.hbase.Cell; 026import org.apache.hadoop.hbase.CellUtil; 027import org.apache.hadoop.hbase.PrivateCellUtil; 028import org.apache.hadoop.hbase.client.RegionInfo; 029import org.apache.hadoop.hbase.ipc.ServerCall; 030import org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl; 031import org.apache.hadoop.hbase.util.Bytes; 032import org.apache.hadoop.hbase.wal.WAL.Entry; 033import org.apache.hadoop.hbase.wal.WALEdit; 034import org.apache.hadoop.hbase.wal.WALKeyImpl; 035import org.apache.yetus.audience.InterfaceAudience; 036 037import org.apache.hbase.thirdparty.org.apache.commons.collections4.CollectionUtils; 038 039/** 040 * A WAL Entry for {@link AbstractFSWAL} implementation. Immutable. A subclass of {@link Entry} that 041 * carries extra info across the ring buffer such as region sequenceid (we want to use this later, 042 * just before we write the WAL to ensure region edits maintain order). The extra info added here is 043 * not 'serialized' as part of the WALEdit hence marked 'transient' to underline this fact. It also 044 * adds mechanism so we can wait on the assign of the region sequence id. See 045 * #stampRegionSequenceId(). 046 */ 047@InterfaceAudience.Private 048class FSWALEntry extends Entry { 049 // The below data members are denoted 'transient' just to highlight these are not persisted; 050 // they are only in memory and held here while passing over the ring buffer. 051 private final transient long txid; 052 053 /** 054 * If false, means this is a meta edit written by the hbase system itself. It was not in memstore. 055 * HBase uses these edit types to note in the log operational transitions such as compactions, 056 * flushes, or region open/closes. 057 */ 058 private final transient boolean inMemstore; 059 060 /** 061 * Set if this is a meta edit and it is of close region type. 062 */ 063 private final transient boolean closeRegion; 064 065 private final transient RegionInfo regionInfo; 066 private final transient Set<byte[]> familyNames; 067 private final transient ServerCall<?> rpcCall; 068 069 /** 070 * @param inMemstore If true, then this is a data edit, one that came from client. If false, it is 071 * a meta edit made by the hbase system itself and is for the WAL only. 072 */ 073 FSWALEntry(final long txid, final WALKeyImpl key, final WALEdit edit, final RegionInfo regionInfo, 074 final boolean inMemstore, ServerCall<?> rpcCall) { 075 super(key, edit); 076 this.inMemstore = inMemstore; 077 this.closeRegion = !inMemstore && edit.isRegionCloseMarker(); 078 this.regionInfo = regionInfo; 079 this.txid = txid; 080 if (inMemstore) { 081 // construct familyNames here to reduce the work of log sinker. 082 Set<byte[]> families = edit.getFamilies(); 083 this.familyNames = families != null ? families : collectFamilies(edit.getCells()); 084 } else { 085 this.familyNames = Collections.emptySet(); 086 } 087 this.rpcCall = rpcCall; 088 if (rpcCall != null) { 089 rpcCall.retainByWAL(); 090 } 091 } 092 093 static Set<byte[]> collectFamilies(List<Cell> cells) { 094 if (CollectionUtils.isEmpty(cells)) { 095 return Collections.emptySet(); 096 } else { 097 Set<byte[]> set = new TreeSet<>(Bytes.BYTES_COMPARATOR); 098 for (Cell cell : cells) { 099 if (!WALEdit.isMetaEditFamily(cell)) { 100 set.add(CellUtil.cloneFamily(cell)); 101 } 102 } 103 return set; 104 } 105 } 106 107 @Override 108 public String toString() { 109 return "sequence=" + this.txid + ", " + super.toString(); 110 } 111 112 boolean isInMemStore() { 113 return this.inMemstore; 114 } 115 116 boolean isCloseRegion() { 117 return closeRegion; 118 } 119 120 RegionInfo getRegionInfo() { 121 return this.regionInfo; 122 } 123 124 /** Returns The transaction id of this edit. */ 125 long getTxid() { 126 return this.txid; 127 } 128 129 /** 130 * Here is where a WAL edit gets its sequenceid. SIDE-EFFECT is our stamping the sequenceid into 131 * every Cell AND setting the sequenceid into the MVCC WriteEntry!!!! 132 * @return The sequenceid we stamped on this edit. 133 */ 134 long stampRegionSequenceId(MultiVersionConcurrencyControl.WriteEntry we) throws IOException { 135 long regionSequenceId = we.getWriteNumber(); 136 if (!this.getEdit().isReplay() && inMemstore) { 137 for (Cell c : getEdit().getCells()) { 138 PrivateCellUtil.setSequenceId(c, regionSequenceId); 139 } 140 } 141 142 getKey().setWriteEntry(we); 143 return regionSequenceId; 144 } 145 146 /** Returns the family names which are effected by this edit. */ 147 Set<byte[]> getFamilyNames() { 148 return familyNames; 149 } 150 151 void release() { 152 if (rpcCall != null) { 153 rpcCall.releaseByWAL(); 154 } 155 } 156}