XRootD
XrdPfcDirState.cc
Go to the documentation of this file.
1 #include "XrdPfcDirState.hh"
3 
4 #include <string>
5 #include <cassert>
6 
7 using namespace XrdPfc;
8 
9 //----------------------------------------------------------------------------
11 //----------------------------------------------------------------------------
12 DirState::DirState() : m_parent(0), m_depth(0)
13 {}
14 
15 //----------------------------------------------------------------------------
18 //----------------------------------------------------------------------------
20  m_parent(parent),
21  m_depth(m_parent->m_depth + 1)
22 {}
23 
24 //----------------------------------------------------------------------------
28 //----------------------------------------------------------------------------
29 DirState::DirState(DirState *parent, const std::string &dname) :
30  DirStateBase(dname),
31  m_parent(parent),
32  m_depth(m_parent->m_depth + 1)
33 {}
34 
35 //----------------------------------------------------------------------------
38 //----------------------------------------------------------------------------
39 DirState *DirState::create_child(const std::string &dir)
40 {
41  std::pair<DsMap_i, bool> ir = m_subdirs.insert(std::make_pair(dir, DirState(this, dir)));
42  return &ir.first->second;
43 }
44 
45 //----------------------------------------------------------------------------
48 //----------------------------------------------------------------------------
49 DirState *DirState::find_path_tok(PathTokenizer &pt, int pos, bool create_subdirs,
50  DirState **last_existing_dir)
51 {
52  if (pos == pt.get_n_dirs())
53  return this;
54 
55  DirState *ds = nullptr;
56 
57  DsMap_i i = m_subdirs.find(pt.m_dirs[pos]);
58 
59  if (i != m_subdirs.end())
60  {
61  ds = &i->second;
62  if (last_existing_dir)
63  *last_existing_dir = ds;
64  }
65  else if (create_subdirs)
66  {
67  ds = create_child(pt.m_dirs[pos]);
68  }
69 
70  if (ds)
71  return ds->find_path_tok(pt, pos + 1, create_subdirs, last_existing_dir);
72 
73  return nullptr;
74 }
75 
76 //----------------------------------------------------------------------------
82 DirState *DirState::find_path(const std::string &path, int max_depth, bool parse_as_lfn,
83  bool create_subdirs, DirState **last_existing_dir)
84 {
85  PathTokenizer pt(path, max_depth, parse_as_lfn);
86 
87  if (last_existing_dir)
88  *last_existing_dir = this;
89 
90  return find_path_tok(pt, 0, create_subdirs, last_existing_dir);
91 }
92 
93 //----------------------------------------------------------------------------
98 DirState *DirState::find_dir(const std::string &dir,
99  bool create_subdirs)
100 {
101  DsMap_i i = m_subdirs.find(dir);
102 
103  if (i != m_subdirs.end())
104  return &i->second;
105 
106  if (create_subdirs)
107  return create_child(dir);
108 
109  return nullptr;
110 }
111 
112 //----------------------------------------------------------------------------
116 int DirState::generate_dir_path(std::string &result)
117 {
118  int n_chars = 0;
119  if (m_parent) {
120  n_chars += m_parent->generate_dir_path(result) + 1 + m_dir_name.length();
121  result += '/';
122  result += m_dir_name;
123  }
124  return n_chars;
125 }
126 
127 //----------------------------------------------------------------------------
130 //----------------------------------------------------------------------------
132 {
133  DirUsage &here = m_here_usage;
135 
136  for (auto & [name, daughter] : m_subdirs)
137  {
138  daughter.upward_propagate_initial_scan_usages();
139 
140  DirUsage &dhere = daughter.m_here_usage;
141  DirUsage &dsubdirs = daughter.m_recursive_subdir_usage;
142 
143  here.m_NDirectories += 1;
144 
145  subdirs.m_StBlocks += dhere.m_StBlocks + dsubdirs.m_StBlocks;
146  subdirs.m_NFiles += dhere.m_NFiles + dsubdirs.m_NFiles;
147  subdirs.m_NDirectories += dhere.m_NDirectories + dsubdirs.m_NDirectories;
148  }
149 }
150 
151 //----------------------------------------------------------------------------
157 
158 void DirState::update_stats_and_usages(bool purge_empty_dirs, unlink_func unlink_foo)
159 {
160  // Hmmh.
161  DsMap_i i = m_subdirs.begin();
162  while (i != m_subdirs.end())
163  {
164  DirState &sub_ds = i->second;
165 
166  sub_ds.update_stats_and_usages(purge_empty_dirs, unlink_foo);
167 
170  // nothing to do for m_here_stats.
171 
172  // Join timestamps from daugters and their sub-daugter trees.
175 
176  // Clean empty leaf directories. Only do one level at a time.
177  // Note that root will never get purged.
178  bool increment_iter = true;
179  if (purge_empty_dirs && sub_ds.m_here_stats.m_NDirectoriesRemoved == 0 &&
180  sub_ds.m_here_usage.m_NDirectories == 0 && sub_ds.m_here_usage.m_NFiles == 0)
181  {
182  assert(sub_ds.m_subdirs.empty());
183 
184  std::string dir_path;
185  dir_path.reserve(1024);
186  sub_ds.generate_dir_path(dir_path);
187 
188  if (unlink_foo(dir_path) == 0) {
189  DsMap_i j = i++;
190  m_subdirs.erase(j);
192  increment_iter = false;
193  }
194  }
195  if (increment_iter)
196  ++i;
197  }
198 
199  // Apply current deltas to sshot_stats (and, if eventually needed, purge_stats).
202 
203  // Apply deltas / stats to usages.
206 
207  // Once we have m_report_stats and m_purge_stats, update them here.
208 }
209 
210 //----------------------------------------------------------------------------
213 //----------------------------------------------------------------------------
215 {
216  for (DsMap_i i = m_subdirs.begin(); i != m_subdirs.end(); ++i)
217  {
218  i->second.reset_stats();
219  }
222 }
223 
225 {
226  for (DsMap_i i = m_subdirs.begin(); i != m_subdirs.end(); ++i)
227  {
228  i->second.reset_sshot_stats();
229  }
231 }
232 
233 int DirState::count_dirs_to_level(int max_depth) const
234 {
235  int n_dirs = 1;
236  if (m_depth < max_depth)
237  {
238  for (auto & [name, ds] : m_subdirs)
239  {
240  n_dirs += ds.count_dirs_to_level(max_depth);
241  }
242  }
243  return n_dirs;
244 }
245 
246 //----------------------------------------------------------------------------
249 //----------------------------------------------------------------------------
250 void DirState::dump_recursively(const char *name, int max_depth) const
251 {
252  printf("%*d %s usage_here=%lld usage_sub=%lld usage_total=%lld num_ios=%d duration=%d b_hit=%lld b_miss=%lld b_byps=%lld b_wrtn=%lld\n",
253  2 + 2 * m_depth, m_depth, name,
256  // XXXXX here_stats or sum up? or both?
260 
261  if (m_depth < max_depth)
262  {
263  for (auto & [name, ds] : m_subdirs)
264  {
265  ds.dump_recursively(name.c_str(), max_depth);
266  }
267  }
268 }
269 
270 
271 //==============================================================================
272 // DataFsState
273 //==============================================================================
274 
275 void DataFsState::update_stats_and_usages(time_t last_update, bool purge_empty_dirs, unlink_func unlink_foo)
276 {
277  m_root.update_stats_and_usages(purge_empty_dirs, unlink_foo);
278  m_usage_update_time = last_update;
279 }
280 
281 void DataFsState::reset_stats(time_t last_update)
282 {
284  m_stats_reset_time = last_update;
285 }
286 
287 void DataFsState::reset_sshot_stats(time_t last_update)
288 {
290  m_sshot_stats_reset_time = last_update;
291 }
292 
293 void DataFsState::dump_recursively(int max_depth) const
294 {
295  if (max_depth < 0)
296  max_depth = 4096;
297 
298  printf("DataFsState::dump_recursively delta_t = %lld, max_dump_depth = %d\n",
299  (long long)(m_usage_update_time - m_stats_reset_time), max_depth);
300 
301  m_root.dump_recursively("root", max_depth);
302 }
static void parent()
void AddUp(const DirStats &s)
Definition: XrdPfcStats.hh:192
long long m_BytesMissed
number of bytes served from remote and cached
Definition: XrdPfcStats.hh:40
long long m_BytesBypassed
number of bytes served directly through XrdCl
Definition: XrdPfcStats.hh:41
int m_Duration
total duration of all IOs attached
Definition: XrdPfcStats.hh:38
int m_NumIos
number of IO objects attached during this access
Definition: XrdPfcStats.hh:37
long long m_BytesHit
number of bytes served from disk
Definition: XrdPfcStats.hh:39
long long m_BytesWritten
number of bytes written to disk
Definition: XrdPfcStats.hh:42
Definition: XrdPfc.hh:41
std::function< int(const std::string &)> unlink_func
void reset_stats(time_t last_update)
void dump_recursively(int max_depth) const
void update_stats_and_usages(time_t last_update, bool purge_empty_dirs, unlink_func unlink_foo)
void reset_sshot_stats(time_t last_update)
DirState * m_parent
DirUsage m_recursive_subdir_usage
DsMap_t::iterator DsMap_i
int count_dirs_to_level(int max_depth) const
DirState * create_child(const std::string &dir)
DirStats m_recursive_subdir_stats
DirState * find_dir(const std::string &dir, bool create_subdirs)
int generate_dir_path(std::string &result)
DirState()
Constructor.
DirState * find_path_tok(PathTokenizer &pt, int pos, bool create_subdirs, DirState **last_existing_dir=nullptr)
DirState * find_path(const std::string &path, int max_depth, bool parse_as_lfn, bool create_subdirs, DirState **last_existing_dir=nullptr)
void dump_recursively(const char *name, int max_depth) const
void upward_propagate_initial_scan_usages()
DirStats m_sshot_stats
void update_stats_and_usages(bool purge_empty_dirs, unlink_func unlink_foo)
void update_from_stats(const DirStats &s)
void update_last_times(const DirUsage &u)
std::vector< const char * > m_dirs