XRootD
Loading...
Searching...
No Matches
XrdPfcResourceMonitor.hh
Go to the documentation of this file.
1#ifndef __XRDPFC_RESOURCEMONITOR_HH__
2#define __XRDPFC_RESOURCEMONITOR_HH__
3
4#include "XrdPfcStats.hh"
6
8
9#include <string>
10#include <vector>
11#include <list>
12
13class XrdOss;
14
15namespace XrdPfc {
16
17struct DataFsState;
18struct DirState;
19struct DirStateElement;
20struct DataFsSnapshot;
21struct DirPurgeElement;
22struct DataFsPurgeshot;
23class FsTraversal;
24
25//==============================================================================
26// ResourceMonitor
27//==============================================================================
28
29// Encapsulates local variables used withing the previous mega-function Purge().
30//
31// This will be used within the continuously/periodically ran heart-beat / breath
32// function ... and then parts of it will be passed to invoked FS scan and purge
33// jobs (which will be controlled throught this as well).
34
35// Andy: XRDADMINPATH Is the directory for administrative files (i.e. all.adminpath)
36// Also: XrdOucEnv::Export("XRDLOGDIR", logParms.logfn); (in XrdOucLogging::configLog)
37
39{
40 template<typename ID, typename RECORD>
41 class Queue {
42 public:
43 struct Entry {
45 RECORD record;
46 };
47 using queue_type = std::vector<Entry>;
48 using iterator = typename queue_type::iterator;
49
50 Queue() = default;
51
52 int write_queue_size() const { return m_write_queue.size(); }
53 bool read_queue_empty() const { return m_read_queue.empty(); }
54 int read_queue_size() const { return m_read_queue.size(); }
55
56 // Writer / producer access
57 void push(ID id, RECORD stat) { m_write_queue.push_back({ id, stat }); }
58 // Existing entry access for updating Stats
59 RECORD& write_record(int pos) { return m_write_queue[pos].record; }
60
61 // Reader / consumer access
62 int swap_queues() { m_read_queue.clear(); m_write_queue.swap(m_read_queue); return read_queue_size(); }
63 const queue_type& read_queue() const { return m_read_queue; }
64 iterator begin() const { return m_read_queue.begin(); }
65 iterator end() const { return m_read_queue.end(); }
66
67 // Shrinkage of overgrown queues
68 void shrink_read_queue() { m_read_queue.clear(); m_read_queue.shrink_to_fit(); }
69
70 private:
71 queue_type m_write_queue, m_read_queue;
72 };
73
74 struct AccessToken {
75 std::string m_filename;
76 unsigned int m_last_queue_swap_u1 = 0xffffffff;
77 int m_last_write_queue_pos = -1;
78 DirState *m_dir_state = nullptr;
79
80 void clear() {
81 m_filename.clear();
82 m_last_queue_swap_u1 = 0xffffffff;
83 m_last_write_queue_pos = -1;
84 m_dir_state = nullptr;
85 }
86 };
87 // Stable addresses: process_queues() uses AccessToken& without m_queue_mutex.
88 // 4096 * 1024 tokens, one per open file. acquire() and release() run under
89 // m_queue_mutex, in the same critical section as the queue push.
90 StableChunkPool<AccessToken, 12, 1024> m_access_tokens;
91
92 struct OpenRecord {
93 time_t m_open_time;
94 bool m_existing_file;
95 };
96
97 struct CloseRecord {
98 time_t m_close_time;
99 Stats m_full_stats;
100 };
101
102 struct PurgeRecord {
103 long long m_size_in_st_blocks;
104 int m_n_files;
105 };
106
107 Queue<int, OpenRecord> m_file_open_q;
108 Queue<int, Stats> m_file_update_stats_q;
109 Queue<int, CloseRecord> m_file_close_q;
110 Queue<DirState*, PurgeRecord> m_file_purge_q1;
111 Queue<std::string, PurgeRecord> m_file_purge_q2;
112 Queue<std::string, long long> m_file_purge_q3;
113 // DirPurge queue -- not needed? But we do need last-change timestamp in DirState.
114
115 long long m_current_usage_in_st_blocks = 0; // aggregate disk usage by files
116 int m_dir_count_discrepancy = 0; // last reported usage-vs-tree mismatch
117 long long m_token_alloc_failures = 0; // token space exhausted, under m_queue_mutex
118
119 XrdSysMutex m_queue_mutex; // mutex shared between queues
120 unsigned int m_queue_swap_u1 = 0u; // identifier of current swap cycle
121
122 DataFsState &m_fs_state;
123 XrdOss &m_oss;
124
125 // Requests for File opens during name-space scans. Such LFNs are processed
126 // with some priority
127 struct LfnCondRecord
128 {
129 const std::string &f_lfn;
130 XrdSysCondVar &f_cond;
131 bool &f_checked;
132 };
133
134 XrdSysMutex m_dir_scan_mutex;
135 std::list<LfnCondRecord> m_dir_scan_open_requests;
136 int m_dir_scan_check_counter = 0;
137 bool m_dir_scan_in_progress = true;
138
139 void process_inter_dir_scan_open_requests(FsTraversal &fst);
140 void cross_check_or_process_oob_lfn(const std::string &lfn, FsTraversal &fst);
141 long long get_file_usage_bytes_to_remove(const DataFsPurgeshot &ps, long long previous_file_usage, int logLeve);
142
143public:
144 ResourceMonitor(XrdOss& oss);
146
147 // --- Initial scan, building of DirState tree
148
149 void scan_dir_and_recurse(FsTraversal &fst);
151
152 // --- Event registration
153
154 int register_file_open(const std::string& filename, time_t open_timestamp, bool existing_file) {
155 // Simply return a token, we will resolve it in the actual processing of the queue.
156 XrdSysMutexHelper _lock(&m_queue_mutex);
157 int token_id = m_access_tokens.acquire();
158 if (token_id < 0) {
159 // Unreachable in practice; heart_beat() reports the count.
160 ++m_token_alloc_failures;
161 return -1;
162 }
163 AccessToken &at = m_access_tokens[token_id];
164 at.m_filename = filename;
165 at.m_last_queue_swap_u1 = m_queue_swap_u1 - 1;
166
167 m_file_open_q.push(token_id, {open_timestamp, existing_file});
168 return token_id;
169 }
170
171 void register_file_update_stats(int token_id, const Stats& stats) {
172 if (token_id < 0) return; // register_file_open() could not get a token
173 XrdSysMutexHelper _lock(&m_queue_mutex);
174 AccessToken &at = token(token_id);
175 // Check if this is the first update within this queue swap cycle.
176 if (at.m_last_queue_swap_u1 != m_queue_swap_u1) {
177 m_file_update_stats_q.push(token_id, stats);
178 at.m_last_queue_swap_u1 = m_queue_swap_u1;
179 at.m_last_write_queue_pos = m_file_update_stats_q.write_queue_size() - 1;
180 } else {
181 Stats &existing_stats = m_file_update_stats_q.write_record(at.m_last_write_queue_pos);
182 existing_stats.AddUp(stats);
183 }
184 // Optionally, one could return "scaler" to moodify stat-reporting
185 // frequency in the file ... if it comes too often or too rarely.
186 // See also the logic for determining reporting interval (in N_bytes_read)
187 // in File::Open().
188 }
189
190 void register_file_close(int token_id, time_t close_timestamp, const Stats& full_stats) {
191 if (token_id < 0) return; // register_file_open() could not get a token
192 XrdSysMutexHelper _lock(&m_queue_mutex);
193 m_file_close_q.push(token_id, {close_timestamp, full_stats});
194 }
195
196 // deletions can come from purge and from direct requests (Cache::UnlinkFile), the latter
197 // also covering the emergency shutdown of a file.
198 void register_file_purge(DirState* target, long long size_in_st_blocks) {
199 XrdSysMutexHelper _lock(&m_queue_mutex);
200 m_file_purge_q1.push(target, {size_in_st_blocks, 1});
201 }
202 void register_multi_file_purge(DirState* target, long long size_in_st_blocks, int n_files) {
203 XrdSysMutexHelper _lock(&m_queue_mutex);
204 m_file_purge_q1.push(target, {size_in_st_blocks, n_files});
205 }
206 void register_multi_file_purge(const std::string& target, long long size_in_st_blocks, int n_files) {
207 XrdSysMutexHelper _lock(&m_queue_mutex);
208 m_file_purge_q2.push(target, {size_in_st_blocks, n_files});
209 }
210 void register_file_purge(const std::string& filename, long long size_in_st_blocks) {
211 XrdSysMutexHelper _lock(&m_queue_mutex);
212 m_file_purge_q3.push(filename, size_in_st_blocks);
213 }
214
215 // void register_dir_purge(DirState* target);
216 // target assumed to be empty at this point, triggered by a file_purge removing the last file in it.
217 // hmmh, this is actually tricky ... who will purge the dirs? we should now at export-to-vector time
218 // and can prune leaf directories. This might fail if a file has been created in there in the meantime, which is ok.
219 // However, is there a race condition between rmdir and creation of a new file in that dir? Ask Andy.
220
221 // --- Helpers for event processing and actions
222
223 AccessToken& token(int i) { return m_access_tokens[i]; }
224
225 // --- Actions
226
227 int process_queues();
228
229 void heart_beat();
230
231 // --- Helpers for export of DirState vector snapshot.
232
233 void fill_sshot_vec_children(const DirState &parent_ds,
234 int parent_idx,
235 std::vector<DirStateElement> &vec,
236 int max_depth);
237
238 void fill_pshot_vec_children(const DirState &parent_ds,
239 int parent_idx,
240 std::vector<DirPurgeElement> &vec,
241 int max_depth);
242
243 // Interface to other part of XCache -- note the CamelCase() notation.
244 void CrossCheckIfScanIsInProgress(const std::string &lfn, XrdSysCondVar &cond);
245
246 // main function, steers startup then enters heart_beat. does not die.
247 void init_before_main(); // called from startup thread / configuration processing
248 void main_thread_function(); // run in dedicated thread
249
251 // The following variables are set under the above lock, purge task signals to heart_beat.
254 bool m_purge_task_active {false}; // from the perspective of heart-beat, set only in heartbeat
255 bool m_purge_task_complete {false}; // from the perspective of the task, reset in heartbeat, set in task
256 // When m_purge_task_active == true, DirState entries are not removed from the tree to
257 // allow purge thread to report cleared files directly via DirState ptr.
258 // Note, DirState removal happens during stat propagation traversal.
259
260 // Purge helpers etc.
262 void perform_purge_check(bool purge_cold_files, int tl);
263
266};
267
268}
269
270#endif
#define stat(a, b)
Definition XrdPosix.hh:101
#define ID
void CrossCheckIfScanIsInProgress(const std::string &lfn, XrdSysCondVar &cond)
int register_file_open(const std::string &filename, time_t open_timestamp, bool existing_file)
void perform_purge_check(bool purge_cold_files, int tl)
void fill_sshot_vec_children(const DirState &parent_ds, int parent_idx, std::vector< DirStateElement > &vec, int max_depth)
void perform_purge_task(DataFsPurgeshot &ps)
void register_file_purge(const std::string &filename, long long size_in_st_blocks)
void scan_dir_and_recurse(FsTraversal &fst)
void register_file_purge(DirState *target, long long size_in_st_blocks)
void fill_pshot_vec_children(const DirState &parent_ds, int parent_idx, std::vector< DirPurgeElement > &vec, int max_depth)
void register_multi_file_purge(DirState *target, long long size_in_st_blocks, int n_files)
void register_file_update_stats(int token_id, const Stats &stats)
void register_multi_file_purge(const std::string &target, long long size_in_st_blocks, int n_files)
void register_file_close(int token_id, time_t close_timestamp, const Stats &full_stats)
Statistics of cache utilisation by a File object.
void AddUp(const Stats &s)
XrdPosixStats Stats