DABC (Data Acquisition Backbone Core)  2.9.9
FileInterface.cxx
Go to the documentation of this file.
1 #include "ltsm/FileInterface.h"
2 
3 #include <cstring>
4 
5 #include "dabc/Url.h"
6 #include "dabc/logging.h"
7 #include "dabc/timing.h"
8 #include "dabc/Manager.h"
9 
11  dabc::FileInterface(), fSession(0), fMaxFilesPerSession(10), fSessionConnectRetries(5), fIsClosing(false), fSessionFileCount(0), fUseDaysubfolders(false)
12 #ifdef LTSM_USE_FSD
13  ,fUseFileSystemDemon(false), fServernameFSD("lxcopytool01.gsi.de"),fPortFSD(7625),fSessionFSD(0)
14 #endif
15 {
16  DOUT3("tsm::FileInterface::FileInterface() ctor starts...");
17  api_msg_set_level(API_MSG_ERROR);
18  DOUT0("tsm::FileInterface::FileInterface() ctor set api message level to %d",
19  API_MSG_ERROR);
20  tsm_init (DSM_MULTITHREAD); // do we need multithread here?
21  DOUT3("tsm::FileInterface::FileInterface() ctor leaving...");
22 }
23 
25 {
26  DOUT3("ltsm::FileInterface::DTOR ... ");
28  tsm_cleanup (DSM_MULTITHREAD);
29 }
30 
32  const char* mode, const char* opt)
33 {
34 
35  DOUT0("ltsm::FileInterface::fopen with options %s",opt);
36  dabc::Url url;
37  url.SetOptions(opt);
38 
39 
40  //here optionally close current session if we exceed file counter:
41 
42  if (url.HasOption("ltsmMaxSessionFiles"))
43  {
44  fMaxFilesPerSession = url.GetOptionInt("ltsmMaxSessionFiles", fMaxFilesPerSession);
45  DOUT0("tsm::FileInterface::fopen uses %d max session files from url options.",fMaxFilesPerSession);
46  }
47  else
48  {
49  DOUT0("tsm::FileInterface::fopen uses %d max session files from DEFAULTS.",fMaxFilesPerSession);
50  }
51 
52  if (url.HasOption("ltsmDaysubfolders"))
53  {
54  fUseDaysubfolders = url.GetOptionBool("ltsmDaysubfolders", fUseDaysubfolders);
55  DOUT0("tsm::FileInterface::fopen uses day prefix in path: %d from url options.",fUseDaysubfolders);
56  }
57  else
58  {
59  DOUT0("tsm::FileInterface::fopen uses uses day prefix in path: %d from DEFAULTS.",fUseDaysubfolders);
60  }
61 
62 
63 
64 
65  if(fSessionFileCount >= fMaxFilesPerSession)
66  {
67  CloseTSMSession();
68  }
69 
70  // here optionally modify file path to contain year/day paths:
71  std::string fileName=fname;
72  // TODO 2020
73  if(fUseDaysubfolders)
74  {
75  // JAM feb-2020: this is similar to the filename evaluation for hld files
76  char buf[128];
77  struct timeval tv;
78  struct tm tm_res;
79  gettimeofday(&tv, NULL);
80  strftime(buf, 128, "%y/%j/", localtime_r(&tv.tv_sec, &tm_res));
81  DOUT0("ltsm::FileInterface uses year day path %s",buf);
82  std::string insertpath(buf);
83 
84  size_t slash = fileName.rfind("/");
85  if (slash == std::string::npos)
86  slash=0;
87  fileName.insert(slash+1,insertpath);
88 
89  DOUT0("ltsm::FileInterface uses new filename %s",fileName.c_str());
90 
91  }
92  // open session before first file is written, or if we have closed previous session to start tape migration on server
93 #ifdef LTSM_USE_FSD
94  if (fUseFileSystemDemon)
95  {
96  if (fSessionFSD == 0)
97  {
98  if(!OpenTSMSession(opt)) return 0;
99  } // if fSesssion==0
100  }
101  else
102 #endif
103  {
104  if (fSession == 0)
105  {
106  if(!OpenTSMSession(opt)) return 0;
107  } // if fSesssion==0
108  }
109 
110  // default description is per file, not per session:
111  dabc::DateTime dt;
112  fDescription = dabc::format(
113  "This file was created by DABC ltsm interface at %s",
114  dt.GetNow().AsJSString().c_str());
115 
116 
117  if (url.HasOption("ltsmDescription"))
118  {
119  fDescription = url.GetOptionStr("ltsmDescription", fDescription);
120  }
121 
122  if (strstr(mode, "w") != 0)
123  {
124  int rc;
125 #ifdef LTSM_USE_FSD
126  if (fUseFileSystemDemon)
127  {
128  rc = fsd_fopen(fFsname.c_str(), (char*) fileName.c_str(),
129  (char*) fDescription.c_str(), fSessionFSD);
130  if (rc)
131  {
132  EOUT(
133  "Fail to open LTSM file for writing to FSD (returncode:%d), using following arguments"
134  "File=%s, FSD Servername=%s, Node=%s, Pass=%s, Owner=%s,Fsname=%s Description=%s",rc,
135  fileName.c_str(), fServernameFSD.c_str(), fNode.c_str(),
136  fPassword.c_str(), fOwner.c_str(), fFsname.c_str(),
137  fDescription.c_str());
138 
139  free(fSessionFSD);
140  fSessionFSD = 0; // on failure we retry open the session. Or keep it?
141  return 0;
142  }
143  fCurrentFile = fileName.c_str();
144  fSessionFileCount++;
145  DOUT0("Opened LTSM file (session count %d) for writing to FSD: "
146  "File=%s, FSD Servername=%s, Description=%s", fSessionFileCount, fname,
147  fServernameFSD.c_str(), fDescription.c_str());
148  return fSessionFSD; // no file structure here, use current session as handle
149  }
150  else
151 #endif
152  {
153  rc = tsm_fopen(fFsname.c_str(), (char*) fileName.c_str(),
154  (char*) fDescription.c_str(), fSession);
155  if (rc)
156  {
157  EOUT(
158  "Fail to open LTSM file for writing (returncode:%d), using following arguments"
159  "File=%s, Servername=%s, Node=%s, Pass=%s, Owner=%s,Fsname=%s Description=%s",rc,
160  fileName.c_str(), fServername.c_str(), fNode.c_str(),
161  fPassword.c_str(), fOwner.c_str(), fFsname.c_str(),
162  fDescription.c_str());
163 
164  free(fSession);
165  fSession = 0; // on failure we retry open the session. Or keep it?
166  return 0;
167  }
168  fCurrentFile = fileName.c_str();
169  fSessionFileCount++;
170  DOUT0("Opened LTSM file (session count %d) for writing: "
171  "File=%s, Servername=%s, Description=%s", fSessionFileCount, fileName.c_str(),
172  fServername.c_str(), fDescription.c_str());
173  return fSession->tsm_file; // pointer to file structure is the handle
174  }
175 
176  }
177  else if (strstr(mode, "r") != 0)
178  {
179  EOUT("tsm_fread is not yet supported!");
180  return 0;
181  }
182  return 0;
183 }
184 
185 int ltsm::FileInterface::GetFileIntPar(Handle, const char* parname)
186 {
187  // TODO: meaningful info for HADES epics display?
188 
189  if (strcmp(parname, "RFIO") == 0)
190  return -1; // return RFIO version number
191  if (strcmp(parname, "DataMoverIndx") == 0)
192  {
193  std::string suffix = fNode.substr(fNode.size() - 2);
194  return std::stoi(suffix); //take first number from node name.
195  // this works for LTSM_TEST01, but not for lxbkhebe.
196  }
197  return 0;
198 }
199 
200 bool ltsm::FileInterface::GetFileStrPar(Handle, const char* parname, char* sbuf,
201  int sbuflen)
202  {
203  // some info for HADES epics display - backward compatibility
204  if (strcmp(parname, "DataMoverName") == 0)
205  {
206  strncpy(sbuf, fNode.c_str(), sbuflen);
207  return true;
208  }
209  // JAM2020: this one will pass the real filename upward for display in logfile and gui
210  if (strcmp(parname, "RealFileName")==0)
211  {
212  strncpy(sbuf,fCurrentFile.c_str(),sbuflen);
213  return true;
214  }
215  return false;
216  }
217 
218 void ltsm::FileInterface::fclose(Handle f)
219 {
220  DOUT3("ltsm::FileInterface::fclose with handle 0x%x...", f);
221  if (f == 0)
222  return;
223  if (fIsClosing)
224  {
225  DOUT0(
226  "ltsm::FileInterface::fclose is called during closing - ignored!");
227  return;
228  }
229  fIsClosing = true;
230  int rc=0;
231 
232 #ifdef LTSM_USE_FSD
233  if (fUseFileSystemDemon)
234  {
235  struct fsd_session_t* theHandleFSD = (struct fsd_session_t*) f;
236  if (theHandleFSD != fSessionFSD)
237  {
238 
239  EOUT(
240  "Inconsistent file handles (0x%x != 0x%x) when closing LTSM file: "
241  "File=%s, FSD Servername=%s, Node=%s, Fsname=%s .... try to close most recent file in session",
242  theHandleFSD, fSessionFSD, fCurrentFile.c_str(),
243  fServernameFSD.c_str(), fNode.c_str(), fFsname.c_str());
244  }
245  rc = fsd_fclose(fSessionFSD);
246  if (rc)
247  {
248  EOUT("Failedto close LTSM file on FSD server: "
249  "File=%s, FSD Servername=%s, Node=%s, Fsname=%s",
250  fCurrentFile.c_str(), fServernameFSD.c_str(), fNode.c_str(),
251  fFsname.c_str());
252  return;
253  }
254  }
255  else
256 #endif
257  {
258  struct tsm_file_t* theHandle = (struct tsm_file_t*) f;
259  if (theHandle != fSession->tsm_file)
260  {
261 
262  EOUT(
263  "Inconsistent file handles (0x%x != 0x%x) when closing LTSM file: "
264  "File=%s, Servername=%s, Node=%s, Fsname=%s .... try to close most recent file in session",
265  theHandle, fSession->tsm_file, fCurrentFile.c_str(),
266  fServername.c_str(), fNode.c_str(), fFsname.c_str());
267  }
268 
269 
270  rc = tsm_fclose(fSession);
271 
272  if (rc)
273  {
274  EOUT("Failedto close LTSM file: "
275  "File=%s, Servername=%s, Node=%s, Fsname=%s",
276  fCurrentFile.c_str(), fServername.c_str(), fNode.c_str(),
277  fFsname.c_str());
278  return;
279  }
280  }
281  DOUT0("ltsm::FileInterface has closed file %s", fCurrentFile.c_str());
282  fIsClosing = false; // do we need such protection anymore? keep it for signalhandler tests maybe.
283  DOUT3("ltsm::FileInterface::fclose END ");
284 }
285 
286 size_t ltsm::FileInterface::fwrite(const void* ptr, size_t sz, size_t nmemb,
287  Handle f)
288  {
289 
290  if ((f == 0) || (ptr == 0) || (sz == 0))
291  return 0;
292 
293  if (fIsClosing)
294  {
295  DOUT0(
296  "ltsm::FileInterface::fwrite is called during closing - ignored!");
297  //tsm_cleanup (DSM_MULTITHREAD); // workaround JAM
298  return 0;
299  }
300 
301  int rc;
302  #ifdef LTSM_USE_FSD
303  if (fUseFileSystemDemon)
304  {
305  struct fsd_session_t* theHandleFSD = (struct fsd_session_t*) f;
306  if (theHandleFSD != fSessionFSD)
307  {
308 
309  EOUT(
310  "Inconsistent file handles (0x%x != 0x%x) when writing to LTSM: "
311  "File=%s, FSD Servername=%s, Node=%s, Fsname=%s .... something is wrong!",
312  theHandleFSD, fSessionFSD, fCurrentFile.c_str(),
313  fServernameFSD.c_str(), fNode.c_str(), fFsname.c_str());
314  return 0;
315  }
316  rc = fsd_fwrite(ptr, sz, nmemb, fSessionFSD);
317  }
318  else
319 #endif
320  {
321  struct tsm_file_t* theHandle = (struct tsm_file_t*) f;
322  if (theHandle != fSession->tsm_file)
323  {
324 
325  EOUT(
326  "Inconsistent tsm_file_t handles (0x%x != 0x%x) when writing to LTSM: "
327  "File=%s, Servername=%s, Node=%s, Fsname=%s .... something is wrong!",
328  theHandle, fSession->tsm_file, fCurrentFile.c_str(),
329  fServername.c_str(), fNode.c_str(), fFsname.c_str());
330  return 0;
331  }
332  rc = tsm_fwrite(ptr, sz, nmemb, fSession);
333  }
334  if (rc < 0)
335  {
336  EOUT("tsm_fwrite failed, handle:0x%x, size:%d, nmemb:%d, rc=%d", f, sz, nmemb,rc);
337  return 0;
338  }
339 
340  if (rc != int(sz * nmemb))
341  {
342  EOUT("tsm_fwrite size mismatch, wrote %d bytes from requested %d bytes",
343  rc, sz * nmemb);
344  }
345 
346  return nmemb; // return value is count of written elements (buffers) - fwrite convention
347  }
348 
349 size_t ltsm::FileInterface::fread(void* ptr, size_t sz, size_t nmemb, Handle f)
350  {
351  EOUT("ltsm::FileInterface::fread is not yet supported!");
352  return 0;
353 
354  }
355 
356 bool ltsm::FileInterface::fseek(Handle f, long int offset, bool relative)
357  {
358  if (f == 0)
359  return false;
360  //TODO: do we have such thing?
361  return false;
362  }
363 
364 bool ltsm::FileInterface::feof(Handle f)
365  {
366  if (f == 0)
367  return false;
368  return false;
369 
370  // return f==0 ? false : (ltsm_fendfile((RFILE*)f) > 0);
371  }
372 
373 bool ltsm::FileInterface::fflush(Handle f)
374  {
375  if (f == 0)
376  return false;
377 
378  return true;
379 
380  // return f==0 ? false : ::fflush((FILE*)f)==0;
381  }
382 
383 dabc::Object* ltsm::FileInterface::fmatch(const char* fmask, bool select_files)
384  {
385  return 0;
386  }
387 
388 
389 
390 bool ltsm::FileInterface::OpenTSMSession(const char* opt)
391 {
392  DOUT3("ltsm::FileInterface::OpenTSMSession ... ");
393  dabc::Url url;
394  url.SetOptions(opt);
395  // open session before first file is written.
396  fCurrentFile = "none";
397  fServername = "lxltsm01-tsm-server";
398  fNode = "LTSM_TEST01";
399  fPassword = "LTSM_TEST01";
400  fOwner = "";
401  fFsname = DEFAULT_FSNAME;
402 
403  DOUT1("ltsm::FileInterface::fOpenTSMSession before options with options %s", opt);
404 
405  if (url.HasOption("ltsmServer"))
406  {
407  fServername = url.GetOptionStr("ltsmServer", fServername);
408  }
409  if (url.HasOption("ltsmNode"))
410  {
411  fNode = url.GetOptionStr("ltsmNode", fNode);
412  }
413  if (url.HasOption("ltsmPass"))
414  {
415  fPassword = url.GetOptionStr("ltsmPass", fPassword);
416  }
417  if (url.HasOption("ltsmOwner"))
418  {
419  fOwner = url.GetOptionStr("ltsmOwner", fOwner);
420  }
421  if (url.HasOption("ltsmFsname"))
422  {
423  fFsname = url.GetOptionStr("ltsmFsname", fFsname);
424  }
425 
426  if (url.HasOption("ltsmSessionConnectRetries"))
427  {
428  fMaxFilesPerSession = url.GetOptionInt("ltsmMaxSessionFiles", fSessionConnectRetries);
429  DOUT0("tsm::FileInterface::OpenTSMSession uses %d session connect retries from url options.",fSessionConnectRetries);
430  }
431  else
432  {
433  DOUT0("tsm::FileInterface::OpenTSMSession uses %d session connect retries from DEFAULTS.", fSessionConnectRetries);
434  }
435 
436 #ifdef LTSM_USE_FSD
437  if (url.HasOption("ltsmUseFSD"))
438  {
439  fUseFileSystemDemon = url.GetOptionBool("ltsmUseFSD", fUseFileSystemDemon);
440  DOUT0("tsm::FileInterface::OpenTSMSession will use %s from url options.",fUseFileSystemDemon ? "file system demon" : "direct TSM connection");
441  }
442  else
443  {
444  DOUT0("tsm::FileInterface::OpenTSMSession will use %s from defaults.",fUseFileSystemDemon ? "file system demon" : "direct TSM connection");
445  }
446 
447  if (fUseFileSystemDemon)
448  {
449  if (url.HasOption("ltsmFSDServerName"))
450  {
451  fServernameFSD = url.GetOptionStr("ltsmFSDServerName", fServernameFSD);
452  DOUT0("tsm::FileInterface::OpenTSMSession with FSD server %s from url options.",fServernameFSD.c_str());
453  }
454  else
455  {
456  DOUT0("tsm::FileInterface::OpenTSMSession with FSD server %s from defaults.",fServernameFSD.c_str());
457  }
458  if (url.HasOption("ltsmFSDServerPort"))
459  {
460  fPortFSD = url.GetOptionInt("ltsmFSDServerPort", fPortFSD);
461  DOUT0("tsm::FileInterface::OpenTSMSession with FSD server port %d from url options.",fPortFSD);
462  }
463  else
464  {
465  DOUT0("tsm::FileInterface::OpenTSMSession with FSD server port %d from defaults.",fPortFSD);
466  }
467 
468  } // if (fUseFileSystemDemon)
469 #endif
470 
471  DOUT2(
472  "Prepare open LTSM file for writing - "
473  "Servername=%s, Node=%s, Pass=%s, Owner=%s,Fsname=%s Description=%s",
474  fServername.c_str(), fNode.c_str(), fPassword.c_str(),
475  fOwner.c_str(), fFsname.c_str(), fDescription.c_str());
476 
477 
478 #ifdef LTSM_USE_FSD
479  struct fsd_login_t fsdlogin;
480  // TODO: function fsd_login_init
481  strncpy(fsdlogin.node, fNode.c_str(), DSM_MAX_NODE_LENGTH);
482  strncpy(fsdlogin.password, fPassword.c_str(), DSM_MAX_VERIFIER_LENGTH);
483  strncpy(fsdlogin.hostname, fServernameFSD.c_str(), DSM_MAX_NODE_LENGTH);
484  fsdlogin.port=fPortFSD;
485 
486  fSessionFSD = (struct fsd_session_t*) malloc(sizeof(struct fsd_session_t));
487 #endif
488  struct login_t tsmlogin;
489  login_init(&tsmlogin, fServername.c_str(), fNode.c_str(),
490  fPassword.c_str(), fOwner.c_str(), LINUX_PLATFORM,
491  fFsname.c_str(), DEFAULT_FSTYPE);
492  fSession = (struct session_t*) malloc(sizeof(struct session_t));
493  if (!fSession) {
494  EOUT("Memory allocation error");
495  return false;
496  }
497 
498  int connectcount=0;
499  int rc=0;
500  while (connectcount++ <fSessionConnectRetries)
501  {
502 #ifdef LTSM_USE_FSD
503  if (fUseFileSystemDemon)
504  {
505  memset(fSessionFSD, 0, sizeof(struct fsd_session_t));
506  rc = fsd_fconnect(&fsdlogin, fSessionFSD);
507  }
508  else
509 #endif
510  {
511  memset(fSession, 0, sizeof(struct session_t));
512  rc = tsm_fconnect(&tsmlogin, fSession);
513  }
514  if (rc==0)
515  {
516  break;
517  }
518  else
519  {
520  EOUT("Fail to connect LTSM session (returncode:%d) using following arguments"
521  "Servername=%s, Node=%s, Pass=%s, Owner=%s,Fsname=%s , retry again %d time...",rc,
522  fServername.c_str(), fNode.c_str(), fPassword.c_str(),
523  fOwner.c_str(), fFsname.c_str(), connectcount);
524  dabc::mgr.Sleep(1);
525  }
526  } // while
527 
528  if (rc)
529  {
530  EOUT("Finally FAILED to connect LTSM session (returncode%d))after %d retries!! - using following arguments"
531  "Servername=%s, Node=%s, Pass=%s, Owner=%s,Fsname=%s", rc, connectcount,
532  fServername.c_str(), fNode.c_str(), fPassword.c_str(),
533  fOwner.c_str(), fFsname.c_str());
534 #ifdef LTSM_USE_FSD
535  if (fUseFileSystemDemon)
536  {
537  free(fSessionFSD);
538  fSessionFSD=0;
539  }
540  else
541 #endif
542  {
543  free(fSession);
544  fSession=0;
545  }
546  return false;
547  } // if(rc)
548 
549  DOUT0("Successfully conncted LTSM session with parameter: "
550  "Servername=%s, Node=%s, Pass=%s, Owner=%s,Fsname=%s",
551  fServername.c_str(), fNode.c_str(), fPassword.c_str(),
552  fOwner.c_str(), fFsname.c_str());
553 
554  #ifdef LTSM_USE_FSD
555  if (fUseFileSystemDemon)
556  DOUT0("Using FSD at server %s ,port %d", fServernameFSD.c_str(), fPortFSD);
557  #endif
558 
559  return true;
560 }
561 
562 
564 {
565 #ifdef LTSM_USE_FSD
566  if (fUseFileSystemDemon)
567  {
568  if(fSessionFSD==0) return false;
569  fsd_fdisconnect(fSessionFSD);
570  free(fSessionFSD);
571  fSessionFSD = 0;
572  }
573  else
574 #endif
575  {
576  if(fSession==0) return false;
577  tsm_fdisconnect(fSession);
578  free(fSession);
579  fSession = 0;
580  }
581  fSessionFileCount=0;
582  return true;
583 }
584 
585 
Class for holding GMT time with precision of nanoseconds.
Definition: timing.h:190
std::string AsJSString(int ndecimal=3) const
convert string into sec.frac format, can be interpret directly in JavaScript ISO 8601 standard is use...
Definition: timing.cxx:212
DateTime & GetNow()
Definition: timing.cxx:147
void * Handle
File handle descriptor.
Definition: BinaryFile.h:37
void Sleep(double tmout, const char *prefix=0)
Sleep for specified time, keep thread event loop running See Manager::Sleep() method for more details...
Definition: Manager.cxx:2269
Base class for most of the DABC classes.
Definition: Object.h:116
Uniform Resource Locator interpreter.
Definition: Url.h:33
std::string GetOptionStr(const std::string &optname, const std::string &dflt="") const
Definition: Url.cxx:281
bool GetOptionBool(const std::string &optname, bool dflt=false) const
Definition: Url.cxx:314
bool HasOption(const std::string &optname) const
Definition: Url.h:70
int GetOptionInt(const std::string &optname, int dflt=0) const
Definition: Url.cxx:290
void SetOptions(const std::string &opt)
Method allows to set URL options directly to be able use all Get methods.
Definition: Url.cxx:102
virtual bool fflush(Handle f)
bool CloseTSMSession()
Shut down current TSM session.
virtual int GetFileIntPar(Handle h, const char *parname)
Method returns file-specific int parameter.
virtual bool GetFileStrPar(Handle h, const char *parname, char *sbuf, int sbuflen)
Method returns file-specific string parameter.
virtual size_t fread(void *ptr, size_t sz, size_t nmemb, Handle f)
virtual void fclose(Handle f)
virtual bool feof(Handle f)
virtual bool fseek(Handle f, long int offset, bool realtive=true)
bool OpenTSMSession(const char *options)
Re-open session with parameters specified in dabc options string.
virtual Handle fopen(const char *fname, const char *mode, const char *opt=0)
virtual dabc::Object * fmatch(const char *fmask, bool select_files=true)
Produce list of files, object must be explicitly destroyed with ref.Destroy call One could decide if ...
virtual size_t fwrite(const void *ptr, size_t sz, size_t nmemb, Handle f)
#define DOUT2(args ...)
Definition: logging.h:170
#define DOUT0(args ...)
Definition: logging.h:156
#define DOUT3(args ...)
Definition: logging.h:176
#define EOUT(args ...)
Definition: logging.h:150
#define DOUT1(args ...)
Definition: logging.h:162
#define LTSM_USE_FSD
Definition: FileInterface.h:10
Event manipulation API.
Definition: api.h:23
ManagerRef mgr
Definition: Manager.cxx:42
std::string format(const char *fmt,...)
Definition: string.cxx:49