37
37
import org .apache .hadoop .conf .Configuration ;
38
38
import org .apache .hadoop .fs .Path ;
39
39
import org .apache .hadoop .hbase .CellComparator ;
40
+ import org .apache .hadoop .hbase .ExtendedCell ;
41
+ import org .apache .hadoop .hbase .KeyValue ;
40
42
import org .apache .hadoop .hbase .io .hfile .BloomFilterMetrics ;
41
43
import org .apache .hadoop .hbase .log .HBaseMarkers ;
42
44
import org .apache .hadoop .hbase .regionserver .compactions .CompactionContext ;
@@ -96,6 +98,9 @@ public abstract class StoreEngine<SF extends StoreFlusher, CP extends Compaction
96
98
97
99
private static final Logger LOG = LoggerFactory .getLogger (StoreEngine .class );
98
100
101
+ private static final String READ_FULLY_ON_VALIDATE_KEY = "hbase.hstore.validate.read_fully" ;
102
+ private static final boolean DEFAULT_READ_FULLY_ON_VALIDATE = false ;
103
+
99
104
protected SF storeFlusher ;
100
105
protected CP compactionPolicy ;
101
106
protected C compactor ;
@@ -163,7 +168,7 @@ public StoreFileManager getStoreFileManager() {
163
168
}
164
169
165
170
/** Returns Store flusher to use. */
166
- public StoreFlusher getStoreFlusher () {
171
+ StoreFlusher getStoreFlusher () {
167
172
return this .storeFlusher ;
168
173
}
169
174
@@ -202,7 +207,7 @@ protected final void createComponentsOnce(Configuration conf, HStore store,
202
207
this .openStoreFileThreadPoolCreator = store .getHRegion ()::getStoreFileOpenAndCloseThreadPool ;
203
208
this .storeFileTracker = createStoreFileTracker (conf , store );
204
209
assert compactor != null && compactionPolicy != null && storeFileManager != null
205
- && storeFlusher != null && storeFileTracker != null ;
210
+ && storeFlusher != null ;
206
211
}
207
212
208
213
/**
@@ -229,12 +234,34 @@ public HStoreFile createStoreFileAndReader(StoreFileInfo info) throws IOExceptio
229
234
/**
230
235
* Validates a store file by opening and closing it. In HFileV2 this should not be an expensive
231
236
* operation.
232
- * @param path the path to the store file
237
+ * @param path the path to the store file
238
+ * @param isCompaction whether this is called from the context of a compaction
233
239
*/
234
- public void validateStoreFile (Path path ) throws IOException {
240
+ public void validateStoreFile (Path path , boolean isCompaction ) throws IOException {
235
241
HStoreFile storeFile = null ;
236
242
try {
237
243
storeFile = createStoreFileAndReader (path );
244
+ if (conf .getBoolean (READ_FULLY_ON_VALIDATE_KEY , DEFAULT_READ_FULLY_ON_VALIDATE )) {
245
+ if (storeFile .getFirstKey ().isEmpty ()) {
246
+ LOG .debug ("'{}=true' but storefile does not contain any data. skipping validation." ,
247
+ READ_FULLY_ON_VALIDATE_KEY );
248
+ return ;
249
+ }
250
+ LOG .debug ("Validating the store file by reading the first cell from each block : {}" , path );
251
+ StoreFileReader reader = storeFile .getReader ();
252
+ try (StoreFileScanner scanner =
253
+ reader .getStoreFileScanner (false , false , isCompaction , Long .MAX_VALUE , 0 , false )) {
254
+ boolean hasNext = scanner .seek (KeyValue .LOWESTKEY );
255
+ assert hasNext : "StoreFile contains no data" ;
256
+ for (ExtendedCell cell = scanner .next (); cell != null ; cell = scanner .next ()) {
257
+ ExtendedCell nextIndexedKey = scanner .getNextIndexedKey ();
258
+ if (nextIndexedKey == null ) {
259
+ break ;
260
+ }
261
+ scanner .seek (nextIndexedKey );
262
+ }
263
+ }
264
+ }
238
265
} catch (IOException e ) {
239
266
LOG .error ("Failed to open store file : {}, keeping it in tmp location" , path , e );
240
267
throw e ;
@@ -294,8 +321,7 @@ private List<HStoreFile> openStoreFiles(Collection<StoreFileInfo> files, boolean
294
321
}
295
322
if (ioe != null ) {
296
323
// close StoreFile readers
297
- boolean evictOnClose =
298
- ctx .getCacheConf () != null ? ctx .getCacheConf ().shouldEvictOnClose () : true ;
324
+ boolean evictOnClose = ctx .getCacheConf () == null || ctx .getCacheConf ().shouldEvictOnClose ();
299
325
for (HStoreFile file : results ) {
300
326
try {
301
327
if (file != null ) {
@@ -315,10 +341,8 @@ private List<HStoreFile> openStoreFiles(Collection<StoreFileInfo> files, boolean
315
341
for (HStoreFile storeFile : results ) {
316
342
if (compactedStoreFiles .contains (storeFile .getPath ().getName ())) {
317
343
LOG .warn ("Clearing the compacted storefile {} from {}" , storeFile , this );
318
- storeFile .getReader ()
319
- .close (storeFile .getCacheConf () != null
320
- ? storeFile .getCacheConf ().shouldEvictOnClose ()
321
- : true );
344
+ storeFile .getReader ().close (
345
+ storeFile .getCacheConf () == null || storeFile .getCacheConf ().shouldEvictOnClose ());
322
346
filesToRemove .add (storeFile );
323
347
}
324
348
}
@@ -380,7 +404,7 @@ private void refreshStoreFilesInternal(Collection<StoreFileInfo> newFiles) throw
380
404
compactedFilesSet .put (sf .getFileInfo (), sf );
381
405
}
382
406
383
- Set <StoreFileInfo > newFilesSet = new HashSet <StoreFileInfo >(newFiles );
407
+ Set <StoreFileInfo > newFilesSet = new HashSet <>(newFiles );
384
408
// Exclude the files that have already been compacted
385
409
newFilesSet = Sets .difference (newFilesSet , compactedFilesSet .keySet ());
386
410
Set <StoreFileInfo > toBeAddedFiles = Sets .difference (newFilesSet , currentFilesSet .keySet ());
@@ -390,8 +414,8 @@ private void refreshStoreFilesInternal(Collection<StoreFileInfo> newFiles) throw
390
414
return ;
391
415
}
392
416
393
- LOG .info ("Refreshing store files for " + this + " files to add: " + toBeAddedFiles
394
- + " files to remove: " + toBeRemovedFiles );
417
+ LOG .info ("Refreshing store files for {} files to add: {} files to remove: {}" , this ,
418
+ toBeAddedFiles , toBeRemovedFiles );
395
419
396
420
Set <HStoreFile > toBeRemovedStoreFiles = new HashSet <>(toBeRemovedFiles .size ());
397
421
for (StoreFileInfo sfi : toBeRemovedFiles ) {
@@ -401,7 +425,7 @@ private void refreshStoreFilesInternal(Collection<StoreFileInfo> newFiles) throw
401
425
// try to open the files
402
426
List <HStoreFile > openedFiles = openStoreFiles (toBeAddedFiles , false );
403
427
404
- // propogate the file changes to the underlying store file manager
428
+ // propagate the file changes to the underlying store file manager
405
429
replaceStoreFiles (toBeRemovedStoreFiles , openedFiles , () -> {
406
430
}, () -> {
407
431
}); // won't throw an exception
@@ -411,25 +435,27 @@ private void refreshStoreFilesInternal(Collection<StoreFileInfo> newFiles) throw
411
435
* Commit the given {@code files}.
412
436
* <p/>
413
437
* We will move the file into data directory, and open it.
414
- * @param files the files want to commit
415
- * @param validate whether to validate the store files
438
+ * @param files the files want to commit
439
+ * @param isCompaction whether this is called from the context of a compaction
440
+ * @param validate whether to validate the store files
416
441
* @return the committed store files
417
442
*/
418
- public List <HStoreFile > commitStoreFiles (List <Path > files , boolean validate ) throws IOException {
443
+ public List <HStoreFile > commitStoreFiles (List <Path > files , boolean isCompaction , boolean validate )
444
+ throws IOException {
419
445
List <HStoreFile > committedFiles = new ArrayList <>(files .size ());
420
446
HRegionFileSystem hfs = ctx .getRegionFileSystem ();
421
447
String familyName = ctx .getFamily ().getNameAsString ();
422
448
Path storeDir = hfs .getStoreDir (familyName );
423
449
for (Path file : files ) {
424
450
try {
425
451
if (validate ) {
426
- validateStoreFile (file );
452
+ validateStoreFile (file , isCompaction );
427
453
}
428
454
Path committedPath ;
429
455
// As we want to support writing to data directory directly, here we need to check whether
430
456
// the store file is already in the right place
431
457
if (file .getParent () != null && file .getParent ().equals (storeDir )) {
432
- // already in the right place, skip renmaing
458
+ // already in the right place, skip renaming
433
459
committedPath = file ;
434
460
} else {
435
461
// Write-out finished successfully, move into the right spot
0 commit comments