001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase.io; 020 021import java.io.BufferedInputStream; 022import java.io.DataInput; 023import java.io.DataInputStream; 024import java.io.IOException; 025import java.io.InputStream; 026import java.util.Arrays; 027 028import org.apache.yetus.audience.InterfaceAudience; 029import org.apache.hadoop.fs.FSDataOutputStream; 030import org.apache.hadoop.fs.FileSystem; 031import org.apache.hadoop.fs.Path; 032import org.apache.hadoop.hbase.KeyValueUtil; 033import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations; 034import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 035import org.apache.hadoop.hbase.shaded.protobuf.generated.FSProtos; 036import org.apache.hadoop.hbase.util.Bytes; 037 038/** 039 * A reference to the top or bottom half of a store file where 'bottom' is the first half 040 * of the file containing the keys that sort lowest and 'top' is the second half 041 * of the file with keys that sort greater than those of the bottom half. The file referenced 042 * lives under a different region. References are made at region split time. 043 * 044 * <p>References work with a special half store file type. References know how 045 * to write out the reference format in the file system and are what is juggled 046 * when references are mixed in with direct store files. The half store file 047 * type is used reading the referred to file. 048 * 049 * <p>References to store files located over in some other region look like 050 * this in the file system 051 * <code>1278437856009925445.3323223323</code>: 052 * i.e. an id followed by hash of the referenced region. 053 * Note, a region is itself not splittable if it has instances of store file 054 * references. References are cleaned up by compactions. 055 */ 056@InterfaceAudience.Private 057public class Reference { 058 private byte [] splitkey; 059 private Range region; 060 061 /** 062 * For split HStoreFiles, it specifies if the file covers the lower half or 063 * the upper half of the key range 064 */ 065 static enum Range { 066 /** HStoreFile contains upper half of key range */ 067 top, 068 /** HStoreFile contains lower half of key range */ 069 bottom 070 } 071 072 /** 073 * @param splitRow 074 * @return A {@link Reference} that points at top half of a an hfile 075 */ 076 public static Reference createTopReference(final byte [] splitRow) { 077 return new Reference(splitRow, Range.top); 078 } 079 080 /** 081 * @param splitRow 082 * @return A {@link Reference} that points at the bottom half of a an hfile 083 */ 084 public static Reference createBottomReference(final byte [] splitRow) { 085 return new Reference(splitRow, Range.bottom); 086 } 087 088 /** 089 * Constructor 090 * @param splitRow This is row we are splitting around. 091 * @param fr 092 */ 093 Reference(final byte [] splitRow, final Range fr) { 094 this.splitkey = splitRow == null? null: KeyValueUtil.createFirstOnRow(splitRow).getKey(); 095 this.region = fr; 096 } 097 098 /** 099 * Used by serializations. 100 * @deprecated need by pb serialization 101 */ 102 @Deprecated 103 // Make this private when it comes time to let go of this constructor. 104 // Needed by pb serialization. 105 public Reference() { 106 this(null, Range.bottom); 107 } 108 109 /** 110 * 111 * @return Range 112 */ 113 public Range getFileRegion() { 114 return this.region; 115 } 116 117 /** 118 * @return splitKey 119 */ 120 public byte [] getSplitKey() { 121 return splitkey; 122 } 123 124 /** 125 * @see java.lang.Object#toString() 126 */ 127 @Override 128 public String toString() { 129 return "" + this.region; 130 } 131 132 public static boolean isTopFileRegion(final Range r) { 133 return r.equals(Range.top); 134 } 135 136 /** 137 * @deprecated Writables are going away. Use the pb serialization methods instead. 138 * Remove in a release after 0.96 goes out. This is here only to migrate 139 * old Reference files written with Writables before 0.96. 140 */ 141 @Deprecated 142 public void readFields(DataInput in) throws IOException { 143 boolean tmp = in.readBoolean(); 144 // If true, set region to top. 145 this.region = tmp? Range.top: Range.bottom; 146 this.splitkey = Bytes.readByteArray(in); 147 } 148 149 public Path write(final FileSystem fs, final Path p) 150 throws IOException { 151 FSDataOutputStream out = fs.create(p, false); 152 try { 153 out.write(toByteArray()); 154 } finally { 155 out.close(); 156 } 157 return p; 158 } 159 160 /** 161 * Read a Reference from FileSystem. 162 * @param fs 163 * @param p 164 * @return New Reference made from passed <code>p</code> 165 * @throws IOException 166 */ 167 public static Reference read(final FileSystem fs, final Path p) 168 throws IOException { 169 InputStream in = fs.open(p); 170 try { 171 // I need to be able to move back in the stream if this is not a pb serialization so I can 172 // do the Writable decoding instead. 173 in = in.markSupported()? in: new BufferedInputStream(in); 174 int pblen = ProtobufUtil.lengthOfPBMagic(); 175 in.mark(pblen); 176 byte [] pbuf = new byte[pblen]; 177 int read = in.read(pbuf); 178 if (read != pblen) throw new IOException("read=" + read + ", wanted=" + pblen); 179 // WATCHOUT! Return in middle of function!!! 180 if (ProtobufUtil.isPBMagicPrefix(pbuf)) return convert(FSProtos.Reference.parseFrom(in)); 181 // Else presume Writables. Need to reset the stream since it didn't start w/ pb. 182 // We won't bother rewriting thie Reference as a pb since Reference is transitory. 183 in.reset(); 184 Reference r = new Reference(); 185 DataInputStream dis = new DataInputStream(in); 186 // Set in = dis so it gets the close below in the finally on our way out. 187 in = dis; 188 r.readFields(dis); 189 return r; 190 } finally { 191 in.close(); 192 } 193 } 194 195 public FSProtos.Reference convert() { 196 FSProtos.Reference.Builder builder = FSProtos.Reference.newBuilder(); 197 builder.setRange(isTopFileRegion(getFileRegion())? 198 FSProtos.Reference.Range.TOP: FSProtos.Reference.Range.BOTTOM); 199 builder.setSplitkey(UnsafeByteOperations.unsafeWrap(getSplitKey())); 200 return builder.build(); 201 } 202 203 public static Reference convert(final FSProtos.Reference r) { 204 Reference result = new Reference(); 205 result.splitkey = r.getSplitkey().toByteArray(); 206 result.region = r.getRange() == FSProtos.Reference.Range.TOP? Range.top: Range.bottom; 207 return result; 208 } 209 210 /** 211 * Use this when writing to a stream and you want to use the pb mergeDelimitedFrom 212 * (w/o the delimiter, pb reads to EOF which may not be what you want). 213 * @return This instance serialized as a delimited protobuf w/ a magic pb prefix. 214 * @throws IOException 215 */ 216 byte [] toByteArray() throws IOException { 217 return ProtobufUtil.prependPBMagic(convert().toByteArray()); 218 } 219 220 @Override 221 public int hashCode() { 222 return Arrays.hashCode(splitkey) + region.hashCode(); 223 } 224 225 @Override 226 public boolean equals(Object o) { 227 if (this == o) return true; 228 if (o == null) return false; 229 if (!(o instanceof Reference)) return false; 230 231 Reference r = (Reference) o; 232 if (splitkey != null && r.splitkey == null) return false; 233 if (splitkey == null && r.splitkey != null) return false; 234 if (splitkey != null && !Arrays.equals(splitkey, r.splitkey)) return false; 235 236 return region.equals(r.region); 237 } 238}