LLFIO v2.00
Loading...
Searching...
No Matches
llfio_v2_xxx::algorithm::contents_visitor Struct Reference

A visitor for the filesystem contents algorithm. More...

#include "contents.hpp"

Inheritance diagram for llfio_v2_xxx::algorithm::contents_visitor:
llfio_v2_xxx::algorithm::traverse_visitor

Classes

struct  _state_type
 
struct  contents_type
 Enumerated contents, and what parts of their stat_t is valid. More...
 

Public Member Functions

 contents_visitor ()=default
 Default construtor.
 
 contents_visitor (stat_t::want _metadata, bool _include_files=true, bool _include_directories=true, bool _include_symlinks=true)
 Construct an instance.
 
virtual result< void > post_enumeration (void *data, const directory_handle &dirh, directory_handle::buffers_type &contents, size_t depth) noexcept
 The default implementation accumulates the contents into thread local storage. At traverse end, all the thread local storages are coalesced into a single result, the member variable contents.
 
virtual result< size_t > finished (void *data, result< size_t > result) noexcept
 Called when a traversal finishes, this default implementation merges all the thread local results into contents, and deallocates the thread local results.
 
virtual result< directory_handledirectory_open_failed (void *data, result< void >::error_type &&error, const directory_handle &dirh, path_view leaf, size_t depth) noexcept
 Called when we failed to open a directory for enumeration. The default fails the traversal with that error. Return a default constructed instance to ignore the failure.
 
virtual result< bool > pre_enumeration (void *data, const directory_handle &dirh, size_t depth) noexcept
 Called to decide whether to enumerate a directory.
 
virtual result< void > stack_updated (void *data, size_t dirs_processed, size_t known_dirs_remaining, size_t depth_processed, size_t known_depth_remaining) noexcept
 Called whenever the traversed stack of directory hierarchy is updated. This can act as an estimated progress indicator, or to give an accurate progress indicator by matching it against a previous traversal.
 

Public Attributes

bool contents_include_files {true}
 Whether to include files in the contents.
 
bool contents_include_directories {true}
 Whether to include directories in the contents.
 
bool contents_include_symlinks {true}
 Whether to include symlinks in the contents.
 
stat_t::want contents_include_metadata {stat_t::want::none}
 What stat_t::want to include, if enumeration doesn't provide these, they will be additionally fetched.
 

Static Protected Member Functions

static std::shared_ptr< contents_type_thread_contents (_state_type *state) noexcept
 

Friends

result< contents_typecontents (const path_handle &dirh, contents_visitor *visitor, size_t threads, bool force_slow_path) noexcept
 Calculate the contents of everything within and under dirh. What is returned is unordered.
 

Detailed Description

A visitor for the filesystem contents algorithm.

Constructor & Destructor Documentation

◆ contents_visitor()

llfio_v2_xxx::algorithm::contents_visitor::contents_visitor ( stat_t::want  _metadata,
bool  _include_files = true,
bool  _include_directories = true,
bool  _include_symlinks = true 
)
inlineexplicit

Construct an instance.

64 : contents_include_files(_include_files)
65 , contents_include_directories(_include_directories)
66 , contents_include_symlinks(_include_symlinks)
67 , contents_include_metadata(_metadata)
68 {
69 }
stat_t::want contents_include_metadata
What stat_t::want to include, if enumeration doesn't provide these, they will be additionally fetched...
Definition contents.hpp:50
bool contents_include_symlinks
Whether to include symlinks in the contents.
Definition contents.hpp:48
bool contents_include_directories
Whether to include directories in the contents.
Definition contents.hpp:46
bool contents_include_files
Whether to include files in the contents.
Definition contents.hpp:44

Member Function Documentation

◆ _thread_contents()

static std::shared_ptr< contents_type > llfio_v2_xxx::algorithm::contents_visitor::_thread_contents ( _state_type state)
inlinestaticprotectednoexcept
91 {
92 LLFIO_EXCEPTION_TRY
93 {
94 static thread_local std::weak_ptr<contents_type> mycontents;
95 auto ret = mycontents.lock();
96 if(ret)
97 {
98 return ret;
99 }
100 ret = std::make_unique<contents_type>();
101 mycontents = ret;
102 std::lock_guard<std::mutex> g(state->lock);
103 state->all_thread_contents.push_back(ret);
104 return ret;
105 }
106 LLFIO_EXCEPTION_CATCH_ALL
107 {
108 return {};
109 }
110 }

◆ directory_open_failed()

virtual result< directory_handle > llfio_v2_xxx::algorithm::traverse_visitor::directory_open_failed ( void *  data,
result< void >::error_type &&  error,
const directory_handle dirh,
path_view  leaf,
size_t  depth 
)
inlinevirtualnoexceptinherited

Called when we failed to open a directory for enumeration. The default fails the traversal with that error. Return a default constructed instance to ignore the failure.

Note
May be called from multiple kernel threads concurrently.

Reimplemented in llfio_v2_xxx::algorithm::reduce_visitor, and llfio_v2_xxx::algorithm::summarize_visitor.

54 {
55 (void) data;
56 (void) dirh;
57 (void) leaf;
58 (void) depth;
59 return failure(std::move(error));
60 }

◆ finished()

virtual result< size_t > llfio_v2_xxx::algorithm::contents_visitor::finished ( void *  data,
result< size_t >  result 
)
inlinevirtualnoexcept

Called when a traversal finishes, this default implementation merges all the thread local results into contents, and deallocates the thread local results.

Reimplemented from llfio_v2_xxx::algorithm::traverse_visitor.

185 {
186 LLFIO_EXCEPTION_TRY
187 {
188 auto *state = (_state_type *) data;
189 state->contents.clear();
190 state->contents.metadata = state->metadata.load(std::memory_order_relaxed);
191 size_t count = 0;
192 for(auto &i : state->all_thread_contents)
193 {
194 count += i->size();
195 }
196 state->contents.reserve(count);
197 for(auto &i : state->all_thread_contents)
198 {
199 state->contents.insert(state->contents.end(), std::make_move_iterator(i->begin()), std::make_move_iterator(i->end()));
200 }
201 state->all_thread_contents.clear();
202 return result;
203 }
204 LLFIO_EXCEPTION_CATCH_ALL
205 {
206 return error_from_exception();
207 }
208 }

◆ post_enumeration()

virtual result< void > llfio_v2_xxx::algorithm::contents_visitor::post_enumeration ( void *  data,
const directory_handle dirh,
directory_handle::buffers_type contents,
size_t  depth 
)
inlinevirtualnoexcept

The default implementation accumulates the contents into thread local storage. At traverse end, all the thread local storages are coalesced into a single result, the member variable contents.

Reimplemented from llfio_v2_xxx::algorithm::traverse_visitor.

118 {
119 LLFIO_EXCEPTION_TRY
120 {
121 auto *state = (_state_type *) data;
122 (void) depth;
123 if(!contents.empty())
124 {
125 contents_type toadd;
126 toadd.reserve(contents.size());
127 filesystem::path dirhpath;
128 for(;;)
129 {
130 OUTCOME_TRY(dirhpath, dirh.current_path());
131 auto rootdirpathlen = state->rootdirpathlen.load(std::memory_order_relaxed);
132 if(dirhpath.native().size() <= rootdirpathlen)
133 {
134 break;
135 }
136 dirhpath = dirhpath.native().substr(rootdirpathlen);
137 auto r = directory_handle::directory(state->rootdirh, dirhpath);
138 if(r && r.value().unique_id() == dirh.unique_id())
139 {
140 break;
141 }
142 OUTCOME_TRY(dirhpath, state->rootdirh.current_path());
143 state->rootdirpathlen.store(dirhpath.native().size() + 1, std::memory_order_relaxed);
144 }
145 auto _metadata_ = state->metadata.load(std::memory_order_relaxed);
146 if((_metadata_ & (contents_include_metadata | contents.metadata())) != _metadata_)
147 {
148 state->metadata.store(_metadata_ & (contents_include_metadata | contents.metadata()), std::memory_order_relaxed);
149 }
150 auto into = _thread_contents(state);
151 for(auto &entry : contents)
152 {
153 auto need_stat = contents_include_metadata & ~contents.metadata();
154 if((contents_include_files && entry.stat.st_type == filesystem::file_type::regular) ||
155 (contents_include_directories && entry.stat.st_type == filesystem::file_type::directory) ||
156 (contents_include_symlinks && entry.stat.st_type == filesystem::file_type::symlink))
157 {
158 if(!need_stat)
159 {
160 into->emplace_back(dirhpath / entry.leafname, entry.stat);
161 continue;
162 }
163 auto r = file_handle::file(dirh, entry.leafname, file_handle::mode::attr_read);
164 if(r)
165 {
166 OUTCOME_TRY(entry.stat.fill(r.value(), need_stat));
167 into->emplace_back(dirhpath / entry.leafname, entry.stat);
168 }
169 }
170 }
171 }
172 return success();
173 }
174 LLFIO_EXCEPTION_CATCH_ALL
175 {
176 return error_from_exception();
177 }
178 }
static result< directory_handle > directory(const path_handle &base, path_view_type path, mode _mode=mode::read, creation _creation=creation::open_existing, caching _caching=caching::all, flag flags=flag::none) noexcept
static result< file_handle > file(const path_handle &base, path_view_type path, mode _mode=mode::read, creation _creation=creation::open_existing, caching _caching=caching::all, flag flags=flag::none) noexcept
friend result< contents_type > contents(const path_handle &dirh, contents_visitor *visitor, size_t threads, bool force_slow_path) noexcept
Calculate the contents of everything within and under dirh. What is returned is unordered.
Definition contents.hpp:223

◆ pre_enumeration()

virtual result< bool > llfio_v2_xxx::algorithm::traverse_visitor::pre_enumeration ( void *  data,
const directory_handle dirh,
size_t  depth 
)
inlinevirtualnoexceptinherited

Called to decide whether to enumerate a directory.

Note that it is more efficient to ignore the directory entry in post_enumeration() than to ignore it here, as a handle is opened for the directory before this callback. Equally, if you need that handle to inspect the directory e.g. to check if one is entering a different filesystem from the root, here is best.

The default returns true.

Note
May be called from multiple kernel threads concurrently.
75 {
76 (void) data;
77 (void) dirh;
78 (void) depth;
79 return true;
80 }

◆ stack_updated()

virtual result< void > llfio_v2_xxx::algorithm::traverse_visitor::stack_updated ( void *  data,
size_t  dirs_processed,
size_t  known_dirs_remaining,
size_t  depth_processed,
size_t  known_depth_remaining 
)
inlinevirtualnoexceptinherited

Called whenever the traversed stack of directory hierarchy is updated. This can act as an estimated progress indicator, or to give an accurate progress indicator by matching it against a previous traversal.

Parameters
dataThe third party data pointer passed to traverse().
dirs_processedThe total number of directories traversed so far.
known_dirs_remainingThe currently known number of directories awaiting traversal.
depth_processedHow many levels deep we have already completely traversed.
known_depth_remainingThe currently known number of levels we shall traverse.
Note
May be called from multiple kernel threads concurrently.
116 {
117 (void) data;
118 (void) dirs_processed;
119 (void) known_dirs_remaining;
120 (void) depth_processed;
121 (void) known_depth_remaining;
122 return success();
123 }

Friends And Related Symbol Documentation

◆ contents

result< contents_type > contents ( const path_handle dirh,
contents_visitor visitor = nullptr,
size_t  threads = 0,
bool  force_slow_path = false 
)
friend

Calculate the contents of everything within and under dirh. What is returned is unordered.

This is a very thin veneer over traverse() which came out of the fact that I kept writing "get me the contents" traversal visitors again and again, so eventually I just wrote a library edition. Its only "clever" bit is that it stores the contents in thread local storage, and merges the contents afterwards.

It is race free to concurrent relocations of dirh. It is entirely implemented in header-only code, as it is very simple.

225 {
226 contents_visitor default_visitor;
227 if(visitor == nullptr)
228 {
229 visitor = &default_visitor;
230 }
231 contents_visitor::_state_type state(dirh);
232 OUTCOME_TRY(auto &&dirhpath, dirh.current_path());
233 state.rootdirpathlen.store(dirhpath.native().size() + 1, std::memory_order_relaxed);
234 OUTCOME_TRY(traverse(dirh, visitor, threads, &state, force_slow_path));
235 return {std::move(state.contents)};
236 }
result< size_t > traverse(const path_handle &dirh, traverse_visitor *visitor, size_t threads=0, void *data=nullptr, bool force_slow_path=false) noexcept
Traverse everything within and under dirh.
contents_visitor()=default
Default construtor.

Member Data Documentation

◆ contents_include_directories

bool llfio_v2_xxx::algorithm::contents_visitor::contents_include_directories {true}

Whether to include directories in the contents.

46{true};

◆ contents_include_files

bool llfio_v2_xxx::algorithm::contents_visitor::contents_include_files {true}

Whether to include files in the contents.

44{true};

◆ contents_include_metadata

stat_t::want llfio_v2_xxx::algorithm::contents_visitor::contents_include_metadata {stat_t::want::none}

What stat_t::want to include, if enumeration doesn't provide these, they will be additionally fetched.

50{stat_t::want::none};

◆ contents_include_symlinks

bool llfio_v2_xxx::algorithm::contents_visitor::contents_include_symlinks {true}

Whether to include symlinks in the contents.

48{true};

The documentation for this struct was generated from the following file: