@nxtedition/rocksdb 10.1.5 → 10.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/binding.cc +5 -7
- package/deps/rocksdb/rocksdb/CMakeLists.txt +16 -5
- package/deps/rocksdb/rocksdb/Makefile +38 -15
- package/deps/rocksdb/rocksdb/TARGETS +10 -0
- package/deps/rocksdb/rocksdb/cache/cache_test.cc +58 -0
- package/deps/rocksdb/rocksdb/db/arena_wrapped_db_iter.cc +4 -4
- package/deps/rocksdb/rocksdb/db/arena_wrapped_db_iter.h +4 -2
- package/deps/rocksdb/rocksdb/db/builder.cc +2 -2
- package/deps/rocksdb/rocksdb/db/builder.h +1 -1
- package/deps/rocksdb/rocksdb/db/c.cc +205 -6
- package/deps/rocksdb/rocksdb/db/c_test.c +189 -1
- package/deps/rocksdb/rocksdb/db/column_family.cc +28 -0
- package/deps/rocksdb/rocksdb/db/column_family.h +17 -0
- package/deps/rocksdb/rocksdb/db/column_family_test.cc +234 -60
- package/deps/rocksdb/rocksdb/db/compaction/compaction.cc +8 -1
- package/deps/rocksdb/rocksdb/db/compaction/compaction.h +11 -9
- package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.cc +4 -4
- package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator.h +2 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_iterator_test.cc +1 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job.cc +22 -25
- package/deps/rocksdb/rocksdb/db/compaction/compaction_job.h +2 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_test.cc +112 -0
- package/deps/rocksdb/rocksdb/db/compaction/compaction_picker_universal.cc +72 -21
- package/deps/rocksdb/rocksdb/db/compaction/compaction_service_job.cc +2 -0
- package/deps/rocksdb/rocksdb/db/compaction/tiered_compaction_test.cc +77 -0
- package/deps/rocksdb/rocksdb/db/convenience.cc +3 -0
- package/deps/rocksdb/rocksdb/db/db_block_cache_test.cc +269 -112
- package/deps/rocksdb/rocksdb/db/db_bloom_filter_test.cc +107 -43
- package/deps/rocksdb/rocksdb/db/db_filesnapshot.cc +93 -24
- package/deps/rocksdb/rocksdb/db/db_flush_test.cc +5 -5
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.cc +157 -68
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl.h +56 -15
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_compaction_flush.cc +78 -105
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_files.cc +39 -9
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_follower.cc +1 -0
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_open.cc +21 -14
- package/deps/rocksdb/rocksdb/db/db_impl/db_impl_write.cc +107 -63
- package/deps/rocksdb/rocksdb/db/db_properties_test.cc +43 -2
- package/deps/rocksdb/rocksdb/db/db_range_del_test.cc +4 -0
- package/deps/rocksdb/rocksdb/db/db_rate_limiter_test.cc +6 -0
- package/deps/rocksdb/rocksdb/db/db_test.cc +10 -2
- package/deps/rocksdb/rocksdb/db/db_test2.cc +1 -1
- package/deps/rocksdb/rocksdb/db/db_test_util.cc +5 -0
- package/deps/rocksdb/rocksdb/db/db_test_util.h +7 -6
- package/deps/rocksdb/rocksdb/db/db_wal_test.cc +92 -2
- package/deps/rocksdb/rocksdb/db/error_handler.cc +34 -39
- package/deps/rocksdb/rocksdb/db/error_handler.h +3 -4
- package/deps/rocksdb/rocksdb/db/error_handler_fs_test.cc +8 -4
- package/deps/rocksdb/rocksdb/db/event_helpers.cc +6 -3
- package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc +71 -15
- package/deps/rocksdb/rocksdb/db/external_sst_file_ingestion_job.h +11 -0
- package/deps/rocksdb/rocksdb/db/external_sst_file_test.cc +383 -4
- package/deps/rocksdb/rocksdb/db/fault_injection_test.cc +88 -72
- package/deps/rocksdb/rocksdb/db/flush_job.cc +30 -3
- package/deps/rocksdb/rocksdb/db/flush_job.h +14 -0
- package/deps/rocksdb/rocksdb/db/internal_stats.cc +60 -1
- package/deps/rocksdb/rocksdb/db/internal_stats.h +20 -1
- package/deps/rocksdb/rocksdb/db/log_writer.cc +24 -0
- package/deps/rocksdb/rocksdb/db/log_writer.h +5 -0
- package/deps/rocksdb/rocksdb/db/memtable.cc +6 -4
- package/deps/rocksdb/rocksdb/db/memtable.h +10 -10
- package/deps/rocksdb/rocksdb/db/memtable_list.cc +4 -4
- package/deps/rocksdb/rocksdb/db/multi_cf_iterator_impl.h +10 -3
- package/deps/rocksdb/rocksdb/db/range_tombstone_fragmenter.h +8 -10
- package/deps/rocksdb/rocksdb/db/repair.cc +4 -3
- package/deps/rocksdb/rocksdb/db/seqno_to_time_mapping.cc +30 -0
- package/deps/rocksdb/rocksdb/db/seqno_to_time_mapping.h +9 -0
- package/deps/rocksdb/rocksdb/db/table_cache.cc +17 -2
- package/deps/rocksdb/rocksdb/db/table_cache.h +9 -1
- package/deps/rocksdb/rocksdb/db/table_properties_collector.h +9 -2
- package/deps/rocksdb/rocksdb/db/table_properties_collector_test.cc +3 -1
- package/deps/rocksdb/rocksdb/db/transaction_log_impl.cc +3 -3
- package/deps/rocksdb/rocksdb/db/transaction_log_impl.h +7 -7
- package/deps/rocksdb/rocksdb/db/version_edit.cc +0 -1
- package/deps/rocksdb/rocksdb/db/version_edit_handler.h +7 -6
- package/deps/rocksdb/rocksdb/db/version_set.cc +54 -31
- package/deps/rocksdb/rocksdb/db/version_set.h +14 -7
- package/deps/rocksdb/rocksdb/db/wal_manager.cc +37 -29
- package/deps/rocksdb/rocksdb/db/wal_manager.h +6 -5
- package/deps/rocksdb/rocksdb/db/wide/wide_columns_helper.cc +6 -0
- package/deps/rocksdb/rocksdb/db/write_batch.cc +54 -23
- package/deps/rocksdb/rocksdb/db/write_callback_test.cc +46 -5
- package/deps/rocksdb/rocksdb/db/write_thread.cc +53 -5
- package/deps/rocksdb/rocksdb/db/write_thread.h +36 -4
- package/deps/rocksdb/rocksdb/db_stress_tool/CMakeLists.txt +1 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/batched_ops_stress.cc +5 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/cf_consistency_stress.cc +57 -17
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.cc +11 -3
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_common.h +8 -4
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_driver.cc +10 -25
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_env_wrapper.h +25 -88
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_filters.cc +93 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_filters.h +16 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_gflags.cc +43 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_listener.h +109 -21
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_shared_state.h +8 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.cc +666 -205
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_test_base.h +55 -10
- package/deps/rocksdb/rocksdb/db_stress_tool/db_stress_tool.cc +18 -16
- package/deps/rocksdb/rocksdb/db_stress_tool/multi_ops_txns_stress.cc +19 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/multi_ops_txns_stress.h +5 -0
- package/deps/rocksdb/rocksdb/db_stress_tool/no_batched_ops_stress.cc +782 -494
- package/deps/rocksdb/rocksdb/env/composite_env_wrapper.h +21 -0
- package/deps/rocksdb/rocksdb/env/env.cc +6 -0
- package/deps/rocksdb/rocksdb/env/io_posix.cc +0 -1
- package/deps/rocksdb/rocksdb/file/file_util.cc +8 -2
- package/deps/rocksdb/rocksdb/file/prefetch_test.cc +34 -19
- package/deps/rocksdb/rocksdb/file/writable_file_writer.cc +29 -32
- package/deps/rocksdb/rocksdb/file/writable_file_writer.h +41 -15
- package/deps/rocksdb/rocksdb/include/rocksdb/advanced_options.h +4 -2
- package/deps/rocksdb/rocksdb/include/rocksdb/c.h +63 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/db.h +16 -5
- package/deps/rocksdb/rocksdb/include/rocksdb/env.h +5 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/iterator.h +0 -16
- package/deps/rocksdb/rocksdb/include/rocksdb/iterator_base.h +16 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/listener.h +21 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/options.h +76 -3
- package/deps/rocksdb/rocksdb/include/rocksdb/table_properties.h +17 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/transaction_log.h +12 -6
- package/deps/rocksdb/rocksdb/include/rocksdb/universal_compaction.h +31 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/user_write_callback.h +29 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/checkpoint.h +4 -2
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/customizable_util.h +0 -1
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/ldb_cmd.h +17 -8
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/stackable_db.h +2 -2
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/table_properties_collectors.h +46 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/utilities/transaction.h +7 -0
- package/deps/rocksdb/rocksdb/include/rocksdb/version.h +2 -2
- package/deps/rocksdb/rocksdb/options/cf_options.cc +13 -2
- package/deps/rocksdb/rocksdb/options/cf_options.h +6 -2
- package/deps/rocksdb/rocksdb/options/db_options.cc +8 -0
- package/deps/rocksdb/rocksdb/options/db_options.h +9 -5
- package/deps/rocksdb/rocksdb/options/options.cc +3 -0
- package/deps/rocksdb/rocksdb/options/options_helper.cc +1 -0
- package/deps/rocksdb/rocksdb/options/options_settable_test.cc +3 -1
- package/deps/rocksdb/rocksdb/port/jemalloc_helper.h +2 -2
- package/deps/rocksdb/rocksdb/port/stack_trace.cc +1 -0
- package/deps/rocksdb/rocksdb/port/win/port_win.cc +3 -2
- package/deps/rocksdb/rocksdb/src.mk +4 -0
- package/deps/rocksdb/rocksdb/table/block_based/binary_search_index_reader.cc +1 -2
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_builder.cc +4 -2
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_iterator.cc +15 -0
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.cc +102 -41
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader.h +15 -7
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_impl.h +1 -3
- package/deps/rocksdb/rocksdb/table/block_based/block_based_table_reader_sync_and_async.h +5 -6
- package/deps/rocksdb/rocksdb/table/block_based/block_cache.h +31 -0
- package/deps/rocksdb/rocksdb/table/block_based/block_prefetcher.cc +6 -0
- package/deps/rocksdb/rocksdb/table/block_based/cachable_entry.h +10 -5
- package/deps/rocksdb/rocksdb/table/block_based/filter_block.h +11 -15
- package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.cc +17 -11
- package/deps/rocksdb/rocksdb/table/block_based/filter_block_reader_common.h +5 -2
- package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.cc +28 -21
- package/deps/rocksdb/rocksdb/table/block_based/full_filter_block.h +9 -11
- package/deps/rocksdb/rocksdb/table/block_based/full_filter_block_test.cc +16 -16
- package/deps/rocksdb/rocksdb/table/block_based/hash_index_reader.cc +1 -2
- package/deps/rocksdb/rocksdb/table/block_based/index_reader_common.cc +14 -9
- package/deps/rocksdb/rocksdb/table/block_based/index_reader_common.h +4 -1
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.cc +82 -41
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block.h +13 -14
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_filter_block_test.cc +18 -22
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_index_reader.cc +51 -13
- package/deps/rocksdb/rocksdb/table/block_based/partitioned_index_reader.h +2 -0
- package/deps/rocksdb/rocksdb/table/block_based/uncompression_dict_reader.cc +3 -11
- package/deps/rocksdb/rocksdb/table/block_based/uncompression_dict_reader.h +2 -3
- package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.cc +9 -10
- package/deps/rocksdb/rocksdb/table/compaction_merging_iterator.h +3 -2
- package/deps/rocksdb/rocksdb/table/format.cc +1 -2
- package/deps/rocksdb/rocksdb/table/merging_iterator.cc +18 -13
- package/deps/rocksdb/rocksdb/table/merging_iterator.h +5 -3
- package/deps/rocksdb/rocksdb/table/plain/plain_table_builder.cc +2 -2
- package/deps/rocksdb/rocksdb/table/sst_file_reader.cc +1 -1
- package/deps/rocksdb/rocksdb/table/sst_file_writer_collectors.h +3 -1
- package/deps/rocksdb/rocksdb/table/table_builder.h +8 -7
- package/deps/rocksdb/rocksdb/table/table_reader.h +9 -0
- package/deps/rocksdb/rocksdb/test_util/testutil.cc +1 -0
- package/deps/rocksdb/rocksdb/test_util/testutil.h +6 -0
- package/deps/rocksdb/rocksdb/tools/db_bench_tool.cc +19 -0
- package/deps/rocksdb/rocksdb/tools/ldb_cmd.cc +434 -110
- package/deps/rocksdb/rocksdb/tools/ldb_cmd_impl.h +3 -1
- package/deps/rocksdb/rocksdb/tools/ldb_tool.cc +3 -0
- package/deps/rocksdb/rocksdb/util/aligned_storage.h +24 -0
- package/deps/rocksdb/rocksdb/util/filter_bench.cc +1 -1
- package/deps/rocksdb/rocksdb/util/random.cc +2 -1
- package/deps/rocksdb/rocksdb/util/stderr_logger.h +1 -1
- package/deps/rocksdb/rocksdb/util/udt_util.cc +33 -0
- package/deps/rocksdb/rocksdb/util/udt_util.h +7 -0
- package/deps/rocksdb/rocksdb/util/udt_util_test.cc +33 -0
- package/deps/rocksdb/rocksdb/util/write_batch_util.h +5 -0
- package/deps/rocksdb/rocksdb/util/xxhash.h +10 -3
- package/deps/rocksdb/rocksdb/utilities/backup/backup_engine_test.cc +13 -13
- package/deps/rocksdb/rocksdb/utilities/checkpoint/checkpoint_test.cc +104 -48
- package/deps/rocksdb/rocksdb/utilities/debug.cc +16 -4
- package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.cc +647 -235
- package/deps/rocksdb/rocksdb/utilities/fault_injection_fs.h +274 -157
- package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_for_tiering_collector.cc +144 -0
- package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_for_tiering_collector.h +45 -0
- package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_for_tiering_collector_test.cc +139 -0
- package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_on_deletion_collector.cc +12 -0
- package/deps/rocksdb/rocksdb/utilities/table_properties_collectors/compact_on_deletion_collector_test.cc +3 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/optimistic_transaction_test.cc +105 -6
- package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.cc +64 -8
- package/deps/rocksdb/rocksdb/utilities/transactions/pessimistic_transaction.h +5 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.cc +43 -5
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_base.h +5 -0
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.cc +154 -6
- package/deps/rocksdb/rocksdb/utilities/transactions/transaction_test.h +1 -1
- package/deps/rocksdb/rocksdb/utilities/transactions/write_committed_transaction_ts_test.cc +158 -2
- package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn.cc +16 -11
- package/deps/rocksdb/rocksdb/utilities/transactions/write_prepared_txn_db.cc +4 -4
- package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn.cc +9 -8
- package/deps/rocksdb/rocksdb/utilities/transactions/write_unprepared_txn_db.cc +2 -1
- package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index.cc +43 -7
- package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index_internal.cc +2 -0
- package/deps/rocksdb/rocksdb/utilities/write_batch_with_index/write_batch_with_index_internal.h +1 -1
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/@nxtedition+rocksdb.node +0 -0
- package/.tap/test-results/node_modules/abstract-level/test/chained-batch-test.js.tap +0 -0
- package/.tap/test-results/node_modules/abstract-level/test/get-test.js.tap +0 -0
- package/.tap/test-results/test/abstract-level-test.js.tap +0 -1077
- package/.tap/test-results/test/batch-test.js.tap +0 -12
- package/.tap/test-results/test/chained-batch-gc-test.js.tap +0 -11
- package/.tap/test-results/test/cleanup-hanging-iterators-test.js.tap +0 -135
- package/.tap/test-results/test/clear-gc-test.js.tap +0 -13
- package/.tap/test-results/test/column-test.js.tap +0 -55
- package/.tap/test-results/test/common.js.tap +0 -0
- package/.tap/test-results/test/compression-test.js.tap +0 -30
- package/.tap/test-results/test/db-identity.js.tap +0 -12
- package/.tap/test-results/test/electron.js.tap +0 -0
- package/.tap/test-results/test/env-cleanup-hook-test.js.tap +0 -40
- package/.tap/test-results/test/env-cleanup-hook.js.tap +0 -0
- package/.tap/test-results/test/gc.js.tap +0 -0
- package/.tap/test-results/test/getproperty-test.js.tap +0 -29
- package/.tap/test-results/test/iterator-gc-test.js.tap +0 -15
- package/.tap/test-results/test/iterator-hwm-test.js.tap +0 -131
- package/.tap/test-results/test/iterator-recursion-test.js.tap +0 -12
- package/.tap/test-results/test/iterator-starvation-test.js.tap +0 -73
- package/.tap/test-results/test/iterator-test.js.tap +0 -6
- package/.tap/test-results/test/leak-tester-batch.js.tap +0 -0
- package/.tap/test-results/test/leak-tester-iterator.js.tap +0 -0
- package/.tap/test-results/test/leak-tester.js.tap +0 -0
- package/.tap/test-results/test/lock-test.js.tap +0 -18
- package/.tap/test-results/test/lock.js.tap +0 -0
- package/.tap/test-results/test/make.js.tap +0 -0
- package/.tap/test-results/test/max-rev-merge.js.tap +0 -0
- package/.tap/test-results/test/merge-operator-test.js.tap +0 -12
- package/.tap/test-results/test/mkdir-test.js.tap +0 -15
- package/.tap/test-results/test/segfault-test.js.tap +0 -76
- package/.tap/test-results/test/stack-blower.js.tap +0 -0
- package/deps/rocksdb/rocksdb/README.md +0 -29
- package/deps/rocksdb/rocksdb/microbench/README.md +0 -60
- package/deps/rocksdb/rocksdb/plugin/README.md +0 -43
- package/deps/rocksdb/rocksdb/port/README +0 -10
- package/deps/rocksdb/rocksdb/utilities/transactions/lock/range/range_tree/lib/README +0 -13
|
@@ -17,12 +17,16 @@
|
|
|
17
17
|
#include "utilities/fault_injection_fs.h"
|
|
18
18
|
|
|
19
19
|
#include <algorithm>
|
|
20
|
+
#include <cstdio>
|
|
20
21
|
#include <functional>
|
|
21
22
|
#include <utility>
|
|
22
23
|
|
|
23
24
|
#include "env/composite_env_wrapper.h"
|
|
24
25
|
#include "port/lang.h"
|
|
25
26
|
#include "port/stack_trace.h"
|
|
27
|
+
#include "rocksdb/env.h"
|
|
28
|
+
#include "rocksdb/io_status.h"
|
|
29
|
+
#include "rocksdb/types.h"
|
|
26
30
|
#include "test_util/sync_point.h"
|
|
27
31
|
#include "util/coding.h"
|
|
28
32
|
#include "util/crc32c.h"
|
|
@@ -92,20 +96,15 @@ IOStatus TestFSDirectory::Fsync(const IOOptions& options, IODebugContext* dbg) {
|
|
|
92
96
|
if (!fs_->IsFilesystemActive()) {
|
|
93
97
|
return fs_->GetError();
|
|
94
98
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
|
|
100
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(
|
|
101
|
+
FaultInjectionIOType::kMetadataWrite, options);
|
|
102
|
+
if (!s.ok()) {
|
|
103
|
+
return s;
|
|
100
104
|
}
|
|
105
|
+
|
|
101
106
|
fs_->SyncDir(dirname_);
|
|
102
|
-
|
|
103
|
-
{
|
|
104
|
-
IOStatus in_s = fs_->InjectMetadataWriteError();
|
|
105
|
-
if (!in_s.ok()) {
|
|
106
|
-
return in_s;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
107
|
+
s = dir_->Fsync(options, dbg);
|
|
109
108
|
return s;
|
|
110
109
|
}
|
|
111
110
|
|
|
@@ -113,7 +112,14 @@ IOStatus TestFSDirectory::Close(const IOOptions& options, IODebugContext* dbg) {
|
|
|
113
112
|
if (!fs_->IsFilesystemActive()) {
|
|
114
113
|
return fs_->GetError();
|
|
115
114
|
}
|
|
116
|
-
|
|
115
|
+
|
|
116
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(
|
|
117
|
+
FaultInjectionIOType::kMetadataWrite, options);
|
|
118
|
+
if (!s.ok()) {
|
|
119
|
+
return s;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
s = dir_->Close(options, dbg);
|
|
117
123
|
return s;
|
|
118
124
|
}
|
|
119
125
|
|
|
@@ -123,20 +129,14 @@ IOStatus TestFSDirectory::FsyncWithDirOptions(
|
|
|
123
129
|
if (!fs_->IsFilesystemActive()) {
|
|
124
130
|
return fs_->GetError();
|
|
125
131
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
132
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(
|
|
133
|
+
FaultInjectionIOType::kMetadataWrite, options);
|
|
134
|
+
if (!s.ok()) {
|
|
135
|
+
return s;
|
|
131
136
|
}
|
|
137
|
+
|
|
132
138
|
fs_->SyncDir(dirname_);
|
|
133
|
-
|
|
134
|
-
{
|
|
135
|
-
IOStatus in_s = fs_->InjectMetadataWriteError();
|
|
136
|
-
if (!in_s.ok()) {
|
|
137
|
-
return in_s;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
139
|
+
s = dir_->FsyncWithDirOptions(options, dbg, dir_fsync_options);
|
|
140
140
|
return s;
|
|
141
141
|
}
|
|
142
142
|
|
|
@@ -148,9 +148,11 @@ TestFSWritableFile::TestFSWritableFile(const std::string& fname,
|
|
|
148
148
|
file_opts_(file_opts),
|
|
149
149
|
target_(std::move(f)),
|
|
150
150
|
writable_file_opened_(true),
|
|
151
|
-
fs_(fs)
|
|
151
|
+
fs_(fs),
|
|
152
|
+
unsync_data_loss_(fs_->InjectUnsyncedDataLoss()) {
|
|
152
153
|
assert(target_ != nullptr);
|
|
153
|
-
state_.
|
|
154
|
+
assert(state_.pos_at_last_append_ == 0);
|
|
155
|
+
assert(state_.pos_at_last_sync_ == 0);
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
TestFSWritableFile::~TestFSWritableFile() {
|
|
@@ -165,15 +167,27 @@ IOStatus TestFSWritableFile::Append(const Slice& data, const IOOptions& options,
|
|
|
165
167
|
if (!fs_->IsFilesystemActive()) {
|
|
166
168
|
return fs_->GetError();
|
|
167
169
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
|
|
171
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
|
|
172
|
+
options, state_.filename_);
|
|
173
|
+
if (!s.ok()) {
|
|
174
|
+
return s;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (target_->use_direct_io() || !unsync_data_loss_) {
|
|
178
|
+
// TODO(hx235): buffer data for direct IO write to simulate data loss like
|
|
179
|
+
// non-direct IO write
|
|
180
|
+
s = target_->Append(data, options, dbg);
|
|
170
181
|
} else {
|
|
171
182
|
state_.buffer_.append(data.data(), data.size());
|
|
172
|
-
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (s.ok()) {
|
|
186
|
+
state_.pos_at_last_append_ += data.size();
|
|
173
187
|
fs_->WritableFileAppended(state_);
|
|
174
188
|
}
|
|
175
|
-
|
|
176
|
-
return
|
|
189
|
+
|
|
190
|
+
return s;
|
|
177
191
|
}
|
|
178
192
|
|
|
179
193
|
// By setting the IngestDataCorruptionBeforeWrite(), the data corruption is
|
|
@@ -189,6 +203,12 @@ IOStatus TestFSWritableFile::Append(
|
|
|
189
203
|
return IOStatus::Corruption("Data is corrupted!");
|
|
190
204
|
}
|
|
191
205
|
|
|
206
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
|
|
207
|
+
options, state_.filename_);
|
|
208
|
+
if (!s.ok()) {
|
|
209
|
+
return s;
|
|
210
|
+
}
|
|
211
|
+
|
|
192
212
|
// Calculate the checksum
|
|
193
213
|
std::string checksum;
|
|
194
214
|
CalculateTypedChecksum(fs_->GetChecksumHandoffFuncType(), data.data(),
|
|
@@ -201,15 +221,65 @@ IOStatus TestFSWritableFile::Append(
|
|
|
201
221
|
"current data checksum: " + Slice(checksum).ToString(true);
|
|
202
222
|
return IOStatus::Corruption(msg);
|
|
203
223
|
}
|
|
204
|
-
|
|
205
|
-
|
|
224
|
+
|
|
225
|
+
if (target_->use_direct_io() || !unsync_data_loss_) {
|
|
226
|
+
// TODO(hx235): buffer data for direct IO write to simulate data loss like
|
|
227
|
+
// non-direct IO write
|
|
228
|
+
s = target_->Append(data, options, dbg);
|
|
206
229
|
} else {
|
|
207
230
|
state_.buffer_.append(data.data(), data.size());
|
|
208
|
-
|
|
231
|
+
}
|
|
232
|
+
if (s.ok()) {
|
|
233
|
+
state_.pos_at_last_append_ += data.size();
|
|
209
234
|
fs_->WritableFileAppended(state_);
|
|
210
235
|
}
|
|
211
|
-
|
|
212
|
-
|
|
236
|
+
return s;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
IOStatus TestFSWritableFile::Truncate(uint64_t size, const IOOptions& options,
|
|
240
|
+
IODebugContext* dbg) {
|
|
241
|
+
MutexLock l(&mutex_);
|
|
242
|
+
if (!fs_->IsFilesystemActive()) {
|
|
243
|
+
return fs_->GetError();
|
|
244
|
+
}
|
|
245
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
|
|
246
|
+
options, state_.filename_);
|
|
247
|
+
if (!s.ok()) {
|
|
248
|
+
return s;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
s = target_->Truncate(size, options, dbg);
|
|
252
|
+
if (s.ok()) {
|
|
253
|
+
state_.pos_at_last_append_ = size;
|
|
254
|
+
}
|
|
255
|
+
return s;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
IOStatus TestFSWritableFile::PositionedAppend(const Slice& data,
|
|
259
|
+
uint64_t offset,
|
|
260
|
+
const IOOptions& options,
|
|
261
|
+
IODebugContext* dbg) {
|
|
262
|
+
MutexLock l(&mutex_);
|
|
263
|
+
if (!fs_->IsFilesystemActive()) {
|
|
264
|
+
return fs_->GetError();
|
|
265
|
+
}
|
|
266
|
+
if (fs_->ShouldDataCorruptionBeforeWrite()) {
|
|
267
|
+
return IOStatus::Corruption("Data is corrupted!");
|
|
268
|
+
}
|
|
269
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
|
|
270
|
+
options, state_.filename_);
|
|
271
|
+
if (!s.ok()) {
|
|
272
|
+
return s;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// TODO(hx235): buffer data for direct IO write to simulate data loss like
|
|
276
|
+
// non-direct IO write
|
|
277
|
+
s = target_->PositionedAppend(data, offset, options, dbg);
|
|
278
|
+
if (s.ok()) {
|
|
279
|
+
state_.pos_at_last_append_ = offset + data.size();
|
|
280
|
+
fs_->WritableFileAppended(state_);
|
|
281
|
+
}
|
|
282
|
+
return s;
|
|
213
283
|
}
|
|
214
284
|
|
|
215
285
|
IOStatus TestFSWritableFile::PositionedAppend(
|
|
@@ -222,6 +292,11 @@ IOStatus TestFSWritableFile::PositionedAppend(
|
|
|
222
292
|
if (fs_->ShouldDataCorruptionBeforeWrite()) {
|
|
223
293
|
return IOStatus::Corruption("Data is corrupted!");
|
|
224
294
|
}
|
|
295
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
|
|
296
|
+
options, state_.filename_);
|
|
297
|
+
if (!s.ok()) {
|
|
298
|
+
return s;
|
|
299
|
+
}
|
|
225
300
|
|
|
226
301
|
// Calculate the checksum
|
|
227
302
|
std::string checksum;
|
|
@@ -235,9 +310,14 @@ IOStatus TestFSWritableFile::PositionedAppend(
|
|
|
235
310
|
"current data checksum: " + Slice(checksum).ToString(true);
|
|
236
311
|
return IOStatus::Corruption(msg);
|
|
237
312
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
313
|
+
// TODO(hx235): buffer data for direct IO write to simulate data loss like
|
|
314
|
+
// non-direct IO write
|
|
315
|
+
s = target_->PositionedAppend(data, offset, options, dbg);
|
|
316
|
+
if (s.ok()) {
|
|
317
|
+
state_.pos_at_last_append_ = offset + data.size();
|
|
318
|
+
fs_->WritableFileAppended(state_);
|
|
319
|
+
}
|
|
320
|
+
return s;
|
|
241
321
|
}
|
|
242
322
|
|
|
243
323
|
IOStatus TestFSWritableFile::Close(const IOOptions& options,
|
|
@@ -247,24 +327,17 @@ IOStatus TestFSWritableFile::Close(const IOOptions& options,
|
|
|
247
327
|
if (!fs_->IsFilesystemActive()) {
|
|
248
328
|
return fs_->GetError();
|
|
249
329
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
}
|
|
330
|
+
IOStatus io_s = fs_->MaybeInjectThreadLocalError(
|
|
331
|
+
FaultInjectionIOType::kMetadataWrite, options);
|
|
332
|
+
if (!io_s.ok()) {
|
|
333
|
+
return io_s;
|
|
255
334
|
}
|
|
256
335
|
writable_file_opened_ = false;
|
|
257
|
-
|
|
336
|
+
|
|
258
337
|
// Drop buffered data that was never synced because close is not a syncing
|
|
259
338
|
// mechanism in POSIX file semantics.
|
|
260
339
|
state_.buffer_.resize(0);
|
|
261
340
|
io_s = target_->Close(options, dbg);
|
|
262
|
-
if (io_s.ok()) {
|
|
263
|
-
IOStatus in_s = fs_->InjectMetadataWriteError();
|
|
264
|
-
if (!in_s.ok()) {
|
|
265
|
-
return in_s;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
341
|
return io_s;
|
|
269
342
|
}
|
|
270
343
|
|
|
@@ -273,9 +346,6 @@ IOStatus TestFSWritableFile::Flush(const IOOptions&, IODebugContext*) {
|
|
|
273
346
|
if (!fs_->IsFilesystemActive()) {
|
|
274
347
|
return fs_->GetError();
|
|
275
348
|
}
|
|
276
|
-
if (fs_->IsFilesystemActive()) {
|
|
277
|
-
state_.pos_at_last_flush_ = state_.pos_;
|
|
278
|
-
}
|
|
279
349
|
return IOStatus::OK();
|
|
280
350
|
}
|
|
281
351
|
|
|
@@ -294,7 +364,7 @@ IOStatus TestFSWritableFile::Sync(const IOOptions& options,
|
|
|
294
364
|
state_.buffer_.resize(0);
|
|
295
365
|
// Ignore sync errors
|
|
296
366
|
target_->Sync(options, dbg).PermitUncheckedError();
|
|
297
|
-
state_.pos_at_last_sync_ = state_.
|
|
367
|
+
state_.pos_at_last_sync_ = state_.pos_at_last_append_;
|
|
298
368
|
fs_->WritableFileSynced(state_);
|
|
299
369
|
return io_s;
|
|
300
370
|
}
|
|
@@ -308,15 +378,13 @@ IOStatus TestFSWritableFile::RangeSync(uint64_t offset, uint64_t nbytes,
|
|
|
308
378
|
}
|
|
309
379
|
// Assumes caller passes consecutive byte ranges.
|
|
310
380
|
uint64_t sync_limit = offset + nbytes;
|
|
311
|
-
uint64_t buf_begin =
|
|
312
|
-
state_.pos_at_last_sync_ < 0 ? 0 : state_.pos_at_last_sync_;
|
|
313
381
|
|
|
314
382
|
IOStatus io_s;
|
|
315
|
-
if (sync_limit <
|
|
383
|
+
if (sync_limit < state_.pos_at_last_sync_) {
|
|
316
384
|
return io_s;
|
|
317
385
|
}
|
|
318
386
|
uint64_t num_to_sync = std::min(static_cast<uint64_t>(state_.buffer_.size()),
|
|
319
|
-
sync_limit -
|
|
387
|
+
sync_limit - state_.pos_at_last_sync_);
|
|
320
388
|
Slice buf_to_sync(state_.buffer_.data(), num_to_sync);
|
|
321
389
|
io_s = target_->Append(buf_to_sync, options, dbg);
|
|
322
390
|
state_.buffer_ = state_.buffer_.substr(num_to_sync);
|
|
@@ -355,6 +423,7 @@ IOStatus TestFSRandomRWFile::Read(uint64_t offset, size_t n,
|
|
|
355
423
|
if (!fs_->IsFilesystemActive()) {
|
|
356
424
|
return fs_->GetError();
|
|
357
425
|
}
|
|
426
|
+
// TODO (low priority): fs_->ReadUnsyncedData()
|
|
358
427
|
return target_->Read(offset, n, options, result, scratch, dbg);
|
|
359
428
|
}
|
|
360
429
|
|
|
@@ -398,15 +467,17 @@ IOStatus TestFSRandomAccessFile::Read(uint64_t offset, size_t n,
|
|
|
398
467
|
if (!fs_->IsFilesystemActive()) {
|
|
399
468
|
return fs_->GetError();
|
|
400
469
|
}
|
|
401
|
-
IOStatus s =
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
return IOStatus::IOError("injected read error");
|
|
470
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(
|
|
471
|
+
FaultInjectionIOType::kRead, options, "",
|
|
472
|
+
FaultInjectionTestFS::ErrorOperation::kRead, result, use_direct_io(),
|
|
473
|
+
scratch, /*need_count_increase=*/true,
|
|
474
|
+
/*fault_injected=*/nullptr);
|
|
475
|
+
if (!s.ok()) {
|
|
476
|
+
return s;
|
|
409
477
|
}
|
|
478
|
+
|
|
479
|
+
s = target_->Read(offset, n, options, result, scratch, dbg);
|
|
480
|
+
// TODO (low priority): fs_->ReadUnsyncedData()
|
|
410
481
|
return s;
|
|
411
482
|
}
|
|
412
483
|
|
|
@@ -414,28 +485,35 @@ IOStatus TestFSRandomAccessFile::ReadAsync(
|
|
|
414
485
|
FSReadRequest& req, const IOOptions& opts,
|
|
415
486
|
std::function<void(FSReadRequest&, void*)> cb, void* cb_arg,
|
|
416
487
|
void** io_handle, IOHandleDeleter* del_fn, IODebugContext* /*dbg*/) {
|
|
417
|
-
IOStatus
|
|
418
|
-
IOStatus s;
|
|
488
|
+
IOStatus res_status;
|
|
419
489
|
FSReadRequest res;
|
|
490
|
+
IOStatus s;
|
|
420
491
|
if (!fs_->IsFilesystemActive()) {
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
|
|
492
|
+
res_status = fs_->GetError();
|
|
493
|
+
}
|
|
494
|
+
if (res_status.ok()) {
|
|
495
|
+
res_status = fs_->MaybeInjectThreadLocalError(
|
|
496
|
+
FaultInjectionIOType::kRead, opts, "",
|
|
424
497
|
FaultInjectionTestFS::ErrorOperation::kRead, &res.result,
|
|
425
498
|
use_direct_io(), req.scratch, /*need_count_increase=*/true,
|
|
426
499
|
/*fault_injected=*/nullptr);
|
|
427
500
|
}
|
|
428
|
-
if (
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
res.status =
|
|
501
|
+
if (res_status.ok()) {
|
|
502
|
+
s = target_->ReadAsync(req, opts, cb, cb_arg, io_handle, del_fn, nullptr);
|
|
503
|
+
// TODO (low priority): fs_->ReadUnsyncedData()
|
|
504
|
+
} else {
|
|
505
|
+
// If there’s no injected error, then cb will be called asynchronously when
|
|
506
|
+
// target_ actually finishes the read. But if there’s an injected error, it
|
|
507
|
+
// needs to immediately call cb(res, cb_arg) s since target_->ReadAsync()
|
|
508
|
+
// isn’t invoked at all.
|
|
509
|
+
res.status = res_status;
|
|
437
510
|
cb(res, cb_arg);
|
|
438
511
|
}
|
|
512
|
+
// We return ReadAsync()'s status intead of injected error status here since
|
|
513
|
+
// the return status is not supposed to be the status of the actual IO (i.e,
|
|
514
|
+
// the actual async read). The actual status of the IO will be passed to cb()
|
|
515
|
+
// callback upon the actual read finishes or like above when injected error
|
|
516
|
+
// happens.
|
|
439
517
|
return s;
|
|
440
518
|
}
|
|
441
519
|
|
|
@@ -446,6 +524,7 @@ IOStatus TestFSRandomAccessFile::MultiRead(FSReadRequest* reqs, size_t num_reqs,
|
|
|
446
524
|
return fs_->GetError();
|
|
447
525
|
}
|
|
448
526
|
IOStatus s = target_->MultiRead(reqs, num_reqs, options, dbg);
|
|
527
|
+
// TODO (low priority): fs_->ReadUnsyncedData()
|
|
449
528
|
bool injected_error = false;
|
|
450
529
|
for (size_t i = 0; i < num_reqs; i++) {
|
|
451
530
|
if (!reqs[i].status.ok()) {
|
|
@@ -453,7 +532,8 @@ IOStatus TestFSRandomAccessFile::MultiRead(FSReadRequest* reqs, size_t num_reqs,
|
|
|
453
532
|
break;
|
|
454
533
|
}
|
|
455
534
|
bool this_injected_error;
|
|
456
|
-
reqs[i].status = fs_->
|
|
535
|
+
reqs[i].status = fs_->MaybeInjectThreadLocalError(
|
|
536
|
+
FaultInjectionIOType::kRead, options, "",
|
|
457
537
|
FaultInjectionTestFS::ErrorOperation::kRead, &(reqs[i].result),
|
|
458
538
|
use_direct_io(), reqs[i].scratch,
|
|
459
539
|
/*need_count_increase=*/true,
|
|
@@ -461,14 +541,12 @@ IOStatus TestFSRandomAccessFile::MultiRead(FSReadRequest* reqs, size_t num_reqs,
|
|
|
461
541
|
injected_error |= this_injected_error;
|
|
462
542
|
}
|
|
463
543
|
if (s.ok()) {
|
|
464
|
-
s = fs_->
|
|
544
|
+
s = fs_->MaybeInjectThreadLocalError(
|
|
545
|
+
FaultInjectionIOType::kRead, options, "",
|
|
465
546
|
FaultInjectionTestFS::ErrorOperation::kMultiRead, nullptr,
|
|
466
547
|
use_direct_io(), nullptr, /*need_count_increase=*/!injected_error,
|
|
467
548
|
/*fault_injected=*/nullptr);
|
|
468
549
|
}
|
|
469
|
-
if (s.ok() && fs_->ShouldInjectRandomReadError()) {
|
|
470
|
-
return IOStatus::IOError("injected read error");
|
|
471
|
-
}
|
|
472
550
|
return s;
|
|
473
551
|
}
|
|
474
552
|
|
|
@@ -479,13 +557,196 @@ size_t TestFSRandomAccessFile::GetUniqueId(char* id, size_t max_size) const {
|
|
|
479
557
|
return target_->GetUniqueId(id, max_size);
|
|
480
558
|
}
|
|
481
559
|
}
|
|
560
|
+
|
|
561
|
+
namespace {
|
|
562
|
+
// Modifies `result` to start at the beginning of `scratch` if not already,
|
|
563
|
+
// copying data there if needed.
|
|
564
|
+
void MoveToScratchIfNeeded(Slice* result, char* scratch) {
|
|
565
|
+
if (result->data() != scratch) {
|
|
566
|
+
// NOTE: might overlap, where result is later in scratch
|
|
567
|
+
std::copy(result->data(), result->data() + result->size(), scratch);
|
|
568
|
+
*result = Slice(scratch, result->size());
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
} // namespace
|
|
572
|
+
|
|
573
|
+
void FaultInjectionTestFS::ReadUnsynced(const std::string& fname,
|
|
574
|
+
uint64_t offset, size_t n,
|
|
575
|
+
Slice* result, char* scratch,
|
|
576
|
+
int64_t* pos_at_last_sync) {
|
|
577
|
+
*result = Slice(scratch, 0); // default empty result
|
|
578
|
+
assert(*pos_at_last_sync == -1); // default "unknown"
|
|
579
|
+
|
|
580
|
+
MutexLock l(&mutex_);
|
|
581
|
+
auto it = db_file_state_.find(fname);
|
|
582
|
+
if (it != db_file_state_.end()) {
|
|
583
|
+
auto& st = it->second;
|
|
584
|
+
*pos_at_last_sync = static_cast<int64_t>(st.pos_at_last_sync_);
|
|
585
|
+
// Find overlap between [offset, offset + n) and
|
|
586
|
+
// [*pos_at_last_sync, *pos_at_last_sync + st.buffer_.size())
|
|
587
|
+
int64_t begin = std::max(static_cast<int64_t>(offset), *pos_at_last_sync);
|
|
588
|
+
int64_t end =
|
|
589
|
+
std::min(static_cast<int64_t>(offset + n),
|
|
590
|
+
*pos_at_last_sync + static_cast<int64_t>(st.buffer_.size()));
|
|
591
|
+
|
|
592
|
+
// Copy and return overlap if there is any
|
|
593
|
+
if (begin < end) {
|
|
594
|
+
size_t offset_in_buffer = static_cast<size_t>(begin - *pos_at_last_sync);
|
|
595
|
+
size_t offset_in_scratch = static_cast<size_t>(begin - offset);
|
|
596
|
+
std::copy_n(st.buffer_.data() + offset_in_buffer, end - begin,
|
|
597
|
+
scratch + offset_in_scratch);
|
|
598
|
+
*result = Slice(scratch + offset_in_scratch, end - begin);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
482
603
|
IOStatus TestFSSequentialFile::Read(size_t n, const IOOptions& options,
|
|
483
604
|
Slice* result, char* scratch,
|
|
484
605
|
IODebugContext* dbg) {
|
|
485
|
-
IOStatus s =
|
|
486
|
-
|
|
487
|
-
|
|
606
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(
|
|
607
|
+
FaultInjectionIOType::kRead, options, "",
|
|
608
|
+
FaultInjectionTestFS::ErrorOperation::kRead, result, use_direct_io(),
|
|
609
|
+
scratch, true /*need_count_increase=*/, nullptr /* fault_injected*/);
|
|
610
|
+
if (!s.ok()) {
|
|
611
|
+
return s;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// Some complex logic is needed to deal with concurrent write to the same
|
|
615
|
+
// file, while keeping good performance (e.g. not holding FS mutex during
|
|
616
|
+
// I/O op), especially in common cases.
|
|
617
|
+
|
|
618
|
+
if (read_pos_ == target_read_pos_) {
|
|
619
|
+
// Normal case: start by reading from underlying file
|
|
620
|
+
s = target()->Read(n, options, result, scratch, dbg);
|
|
621
|
+
if (!s.ok()) {
|
|
622
|
+
return s;
|
|
623
|
+
}
|
|
624
|
+
target_read_pos_ += result->size();
|
|
625
|
+
} else {
|
|
626
|
+
// We must have previously read buffered data (unsynced) not written to
|
|
627
|
+
// target. Deal with this case (and more) below.
|
|
628
|
+
*result = {};
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (fs_->ReadUnsyncedData() && result->size() < n) {
|
|
632
|
+
// We need to check if there's unsynced data to fill out the rest of the
|
|
633
|
+
// read.
|
|
634
|
+
|
|
635
|
+
// First, ensure target read data is in scratch for easy handling.
|
|
636
|
+
MoveToScratchIfNeeded(result, scratch);
|
|
637
|
+
assert(result->data() == scratch);
|
|
638
|
+
|
|
639
|
+
// If we just did a target Read, we only want unsynced data after it
|
|
640
|
+
// (target_read_pos_). Otherwise (e.g. if target is behind because of
|
|
641
|
+
// unsynced data) we want unsynced data starting at the current read pos
|
|
642
|
+
// (read_pos_, not yet updated).
|
|
643
|
+
const uint64_t unsynced_read_pos = std::max(target_read_pos_, read_pos_);
|
|
644
|
+
const size_t offset_from_read_pos =
|
|
645
|
+
static_cast<size_t>(unsynced_read_pos - read_pos_);
|
|
646
|
+
Slice unsynced_result;
|
|
647
|
+
int64_t pos_at_last_sync = -1;
|
|
648
|
+
fs_->ReadUnsynced(fname_, unsynced_read_pos, n - offset_from_read_pos,
|
|
649
|
+
&unsynced_result, scratch + offset_from_read_pos,
|
|
650
|
+
&pos_at_last_sync);
|
|
651
|
+
assert(unsynced_result.data() >= scratch + offset_from_read_pos);
|
|
652
|
+
assert(unsynced_result.data() < scratch + n);
|
|
653
|
+
// Now, there are several cases to consider (some grouped together):
|
|
654
|
+
if (pos_at_last_sync <= static_cast<int64_t>(unsynced_read_pos)) {
|
|
655
|
+
// 1. We didn't get any unsynced data because nothing has been written
|
|
656
|
+
// to the file beyond unsynced_read_pos (including untracked
|
|
657
|
+
// pos_at_last_sync == -1)
|
|
658
|
+
// 2. We got some unsynced data starting at unsynced_read_pos (possibly
|
|
659
|
+
// on top of some synced data from target). We don't need to try reading
|
|
660
|
+
// any more from target because we established a "point in time" for
|
|
661
|
+
// completing this Read in which we read as much tail data (unsynced) as
|
|
662
|
+
// we could.
|
|
663
|
+
|
|
664
|
+
// We got pos_at_last_sync info if we got any unsynced data.
|
|
665
|
+
assert(pos_at_last_sync >= 0 || unsynced_result.size() == 0);
|
|
666
|
+
|
|
667
|
+
// Combined data is already lined up in scratch.
|
|
668
|
+
assert(result->data() + result->size() == unsynced_result.data());
|
|
669
|
+
assert(result->size() + unsynced_result.size() <= n);
|
|
670
|
+
// Combine results
|
|
671
|
+
*result = Slice(result->data(), result->size() + unsynced_result.size());
|
|
672
|
+
} else {
|
|
673
|
+
// 3. Any unsynced data we got was after unsynced_read_pos because the
|
|
674
|
+
// file was synced some time since our last target Read (either from this
|
|
675
|
+
// Read or a prior Read). We need to read more data from target to ensure
|
|
676
|
+
// this Read is filled out, even though we might have already read some
|
|
677
|
+
// (but not all due to a race). This code handles:
|
|
678
|
+
//
|
|
679
|
+
// * Catching up target after prior read(s) of unsynced data
|
|
680
|
+
// * Racing Sync in another thread since we called target Read above
|
|
681
|
+
//
|
|
682
|
+
// And merging potentially three results together for this Read:
|
|
683
|
+
// * The original target Read above
|
|
684
|
+
// * The following (non-throw-away) target Read
|
|
685
|
+
// * The ReadUnsynced above, which is always last if it returned data,
|
|
686
|
+
// so that we have a "point in time" for completing this Read in which we
|
|
687
|
+
// read as much tail data (unsynced) as we could.
|
|
688
|
+
//
|
|
689
|
+
// Deeper note about the race: we cannot just treat the original target
|
|
690
|
+
// Read as a "point in time" view of available data in the file, because
|
|
691
|
+
// there might have been unsynced data at that time, which became synced
|
|
692
|
+
// data by the time we read unsynced data. That is the race we are
|
|
693
|
+
// resolving with this "double check"-style code.
|
|
694
|
+
const size_t supplemental_read_pos = unsynced_read_pos;
|
|
695
|
+
|
|
696
|
+
// First, if there's any data from target that we know we would need to
|
|
697
|
+
// throw away to catch up, try to do it.
|
|
698
|
+
if (target_read_pos_ < supplemental_read_pos) {
|
|
699
|
+
Slice throw_away_result;
|
|
700
|
+
size_t throw_away_n = supplemental_read_pos - target_read_pos_;
|
|
701
|
+
std::unique_ptr<char[]> throw_away_scratch{new char[throw_away_n]};
|
|
702
|
+
s = target()->Read(throw_away_n, options, &throw_away_result,
|
|
703
|
+
throw_away_scratch.get(), dbg);
|
|
704
|
+
if (!s.ok()) {
|
|
705
|
+
read_pos_ += result->size();
|
|
706
|
+
return s;
|
|
707
|
+
}
|
|
708
|
+
target_read_pos_ += throw_away_result.size();
|
|
709
|
+
if (target_read_pos_ < supplemental_read_pos) {
|
|
710
|
+
// Because of pos_at_last_sync > supplemental_read_pos, we should
|
|
711
|
+
// have been able to catch up
|
|
712
|
+
read_pos_ += result->size();
|
|
713
|
+
return IOStatus::IOError(
|
|
714
|
+
"Unexpected truncation or short read of file " + fname_);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
// Now we can do a productive supplemental Read from target
|
|
718
|
+
assert(target_read_pos_ == supplemental_read_pos);
|
|
719
|
+
Slice supplemental_result;
|
|
720
|
+
size_t supplemental_n =
|
|
721
|
+
unsynced_result.size() == 0
|
|
722
|
+
? n - offset_from_read_pos
|
|
723
|
+
: unsynced_result.data() - (scratch + offset_from_read_pos);
|
|
724
|
+
s = target()->Read(supplemental_n, options, &supplemental_result,
|
|
725
|
+
scratch + offset_from_read_pos, dbg);
|
|
726
|
+
if (!s.ok()) {
|
|
727
|
+
read_pos_ += result->size();
|
|
728
|
+
return s;
|
|
729
|
+
}
|
|
730
|
+
target_read_pos_ += supplemental_result.size();
|
|
731
|
+
MoveToScratchIfNeeded(&supplemental_result,
|
|
732
|
+
scratch + offset_from_read_pos);
|
|
733
|
+
|
|
734
|
+
// Combined data is already lined up in scratch.
|
|
735
|
+
assert(result->data() + result->size() == supplemental_result.data());
|
|
736
|
+
assert(unsynced_result.size() == 0 ||
|
|
737
|
+
supplemental_result.data() + supplemental_result.size() ==
|
|
738
|
+
unsynced_result.data());
|
|
739
|
+
assert(result->size() + supplemental_result.size() +
|
|
740
|
+
unsynced_result.size() <=
|
|
741
|
+
n);
|
|
742
|
+
// Combine results
|
|
743
|
+
*result =
|
|
744
|
+
Slice(result->data(), result->size() + supplemental_result.size() +
|
|
745
|
+
unsynced_result.size());
|
|
746
|
+
}
|
|
488
747
|
}
|
|
748
|
+
read_pos_ += result->size();
|
|
749
|
+
|
|
489
750
|
return s;
|
|
490
751
|
}
|
|
491
752
|
|
|
@@ -493,11 +754,16 @@ IOStatus TestFSSequentialFile::PositionedRead(uint64_t offset, size_t n,
|
|
|
493
754
|
const IOOptions& options,
|
|
494
755
|
Slice* result, char* scratch,
|
|
495
756
|
IODebugContext* dbg) {
|
|
496
|
-
IOStatus s =
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
757
|
+
IOStatus s = fs_->MaybeInjectThreadLocalError(
|
|
758
|
+
FaultInjectionIOType::kRead, options, "",
|
|
759
|
+
FaultInjectionTestFS::ErrorOperation::kRead, result, use_direct_io(),
|
|
760
|
+
scratch, true /*need_count_increase=*/, nullptr /* fault_injected */);
|
|
761
|
+
if (!s.ok()) {
|
|
762
|
+
return s;
|
|
500
763
|
}
|
|
764
|
+
|
|
765
|
+
s = target()->PositionedRead(offset, n, options, result, scratch, dbg);
|
|
766
|
+
// TODO (low priority): fs_->ReadUnsyncedData()
|
|
501
767
|
return s;
|
|
502
768
|
}
|
|
503
769
|
|
|
@@ -514,24 +780,76 @@ IOStatus FaultInjectionTestFS::NewDirectory(
|
|
|
514
780
|
return IOStatus::OK();
|
|
515
781
|
}
|
|
516
782
|
|
|
783
|
+
IOStatus FaultInjectionTestFS::FileExists(const std::string& fname,
|
|
784
|
+
const IOOptions& options,
|
|
785
|
+
IODebugContext* dbg) {
|
|
786
|
+
if (!IsFilesystemActive()) {
|
|
787
|
+
return GetError();
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
IOStatus io_s =
|
|
791
|
+
MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
|
|
792
|
+
if (!io_s.ok()) {
|
|
793
|
+
return io_s;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
io_s = target()->FileExists(fname, options, dbg);
|
|
797
|
+
return io_s;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
IOStatus FaultInjectionTestFS::GetChildren(const std::string& dir,
|
|
801
|
+
const IOOptions& options,
|
|
802
|
+
std::vector<std::string>* result,
|
|
803
|
+
IODebugContext* dbg) {
|
|
804
|
+
if (!IsFilesystemActive()) {
|
|
805
|
+
return GetError();
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
IOStatus io_s =
|
|
809
|
+
MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
|
|
810
|
+
if (!io_s.ok()) {
|
|
811
|
+
return io_s;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
io_s = target()->GetChildren(dir, options, result, dbg);
|
|
815
|
+
return io_s;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
IOStatus FaultInjectionTestFS::GetChildrenFileAttributes(
|
|
819
|
+
const std::string& dir, const IOOptions& options,
|
|
820
|
+
std::vector<FileAttributes>* result, IODebugContext* dbg) {
|
|
821
|
+
if (!IsFilesystemActive()) {
|
|
822
|
+
return GetError();
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
IOStatus io_s =
|
|
826
|
+
MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
|
|
827
|
+
if (!io_s.ok()) {
|
|
828
|
+
return io_s;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
io_s = target()->GetChildrenFileAttributes(dir, options, result, dbg);
|
|
832
|
+
return io_s;
|
|
833
|
+
}
|
|
834
|
+
|
|
517
835
|
IOStatus FaultInjectionTestFS::NewWritableFile(
|
|
518
836
|
const std::string& fname, const FileOptions& file_opts,
|
|
519
837
|
std::unique_ptr<FSWritableFile>* result, IODebugContext* dbg) {
|
|
520
838
|
if (!IsFilesystemActive()) {
|
|
521
839
|
return GetError();
|
|
522
840
|
}
|
|
523
|
-
{
|
|
524
|
-
IOStatus in_s = InjectMetadataWriteError();
|
|
525
|
-
if (!in_s.ok()) {
|
|
526
|
-
return in_s;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
841
|
|
|
530
|
-
if (
|
|
842
|
+
if (IsFilesystemDirectWritable()) {
|
|
531
843
|
return target()->NewWritableFile(fname, file_opts, result, dbg);
|
|
532
844
|
}
|
|
533
845
|
|
|
534
|
-
IOStatus io_s =
|
|
846
|
+
IOStatus io_s = MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
|
|
847
|
+
file_opts.io_options, fname);
|
|
848
|
+
if (!io_s.ok()) {
|
|
849
|
+
return io_s;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
io_s = target()->NewWritableFile(fname, file_opts, result, dbg);
|
|
535
853
|
if (io_s.ok()) {
|
|
536
854
|
result->reset(
|
|
537
855
|
new TestFSWritableFile(fname, file_opts, std::move(*result), this));
|
|
@@ -548,12 +866,6 @@ IOStatus FaultInjectionTestFS::NewWritableFile(
|
|
|
548
866
|
// dropping unsynced files.
|
|
549
867
|
list[dir_and_name.second] = kNewFileNoOverwrite;
|
|
550
868
|
}
|
|
551
|
-
{
|
|
552
|
-
IOStatus in_s = InjectMetadataWriteError();
|
|
553
|
-
if (!in_s.ok()) {
|
|
554
|
-
return in_s;
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
869
|
}
|
|
558
870
|
return io_s;
|
|
559
871
|
}
|
|
@@ -564,19 +876,18 @@ IOStatus FaultInjectionTestFS::ReopenWritableFile(
|
|
|
564
876
|
if (!IsFilesystemActive()) {
|
|
565
877
|
return GetError();
|
|
566
878
|
}
|
|
567
|
-
if (
|
|
879
|
+
if (IsFilesystemDirectWritable()) {
|
|
568
880
|
return target()->ReopenWritableFile(fname, file_opts, result, dbg);
|
|
569
881
|
}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
}
|
|
882
|
+
IOStatus io_s = MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
|
|
883
|
+
file_opts.io_options, fname);
|
|
884
|
+
if (!io_s.ok()) {
|
|
885
|
+
return io_s;
|
|
575
886
|
}
|
|
576
887
|
|
|
577
888
|
bool exists;
|
|
578
|
-
IOStatus
|
|
579
|
-
|
|
889
|
+
IOStatus exists_s =
|
|
890
|
+
target()->FileExists(fname, IOOptions(), nullptr /* dbg */);
|
|
580
891
|
if (exists_s.IsNotFound()) {
|
|
581
892
|
exists = false;
|
|
582
893
|
} else if (exists_s.ok()) {
|
|
@@ -586,10 +897,12 @@ IOStatus FaultInjectionTestFS::ReopenWritableFile(
|
|
|
586
897
|
exists = false;
|
|
587
898
|
}
|
|
588
899
|
|
|
589
|
-
if (io_s.ok()) {
|
|
590
|
-
io_s
|
|
900
|
+
if (!io_s.ok()) {
|
|
901
|
+
return io_s;
|
|
591
902
|
}
|
|
592
903
|
|
|
904
|
+
io_s = target()->ReopenWritableFile(fname, file_opts, result, dbg);
|
|
905
|
+
|
|
593
906
|
// Only track files we created. Files created outside of this
|
|
594
907
|
// `FaultInjectionTestFS` are not eligible for tracking/data dropping
|
|
595
908
|
// (for example, they may contain data a previous db_stress run expects to
|
|
@@ -618,12 +931,6 @@ IOStatus FaultInjectionTestFS::ReopenWritableFile(
|
|
|
618
931
|
result->reset(
|
|
619
932
|
new TestFSWritableFile(fname, file_opts, std::move(*result), this));
|
|
620
933
|
}
|
|
621
|
-
{
|
|
622
|
-
IOStatus in_s = InjectMetadataWriteError();
|
|
623
|
-
if (!in_s.ok()) {
|
|
624
|
-
return in_s;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
934
|
}
|
|
628
935
|
return io_s;
|
|
629
936
|
}
|
|
@@ -645,16 +952,17 @@ IOStatus FaultInjectionTestFS::NewRandomRWFile(
|
|
|
645
952
|
if (!IsFilesystemActive()) {
|
|
646
953
|
return GetError();
|
|
647
954
|
}
|
|
648
|
-
if (
|
|
955
|
+
if (IsFilesystemDirectWritable()) {
|
|
649
956
|
return target()->NewRandomRWFile(fname, file_opts, result, dbg);
|
|
650
957
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
}
|
|
958
|
+
IOStatus io_s = MaybeInjectThreadLocalError(FaultInjectionIOType::kWrite,
|
|
959
|
+
file_opts.io_options, fname);
|
|
960
|
+
if (!io_s.ok()) {
|
|
961
|
+
return io_s;
|
|
656
962
|
}
|
|
657
|
-
|
|
963
|
+
|
|
964
|
+
io_s = target()->NewRandomRWFile(fname, file_opts, result, dbg);
|
|
965
|
+
|
|
658
966
|
if (io_s.ok()) {
|
|
659
967
|
result->reset(new TestFSRandomRWFile(fname, std::move(*result), this));
|
|
660
968
|
// WritableFileWriter* file is opened
|
|
@@ -669,12 +977,6 @@ IOStatus FaultInjectionTestFS::NewRandomRWFile(
|
|
|
669
977
|
// implementation by ignoring it.
|
|
670
978
|
list[dir_and_name.second] = kNewFileNoOverwrite;
|
|
671
979
|
}
|
|
672
|
-
{
|
|
673
|
-
IOStatus in_s = InjectMetadataWriteError();
|
|
674
|
-
if (!in_s.ok()) {
|
|
675
|
-
return in_s;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
980
|
}
|
|
679
981
|
return io_s;
|
|
680
982
|
}
|
|
@@ -685,16 +987,17 @@ IOStatus FaultInjectionTestFS::NewRandomAccessFile(
|
|
|
685
987
|
if (!IsFilesystemActive()) {
|
|
686
988
|
return GetError();
|
|
687
989
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
if (io_s.ok()) {
|
|
696
|
-
io_s = target()->NewRandomAccessFile(fname, file_opts, result, dbg);
|
|
990
|
+
IOStatus io_s = MaybeInjectThreadLocalError(
|
|
991
|
+
FaultInjectionIOType::kRead, file_opts.io_options, fname,
|
|
992
|
+
ErrorOperation::kOpen, nullptr /* result */, false /* direct_io */,
|
|
993
|
+
nullptr /* scratch */, true /*need_count_increase*/,
|
|
994
|
+
nullptr /*fault_injected*/);
|
|
995
|
+
if (!io_s.ok()) {
|
|
996
|
+
return io_s;
|
|
697
997
|
}
|
|
998
|
+
|
|
999
|
+
io_s = target()->NewRandomAccessFile(fname, file_opts, result, dbg);
|
|
1000
|
+
|
|
698
1001
|
if (io_s.ok()) {
|
|
699
1002
|
result->reset(new TestFSRandomAccessFile(fname, std::move(*result), this));
|
|
700
1003
|
}
|
|
@@ -707,13 +1010,19 @@ IOStatus FaultInjectionTestFS::NewSequentialFile(
|
|
|
707
1010
|
if (!IsFilesystemActive()) {
|
|
708
1011
|
return GetError();
|
|
709
1012
|
}
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
1013
|
+
IOStatus io_s = MaybeInjectThreadLocalError(
|
|
1014
|
+
FaultInjectionIOType::kRead, file_opts.io_options, fname,
|
|
1015
|
+
ErrorOperation::kOpen, nullptr /* result */, false /* direct_io */,
|
|
1016
|
+
nullptr /* scratch */, true /*need_count_increase*/,
|
|
1017
|
+
nullptr /*fault_injected*/);
|
|
1018
|
+
if (!io_s.ok()) {
|
|
1019
|
+
return io_s;
|
|
713
1020
|
}
|
|
714
|
-
|
|
1021
|
+
|
|
1022
|
+
io_s = target()->NewSequentialFile(fname, file_opts, result, dbg);
|
|
1023
|
+
|
|
715
1024
|
if (io_s.ok()) {
|
|
716
|
-
result->reset(new TestFSSequentialFile(std::move(*result), this));
|
|
1025
|
+
result->reset(new TestFSSequentialFile(std::move(*result), this, fname));
|
|
717
1026
|
}
|
|
718
1027
|
return io_s;
|
|
719
1028
|
}
|
|
@@ -724,25 +1033,66 @@ IOStatus FaultInjectionTestFS::DeleteFile(const std::string& f,
|
|
|
724
1033
|
if (!IsFilesystemActive()) {
|
|
725
1034
|
return GetError();
|
|
726
1035
|
}
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
}
|
|
1036
|
+
IOStatus io_s = MaybeInjectThreadLocalError(
|
|
1037
|
+
FaultInjectionIOType::kMetadataWrite, options);
|
|
1038
|
+
if (!io_s.ok()) {
|
|
1039
|
+
return io_s;
|
|
732
1040
|
}
|
|
733
|
-
|
|
1041
|
+
|
|
1042
|
+
io_s = FileSystemWrapper::DeleteFile(f, options, dbg);
|
|
1043
|
+
|
|
734
1044
|
if (io_s.ok()) {
|
|
735
1045
|
UntrackFile(f);
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
1046
|
+
}
|
|
1047
|
+
return io_s;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
IOStatus FaultInjectionTestFS::GetFileSize(const std::string& f,
|
|
1051
|
+
const IOOptions& options,
|
|
1052
|
+
uint64_t* file_size,
|
|
1053
|
+
IODebugContext* dbg) {
|
|
1054
|
+
if (!IsFilesystemActive()) {
|
|
1055
|
+
return GetError();
|
|
1056
|
+
}
|
|
1057
|
+
IOStatus io_s =
|
|
1058
|
+
MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
|
|
1059
|
+
if (!io_s.ok()) {
|
|
1060
|
+
return io_s;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
io_s = target()->GetFileSize(f, options, file_size, dbg);
|
|
1064
|
+
if (!io_s.ok()) {
|
|
1065
|
+
return io_s;
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
if (ReadUnsyncedData()) {
|
|
1069
|
+
// Need to report flushed size, not synced size
|
|
1070
|
+
MutexLock l(&mutex_);
|
|
1071
|
+
auto it = db_file_state_.find(f);
|
|
1072
|
+
if (it != db_file_state_.end()) {
|
|
1073
|
+
*file_size = it->second.pos_at_last_append_;
|
|
741
1074
|
}
|
|
742
1075
|
}
|
|
743
1076
|
return io_s;
|
|
744
1077
|
}
|
|
745
1078
|
|
|
1079
|
+
IOStatus FaultInjectionTestFS::GetFileModificationTime(const std::string& fname,
|
|
1080
|
+
const IOOptions& options,
|
|
1081
|
+
uint64_t* file_mtime,
|
|
1082
|
+
IODebugContext* dbg) {
|
|
1083
|
+
if (!IsFilesystemActive()) {
|
|
1084
|
+
return GetError();
|
|
1085
|
+
}
|
|
1086
|
+
IOStatus io_s =
|
|
1087
|
+
MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
|
|
1088
|
+
if (!io_s.ok()) {
|
|
1089
|
+
return io_s;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
io_s = target()->GetFileModificationTime(fname, options, file_mtime, dbg);
|
|
1093
|
+
return io_s;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
746
1096
|
IOStatus FaultInjectionTestFS::RenameFile(const std::string& s,
|
|
747
1097
|
const std::string& t,
|
|
748
1098
|
const IOOptions& options,
|
|
@@ -750,11 +1100,10 @@ IOStatus FaultInjectionTestFS::RenameFile(const std::string& s,
|
|
|
750
1100
|
if (!IsFilesystemActive()) {
|
|
751
1101
|
return GetError();
|
|
752
1102
|
}
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
}
|
|
1103
|
+
IOStatus io_s = MaybeInjectThreadLocalError(
|
|
1104
|
+
FaultInjectionIOType::kMetadataWrite, options);
|
|
1105
|
+
if (!io_s.ok()) {
|
|
1106
|
+
return io_s;
|
|
758
1107
|
}
|
|
759
1108
|
|
|
760
1109
|
// We preserve contents of overwritten files up to a size threshold.
|
|
@@ -769,7 +1118,7 @@ IOStatus FaultInjectionTestFS::RenameFile(const std::string& s,
|
|
|
769
1118
|
ReadFileToString(target(), t, &previous_contents).PermitUncheckedError();
|
|
770
1119
|
}
|
|
771
1120
|
}
|
|
772
|
-
|
|
1121
|
+
io_s = FileSystemWrapper::RenameFile(s, t, options, dbg);
|
|
773
1122
|
|
|
774
1123
|
if (io_s.ok()) {
|
|
775
1124
|
{
|
|
@@ -783,16 +1132,10 @@ IOStatus FaultInjectionTestFS::RenameFile(const std::string& s,
|
|
|
783
1132
|
auto tdn = TestFSGetDirAndName(t);
|
|
784
1133
|
if (dir_to_new_files_since_last_sync_[sdn.first].erase(sdn.second) != 0) {
|
|
785
1134
|
auto& tlist = dir_to_new_files_since_last_sync_[tdn.first];
|
|
786
|
-
assert(tlist.find(tdn.second) == tlist.end());
|
|
787
1135
|
tlist[tdn.second] = previous_contents;
|
|
788
1136
|
}
|
|
789
1137
|
}
|
|
790
|
-
IOStatus in_s = InjectMetadataWriteError();
|
|
791
|
-
if (!in_s.ok()) {
|
|
792
|
-
return in_s;
|
|
793
|
-
}
|
|
794
1138
|
}
|
|
795
|
-
|
|
796
1139
|
return io_s;
|
|
797
1140
|
}
|
|
798
1141
|
|
|
@@ -803,22 +1146,27 @@ IOStatus FaultInjectionTestFS::LinkFile(const std::string& s,
|
|
|
803
1146
|
if (!IsFilesystemActive()) {
|
|
804
1147
|
return GetError();
|
|
805
1148
|
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
}
|
|
1149
|
+
IOStatus io_s = MaybeInjectThreadLocalError(
|
|
1150
|
+
FaultInjectionIOType::kMetadataWrite, options);
|
|
1151
|
+
if (!io_s.ok()) {
|
|
1152
|
+
return io_s;
|
|
811
1153
|
}
|
|
812
1154
|
|
|
813
1155
|
// Using the value in `dir_to_new_files_since_last_sync_` for the source file
|
|
814
1156
|
// may be a more reasonable choice.
|
|
815
1157
|
std::string previous_contents = kNewFileNoOverwrite;
|
|
816
1158
|
|
|
817
|
-
|
|
1159
|
+
io_s = FileSystemWrapper::LinkFile(s, t, options, dbg);
|
|
818
1160
|
|
|
819
1161
|
if (io_s.ok()) {
|
|
820
1162
|
{
|
|
821
1163
|
MutexLock l(&mutex_);
|
|
1164
|
+
if (!allow_link_open_file_ &&
|
|
1165
|
+
open_managed_files_.find(s) != open_managed_files_.end()) {
|
|
1166
|
+
fprintf(stderr, "Attempt to LinkFile while open for write: %s\n",
|
|
1167
|
+
s.c_str());
|
|
1168
|
+
abort();
|
|
1169
|
+
}
|
|
822
1170
|
if (db_file_state_.find(s) != db_file_state_.end()) {
|
|
823
1171
|
db_file_state_[t] = db_file_state_[s];
|
|
824
1172
|
}
|
|
@@ -832,12 +1180,74 @@ IOStatus FaultInjectionTestFS::LinkFile(const std::string& s,
|
|
|
832
1180
|
tlist[tdn.second] = previous_contents;
|
|
833
1181
|
}
|
|
834
1182
|
}
|
|
835
|
-
IOStatus in_s = InjectMetadataWriteError();
|
|
836
|
-
if (!in_s.ok()) {
|
|
837
|
-
return in_s;
|
|
838
|
-
}
|
|
839
1183
|
}
|
|
1184
|
+
return io_s;
|
|
1185
|
+
}
|
|
840
1186
|
|
|
1187
|
+
IOStatus FaultInjectionTestFS::NumFileLinks(const std::string& fname,
|
|
1188
|
+
const IOOptions& options,
|
|
1189
|
+
uint64_t* count,
|
|
1190
|
+
IODebugContext* dbg) {
|
|
1191
|
+
if (!IsFilesystemActive()) {
|
|
1192
|
+
return GetError();
|
|
1193
|
+
}
|
|
1194
|
+
IOStatus io_s =
|
|
1195
|
+
MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
|
|
1196
|
+
if (!io_s.ok()) {
|
|
1197
|
+
return io_s;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
io_s = target()->NumFileLinks(fname, options, count, dbg);
|
|
1201
|
+
return io_s;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
IOStatus FaultInjectionTestFS::AreFilesSame(const std::string& first,
|
|
1205
|
+
const std::string& second,
|
|
1206
|
+
const IOOptions& options, bool* res,
|
|
1207
|
+
IODebugContext* dbg) {
|
|
1208
|
+
if (!IsFilesystemActive()) {
|
|
1209
|
+
return GetError();
|
|
1210
|
+
}
|
|
1211
|
+
IOStatus io_s =
|
|
1212
|
+
MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
|
|
1213
|
+
if (!io_s.ok()) {
|
|
1214
|
+
return io_s;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
io_s = target()->AreFilesSame(first, second, options, res, dbg);
|
|
1218
|
+
return io_s;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
IOStatus FaultInjectionTestFS::GetAbsolutePath(const std::string& db_path,
|
|
1222
|
+
const IOOptions& options,
|
|
1223
|
+
std::string* output_path,
|
|
1224
|
+
IODebugContext* dbg) {
|
|
1225
|
+
if (!IsFilesystemActive()) {
|
|
1226
|
+
return GetError();
|
|
1227
|
+
}
|
|
1228
|
+
IOStatus io_s =
|
|
1229
|
+
MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
|
|
1230
|
+
if (!io_s.ok()) {
|
|
1231
|
+
return io_s;
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
io_s = target()->GetAbsolutePath(db_path, options, output_path, dbg);
|
|
1235
|
+
return io_s;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
IOStatus FaultInjectionTestFS::IsDirectory(const std::string& path,
|
|
1239
|
+
const IOOptions& options,
|
|
1240
|
+
bool* is_dir, IODebugContext* dgb) {
|
|
1241
|
+
if (!IsFilesystemActive()) {
|
|
1242
|
+
return GetError();
|
|
1243
|
+
}
|
|
1244
|
+
IOStatus io_s =
|
|
1245
|
+
MaybeInjectThreadLocalError(FaultInjectionIOType::kMetadataRead, options);
|
|
1246
|
+
if (!io_s.ok()) {
|
|
1247
|
+
return io_s;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
io_s = target()->IsDirectory(path, options, is_dir, dgb);
|
|
841
1251
|
return io_s;
|
|
842
1252
|
}
|
|
843
1253
|
|
|
@@ -954,14 +1364,17 @@ void FaultInjectionTestFS::UntrackFile(const std::string& f) {
|
|
|
954
1364
|
open_managed_files_.erase(f);
|
|
955
1365
|
}
|
|
956
1366
|
|
|
957
|
-
IOStatus FaultInjectionTestFS::
|
|
958
|
-
ErrorOperation op, Slice* result,
|
|
959
|
-
bool
|
|
1367
|
+
IOStatus FaultInjectionTestFS::MaybeInjectThreadLocalReadError(
|
|
1368
|
+
const IOOptions& io_options, ErrorOperation op, Slice* result,
|
|
1369
|
+
bool direct_io, char* scratch, bool need_count_increase,
|
|
1370
|
+
bool* fault_injected) {
|
|
960
1371
|
bool dummy_bool;
|
|
961
1372
|
bool& ret_fault_injected = fault_injected ? *fault_injected : dummy_bool;
|
|
962
1373
|
ret_fault_injected = false;
|
|
963
|
-
ErrorContext* ctx =
|
|
964
|
-
|
|
1374
|
+
ErrorContext* ctx =
|
|
1375
|
+
static_cast<ErrorContext*>(injected_thread_local_read_error_.Get());
|
|
1376
|
+
if (ctx == nullptr || !ctx->enable_error_injection || !ctx->one_in ||
|
|
1377
|
+
ShouldIOActivtiesExcludedFromFaultInjection(io_options.io_activity)) {
|
|
965
1378
|
return IOStatus::OK();
|
|
966
1379
|
}
|
|
967
1380
|
|
|
@@ -1013,9 +1426,9 @@ IOStatus FaultInjectionTestFS::InjectThreadSpecificReadError(
|
|
|
1013
1426
|
ret = IOStatus::IOError(ctx->message);
|
|
1014
1427
|
}
|
|
1015
1428
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1429
|
+
|
|
1430
|
+
ret.SetRetryable(ctx->retryable);
|
|
1431
|
+
ret.SetDataLoss(ctx->has_data_loss);
|
|
1019
1432
|
return ret;
|
|
1020
1433
|
}
|
|
1021
1434
|
|
|
@@ -1026,59 +1439,58 @@ bool FaultInjectionTestFS::TryParseFileName(const std::string& file_name,
|
|
|
1026
1439
|
return ParseFileName(file, number, type);
|
|
1027
1440
|
}
|
|
1028
1441
|
|
|
1029
|
-
IOStatus FaultInjectionTestFS::
|
|
1030
|
-
|
|
1031
|
-
|
|
1442
|
+
IOStatus FaultInjectionTestFS::MaybeInjectThreadLocalError(
|
|
1443
|
+
FaultInjectionIOType type, const IOOptions& io_options,
|
|
1444
|
+
const std::string& file_name, ErrorOperation op, Slice* result,
|
|
1445
|
+
bool direct_io, char* scratch, bool need_count_increase,
|
|
1446
|
+
bool* fault_injected) {
|
|
1447
|
+
if (type == FaultInjectionIOType::kRead) {
|
|
1448
|
+
return MaybeInjectThreadLocalReadError(io_options, op, result, direct_io,
|
|
1449
|
+
scratch, need_count_increase,
|
|
1450
|
+
fault_injected);
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
ErrorContext* ctx = GetErrorContextFromFaultInjectionIOType(type);
|
|
1454
|
+
if (ctx == nullptr || !ctx->enable_error_injection || !ctx->one_in ||
|
|
1455
|
+
ShouldIOActivtiesExcludedFromFaultInjection(io_options.io_activity) ||
|
|
1456
|
+
(type == FaultInjectionIOType::kWrite &&
|
|
1457
|
+
ShouldExcludeFromWriteFaultInjection(file_name))) {
|
|
1032
1458
|
return IOStatus::OK();
|
|
1033
1459
|
}
|
|
1034
|
-
bool allowed_type = false;
|
|
1035
|
-
|
|
1036
|
-
if (inject_for_all_file_types_) {
|
|
1037
|
-
allowed_type = true;
|
|
1038
|
-
} else {
|
|
1039
|
-
uint64_t number;
|
|
1040
|
-
FileType cur_type = kTempFile;
|
|
1041
|
-
if (TryParseFileName(file_name, &number, &cur_type)) {
|
|
1042
|
-
for (const auto& type : write_error_allowed_types_) {
|
|
1043
|
-
if (cur_type == type) {
|
|
1044
|
-
allowed_type = true;
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
1460
|
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1461
|
+
IOStatus ret;
|
|
1462
|
+
if (ctx->rand.OneIn(ctx->one_in)) {
|
|
1463
|
+
ctx->count++;
|
|
1464
|
+
if (ctx->callstack) {
|
|
1465
|
+
free(ctx->callstack);
|
|
1053
1466
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
!metadata_write_error_one_in_ ||
|
|
1063
|
-
!write_error_rand_.OneIn(metadata_write_error_one_in_)) {
|
|
1064
|
-
return IOStatus::OK();
|
|
1467
|
+
ctx->callstack = port::SaveStack(&ctx->frames);
|
|
1468
|
+
ctx->message = GetErrorMessageFromFaultInjectionIOType(type);
|
|
1469
|
+
ret = IOStatus::IOError(ctx->message);
|
|
1470
|
+
ret.SetRetryable(ctx->retryable);
|
|
1471
|
+
ret.SetDataLoss(ctx->has_data_loss);
|
|
1472
|
+
if (type == FaultInjectionIOType::kWrite) {
|
|
1473
|
+
TEST_SYNC_POINT(
|
|
1474
|
+
"FaultInjectionTestFS::InjectMetadataWriteError:Injected");
|
|
1065
1475
|
}
|
|
1066
1476
|
}
|
|
1067
|
-
|
|
1068
|
-
return IOStatus::IOError("injected metadata write error");
|
|
1477
|
+
return ret;
|
|
1069
1478
|
}
|
|
1070
1479
|
|
|
1071
|
-
void FaultInjectionTestFS::
|
|
1480
|
+
void FaultInjectionTestFS::PrintInjectedThreadLocalErrorBacktrace(
|
|
1481
|
+
FaultInjectionIOType type) {
|
|
1072
1482
|
#if defined(OS_LINUX)
|
|
1073
|
-
ErrorContext* ctx =
|
|
1074
|
-
if (ctx
|
|
1075
|
-
|
|
1483
|
+
ErrorContext* ctx = GetErrorContextFromFaultInjectionIOType(type);
|
|
1484
|
+
if (ctx) {
|
|
1485
|
+
if (type == FaultInjectionIOType::kRead) {
|
|
1486
|
+
fprintf(stderr, "Injected read error type = %d\n", ctx->type);
|
|
1487
|
+
}
|
|
1488
|
+
fprintf(stderr, "Message: %s\n", ctx->message.c_str());
|
|
1489
|
+
port::PrintAndFreeStack(ctx->callstack, ctx->frames);
|
|
1490
|
+
ctx->callstack = nullptr;
|
|
1076
1491
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
port::PrintAndFreeStack(ctx->callstack, ctx->frames);
|
|
1080
|
-
ctx->callstack = nullptr;
|
|
1492
|
+
#else
|
|
1493
|
+
(void)type;
|
|
1081
1494
|
#endif
|
|
1082
1495
|
}
|
|
1083
|
-
|
|
1084
1496
|
} // namespace ROCKSDB_NAMESPACE
|