Skip to content

Commit 89c5d7e

Browse files
committed
[libcxx] Fixes after review, add & improve test.
1 parent d8211d9 commit 89c5d7e

File tree

5 files changed

+109
-52
lines changed

5 files changed

+109
-52
lines changed

libcxx/include/__configuration/availability.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,9 +353,10 @@
353353
#define _LIBCPP_AVAILABILITY_HAS_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19
354354
#define _LIBCPP_AVAILABILITY_BAD_EXPECTED_ACCESS_KEY_FUNCTION _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE
355355

356-
// This controls the availability of populating cache for directory entry
357-
// filesystem system. A directory_iterator builds cache for directory_entry
358-
// in the library.
356+
// This determines whether std::filesystem::directory_entry caches all the properties
357+
// it contains, which improves the performance when accessing a directory entry.
358+
// Code in the headers like filesystem::directory_entry's implementation needs to
359+
// know whether the dylib populated the cache or not.
359360
#define _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY _LIBCPP_INTRODUCED_IN_LLVM_19
360361
#define _LIBCPP_AVAILABILITY_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY _LIBCPP_INTRODUCED_IN_LLVM_19_ATTRIBUTE
361362

libcxx/include/__filesystem/directory_entry.h

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,8 @@ class directory_entry {
202202
_RefreshSymlink,
203203
_RefreshSymlinkUnresolved,
204204
_RefreshNonSymlink,
205-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
206205
_IterCachedSymlink,
207206
_IterCachedNonSymlink
208-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
209207
};
210208

211209
struct __cached_data {
@@ -244,7 +242,6 @@ class directory_entry {
244242
return __data;
245243
}
246244

247-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
248245
_LIBCPP_HIDE_FROM_ABI static __cached_data
249246
__create_iter_cached_result(file_type __ft, uintmax_t __size, perms __perm, file_time_type __write_time) {
250247
__cached_data __data;
@@ -267,7 +264,6 @@ class directory_entry {
267264
}();
268265
return __data;
269266
}
270-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
271267

272268
_LIBCPP_HIDE_FROM_ABI void __assign_iter_entry(_Path&& __p, __cached_data __dt) {
273269
__p_ = std::move(__p);
@@ -310,17 +306,13 @@ class directory_entry {
310306
case _Empty:
311307
return __symlink_status(__p_, __ec).type();
312308
case _IterSymlink:
313-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
314309
case _IterCachedSymlink:
315-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
316310
case _RefreshSymlink:
317311
case _RefreshSymlinkUnresolved:
318312
if (__ec)
319313
__ec->clear();
320314
return file_type::symlink;
321-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
322315
case _IterCachedNonSymlink:
323-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
324316
case _IterNonSymlink:
325317
case _RefreshNonSymlink: {
326318
file_status __st(__data_.__type_);
@@ -338,13 +330,10 @@ class directory_entry {
338330
switch (__data_.__cache_type_) {
339331
case _Empty:
340332
case _IterSymlink:
341-
case _RefreshSymlinkUnresolved:
342-
return __status(__p_, __ec).type();
343-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
344333
case _IterCachedSymlink:
334+
case _RefreshSymlinkUnresolved:
345335
return __status(__p_, __ec).type();
346336
case _IterCachedNonSymlink:
347-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
348337
case _IterNonSymlink:
349338
case _RefreshNonSymlink:
350339
case _RefreshSymlink: {
@@ -364,17 +353,13 @@ class directory_entry {
364353
case _Empty:
365354
case _IterNonSymlink:
366355
case _IterSymlink:
356+
case _IterCachedSymlink:
367357
case _RefreshSymlinkUnresolved:
368358
return __status(__p_, __ec);
359+
case _IterCachedNonSymlink:
369360
case _RefreshNonSymlink:
370361
case _RefreshSymlink:
371362
return file_status(__get_ft(__ec), __data_.__non_sym_perms_);
372-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
373-
case _IterCachedSymlink:
374-
return __status(__p_, __ec);
375-
case _IterCachedNonSymlink:
376-
return file_status(__get_ft(__ec), __data_.__non_sym_perms_);
377-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
378363
}
379364
__libcpp_unreachable();
380365
}
@@ -385,17 +370,13 @@ class directory_entry {
385370
case _IterNonSymlink:
386371
case _IterSymlink:
387372
return __symlink_status(__p_, __ec);
373+
case _IterCachedNonSymlink:
388374
case _RefreshNonSymlink:
389375
return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_);
376+
case _IterCachedSymlink:
390377
case _RefreshSymlink:
391378
case _RefreshSymlinkUnresolved:
392379
return file_status(__get_sym_ft(__ec), __data_.__sym_perms_);
393-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
394-
case _IterCachedNonSymlink:
395-
return file_status(__get_sym_ft(__ec), __data_.__non_sym_perms_);
396-
case _IterCachedSymlink:
397-
return file_status(__get_sym_ft(__ec), __data_.__sym_perms_);
398-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
399380
}
400381
__libcpp_unreachable();
401382
}
@@ -405,13 +386,10 @@ class directory_entry {
405386
case _Empty:
406387
case _IterNonSymlink:
407388
case _IterSymlink:
408-
case _RefreshSymlinkUnresolved:
409-
return filesystem::__file_size(__p_, __ec);
410-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
411389
case _IterCachedSymlink:
390+
case _RefreshSymlinkUnresolved:
412391
return filesystem::__file_size(__p_, __ec);
413392
case _IterCachedNonSymlink:
414-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
415393
case _RefreshSymlink:
416394
case _RefreshNonSymlink: {
417395
error_code __m_ec;
@@ -432,10 +410,8 @@ class directory_entry {
432410
case _Empty:
433411
case _IterNonSymlink:
434412
case _IterSymlink:
435-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
436413
case _IterCachedNonSymlink:
437414
case _IterCachedSymlink:
438-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
439415
case _RefreshSymlinkUnresolved:
440416
return filesystem::__hard_link_count(__p_, __ec);
441417
case _RefreshSymlink:
@@ -454,13 +430,10 @@ class directory_entry {
454430
case _Empty:
455431
case _IterNonSymlink:
456432
case _IterSymlink:
457-
case _RefreshSymlinkUnresolved:
458-
return filesystem::__last_write_time(__p_, __ec);
459-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
460433
case _IterCachedSymlink:
434+
case _RefreshSymlinkUnresolved:
461435
return filesystem::__last_write_time(__p_, __ec);
462436
case _IterCachedNonSymlink:
463-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
464437
case _RefreshSymlink:
465438
case _RefreshNonSymlink: {
466439
error_code __m_ec;

libcxx/src/filesystem/directory_iterator.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,11 @@ class __dir_stream {
7979
return false;
8080
__entry_.__assign_iter_entry(
8181
__root_ / __data_.cFileName,
82-
# if _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
8382
directory_entry::__create_iter_cached_result(
8483
detail::get_file_type(__data_),
8584
detail::get_file_size(__data_),
8685
detail::get_file_perm(__data_),
87-
detail::get_write_time(__data_))
88-
# else
89-
directory_entry::__create_iter_result(detail::get_file_type(__data_))
90-
# endif // _LIBCPP_AVAILABILITY_HAS_FILESYSTEM_FULLY_POPULATED_CACHED_ENTRY
91-
);
86+
detail::get_write_time(__data_)));
9287
return true;
9388
}
9489

libcxx/src/filesystem/file_descriptor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ inline uintmax_t get_file_size(const WIN32_FIND_DATAW& data) {
9999
inline file_time_type get_write_time(const WIN32_FIND_DATAW& data) {
100100
using detail::fs_time;
101101
const FILETIME& time = data.ftLastWriteTime;
102-
auto ts = filetime_to_timespec(time);
102+
auto ts = filetime_to_timespec(time);
103103
if (!fs_time::is_representable(ts))
104104
return file_time_type::min();
105105
return fs_time::convert_from_timespec(ts);

libcxx/test/std/input.output/filesystems/class.rec.dir.itr/cache_refresh_iter.pass.cpp

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,39 +32,81 @@ static void set_last_write_time_in_iteration(const fs::path& dir) {
3232
// See
3333
// https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times
3434
// To force updating file entries calls "last_write_time" with own value.
35-
const recursive_directory_iterator endIt{};
35+
const recursive_directory_iterator end_it{};
3636

3737
std::error_code ec;
3838
recursive_directory_iterator it(dir, ec);
3939
assert(!ec);
4040

4141
file_time_type now_time = file_time_type::clock::now();
42-
for (; it != endIt; ++it) {
42+
for (; it != end_it; ++it) {
4343
const path entry = *it;
4444
last_write_time(entry, now_time, ec);
4545
assert(!ec);
4646
}
4747

48-
assert(it == endIt);
48+
assert(it == end_it);
49+
}
50+
51+
struct directory_entry_and_values {
52+
directory_entry entry;
53+
54+
file_status symlink_status;
55+
file_status status;
56+
std::uintmax_t file_size;
57+
file_time_type last_write_time;
58+
};
59+
60+
std::vector<directory_entry_and_values> get_directory_entries_for(const path& dir, const std::set<path>& dir_contents) {
61+
const recursive_directory_iterator end_it{};
62+
63+
std::error_code ec;
64+
recursive_directory_iterator it(dir, ec);
65+
assert(!ec);
66+
67+
std::vector<directory_entry_and_values> dir_entries;
68+
std::set<path> unseen_entries = dir_contents;
69+
while (!unseen_entries.empty()) {
70+
assert(it != end_it);
71+
const directory_entry& entry = *it;
72+
73+
assert(unseen_entries.erase(entry.path()) == 1);
74+
75+
dir_entries.push_back(directory_entry_and_values{
76+
.entry = entry,
77+
.symlink_status = entry.symlink_status(),
78+
.status = entry.status(),
79+
.file_size = entry.is_regular_file() ? entry.file_size() : 0,
80+
.last_write_time = entry.last_write_time()});
81+
82+
recursive_directory_iterator& it_ref = it.increment(ec);
83+
assert(!ec);
84+
assert(&it_ref == &it);
85+
}
86+
return dir_entries;
4987
}
5088
#endif
5189

90+
// Checks that the directory_entry properties will be the same before and after
91+
// calling "refresh" in case of iteration.
92+
// In case of Windows expects that directory_entry caches the properties during
93+
// iteration.
5294
static void test_cache_and_refresh_in_iteration() {
5395
static_test_env static_env;
54-
const path testDir = static_env.Dir;
96+
const path test_dir = static_env.Dir;
5597
#if defined(_WIN32)
56-
set_last_write_time_in_iteration(testDir);
98+
set_last_write_time_in_iteration(test_dir);
5799
#endif
58100
const std::set<path> dir_contents(static_env.RecDirIterationList.begin(), static_env.RecDirIterationList.end());
59-
const recursive_directory_iterator endIt{};
101+
const recursive_directory_iterator end_it{};
60102

61103
std::error_code ec;
62-
recursive_directory_iterator it(testDir, ec);
104+
recursive_directory_iterator it(test_dir, ec);
63105
assert(!ec);
64106

65107
std::set<path> unseen_entries = dir_contents;
66108
while (!unseen_entries.empty()) {
67-
assert(it != endIt);
109+
assert(it != end_it);
68110
const directory_entry& entry = *it;
69111

70112
assert(unseen_entries.erase(entry.path()) == 1);
@@ -92,8 +134,54 @@ static void test_cache_and_refresh_in_iteration() {
92134
}
93135
}
94136

137+
#if defined(_WIN32)
138+
// In case of Windows expects that the directory_entry caches the properties
139+
// during iteration and the properties don't change after deleting folders
140+
// and files.
141+
static void test_cached_values_in_iteration() {
142+
std::vector<directory_entry_and_values> dir_entries;
143+
{
144+
static_test_env static_env;
145+
const path testDir = static_env.Dir;
146+
set_last_write_time_in_iteration(testDir);
147+
const std::set<path> dir_contents(static_env.RecDirIterationList.begin(), static_env.RecDirIterationList.end());
148+
dir_entries = get_directory_entries_for(testDir, dir_contents);
149+
}
150+
// Testing folder should be deleted after destoying static_test_env.
151+
152+
for (const auto& dir_entry : dir_entries) {
153+
// During iteration Windows provides information only about symlink itself
154+
// not about file/folder which symlink points to.
155+
if (dir_entry.entry.is_symlink()) {
156+
// Check that symlink is not using cached value about existing file.
157+
assert(!dir_entry.entry.exists());
158+
} else {
159+
// Check that entry uses cached value about existing file.
160+
assert(dir_entry.entry.exists());
161+
}
162+
file_status symlink_status = dir_entry.entry.symlink_status();
163+
assert(dir_entry.symlink_status.type() == symlink_status.type() &&
164+
dir_entry.symlink_status.permissions() == symlink_status.permissions());
165+
166+
if (!dir_entry.entry.is_symlink()) {
167+
file_status status = dir_entry.entry.status();
168+
assert(dir_entry.status.type() == status.type() && dir_entry.status.permissions() == status.permissions());
169+
170+
std::uintmax_t file_size = dir_entry.entry.is_regular_file() ? dir_entry.entry.file_size() : 0;
171+
assert(dir_entry.file_size == file_size);
172+
173+
file_time_type last_write_time = dir_entry.entry.last_write_time();
174+
assert(dir_entry.last_write_time == last_write_time);
175+
}
176+
}
177+
}
178+
#endif
179+
95180
int main(int, char**) {
96181
test_cache_and_refresh_in_iteration();
182+
#if defined(_WIN32)
183+
test_cached_values_in_iteration();
184+
#endif
97185

98186
return 0;
99187
}

0 commit comments

Comments
 (0)