1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.mapred;
20
21 import static org.apache.hadoop.hbase.mapreduce.TableRecordReaderImpl.LOG_PER_ROW_COUNT;
22
23 import java.io.IOException;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.hbase.classification.InterfaceAudience;
29 import org.apache.hadoop.hbase.classification.InterfaceStability;
30 import org.apache.hadoop.hbase.client.HTable;
31 import org.apache.hadoop.hbase.client.Result;
32 import org.apache.hadoop.hbase.client.ResultScanner;
33 import org.apache.hadoop.hbase.client.Scan;
34 import org.apache.hadoop.hbase.client.ScannerCallable;
35 import org.apache.hadoop.hbase.client.Table;
36 import org.apache.hadoop.hbase.DoNotRetryIOException;
37 import org.apache.hadoop.hbase.filter.Filter;
38 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
39 import org.apache.hadoop.hbase.mapreduce.TableInputFormat;
40 import org.apache.hadoop.hbase.util.Bytes;
41 import org.apache.hadoop.util.StringUtils;
42
43
44
45
46 @InterfaceAudience.Public
47 @InterfaceStability.Stable
48 public class TableRecordReaderImpl {
49 private static final Log LOG = LogFactory.getLog(TableRecordReaderImpl.class);
50
51 private byte [] startRow;
52 private byte [] endRow;
53 private byte [] lastSuccessfulRow;
54 private Filter trrRowFilter;
55 private ResultScanner scanner;
56 private Table htable;
57 private byte [][] trrInputColumns;
58 private long timestamp;
59 private int rowcount;
60 private boolean logScannerActivity = false;
61 private int logPerRowCount = 100;
62
63
64
65
66
67
68
69 public void restart(byte[] firstRow) throws IOException {
70 Scan currentScan;
71 if ((endRow != null) && (endRow.length > 0)) {
72 if (trrRowFilter != null) {
73 Scan scan = new Scan(firstRow, endRow);
74 TableInputFormat.addColumns(scan, trrInputColumns);
75 scan.setFilter(trrRowFilter);
76 scan.setCacheBlocks(false);
77 this.scanner = this.htable.getScanner(scan);
78 currentScan = scan;
79 } else {
80 LOG.debug("TIFB.restart, firstRow: " +
81 Bytes.toStringBinary(firstRow) + ", endRow: " +
82 Bytes.toStringBinary(endRow));
83 Scan scan = new Scan(firstRow, endRow);
84 TableInputFormat.addColumns(scan, trrInputColumns);
85 this.scanner = this.htable.getScanner(scan);
86 currentScan = scan;
87 }
88 } else {
89 LOG.debug("TIFB.restart, firstRow: " +
90 Bytes.toStringBinary(firstRow) + ", no endRow");
91
92 Scan scan = new Scan(firstRow);
93 TableInputFormat.addColumns(scan, trrInputColumns);
94 scan.setFilter(trrRowFilter);
95 this.scanner = this.htable.getScanner(scan);
96 currentScan = scan;
97 }
98 if (logScannerActivity) {
99 LOG.info("Current scan=" + currentScan.toString());
100 timestamp = System.currentTimeMillis();
101 rowcount = 0;
102 }
103 }
104
105
106
107
108
109
110 public void init() throws IOException {
111 restart(startRow);
112 }
113
114 byte[] getStartRow() {
115 return this.startRow;
116 }
117
118
119
120 public void setHTable(Table htable) {
121 Configuration conf = htable.getConfiguration();
122 logScannerActivity = conf.getBoolean(
123 ScannerCallable.LOG_SCANNER_ACTIVITY, false);
124 logPerRowCount = conf.getInt(LOG_PER_ROW_COUNT, 100);
125 this.htable = htable;
126 }
127
128
129
130
131
132 @Deprecated
133 public void setHTable(HTable htable) {
134 setHTable((Table)htable);
135 }
136
137
138
139
140 public void setInputColumns(final byte [][] inputColumns) {
141 this.trrInputColumns = inputColumns;
142 }
143
144
145
146
147 public void setStartRow(final byte [] startRow) {
148 this.startRow = startRow;
149 }
150
151
152
153
154
155 public void setEndRow(final byte [] endRow) {
156 this.endRow = endRow;
157 }
158
159
160
161
162 public void setRowFilter(Filter rowFilter) {
163 this.trrRowFilter = rowFilter;
164 }
165
166 public void close() {
167 this.scanner.close();
168 try {
169 this.htable.close();
170 } catch (IOException ioe) {
171 LOG.warn("Error closing table", ioe);
172 }
173 }
174
175
176
177
178
179
180 public ImmutableBytesWritable createKey() {
181 return new ImmutableBytesWritable();
182 }
183
184
185
186
187
188
189 public Result createValue() {
190 return new Result();
191 }
192
193 public long getPos() {
194
195
196 return 0;
197 }
198
199 public float getProgress() {
200
201 return 0;
202 }
203
204
205
206
207
208
209
210 public boolean next(ImmutableBytesWritable key, Result value)
211 throws IOException {
212 Result result;
213 try {
214 try {
215 result = this.scanner.next();
216 if (logScannerActivity) {
217 rowcount ++;
218 if (rowcount >= logPerRowCount) {
219 long now = System.currentTimeMillis();
220 LOG.info("Mapper took " + (now-timestamp)
221 + "ms to process " + rowcount + " rows");
222 timestamp = now;
223 rowcount = 0;
224 }
225 }
226 } catch (IOException e) {
227
228 if (e instanceof DoNotRetryIOException) {
229 throw e;
230 }
231
232
233 LOG.debug("recovered from " + StringUtils.stringifyException(e));
234 if (lastSuccessfulRow == null) {
235 LOG.warn("We are restarting the first next() invocation," +
236 " if your mapper has restarted a few other times like this" +
237 " then you should consider killing this job and investigate" +
238 " why it's taking so long.");
239 }
240 if (lastSuccessfulRow == null) {
241 restart(startRow);
242 } else {
243 restart(lastSuccessfulRow);
244 this.scanner.next();
245 }
246 result = this.scanner.next();
247 }
248
249 if (result != null && result.size() > 0) {
250 key.set(result.getRow());
251 lastSuccessfulRow = key.get();
252 value.copyFrom(result);
253 return true;
254 }
255 return false;
256 } catch (IOException ioe) {
257 if (logScannerActivity) {
258 long now = System.currentTimeMillis();
259 LOG.info("Mapper took " + (now-timestamp)
260 + "ms to process " + rowcount + " rows");
261 LOG.info(ioe);
262 String lastRow = lastSuccessfulRow == null ?
263 "null" : Bytes.toStringBinary(lastSuccessfulRow);
264 LOG.info("lastSuccessfulRow=" + lastRow);
265 }
266 throw ioe;
267 }
268 }
269 }