[
https://issues.apache.org/jira/browse/HBASE-29111?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Duo Zhang resolved HBASE-29111.
-------------------------------
Fix Version/s: 2.7.0
3.0.0-beta-2
2.6.2
2.5.12
Hadoop Flags: Reviewed
Resolution: Fixed
Pushed to all active branches.
Thanks [~junegunn] for contributing!
> Data loss in table cloned from a snapshot
> -----------------------------------------
>
> Key: HBASE-29111
> URL: https://issues.apache.org/jira/browse/HBASE-29111
> Project: HBase
> Issue Type: Bug
> Components: dataloss, snapshots
> Reporter: Junegunn Choi
> Assignee: Junegunn Choi
> Priority: Major
> Labels: pull-request-available
> Fix For: 2.7.0, 3.0.0-beta-2, 2.6.2, 2.5.12
>
>
> We experienced permanent data loss in a table cloned from a snapshot.
> Here's what we found.
> * If you clone a table from a snapshot that contains split regions and
> reference files, and immediately delete the snapshot, HBase can prematurely
> delete the original HFiles causing data loss.
> h2. How to reproduce
> To quickly reproduce the issue, adjust the cleaner and janitor intervals and
> set HFile TTL to zero. Also disable compaction so that reference files are
> not compacted away. Or, you can put a lot of data so that compaction doesn't
> finish during the test.
> {code:java}
> <property>
> <name>hbase.master.cleaner.interval</name>
> <value>1000</value>
> </property>
> <property>
> <name>hbase.catalogjanitor.interval</name>
> <value>1000</value>
> </property>
> <property>
> <name>hbase.master.hfilecleaner.ttl</name>
> <value>0</value>
> </property>
> <property>
> <name>hbase.regionserver.compaction.enabled</name>
> <value>false</value>
> </property>
> {code}
> And run this code on HBase shell.
> {code:java}
> # Create test table and write some data
> create 't', 'd'
> 10.times do |i|
> put 't', i, 'd:foo', '_' * 1024
> end
> # Split in the middle and take the snapshot
> split 't', '5'
> snapshot 't', 's'
> # Drop the table and clone it from the snapshot
> disable 't'
> drop 't'
> clone_snapshot 's', 't'
> # Immediately delete the snapshot
> delete_snapshot 's'
> # Try disabling and re-enabling the table
> sleep 2
> disable 't'
> enable 't'
> # java.io.FileNotFoundException: HFileLink locations=[...]
> {code}
> h2. What actually happens
> User clones a table from a snapshot containing split regions and reference
> files.
> {noformat}
> snapshot.RestoreSnapshotHelper: clone region=a23be88470c13611f6f24f20e0cf00ed
> as a23be88470c13611f6f24f20e0cf00ed in snapshot s
> ...
> regionserver.HRegion: creating {ENCODED => a23be88470c13611f6f24f20e0cf00ed,
> NAME => 't,40000000,1738562472443.a23be88470c13611f6f24f20e0cf00ed.',
> STARTKEY => '40000000', ENDKEY => '80000000', OFFLINE => true, SPLIT =>
> true}, tableDescriptor='t', {TABLE_ATTRIBUTES => {METADATA =>
> {'hbase.store.file-tracker.impl' => 'DEFAULT'}}}, {NAME => 'd',
> INDEX_BLOCK_ENCODING => 'NONE', VERSIONS => '1', KEEP_DELETED_CELLS =>
> 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', MIN_VERSIONS =>
> '0', REPLICATION_SCOPE => '0', BLOOMFILTER => 'ROW', IN_MEMORY => 'false',
> COMPRESSION => 'NONE', BLOCKCACHE => 'true', BLOCKSIZE => '65536 B (64KB)'},
> regionDir=file:/Users/jg/github/hbase/tmp/hbase
> ...
> snapshot.RestoreSnapshotHelper: finishing restore table regions using
> snapshot=name: "s"
> {noformat}
> And the user deletes the snapshot.
> {noformat}
> snapshot.SnapshotManager: Deleting snapshot: s
> {noformat}
> After a while, CatalogJanitor garbage-collects the split parents as it sees
> no daughter information in the meta table.
> {noformat}
> janitor.CatalogJanitor: Cleaning parent region {ENCODED =>
> a23be88470c13611f6f24f20e0cf00ed, NAME =>
> 't,40000000,1738562472443.a23be88470c13611f6f24f20e0cf00ed.', STARTKEY =>
> '40000000', ENDKEY => '80000000', OFFLINE => true, SPLIT => true}
> janitor.CatalogJanitor: Deleting region a23be88470c13611f6f24f20e0cf00ed
> because daughters -- null, null -- no longer hold references
> {noformat}
> (see "{{{}null, null"{}}} part)
> This causes the HFileLinks to be archived.
> {noformat}
> backup.HFileArchiver: Archived from FileablePath,
> file:/Users/jg/github/hbase/tmp/hbase/data/default/t/a23be88470c13611f6f24f20e0cf00ed/d/t=a23be88470c13611f6f24f20e0cf00ed-ecdd6aa22a6146599467839c56767522
> to
> file:/Users/jg/github/hbase/tmp/hbase/archive/data/default/t/a23be88470c13611f6f24f20e0cf00ed/d/t=a23be88470c13611f6f24f20e0cf00ed-ecdd6aa22a6146599467839c56767522
> {noformat}
> And the cleaners unanimously agree to delete the original HFile.
> * We already deleted the snapshot, so SnapshotHFileCleaner won't complain.
> * Because HFileLink is archived, HFileLinkCleaner won't complain.
> And the HFile is deleted before the daughter regions succeed to rebuild the
> data in it through compaction.
> {noformat}
> cleaner.HFileCleaner: Removing
> file:/Users/jg/github/hbase/tmp/hbase/archive/data/default/t/a23be88470c13611f6f24f20e0cf00ed/d/ecdd6aa22a6146599467839c56767522
> {noformat}
> And the data loss.
> {noformat}
> regionserver.CompactSplit: Compaction selection failed
> region=t,6,1738562566034.8ad3785a3afe89e59b72db5d5d3a1bf5.,
> storeName=8ad3785a3afe89e59b72db5d5d3a1bf5/d, priority=14,
> startTime=1738562622689
> java.io.FileNotFoundException: HFileLink locations=[
>
> file:/Users/jg/github/hbase/tmp/hbase/data/default/t/a23be88470c13611f6f24f20e0cf00ed/d/ecdd6aa22a6146599467839c56767522,
>
> file:/Users/jg/github/hbase/tmp/hbase/archive/data/default/t/a23be88470c13611f6f24f20e0cf00ed/d/ecdd6aa22a6146599467839c56767522,
>
> file:/Users/jg/github/hbase/tmp/hbase/.tmp/data/default/t/a23be88470c13611f6f24f20e0cf00ed/d/ecdd6aa22a6146599467839c56767522,
>
> file:/Users/jg/github/hbase/tmp/hbase/mobdir/data/default/t/a23be88470c13611f6f24f20e0cf00ed/d/ecdd6aa22a6146599467839c56767522
> ]
> {noformat}
> h2. Fix
> Make sure to put the split information to the meta table when cloning a
> table. The information was already there, we just didn't use it.
> Let me open pull requests both on master and branch-2.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)