archive_r_ruby 0.1.7 → 0.1.9
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.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/NOTICE +71 -0
- data/VERSION +1 -0
- data/ext/archive_r/archive_r_ext.cc +9 -8
- data/ext/archive_r/vendor/archive_r/LICENSE +21 -0
- data/ext/archive_r/vendor/archive_r/NOTICE +71 -0
- data/ext/archive_r/vendor/archive_r/include/archive_r/data_stream.h +2 -2
- data/ext/archive_r/vendor/archive_r/include/archive_r/entry.h +8 -8
- data/ext/archive_r/vendor/archive_r/include/archive_r/multi_volume_stream_base.h +2 -2
- data/ext/archive_r/vendor/archive_r/include/archive_r/path_hierarchy_utils.h +0 -1
- data/ext/archive_r/vendor/archive_r/include/archive_r/platform_compat.h +8 -8
- data/ext/archive_r/vendor/archive_r/include/archive_r/traverser.h +2 -2
- data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.cc +10 -34
- data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.h +1 -3
- data/ext/archive_r/vendor/archive_r/src/archive_stack_orchestrator.cc +5 -6
- data/ext/archive_r/vendor/archive_r/src/archive_stack_orchestrator.h +2 -3
- data/ext/archive_r/vendor/archive_r/src/archive_type.cc +6 -13
- data/ext/archive_r/vendor/archive_r/src/archive_type.h +3 -3
- data/ext/archive_r/vendor/archive_r/src/entry.cc +2 -17
- data/ext/archive_r/vendor/archive_r/src/entry_fault_error.cc +23 -23
- data/ext/archive_r/vendor/archive_r/src/entry_impl.h +1 -2
- data/ext/archive_r/vendor/archive_r/src/multi_volume_manager.cc +3 -8
- data/ext/archive_r/vendor/archive_r/src/multi_volume_manager.h +2 -4
- data/ext/archive_r/vendor/archive_r/src/multi_volume_stream_base.cc +23 -14
- data/ext/archive_r/vendor/archive_r/src/path_hierarchy.cc +1 -4
- data/ext/archive_r/vendor/archive_r/src/path_hierarchy_utils.cc +14 -36
- data/ext/archive_r/vendor/archive_r/src/simple_profiler.h +64 -75
- data/ext/archive_r/vendor/archive_r/src/system_file_stream.cc +21 -26
- data/ext/archive_r/vendor/archive_r/src/system_file_stream.h +2 -2
- data/ext/archive_r/vendor/archive_r/src/traverser.cc +18 -42
- data/lib/archive_r.rb +5 -1
- metadata +11 -5
- data/LICENSE.txt +0 -97
- data/ext/archive_r/vendor/archive_r/LICENSE.txt +0 -97
|
@@ -18,35 +18,35 @@ EntryFaultError::EntryFaultError(EntryFault fault, const std::string &internal_m
|
|
|
18
18
|
, _fault(std::move(fault)) {}
|
|
19
19
|
|
|
20
20
|
EntryFaultError make_entry_fault_error(const std::string &message, PathHierarchy hierarchy, int errno_value) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
EntryFault fault;
|
|
22
|
+
fault.hierarchy = std::move(hierarchy);
|
|
23
|
+
fault.message = message;
|
|
24
|
+
fault.errno_value = errno_value;
|
|
25
|
+
return EntryFaultError(std::move(fault));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
std::string format_errno_error(const std::string &prefix, int err) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
if (err == 0) {
|
|
30
|
+
return prefix;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
std::string message = prefix;
|
|
34
|
+
message.append(": ");
|
|
35
|
+
message.append(std::strerror(err));
|
|
36
|
+
message.append(" (posix errno=");
|
|
37
|
+
message.append(std::to_string(err));
|
|
38
|
+
message.push_back(')');
|
|
39
|
+
return message;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
std::string format_path_errno_error(const std::string &action, const std::string &path, int err) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
std::string prefix = action;
|
|
44
|
+
if (!path.empty()) {
|
|
45
|
+
prefix.append(" '");
|
|
46
|
+
prefix.append(path);
|
|
47
|
+
prefix.push_back('\'');
|
|
48
|
+
}
|
|
49
|
+
return format_errno_error(prefix, err);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
std::string prefer_error_detail(const std::string &detail, const std::string &fallback) { return detail.empty() ? fallback : detail; }
|
|
@@ -19,7 +19,6 @@ public:
|
|
|
19
19
|
// No libarchive dependency
|
|
20
20
|
// Copy constructor and assignment (orchestrator is not copied)
|
|
21
21
|
Impl(const Impl &other);
|
|
22
|
-
Impl &operator=(const Impl &other);
|
|
23
22
|
|
|
24
23
|
Impl(const PathHierarchy &hierarchy, std::shared_ptr<ArchiveStackOrchestrator> data_source_orchestrator, bool default_descent);
|
|
25
24
|
|
|
@@ -45,7 +44,7 @@ private:
|
|
|
45
44
|
EntryMetadataMap _metadata;
|
|
46
45
|
bool _descend_enabled = true; // Flag to control automatic descent
|
|
47
46
|
|
|
48
|
-
std::shared_ptr<ArchiveStackOrchestrator> _orchestrator;
|
|
47
|
+
std::shared_ptr<ArchiveStackOrchestrator> _orchestrator; ///< Active orchestrator (shared with traverser or detached copy)
|
|
49
48
|
bool _shares_traverser_orchestrator = false;
|
|
50
49
|
|
|
51
50
|
mutable std::optional<ArchiveOption> _archive_options;
|
|
@@ -10,9 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
namespace archive_r {
|
|
12
12
|
|
|
13
|
-
MultiVolumeManager::MultiVolumeGroup &MultiVolumeManager::get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy,
|
|
14
|
-
const std::string &base_name,
|
|
15
|
-
PathEntry::Parts::Ordering ordering) {
|
|
13
|
+
MultiVolumeManager::MultiVolumeGroup &MultiVolumeManager::get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy, const std::string &base_name, PathEntry::Parts::Ordering ordering) {
|
|
16
14
|
GroupList &groups = _multi_volume_groups[parent_hierarchy];
|
|
17
15
|
auto it = std::find_if(groups.begin(), groups.end(), [&](const MultiVolumeGroup &group) { return group.base_name == base_name; });
|
|
18
16
|
|
|
@@ -47,17 +45,14 @@ bool MultiVolumeManager::pop_group_for_parent(const PathHierarchy &parent_hierar
|
|
|
47
45
|
return true;
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
void MultiVolumeManager::mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name,
|
|
51
|
-
PathEntry::Parts::Ordering ordering) {
|
|
48
|
+
void MultiVolumeManager::mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name, PathEntry::Parts::Ordering ordering) {
|
|
52
49
|
if (entry_path.empty() || pathhierarchy_is_multivolume(entry_path)) {
|
|
53
50
|
return;
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
MultiVolumeGroup &target = get_or_create_multi_volume_group(parent_hierarchy(entry_path), base_name, ordering);
|
|
57
54
|
auto &parts = target.parts;
|
|
58
|
-
const bool exists = std::any_of(parts.begin(), parts.end(), [&](const PathHierarchy &existing) {
|
|
59
|
-
return hierarchies_equal(existing, entry_path);
|
|
60
|
-
});
|
|
55
|
+
const bool exists = std::any_of(parts.begin(), parts.end(), [&](const PathHierarchy &existing) { return hierarchies_equal(existing, entry_path); });
|
|
61
56
|
if (!exists) {
|
|
62
57
|
parts.push_back(entry_path);
|
|
63
58
|
}
|
|
@@ -24,14 +24,12 @@ public:
|
|
|
24
24
|
using GroupList = std::vector<MultiVolumeGroup>;
|
|
25
25
|
using ParentGroupMap = std::map<PathHierarchy, GroupList, PathHierarchyLess>;
|
|
26
26
|
|
|
27
|
-
void mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name,
|
|
28
|
-
PathEntry::Parts::Ordering ordering = PathEntry::Parts::Ordering::Natural);
|
|
27
|
+
void mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name, PathEntry::Parts::Ordering ordering = PathEntry::Parts::Ordering::Natural);
|
|
29
28
|
|
|
30
29
|
bool pop_multi_volume_group(const PathHierarchy ¤t_hierarchy, PathHierarchy &multi_volume_hierarchy);
|
|
31
30
|
|
|
32
31
|
private:
|
|
33
|
-
MultiVolumeGroup &get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy, const std::string &base_name,
|
|
34
|
-
PathEntry::Parts::Ordering ordering);
|
|
32
|
+
MultiVolumeGroup &get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy, const std::string &base_name, PathEntry::Parts::Ordering ordering);
|
|
35
33
|
|
|
36
34
|
bool pop_group_for_parent(const PathHierarchy &parent_hierarchy, MultiVolumeGroup &out_group);
|
|
37
35
|
|
|
@@ -33,9 +33,9 @@ struct MultiVolumeStreamBase::Impl {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
MultiVolumeStreamBase::MultiVolumeStreamBase(PathHierarchy logical_path, bool supports_seek)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
: _logical_path(std::move(logical_path))
|
|
37
|
+
, _supports_seek(supports_seek)
|
|
38
|
+
, _impl(std::make_unique<Impl>(*this)) {
|
|
39
39
|
_impl->total_parts = pathhierarchy_volume_size(_logical_path);
|
|
40
40
|
if (_impl->total_parts == 0) {
|
|
41
41
|
throw std::invalid_argument("MultiVolumeStreamBase requires at least one volume component");
|
|
@@ -84,9 +84,7 @@ void MultiVolumeStreamBase::rewind() {
|
|
|
84
84
|
_impl->logical_offset = 0;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
bool MultiVolumeStreamBase::at_end() const {
|
|
88
|
-
return _impl->active_part_index >= _impl->total_parts;
|
|
89
|
-
}
|
|
87
|
+
bool MultiVolumeStreamBase::at_end() const { return _impl->active_part_index >= _impl->total_parts; }
|
|
90
88
|
|
|
91
89
|
int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
|
|
92
90
|
if (!_supports_seek) {
|
|
@@ -122,6 +120,17 @@ int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
|
|
|
122
120
|
|
|
123
121
|
int64_t MultiVolumeStreamBase::tell() const { return _impl->logical_offset; }
|
|
124
122
|
|
|
123
|
+
int64_t MultiVolumeStreamBase::seek_within_single_part(int64_t offset, int whence) {
|
|
124
|
+
(void)offset;
|
|
125
|
+
(void)whence;
|
|
126
|
+
return -1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
int64_t MultiVolumeStreamBase::size_of_single_part(const PathHierarchy &single_part) {
|
|
130
|
+
(void)single_part;
|
|
131
|
+
return -1;
|
|
132
|
+
}
|
|
133
|
+
|
|
125
134
|
void MultiVolumeStreamBase::Impl::ensure_part_active(std::size_t part_index) {
|
|
126
135
|
if (part_open && open_part_index == part_index) {
|
|
127
136
|
return;
|
|
@@ -173,14 +182,14 @@ bool MultiVolumeStreamBase::Impl::ensure_size_metadata() {
|
|
|
173
182
|
|
|
174
183
|
int64_t MultiVolumeStreamBase::Impl::compute_target_offset(int64_t offset, int whence) const {
|
|
175
184
|
switch (whence) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
185
|
+
case SEEK_SET:
|
|
186
|
+
return offset;
|
|
187
|
+
case SEEK_CUR:
|
|
188
|
+
return logical_offset + offset;
|
|
189
|
+
case SEEK_END:
|
|
190
|
+
return total_size + offset;
|
|
191
|
+
default:
|
|
192
|
+
return -1;
|
|
184
193
|
}
|
|
185
194
|
}
|
|
186
195
|
|
|
@@ -107,9 +107,7 @@ PathHierarchy make_single_path(const std::string &root) {
|
|
|
107
107
|
|
|
108
108
|
void append_single(PathHierarchy &hierarchy, std::string value) { hierarchy.emplace_back(PathEntry::single(std::move(value))); }
|
|
109
109
|
|
|
110
|
-
void append_multi_volume(PathHierarchy &hierarchy, std::vector<std::string> parts, PathEntry::Parts::Ordering ordering) {
|
|
111
|
-
hierarchy.emplace_back(PathEntry::multi_volume(std::move(parts), ordering));
|
|
112
|
-
}
|
|
110
|
+
void append_multi_volume(PathHierarchy &hierarchy, std::vector<std::string> parts, PathEntry::Parts::Ordering ordering) { hierarchy.emplace_back(PathEntry::multi_volume(std::move(parts), ordering)); }
|
|
113
111
|
|
|
114
112
|
PathHierarchy pathhierarchy_prefix_until(const PathHierarchy &hierarchy, size_t inclusive_index) {
|
|
115
113
|
if (hierarchy.empty() || inclusive_index >= hierarchy.size()) {
|
|
@@ -126,5 +124,4 @@ PathHierarchy parent_hierarchy(const PathHierarchy &hierarchy) {
|
|
|
126
124
|
return pathhierarchy_prefix_until(hierarchy, hierarchy.size() - 2);
|
|
127
125
|
}
|
|
128
126
|
|
|
129
|
-
|
|
130
127
|
} // namespace archive_r
|
|
@@ -73,10 +73,6 @@ bool determine_multi_volume_segments(const std::vector<PathHierarchy> &sources,
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
bool collect_multi_volume_parts(const std::vector<PathHierarchy> &sources, const CollapseSegments &segments, std::vector<std::string> &parts) {
|
|
76
|
-
if (sources.empty()) {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
76
|
const std::size_t suffix_size = segments.suffix.size();
|
|
81
77
|
const std::size_t required_size = segments.multi_volume_depth + 1 + suffix_size;
|
|
82
78
|
|
|
@@ -111,14 +107,6 @@ bool collect_multi_volume_parts(const std::vector<PathHierarchy> &sources, const
|
|
|
111
107
|
return true;
|
|
112
108
|
}
|
|
113
109
|
|
|
114
|
-
bool flatten_single_entry(const PathEntry &entry, std::string &output) {
|
|
115
|
-
if (entry.is_single()) {
|
|
116
|
-
output = entry.single_value();
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
return flatten_entry_to_string(entry, output);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
110
|
} // namespace
|
|
123
111
|
|
|
124
112
|
const std::string *path_entry_component_at(const PathEntry &entry, std::size_t index) {
|
|
@@ -129,14 +117,10 @@ const std::string *path_entry_component_at(const PathEntry &entry, std::size_t i
|
|
|
129
117
|
return nullptr;
|
|
130
118
|
}
|
|
131
119
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return &parts[index];
|
|
136
|
-
}
|
|
137
|
-
return nullptr;
|
|
120
|
+
const auto &parts = entry.multi_volume_parts().values;
|
|
121
|
+
if (index < parts.size()) {
|
|
122
|
+
return &parts[index];
|
|
138
123
|
}
|
|
139
|
-
|
|
140
124
|
return nullptr;
|
|
141
125
|
}
|
|
142
126
|
|
|
@@ -162,11 +146,7 @@ std::string pathhierarchy_volume_entry_name(const PathHierarchy &logical, std::s
|
|
|
162
146
|
return {};
|
|
163
147
|
}
|
|
164
148
|
|
|
165
|
-
|
|
166
|
-
if (!flatten_single_entry(tail, entry_name)) {
|
|
167
|
-
return {};
|
|
168
|
-
}
|
|
169
|
-
return entry_name;
|
|
149
|
+
return tail.single_value();
|
|
170
150
|
}
|
|
171
151
|
|
|
172
152
|
const auto &parts = tail.multi_volume_parts().values;
|
|
@@ -241,20 +221,18 @@ std::string path_entry_display(const PathEntry &entry) {
|
|
|
241
221
|
if (entry.is_single()) {
|
|
242
222
|
return entry.single_value();
|
|
243
223
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
value += part;
|
|
252
|
-
first = false;
|
|
224
|
+
|
|
225
|
+
std::string value = "[";
|
|
226
|
+
bool first = true;
|
|
227
|
+
for (const auto &part : entry.multi_volume_parts().values) {
|
|
228
|
+
if (!first) {
|
|
229
|
+
value.push_back('|');
|
|
253
230
|
}
|
|
254
|
-
value
|
|
255
|
-
|
|
231
|
+
value += part;
|
|
232
|
+
first = false;
|
|
256
233
|
}
|
|
257
|
-
|
|
234
|
+
value.push_back(']');
|
|
235
|
+
return value;
|
|
258
236
|
}
|
|
259
237
|
|
|
260
238
|
std::string hierarchy_display(const PathHierarchy &hierarchy) {
|
|
@@ -4,106 +4,95 @@
|
|
|
4
4
|
#pragma once
|
|
5
5
|
#include <string>
|
|
6
6
|
|
|
7
|
+
#include <algorithm>
|
|
7
8
|
#include <chrono>
|
|
9
|
+
#include <iomanip>
|
|
8
10
|
#include <iostream>
|
|
9
11
|
#include <map>
|
|
10
|
-
#include <vector>
|
|
11
|
-
#include <algorithm>
|
|
12
|
-
#include <iomanip>
|
|
13
12
|
#include <mutex>
|
|
14
|
-
|
|
13
|
+
#include <vector>
|
|
15
14
|
|
|
16
15
|
namespace archive_r {
|
|
17
16
|
namespace internal {
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
18
|
class SimpleProfiler {
|
|
22
19
|
public:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
static SimpleProfiler &instance() {
|
|
21
|
+
static SimpleProfiler inst;
|
|
22
|
+
return inst;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
~SimpleProfiler() { report(); }
|
|
26
|
+
|
|
27
|
+
void start(const std::string &name) {
|
|
28
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
29
|
+
auto now = std::chrono::high_resolution_clock::now();
|
|
30
|
+
start_times_[name] = now;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void stop(const std::string &name) {
|
|
34
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
35
|
+
auto now = std::chrono::high_resolution_clock::now();
|
|
36
|
+
auto it = start_times_.find(name);
|
|
37
|
+
if (it != start_times_.end()) {
|
|
38
|
+
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(now - it->second).count();
|
|
39
|
+
durations_[name] += duration;
|
|
40
|
+
counts_[name]++;
|
|
26
41
|
}
|
|
42
|
+
}
|
|
27
43
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
44
|
+
void report() {
|
|
45
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
46
|
+
if (durations_.empty())
|
|
47
|
+
return;
|
|
31
48
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
std::cout << "\n=== Profiling Report (archive_r::internal) ===" << std::endl;
|
|
50
|
+
std::vector<std::pair<std::string, long long>> sorted_durations;
|
|
51
|
+
for (const auto &pair : durations_) {
|
|
52
|
+
sorted_durations.push_back(pair);
|
|
36
53
|
}
|
|
37
54
|
|
|
38
|
-
|
|
39
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
40
|
-
auto now = std::chrono::high_resolution_clock::now();
|
|
41
|
-
auto it = start_times_.find(name);
|
|
42
|
-
if (it != start_times_.end()) {
|
|
43
|
-
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(now - it->second).count();
|
|
44
|
-
durations_[name] += duration;
|
|
45
|
-
counts_[name]++;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
55
|
+
std::sort(sorted_durations.begin(), sorted_durations.end(), [](const auto &a, const auto &b) { return a.second > b.second; });
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
std::sort(sorted_durations.begin(), sorted_durations.end(),
|
|
60
|
-
[](const auto& a, const auto& b) { return a.second > b.second; });
|
|
61
|
-
|
|
62
|
-
std::cout << std::left << std::setw(40) << "Name"
|
|
63
|
-
<< std::right << std::setw(15) << "Total (ms)"
|
|
64
|
-
<< std::setw(10) << "Count"
|
|
65
|
-
<< std::setw(15) << "Avg (us)" << std::endl;
|
|
66
|
-
std::cout << std::string(80, '-') << std::endl;
|
|
67
|
-
|
|
68
|
-
for (const auto& pair : sorted_durations) {
|
|
69
|
-
const auto& name = pair.first;
|
|
70
|
-
long long total_ns = pair.second;
|
|
71
|
-
long long count = counts_[name];
|
|
72
|
-
double avg_ns = count > 0 ? (double)total_ns / count : 0;
|
|
73
|
-
|
|
74
|
-
std::cout << std::left << std::setw(40) << name
|
|
75
|
-
<< std::right << std::setw(15) << std::fixed << std::setprecision(3) << total_ns / 1000000.0
|
|
76
|
-
<< std::setw(10) << count
|
|
77
|
-
<< std::setw(15) << std::fixed << std::setprecision(3) << avg_ns / 1000.0
|
|
78
|
-
<< std::endl;
|
|
79
|
-
}
|
|
80
|
-
std::cout << "==============================================\n" << std::endl;
|
|
81
|
-
}
|
|
57
|
+
std::cout << std::left << std::setw(40) << "Name" << std::right << std::setw(15) << "Total (ms)" << std::setw(10) << "Count" << std::setw(15) << "Avg (us)" << std::endl;
|
|
58
|
+
std::cout << std::string(80, '-') << std::endl;
|
|
59
|
+
|
|
60
|
+
for (const auto &pair : sorted_durations) {
|
|
61
|
+
const auto &name = pair.first;
|
|
62
|
+
long long total_ns = pair.second;
|
|
63
|
+
long long count = counts_[name];
|
|
64
|
+
double avg_ns = count > 0 ? (double)total_ns / count : 0;
|
|
82
65
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
start_times_.clear();
|
|
86
|
-
durations_.clear();
|
|
87
|
-
counts_.clear();
|
|
66
|
+
std::cout << std::left << std::setw(40) << name << std::right << std::setw(15) << std::fixed << std::setprecision(3) << total_ns / 1000000.0 << std::setw(10) << count << std::setw(15)
|
|
67
|
+
<< std::fixed << std::setprecision(3) << avg_ns / 1000.0 << std::endl;
|
|
88
68
|
}
|
|
69
|
+
std::cout << "==============================================\n" << std::endl;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
void reset() {
|
|
73
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
74
|
+
start_times_.clear();
|
|
75
|
+
durations_.clear();
|
|
76
|
+
counts_.clear();
|
|
77
|
+
}
|
|
89
78
|
|
|
90
79
|
private:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
80
|
+
std::map<std::string, std::chrono::high_resolution_clock::time_point> start_times_;
|
|
81
|
+
std::map<std::string, long long> durations_;
|
|
82
|
+
std::map<std::string, long long> counts_;
|
|
83
|
+
std::mutex mutex_;
|
|
95
84
|
};
|
|
96
85
|
|
|
97
86
|
class ScopedTimer {
|
|
98
87
|
public:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
88
|
+
ScopedTimer(const std::string &name)
|
|
89
|
+
: name_(name) {
|
|
90
|
+
SimpleProfiler::instance().start(name_);
|
|
91
|
+
}
|
|
92
|
+
~ScopedTimer() { SimpleProfiler::instance().stop(name_); }
|
|
93
|
+
|
|
105
94
|
private:
|
|
106
|
-
|
|
95
|
+
std::string name_;
|
|
107
96
|
};
|
|
108
97
|
|
|
109
98
|
} // namespace internal
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
#include <cstdio>
|
|
12
12
|
#include <filesystem>
|
|
13
13
|
#include <stdexcept>
|
|
14
|
+
#include <string_view>
|
|
14
15
|
#include <sys/stat.h>
|
|
15
16
|
#include <system_error>
|
|
16
|
-
#include <string_view>
|
|
17
17
|
#include <utility>
|
|
18
18
|
#include <vector>
|
|
19
19
|
|
|
20
20
|
#if !defined(_WIN32)
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
21
|
+
#include <grp.h>
|
|
22
|
+
#include <pwd.h>
|
|
23
|
+
#include <unistd.h>
|
|
24
24
|
#endif
|
|
25
25
|
|
|
26
26
|
namespace archive_r {
|
|
@@ -66,21 +66,10 @@ static bool lookup_groupname(gid_t gid, std::string &name_out) {
|
|
|
66
66
|
} // namespace
|
|
67
67
|
|
|
68
68
|
SystemFileStream::SystemFileStream(PathHierarchy logical_path)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (_logical_path.empty()) {
|
|
72
|
-
throw std::invalid_argument("Root file hierarchy cannot be empty");
|
|
73
|
-
}
|
|
69
|
+
: MultiVolumeStreamBase(std::move(logical_path), true)
|
|
70
|
+
, _handle(nullptr) {}
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
if (!root_entry.is_single() && !root_entry.is_multi_volume()) {
|
|
77
|
-
throw std::invalid_argument("Root file hierarchy must be a single file or multi-volume source");
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
SystemFileStream::~SystemFileStream() {
|
|
82
|
-
deactivate_active_part();
|
|
83
|
-
}
|
|
72
|
+
SystemFileStream::~SystemFileStream() { deactivate_active_part(); }
|
|
84
73
|
|
|
85
74
|
void SystemFileStream::open_single_part(const PathHierarchy &single_part) {
|
|
86
75
|
const PathEntry &entry = single_part.back();
|
|
@@ -100,7 +89,7 @@ void SystemFileStream::open_single_part(const PathHierarchy &single_part) {
|
|
|
100
89
|
// Enable larger buffering on Windows to improve performance
|
|
101
90
|
// Use 64KB buffer to match StreamArchive's buffer size
|
|
102
91
|
if (_handle) {
|
|
103
|
-
|
|
92
|
+
std::setvbuf(_handle, nullptr, _IOFBF, 65536);
|
|
104
93
|
}
|
|
105
94
|
#endif
|
|
106
95
|
}
|
|
@@ -168,6 +157,8 @@ void SystemFileStream::report_read_failure(int err) {
|
|
|
168
157
|
throw make_entry_fault_error(detailed, _logical_path, err);
|
|
169
158
|
}
|
|
170
159
|
|
|
160
|
+
// Collect filesystem metadata for the root path in the hierarchy.
|
|
161
|
+
// Returns an empty info struct when metadata is unavailable or disallowed.
|
|
171
162
|
FilesystemMetadataInfo collect_root_path_metadata(const PathHierarchy &hierarchy, const std::unordered_set<std::string> &allowed_keys) {
|
|
172
163
|
FilesystemMetadataInfo info;
|
|
173
164
|
|
|
@@ -187,6 +178,12 @@ FilesystemMetadataInfo collect_root_path_metadata(const PathHierarchy &hierarchy
|
|
|
187
178
|
return info;
|
|
188
179
|
}
|
|
189
180
|
|
|
181
|
+
ec.clear();
|
|
182
|
+
const bool exists = entry.exists(ec);
|
|
183
|
+
if (ec || !exists) {
|
|
184
|
+
return info;
|
|
185
|
+
}
|
|
186
|
+
|
|
190
187
|
mode_t filetype = 0;
|
|
191
188
|
uint64_t size = 0;
|
|
192
189
|
|
|
@@ -219,9 +216,7 @@ FilesystemMetadataInfo collect_root_path_metadata(const PathHierarchy &hierarchy
|
|
|
219
216
|
info.filetype = filetype;
|
|
220
217
|
EntryMetadataMap metadata;
|
|
221
218
|
if (!allowed_keys.empty()) {
|
|
222
|
-
const auto wants = [&allowed_keys](std::string_view key) {
|
|
223
|
-
return allowed_keys.find(std::string(key)) != allowed_keys.end();
|
|
224
|
-
};
|
|
219
|
+
const auto wants = [&allowed_keys](std::string_view key) { return allowed_keys.find(std::string(key)) != allowed_keys.end(); };
|
|
225
220
|
|
|
226
221
|
// Path hierarchy / directory entry derived metadata
|
|
227
222
|
if (wants("pathname")) {
|
|
@@ -246,10 +241,10 @@ FilesystemMetadataInfo collect_root_path_metadata(const PathHierarchy &hierarchy
|
|
|
246
241
|
}
|
|
247
242
|
|
|
248
243
|
const bool needs_stat = (wants("size") && size == 0)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
244
|
+
#if !defined(_WIN32)
|
|
245
|
+
|| wants("uid") || wants("gid") || wants("uname") || wants("gname")
|
|
246
|
+
#endif
|
|
247
|
+
;
|
|
253
248
|
|
|
254
249
|
struct stat stat_buffer;
|
|
255
250
|
bool have_stat = false;
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
#include <unordered_set>
|
|
11
11
|
#include <vector>
|
|
12
12
|
|
|
13
|
-
#include "archive_r/multi_volume_stream_base.h"
|
|
14
|
-
#include "archive_r/platform_compat.h"
|
|
15
13
|
#include "archive_r/entry_metadata.h"
|
|
14
|
+
#include "archive_r/multi_volume_stream_base.h"
|
|
16
15
|
#include "archive_r/path_hierarchy.h"
|
|
16
|
+
#include "archive_r/platform_compat.h"
|
|
17
17
|
|
|
18
18
|
namespace archive_r {
|
|
19
19
|
|