forked from OpenTSDB/asynchbase
/
GetRequest.java
292 lines (260 loc) · 10.3 KB
/
GetRequest.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
* Copyright (c) 2010, 2011 StumbleUpon, Inc. All rights reserved.
* This file is part of Async HBase.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the StumbleUpon nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.hbase.async;
import org.jboss.netty.buffer.ChannelBuffer;
/**
* Reads something from HBase.
*
* <h1>A note on passing {@code byte} arrays in argument</h1>
* None of the method that receive a {@code byte[]} in argument will copy it.
* For more info, please refer to the documentation of {@link HBaseRpc}.
* <h1>A note on passing {@code String}s in argument</h1>
* All strings are assumed to use the platform's default charset.
*/
public final class GetRequest extends HBaseRpc
implements HBaseRpc.HasTable, HBaseRpc.HasKey,
HBaseRpc.HasFamily, HBaseRpc.HasQualifiers {
private static final byte[] GET = new byte[] { 'g', 'e', 't' };
private static final byte[] EXISTS =
new byte[] { 'e', 'x', 'i', 's', 't', 's' };
private byte[] family; // TODO(tsuna): Handle multiple families?
private byte[][] qualifiers;
private long lockid = RowLock.NO_LOCK;
/**
* Constructor.
* <strong>These byte arrays will NOT be copied.</strong>
* @param table The non-empty name of the table to use.
* @param key The row key to get in that table.
*/
public GetRequest(final byte[] table, final byte[] key) {
super(GET, table, key);
}
/**
* Constructor.
* @param table The non-empty name of the table to use.
* @param key The row key to get in that table.
* <strong>This byte array will NOT be copied.</strong>
*/
public GetRequest(final String table, final byte[] key) {
this(table.getBytes(), key);
}
/**
* Constructor.
* @param table The non-empty name of the table to use.
* @param key The row key to get in that table.
*/
public GetRequest(final String table, final String key) {
this(table.getBytes(), key.getBytes());
}
/**
* Private constructor to build an "exists" RPC.
* @param unused Unused, simply used to help the compiler find this ctor.
* @param table The non-empty name of the table to use.
* @param key The row key to get in that table.
*/
private GetRequest(final float unused,
final byte[] table,
final byte[] key) {
super(EXISTS, table, key);
}
/**
* Package-private factory method to build an "exists" RPC.
* @param table The non-empty name of the table to use.
* @param key The row key to get in that table.
* @return An {@link HBaseRpc} that will return a {@link Boolean}
* indicating whether or not the given table / key exists.
*/
static HBaseRpc exists(final byte[] table, final byte[] key) {
return new GetRequest(0F, table, key);
}
/**
* Specifies a particular column family to get.
* @param family The column family.
* <strong>This byte array will NOT be copied.</strong>
* @return {@code this}, always.
*/
public GetRequest family(final byte[] family) {
KeyValue.checkFamily(family);
this.family = family;
return this;
}
/** Specifies a particular column family to get. */
public GetRequest family(final String family) {
return family(family.getBytes());
}
/**
* Specifies a particular column qualifier to get.
* @param qualifier The column qualifier.
* <strong>This byte array will NOT be copied.</strong>
* @return {@code this}, always.
*/
public GetRequest qualifier(final byte[] qualifier) {
if (qualifier == null) {
throw new NullPointerException("qualifier");
}
KeyValue.checkQualifier(qualifier);
this.qualifiers = new byte[][] { qualifier };
return this;
}
/**
* Specifies a particular set of column qualifiers to get.
* @param qualifiers The column qualifiers.
* <strong>This byte array will NOT be copied.</strong>
* @return {@code this}, always.
* @since 1.1
*/
public GetRequest qualifiers(final byte[][] qualifiers) {
if (qualifiers == null) {
throw new NullPointerException("qualifiers");
}
for (final byte[] qualifier : qualifiers) {
KeyValue.checkQualifier(qualifier);
}
this.qualifiers = qualifiers;
return this;
}
/** Specifies a particular column qualifier to get. */
public GetRequest qualifier(final String qualifier) {
return qualifier(qualifier.getBytes());
}
/** Specifies an explicit row lock to use with this request. */
public GetRequest withRowLock(final RowLock lock) {
lockid = lock.id();
return this;
}
@Override
public byte[] table() {
return table;
}
@Override
public byte[] key() {
return key;
}
@Override
public byte[] family() {
return family;
}
@Override
public byte[][] qualifiers() {
return qualifiers;
}
public String toString() {
final String klass = method() == GET ? "GetRequest" : "Exists";
return super.toStringWithQualifiers(klass, family, qualifiers);
}
// ---------------------- //
// Package private stuff. //
// ---------------------- //
boolean versionSensitive() {
return true; // Sad. HBASE-3174 broke backwards compatibilty!@#$%^ :(
}
/**
* Predicts a lower bound on the serialized size of this RPC.
* This is to avoid using a dynamic buffer, to avoid re-sizing the buffer.
* Since we use a static buffer, if the prediction is wrong and turns out
* to be less than what we need, there will be an exception which will
* prevent the RPC from being serialized. That'd be a severe bug.
*/
private int predictSerializedSize(final byte server_version) {
int size = 0;
size += 4; // int: Number of parameters.
size += 1; // byte: Type of the 1st parameter.
size += 3; // vint: region name length (3 bytes => max length = 32768).
size += region.name().length; // The region name.
size += 1; // byte: Type of the 2nd parameter.
size += 1; // byte: Type again (see HBASE-2877).
size += 1; // byte: Version of Get.
size += 3; // vint: row key length (3 bytes => max length = 32768).
size += key.length; // The row key.
size += 8; // long: Lock ID.
size += 4; // int: Max number of versions to return.
size += 1; // byte: Whether or not to use a filter.
if (server_version >= 26) { // New in 0.90 (because of HBASE-3174).
size += 1; // byte: Whether or not to cache the blocks read.
}
size += 8; // long: Minimum timestamp.
size += 8; // long: Maximum timestamp.
size += 1; // byte: Boolean: "all time".
size += 4; // int: Number of families.
if (family != null) {
size += 1; // vint: Family length (guaranteed on 1 byte).
size += family.length; // The family.
size += 1; // byte: Boolean: do we want specific qualifiers?
if (qualifiers != null) {
size += 4; // int: How many qualifiers follow?
for (final byte[] qualifier : qualifiers) {
size += 3; // vint: Qualifier length.
size += qualifier.length; // The qualifier.
}
}
}
return size;
}
/** Serializes this request. */
ChannelBuffer serialize(final byte server_version) {
final ChannelBuffer buf = newBuffer(predictSerializedSize(server_version));
buf.writeInt(2); // Number of parameters.
// 1st param: byte array containing region name
writeHBaseByteArray(buf, region.name());
// 2nd param: Get object
buf.writeByte(32); // Code for a `Get' parameter.
buf.writeByte(32); // Code again (see HBASE-2877).
buf.writeByte(1); // Get#GET_VERSION. Undocumented versioning of Get.
writeByteArray(buf, key);
buf.writeLong(lockid); // Lock ID.
buf.writeInt(1); // Max number of versions to return.
buf.writeByte(0x00); // boolean (false): whether or not to use a filter.
// If the previous boolean was true:
// writeByteArray(buf, filter name as byte array);
// write the filter itself
if (server_version >= 26) { // New in 0.90 (because of HBASE-3174).
buf.writeByte(0x01); // boolean (true): whether to cache the blocks.
}
// TimeRange
buf.writeLong(0); // Minimum timestamp.
buf.writeLong(Long.MAX_VALUE); // Maximum timestamp.
buf.writeByte(0x01); // Boolean: "all time".
// The "all time" boolean indicates whether or not this time range covers
// all possible times. Not sure why it's part of the serialized RPC...
// Families.
buf.writeInt(family != null ? 1 : 0); // Number of families that follow.
if (family != null) {
// Each family is then written like so:
writeByteArray(buf, family); // Column family name.
if (qualifiers != null) {
buf.writeByte(0x01); // Boolean: We want specific qualifiers.
buf.writeInt(qualifiers.length); // How many qualifiers do we want?
for (final byte[] qualifier : qualifiers) {
writeByteArray(buf, qualifier); // Column qualifier name.
}
} else {
buf.writeByte(0x00); // Boolean: we don't want specific qualifiers.
}
}
return buf;
}
}