ATLAS Offline Software
Loading...
Searching...
No Matches
EL::Detail::SubmitDirManager Class Referencefinal

a Manager to handle the submission directory itself More...

#include <SubmitDirManager.h>

Inheritance diagram for EL::Detail::SubmitDirManager:
Collaboration diagram for EL::Detail::SubmitDirManager:

Public Member Functions

virtual std::pair< Detail::ManagerOrder, std::string > getManagerOrder () const noexcept override
 get the order/name of this manager
virtual::StatusCode doManagerStep (Detail::ManagerData &data) const override
 do whatever needs to be done for the given submission step

Detailed Description

a Manager to handle the submission directory itself

Definition at line 22 of file SubmitDirManager.h.

Member Function Documentation

◆ doManagerStep()

StatusCode EL::Detail::SubmitDirManager::doManagerStep ( Detail::ManagerData & data) const
overridevirtual

do whatever needs to be done for the given submission step

Guarantee
basic
Failures
job configuration errors
driver errors

Implements EL::Detail::Manager.

Definition at line 68 of file SubmitDirManager.cxx.

70 {
71 switch (data.step)
72 {
74 {
75 std::smatch match;
76
77 // make sure directory is absolute
78 if (data.submitDir[0] != '/')
79 data.submitDir = gSystem->WorkingDirectory () + ("/" + data.submitDir);
80
81 // make sure we don't end in "/", "/." or "/.."
82 const std::regex identityEndExpr {"(/$)|(/\\.$)"};
83 while (std::regex_search (data.submitDir, match, identityEndExpr))
84 data.submitDir.replace (match.position(0), match.length(0), "");
85 const std::regex relativeEndExpr {"/\\.\\.$"};
86 if (std::regex_search (data.submitDir, match, relativeEndExpr))
87 {
88 ANA_MSG_ERROR ("submit directory can not end in \"..\": " + data.submitDir);
89 return ::StatusCode::FAILURE;
90 }
91
92 // make sure we don't include any '..' in our path. this is
93 // mainly relevant for Ganga Tasks which may crash
94 // otherwise. this specifically doesn't use any of the
95 // "normal" regularization functions because those resolve
96 // symlinks as well, and depending on the driver we may not
97 // want that to happen.
98 const std::regex identityExpr {"(/\\./)|(//)|(^/\\.\\./)"};
99 while (std::regex_search (data.submitDir, match, identityExpr))
100 data.submitDir.replace (match.position(0), match.length(0), "/");
101 const std::regex relativeExpr {"/[^/]+/\\.\\./"};
102 while (std::regex_search (data.submitDir, match, relativeExpr))
103 data.submitDir.replace (match.position(0), match.length(0), "/");
104
105 if (data.submitDir.find ("/pnfs/") == 0)
106 {
107 ANA_MSG_ERROR ("can not place submit directory on pnfs: " + data.submitDir);
108 return ::StatusCode::FAILURE;
109 }
110
111 ANA_MSG_DEBUG ("changed submit-dir to " << data.submitDir);
112 }
113 break;
114
116 {
117 std::string mode = data.options.castString (Job::optSubmitDirMode);
118 if (!mode.empty())
119 {
120 if (mode == "no-clobber")
121 data.submitDirMode = SubmitDirMode::NO_CLOBBER;
122 else if (mode == "overwrite")
123 data.submitDirMode = SubmitDirMode::OVERWRITE;
124 else if (mode == "unique")
125 data.submitDirMode = SubmitDirMode::UNIQUE;
126 else if (mode == "unique-link")
127 data.submitDirMode = SubmitDirMode::UNIQUE_LINK;
128 else
129 {
130 ANA_MSG_ERROR ("unknown submit-dir mode: " << mode);
131 ANA_MSG_ERROR ("known modes: no-clobber, overwrite, unique, unique-link");
132 return ::StatusCode::FAILURE;
133 }
134 }
135
136 if (data.options.castBool (Job::optRemoveSubmitDir, false))
137 {
138 if (!mode.empty())
139 {
140 ANA_MSG_ERROR ("can't specify both an explicit submit-dir mode and optRemoveSubmitDir");
141 return ::StatusCode::FAILURE;
142 }
143 data.submitDirMode = SubmitDirMode::OVERWRITE;
144 }
145 }
146 break;
147
149 {
150 ANA_MSG_DEBUG ("using submit-dir mode: " << unsigned (data.submitDirMode));
151
152 bool success {false};
153 unsigned tries {0};
154 std::string submitDir;
155 std::size_t hash {0};
156 while (success == false && tries < 10)
157 {
158 tries += 1;
159
160 switch (data.submitDirMode)
161 {
164 submitDir = data.submitDir;
165 break;
166
169 {
170 timeval tv;
171 tm tvSplit;
172 if (gettimeofday (&tv, nullptr) == -1 ||
173 localtime_r (&tv.tv_sec, &tvSplit) == nullptr)
174 {
175 reportErrno ();
176 ANA_MSG_ERROR ("failed to get time of day???");
177 return ::StatusCode::FAILURE;
178 }
179 const std::string uniqueDateFormat {
180 data.options.castString (Job::optUniqueDateFormat,
181 "-%Y-%m-%d-%H%M-")};
182 char timeString [160];
183 strftime (timeString, sizeof (timeString),
184 uniqueDateFormat.c_str(), &tvSplit);
185
186 // make a hash value and reduce it to 16 bits
187 boost::hash_combine (hash, std::hash<pid_t>() (getpid()));
188 boost::hash_combine (hash, std::hash<suseconds_t>() (tv.tv_usec));
189 std::size_t hash16 {hash};
190 while (hash16 > 0xffff)
191 hash16 = (hash16&0xffff) ^ (hash16 >> 16);
192
193 // we are appending both a date and a unique hash
194 // here, in most cases the date should be sufficient
195 // to make it unique, but for unit tests a lot of jobs
196 // may be submitted in rapid succcession, so having
197 // some random suffix should help avoid clashes. the
198 // date is purposely put first because in some cases
199 // that can provide a useful ordering of output
200 // directories, i.e. the latest results will be listed
201 // last.
202 submitDir = data.submitDir + timeString +
203 std::format("{:04x}", hash16);
204 ANA_MSG_DEBUG ("unique submit-dir: " << submitDir);
205 }
206 break;
207 }
208
209 if (::mkdir (submitDir.c_str(), 0777) == 0)
210 {
211 success = true;
212 } else
213 {
214 const int myerrno {errno};
215 if (myerrno == EEXIST)
216 {
217 switch (data.submitDirMode)
218 {
220 ANA_MSG_ERROR ("cowardly refusing to overwrite " << submitDir);
221 ANA_MSG_ERROR ("change the name or remove file/directory already there");
222 return ::StatusCode::FAILURE;
224 if (tries > 1)
225 {
226 ANA_MSG_ERROR ("failed to remove directory " << submitDir);
227 ANA_MSG_ERROR ("please try to remove it manually");
228 return ::StatusCode::FAILURE;
229 }
230 ANA_MSG_DEBUG ("removing directory " << submitDir);
231 gSystem->Exec (("rm -rf " + submitDir).c_str());
232 break;
235 // just pass through, try again with a new directory
236 // name next time
237 break;
238 }
239 } else
240 {
241 reportErrno (myerrno);
242 ANA_MSG_ERROR ("failed to create directory: " << submitDir);
243 return ::StatusCode::FAILURE;
244 }
245 }
246 }
247
248 if (success)
249 {
250 ANA_MSG_INFO ("created submission directory " + submitDir);
251 switch (data.submitDirMode)
252 {
256 // no-op
257 break;
258
260 {
261 if (unlink (data.submitDir.c_str()) == -1 && errno != ENOENT)
262 {
263 reportErrno ();
264 ANA_MSG_ERROR ("failed to remove: " << data.submitDir);
265 return ::StatusCode::FAILURE;
266 }
267
268 std::string file = submitDir.substr (submitDir.rfind ('/')+1);
269 if (symlink (file.c_str(), data.submitDir.c_str()) == -1)
270 {
271 reportErrno ();
272 ANA_MSG_ERROR ("failed to create symlink at: " << data.submitDir);
273 return ::StatusCode::FAILURE;
274 }
275 ANA_MSG_INFO ("created sym-link at: " << data.submitDir);
276 }
277 break;
278 }
279 data.submitDir = submitDir;
280 } else
281 {
282 ANA_MSG_ERROR ("tried " << tries << " times to create directory and failed: " << data.submitDir);
283 ANA_MSG_ERROR ("try removing existing directory manually");
284 return ::StatusCode::FAILURE;
285 }
286 }
287 break;
288
289 default:
290 // no-op
291 break;
292 }
293 return ::StatusCode::SUCCESS;
294 }
#define ANA_MSG_INFO(xmsg)
Macro printing info messages.
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
#define ANA_MSG_DEBUG(xmsg)
Macro printing debug messages.
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
static const std::string optSubmitDirMode
the submit-dir mode (allowed values: "no-clobber", "overwrite", "unique", "unique-link")
Definition Job.h:195
static const std::string optUniqueDateFormat
the date-format to use when generating unique submission directory names
Definition Job.h:200
static const std::string optRemoveSubmitDir
description: the name of the option for overwriting the submission directory.
Definition Job.h:189
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
@ OVERWRITE
create the directory as is, removing existing directories if needed
@ UNIQUE_LINK
append a unique suffix to the directory name and place a symbolic link in place of the originally req...
@ NO_CLOBBER
create the directory as is, raise an error if it already exists
@ UNIQUE
append a unique suffix to the directory name
@ updateSubmitDir
update the submitDir variable to be an absolute path
Definition ManagerStep.h:51
@ extractOptions
extract any options into ManagerData for which it is appropriate
Definition ManagerStep.h:60
@ createSubmitDir
create the submission directory
Definition ManagerStep.h:63
TFile * file

◆ getManagerOrder()

std::pair< Detail::ManagerOrder, std::string > EL::Detail::SubmitDirManager::getManagerOrder ( ) const
overridevirtualnoexcept

get the order/name of this manager

This is both used to identify the manager we are looking at, and to make sure they get executed in the right order. It is a mistake to load two managers that report the same order.

This is a pair of an enum that defines the absolute order of managers, and a string that identifies the stream that this manager belongs to. If this manager is not specific to a stream this should be the empty stream.

Guarantee
no-fail

Implements EL::Detail::Manager.

Definition at line 60 of file SubmitDirManager.cxx.

62 {
63 return std::make_pair (ManagerOrder::SUBMIT_DIR, "");
64 }
@ SUBMIT_DIR
the basic operations for the submission directory

The documentation for this class was generated from the following files: