ATLAS Offline Software
Loading...
Searching...
No Matches
DiskWriterXRD.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
8//
9// includes
10//
11
13
16#include <TFile.h>
17#include <TSystem.h>
18#include <format>
19#include <boost/functional/hash.hpp>
20#include <chrono>
21#include <iostream>
22#include <optional>
23#include <random>
24#include <sstream>
25#include <stdexcept>
26#include <sys/types.h>
27#include <thread>
28#include <unistd.h>
29
30//
31// method implementations
32//
33
34namespace SH
35{
36 void DiskWriterXRD ::
37 testInvariant () const
38 {
39 }
40
41
42
43 DiskWriterXRD ::
44 DiskWriterXRD (const std::string& val_path)
45 : m_path (val_path)
46 {
47 RCU_REQUIRE (val_path.find ("root://") == 0);
48
49 const char *tmpdir = getenv ("TMPDIR");
50 std::size_t hash {0};
51 boost::hash_combine (hash, std::hash<pid_t>() (getpid()));
52 std::size_t tries = 0;
53 while (m_file == nullptr || !m_file->IsOpen())
54 {
55 if (++ tries == 10)
56 throw std::runtime_error ("infinite loop trying to create tempory file for DiskWriterXRD");
57
58 auto time = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
59 boost::hash_combine (hash, std::hash<decltype(time)>() (time));
60 std::size_t hash16 {hash};
61 while (hash16 > 0xffff)
62 hash16 = (hash16&0xffff) ^ (hash16 >> 16);
63
64 std::ostringstream str;
65 if (tmpdir)
66 str << tmpdir;
67 else
68 str << "/tmp";
69 str << "/SH-XRD-" << m_path.substr (m_path.rfind ("/")+1)
70 << "-" << std::format("{:04x}", hash16);
71 m_tmp = str.str();
72 if (gSystem->AccessPathName (m_tmp.c_str()) != 0)
73 m_file.reset (TFile::Open (m_tmp.c_str(), "CREATE"));
74 }
75
76 RCU_NEW_INVARIANT (this);
77 }
78
79
80
81 DiskWriterXRD ::
82 ~DiskWriterXRD ()
83 {
85
86 if (m_file != nullptr)
87 {
88 try
89 {
90 close ();
91 } catch (std::exception& e)
92 {
93 std::cerr << "exception closing file " << m_path << ": "
94 << e.what() << std::endl;
95
96 } catch (...)
97 {
98 std::cerr << "unknown exception closing file " << m_path << std::endl;
99 }
100 }
101 }
102
103
104
105 std::string DiskWriterXRD ::
106 getPath () const
107 {
108 RCU_READ_INVARIANT (this);
109 return m_path;
110 }
111
112
113
114 TFile *DiskWriterXRD ::
115 getFile ()
116 {
118 RCU_REQUIRE2_SOFT (m_file != nullptr, "file already closed");
119 return m_file.get();
120 }
121
122
123
124 void DiskWriterXRD ::
125 doClose ()
126 {
128 RCU_REQUIRE2_SOFT (m_file != nullptr, "file already closed");
129
130 if (m_file->IsOpen())
131 {
132 m_file->Write ();
133 if (m_file->TestBit (TFile::kWriteError))
134 throw std::runtime_error ("failed to write to file: " + m_path);
135 m_file->Close ();
136 }
137
138 // rationale: the RNG is only needed on the retry path, and
139 // constructing std::random_device typically opens /dev/urandom,
140 // so we construct it lazily on first use.
141 std::optional<std::mt19937> gen;
142 bool success = false;
143 unsigned tries = 0u;
144 while (!success)
145 {
146 try
147 {
148 // using the -f flag, because if this copy failed previously
149 // we need to force an overwrite. note that there would be no
150 // point in leaving this out on the first try (even though
151 // there should be no file there), because it would just fail
152 // and retry with the flag set.
154 success = true;
155 } catch (...)
156 {
157 std::cerr << "encountered error copying files to XRD path: \"" << m_path << "\"" << std::endl;
158 if (tries < 10u)
159 {
160 tries += 1;
161 if (!gen)
162 {
163 std::random_device rd;
164 gen.emplace (rd());
165 }
166 // sleeping for a random period of time, to reduce the
167 // chance that the problem is that multiple jobs finishing
168 // at the same time keep overloading the server by
169 // repeatedly hitting it at the same time.
170 unsigned seconds = std::uniform_int_distribution<>(30,60) (*gen);
171 std::cerr << "sleeping for " << seconds << " seconds before retrying" << std::endl;
172 std::this_thread::sleep_for (std::chrono::seconds(seconds));
173 } else
174 {
175 std::cerr << "giving up, leaving file at " << m_tmp << std::endl;
176 throw std::runtime_error ("failed to copy file to XRD");
177 }
178 }
179 }
180 // rationale: the upload has succeeded, so release the file handle
181 // now. that way a failure to remove the temporary file does not
182 // leave the writer looking un-closed and trigger a second upload
183 // from the destructor; a failed cleanup is only a warning.
184 m_file.reset ();
185 try
186 {
188 } catch (std::exception& e)
189 {
190 std::cerr << "failed to remove temporary file " << m_tmp << ": "
191 << e.what() << std::endl;
192 }
193 }
194}
#define RCU_DESTROY_INVARIANT(x)
Definition Assert.h:223
#define RCU_CHANGE_INVARIANT(x)
Definition Assert.h:219
#define RCU_REQUIRE2_SOFT(x, y)
Definition Assert.h:143
#define RCU_NEW_INVARIANT(x)
Definition Assert.h:221
#define RCU_REQUIRE(x)
Definition Assert.h:196
#define RCU_READ_INVARIANT(x)
Definition Assert.h:217
std::string m_tmp
the temporary path being used
std::string m_path
the path being used
std::unique_ptr< TFile > m_file
the actual file object
void close()
closes the file we are writing to
void exec(const std::string &cmd)
effects: execute the given command guarantee: strong failures: out of memory II failures: system fail...
Definition ShellExec.cxx:27
std::string quote(const std::string &name)
effects: quote the given name to protect it from the shell returns: the quoted name guarantee: strong...
Definition ShellExec.cxx:65
This module provides a lot of global definitions, forward declarations and includes that are used by ...
Definition DiskList.cxx:21