XRootD
Loading...
Searching...
No Matches
XrdPfcPrint.cc
Go to the documentation of this file.
1//----------------------------------------------------------------------------------
2// Copyright (c) 2014 by Board of Trustees of the Leland Stanford, Jr., University
3// Author: Alja Mrak-Tadel
4//----------------------------------------------------------------------------------
5// XRootD is free software: you can redistribute it and/or modify
6// it under the terms of the GNU Lesser General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// XRootD is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU Lesser General Public License
16// along with XRootD. If not, see <http://www.gnu.org/licenses/>.
17//----------------------------------------------------------------------------------
18
19#include <iostream>
20#include <fcntl.h>
21#include <vector>
22#include "XrdPfcPrint.hh"
23#include "XrdPfcInfo.hh"
24#include "XrdOuc/XrdOucEnv.hh"
26#include "XrdOuc/XrdOucArgs.hh"
27#include "XrdOuc/XrdOucJson.hh"
28#include "XrdSys/XrdSysTrace.hh"
31#include "XrdOss/XrdOss.hh"
32
33using namespace XrdPfc;
34
35Print::Print(XrdOss* oss, char u, bool v, bool j, int i, const char* path) :
36 m_oss(oss), m_verbose(v), m_json(j), m_indent(i), m_ossUser("nobody")
37{
38 if (u == 'k') {
39 m_unit_shift = 10;
40 m_unit_width = 12;
41 m_unit[0] = u; m_unit[1] = 'B'; m_unit[2] = 0;
42 } else if (u == 'M') {
43 m_unit_shift = 20;
44 m_unit_width = 12; // need 12 chars for header
45 m_unit[0] = u; m_unit[1] = 'B'; m_unit[2] = 0;
46 } else {
47 m_unit_shift = 0;
48 m_unit_width = 15;
49 m_unit[0] = 'B'; m_unit[1] = 0;
50 }
51
52 if (isInfoFile(path))
53 {
54 if (m_json) printFileJson(std::string(path));
55 else printFile(std::string(path));
56 }
57 else
58 {
59 XrdOssDF* dh = m_oss->newDir(m_ossUser);
60 if ( dh->Opendir(path, m_env) >= 0 )
61 {
62 printDir(dh, path);
63 }
64 delete dh;
65 }
66}
67
68bool Print::isInfoFile(const char* path)
69{
70 if (strncmp(&path[strlen(path)-6], ".cinfo", 6))
71 {
72 // printf("%s is not cinfo file.\n\n", path);
73 return false;
74 }
75 return true;
76}
77
78
79void Print::printFileJson(const std::string& path)
80{
81 XrdOssDF* fh = m_oss->newFile(m_ossUser);
82 fh->Open((path).c_str(),O_RDONLY, 0600, m_env);
83
84 XrdSysTrace tr("XrdPfcPrint"); tr.What = 2;
85 Info cfi(&tr);
86
87 if ( ! cfi.Read(fh, path.c_str()))
88 {
89 return;
90 }
91
92 int cntd = 0;
93 for (int i = 0; i < cfi.GetNBlocks(); ++i)
94 {
95 if (cfi.TestBitWritten(i)) cntd++;
96 }
97 const Info::Store& store = cfi.RefStoredData();
98 char timeBuff[128];
99 strftime(timeBuff, 128, "%c", localtime(&store.m_creationTime));
100
101 nlohmann::json jobj = {
102 { "file", path },
103 { "version", cfi.GetVersion() },
104 { "created", timeBuff },
105 { "cksum", cfi.GetCkSumStateAsText() },
106 { "file_size", cfi.GetFileSize() },
107 { "buffer_size", cfi.GetBufferSize() },
108 { "n_blocks", cfi.GetNBlocks() },
109 { "state_complete", cntd < cfi.GetNBlocks() ? "incomplete" : "complete" },
110 { "state_percentage", 100.0 * cntd / cfi.GetNBlocks() },
111 { "n_acc_total", store.m_accessCnt }
112 };
113
114 if (cfi.HasNoCkSumTime()) {
115 strftime(timeBuff, 128, "%c", localtime(&store.m_noCkSumTime));
116 jobj["no-cksum-time"] = timeBuff;
117 }
118
119 // verbose needed in json?
120 if (m_verbose)
121 {
122 nlohmann::json jarr = nlohmann::json::array();
123 for (int i = 0; i < cfi.GetNBlocks(); ++i)
124 {
125 jarr.push_back(cfi.TestBitWritten(i) ? 1 : 0);
126 }
127 jobj["block_array"] = jarr;
128 }
129
130 int idx = 1;
131 const std::vector<Info::AStat> &astats = cfi.RefAStats();
132 nlohmann::json acc_arr = nlohmann::json::array();
133 for (std::vector<Info::AStat>::const_iterator it = astats.begin(); it != astats.end(); ++it)
134 {
135 const int MM = 128;
136 char s[MM];
137
138 strftime(s, MM, "%y%m%d:%H%M%S", localtime(&(it->AttachTime)));
139 std::string at = s;
140 strftime(s, MM, "%y%m%d:%H%M%S", localtime(&(it->DetachTime)));
141 std::string dt = it->DetachTime > 0 ? s : "------:------";
142 {
143 int hours = it->Duration/3600;
144 int min = (it->Duration - hours * 3600)/60;
145 int sec = it->Duration % 60;
146 snprintf(s, MM, "%d:%02d:%02d", hours, min, sec);
147 }
148 std::string dur = s;
149
150 nlohmann::json acc = {
151 { "record", idx++ },
152 { "attach", at },
153 { "detach", dt },
154 { "duration", dur },
155 { "n_ios", it->NumIos },
156 { "n_mrg", it->NumMerged },
157 { "B_hit", it->BytesHit },
158 { "B_miss", it->BytesMissed },
159 { "B_bypass", it->BytesBypassed }
160 };
161 acc_arr.push_back(acc);
162 }
163 jobj["accesses"] = acc_arr;
164
165 std::cout << jobj.dump(m_indent) << "\n";
166
167 delete fh;
168}
169
170
171void Print::printFile(const std::string& path)
172{
173 printf("FILE: %s\n", path.c_str());
174 XrdOssDF* fh = m_oss->newFile(m_ossUser);
175 fh->Open((path).c_str(),O_RDONLY, 0600, m_env);
176
177 XrdSysTrace tr("XrdPfcPrint"); tr.What = 2;
178 Info cfi(&tr);
179
180 if ( ! cfi.Read(fh, path.c_str()))
181 {
182 return;
183 }
184
185 int cntd = 0;
186 for (int i = 0; i < cfi.GetNBlocks(); ++i)
187 {
188 if (cfi.TestBitWritten(i)) cntd++;
189 }
190 const Info::Store& store = cfi.RefStoredData();
191 char timeBuff[128];
192 strftime(timeBuff, 128, "%c", localtime(&store.m_creationTime));
193
194 printf("version %d, created %s; cksum %s", cfi.GetVersion(), timeBuff, cfi.GetCkSumStateAsText());
195 if (cfi.HasNoCkSumTime()) {
196 strftime(timeBuff, 128, "%c", localtime(&store.m_noCkSumTime));
197 printf(", no-cksum-time %s\n", timeBuff);
198 } else printf("\n");
199
200 printf("file_size %lld %s, buffer_size %lld %s, n_blocks %d, n_downloaded %d, state %scomplete [%.3f%%]\n",
201 cfi.GetFileSize() >> m_unit_shift, m_unit,
202 cfi.GetBufferSize() >> (m_unit[0] == 'M' ? 10 : m_unit_shift), m_unit[0] == 'M' ? "kB" : m_unit,
203 cfi.GetNBlocks(), cntd,
204 (cntd < cfi.GetNBlocks()) ? "in" : "", 100.0 * cntd / cfi.GetNBlocks());
205
206 if (m_verbose)
207 {
208 int8_t n_db = 0;
209 { int x = cfi.GetNBlocks(); while (x)
210 {
211 x /= 10; ++n_db;
212 }
213 }
214 static const char *nums = "0123456789";
215 printf("printing %d blocks:\n", cfi.GetNBlocks());
216 printf("%*s %10d%10d%10d%10d%10d%10d\n", n_db, "", 1, 2, 3, 4, 5, 6);
217 printf("%*s %s%s%s%s%s%s0123", n_db, "", nums, nums, nums, nums, nums, nums);
218 for (int i = 0; i < cfi.GetNBlocks(); ++i)
219 {
220 if (i % 64 == 0)
221 printf("\n%*d ", n_db, i);
222 printf("%c", cfi.TestBitWritten(i) ? 'x' : '.');
223 }
224 printf("\n");
225 }
226
227 int ww = m_unit_width - 2 - strlen(m_unit);
228 printf("Access records (N_acc_total=%llu):\n"
229 "%-6s %-13s %-13s %-12s %-5s %-5s %*s[%s] %*s[%s] %*s[%s]\n",
230 (unsigned long long) store.m_accessCnt,
231 "Record", "Attach", "Detach", "Duration", "N_ios", "N_mrg",
232 ww, "B_hit", m_unit, ww, "B_miss", m_unit, ww, "B_bypass", m_unit);
233
234 int idx = 1;
235 const std::vector<Info::AStat> &astats = cfi.RefAStats();
236 for (std::vector<Info::AStat>::const_iterator it = astats.begin(); it != astats.end(); ++it)
237 {
238 const int MM = 128;
239 char s[MM];
240
241 strftime(s, MM, "%y%m%d:%H%M%S", localtime(&(it->AttachTime)));
242 std::string at = s;
243 strftime(s, MM, "%y%m%d:%H%M%S", localtime(&(it->DetachTime)));
244 std::string dt = it->DetachTime > 0 ? s : "------:------";
245 {
246 int hours = it->Duration/3600;
247 int min = (it->Duration - hours * 3600)/60;
248 int sec = it->Duration % 60;
249 snprintf(s, MM, "%d:%02d:%02d", hours, min, sec);
250 }
251 std::string dur = s;
252
253 printf("%-6d %-13s %-13s %-12s %5d %5d %*lld %*lld %*lld\n", idx++,
254 at.c_str(), dt.c_str(), dur.c_str(), it->NumIos, it->NumMerged,
255 m_unit_width, it->BytesHit >> m_unit_shift,
256 m_unit_width, it->BytesMissed >> m_unit_shift,
257 m_unit_width, it->BytesBypassed >> m_unit_shift);
258 }
259
260 delete fh;
261}
262
263void Print::printDir(XrdOssDF* iOssDF, const std::string& path)
264{
265 // printf("---------> print dir %s \n", path.c_str());
266
267 const int MM = 1024;
268 char buff[MM];
269 int rdr;
270 bool first = true;
271
272 while ((rdr = iOssDF->Readdir(&buff[0], MM)) >= 0)
273 {
274 if (strncmp("..", &buff[0], 2) && strncmp(".", &buff[0], 1))
275 {
276 if (strlen(buff) == 0)
277 {
278 break; // end of readdir
279 }
280 std::string np = path + "/" + std::string(&buff[0]);
281 if (isInfoFile(buff))
282 {
283 if (m_json) {
284 printFileJson(np);
285 } else {
286 if (first) first = false;
287 else printf("\n");
288 printFile(np);
289 }
290 }
291 else
292 {
293 XrdOssDF* dh = m_oss->newDir(m_ossUser);
294 if (dh->Opendir(np.c_str(), m_env) >= 0)
295 {
296 printDir(dh, np);
297 }
298 delete dh;
299 }
300 }
301 }
302}
303
304
305//------------------------------------------------------------------------------
306
307int main(int argc, char *argv[])
308{
309 static const char* usage = "Usage: pfc_print [-h] [-c config_file] [-u B|kB|MB] [-v] [-j] [-i indent] path ...\n";
310 char unit = 'k';
311 bool verbose = false;
312 bool json = false;
313 int indent = -1;
314 const char* cfgn = 0;
315
316 XrdOucEnv myEnv;
317
318 XrdSysLogger log;
319 XrdSysError err(&log);
320
321 XrdOucStream Config(&err, getenv("XRDINSTANCE"), &myEnv, "=====> ");
322 XrdOucArgs Spec(&err, "xrdpfc_print: ", "",
323 "help", 1, "h",
324 "config", 1, "c:",
325 "unit", 1, "u:",
326 "verbose", 1, "v",
327 "json", 1, "j",
328 "indent", 1, "i:",
329 (const char *) 0);
330
331 Spec.Set(argc-1, &argv[1]);
332 char theOpt;
333
334 while ((theOpt = Spec.getopt()) != (char)-1)
335 {
336 // printf("GETOPT %c -- arg=%s\n", theOpt, Spec.argval);
337 switch (theOpt)
338 {
339 case 'c': {
340 cfgn = Spec.argval;
341 int fd = open(cfgn, O_RDONLY, 0);
342 Config.Attach(fd);
343 break;
344 }
345 case 'u': {
346 if (strcmp(Spec.argval,"B") && strcmp(Spec.argval,"kB") && strcmp(Spec.argval,"MB")) {
347 printf("%s Error: -unit argument can only be B, kB or MB\n", usage);
348 exit(1);
349 }
350 unit = Spec.argval[0];
351 break;
352 }
353 case 'v': {
354 verbose = true;
355 break;
356 }
357 case 'j': {
358 json = true;
359 break;
360 }
361 case 'i': {
362 indent = std::stoi(Spec.argval);
363 break;
364 }
365 case 'h':
366 default: {
367 printf("%s", usage);
368 exit(1);
369 }
370 }
371 }
372
373 // suppress oss init messages
374 int efs = open("/dev/null",O_RDWR, 0);
375 XrdSysLogger ossLog(efs);
376 XrdSysError ossErr(&ossLog, "print");
377 XrdOss *oss;
378 XrdOfsConfigPI *ofsCfg = XrdOfsConfigPI::New(cfgn,&Config,&ossErr);
379 bool ossSucc = ofsCfg->Load(XrdOfsConfigPI::theOssLib);
380 if ( ! ossSucc)
381 {
382 printf("can't load oss\n");
383 exit(1);
384 }
385 ofsCfg->Plugin(oss);
386
387 const char* path;
388 while ((path = Spec.getarg()))
389 {
390 if ( ! path)
391 {
392 printf("%s", usage);
393 exit(1);
394 }
395
396 // append oss.localroot if path starts with 'root://'
397 if ( ! strncmp(&path[0], "root:/", 6))
398 {
399 if (Config.FDNum() < 0)
400 {
401 printf("Configuration file not specified.\n");
402 exit(1);
403 }
404 char *var;
405 while((var = Config.GetFirstWord()))
406 {
407 // printf("var %s \n", var);
408 if ( ! strncmp(var,"oss.localroot", strlen("oss.localroot")))
409 {
410 std::string tmp = Config.GetWord();
411 tmp += &path[6];
412 // printf("Absolute path %s \n", tmp.c_str());
413 XrdPfc::Print p(oss, unit, verbose, json, indent, tmp.c_str());
414 }
415 }
416 }
417 else
418 {
419 XrdPfc::Print p(oss, unit, verbose, json, indent, path);
420 }
421 }
422
423 return 0;
424}
void usage()
int main(int argc, char *argv[])
Definition XrdMain.cc:161
nlohmann::json json
#define open
Definition XrdPosix.hh:76
bool Plugin(XrdAccAuthorize *&piP)
Get Authorization plugin.
static XrdOfsConfigPI * New(const char *cfn, XrdOucStream *cfgP, XrdSysError *errP, XrdVersionInfo *verP=0, XrdSfsFileSystem *sfsP=0)
bool Load(int what, XrdOucEnv *envP=0)
@ theOssLib
Oss plugin.
virtual int Opendir(const char *path, XrdOucEnv &env)
Definition XrdOss.hh:79
virtual int Readdir(char *buff, int blen)
Definition XrdOss.hh:92
virtual int Open(const char *path, int Oflag, mode_t Mode, XrdOucEnv &env)
Definition XrdOss.hh:200
virtual XrdOssDF * newFile(const char *tident)=0
virtual XrdOssDF * newDir(const char *tident)=0
char getopt()
char * getarg()
void Set(char *arglist)
char * argval
Status of cached file. Can be read from and written into a binary file.
Definition XrdPfcInfo.hh:41
Print(XrdOss *oss, char u, bool v, bool j, int i, const char *path)
Constructor.
time_t m_noCkSumTime
time when first non-cksummed block was detected
Definition XrdPfcInfo.hh:81
size_t m_accessCnt
total access count for the file
Definition XrdPfcInfo.hh:82
time_t m_creationTime
time the info file was created
Definition XrdPfcInfo.hh:80