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