~ubuntu-branches/ubuntu/trusty/nordugrid-arc/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/nordugrid-arc-recursive.patch/src/hed/libs/client/Job.cpp

  • Committer: Package Import Robot
  • Author(s): Mattias Ellert
  • Date: 2012-06-16 11:56:52 UTC
  • Revision ID: package-import@ubuntu.com-20120616115652-dk6bt47xjdsfvxmn
Tags: 2.0.0-2
Fix problem with directory hierarchies during job retrieval

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- indent-tabs-mode: nil -*-
 
2
 
 
3
#ifdef HAVE_CONFIG_H
 
4
#include <config.h>
 
5
#endif
 
6
 
 
7
#include <unistd.h>
 
8
 
 
9
#include <algorithm>
 
10
 
 
11
#include <arc/ArcConfig.h>
 
12
#include <arc/FileLock.h>
 
13
#include <arc/IString.h>
 
14
#include <arc/Logger.h>
 
15
#include <arc/StringConv.h>
 
16
#include <arc/XMLNode.h>
 
17
#include <arc/client/JobControllerPlugin.h>
 
18
#include <arc/data/DataHandle.h>
 
19
#include <arc/data/DataMover.h>
 
20
#include <arc/data/FileCache.h>
 
21
 
 
22
#include "Job.h"
 
23
 
 
24
#define JXMLTOSTRING(NAME) \
 
25
    if (job[ #NAME ]) {\
 
26
      NAME = (std::string)job[ #NAME ];\
 
27
    }
 
28
 
 
29
#define JXMLSTRINGTO(TYPE, NAME) \
 
30
    if (job[ #NAME ]) {\
 
31
      TYPE temp##TYPE##NAME;\
 
32
      if (stringto((std::string)job[ #NAME ], temp##TYPE##NAME)) {\
 
33
        NAME = temp##TYPE##NAME;\
 
34
      }\
 
35
    }
 
36
 
 
37
#define JXMLTOTIME(NAME) \
 
38
    if (job[ #NAME ]) {\
 
39
      Time temp##NAME((std::string)job[ #NAME ]);\
 
40
      if (temp##NAME.GetTime() != -1) {\
 
41
        NAME = temp##NAME;\
 
42
      }\
 
43
    }
 
44
 
 
45
#define JXMLTOSTRINGLIST(NAME) \
 
46
    NAME.clear();\
 
47
    for (XMLNode n = job[ #NAME ]; n; ++n) {\
 
48
      NAME.push_back((std::string)n);\
 
49
    }
 
50
 
 
51
#define STRINGTOXML(NAME) \
 
52
    if (!(NAME).empty()) {\
 
53
      node.NewChild( #NAME ) = NAME;\
 
54
    }
 
55
 
 
56
#define URLTOXML(NAME) \
 
57
    if (NAME) {\
 
58
      node.NewChild( #NAME ) = NAME.fullstr();\
 
59
    }
 
60
 
 
61
#define INTTOXML(NAME) \
 
62
    if (NAME != -1) {\
 
63
      node.NewChild( #NAME ) = tostring(NAME);\
 
64
    }
 
65
 
 
66
#define TIMETOSTRING(NAME) \
 
67
    if (NAME != -1) {\
 
68
      node.NewChild( #NAME ) = (NAME).str(UTCTime);\
 
69
    }
 
70
 
 
71
#define PERIODTOSTRING(NAME) \
 
72
    if (NAME != -1) {\
 
73
      node.NewChild( #NAME ) = (std::string)NAME;\
 
74
    }
 
75
 
 
76
#define STRINGLISTTOXML(NAME) \
 
77
    for (std::list<std::string>::const_iterator it = NAME.begin();\
 
78
         it != NAME.end(); it++) {\
 
79
      node.NewChild( #NAME ) = *it;\
 
80
    }
 
81
 
 
82
namespace Arc {
 
83
 
 
84
  Logger Job::logger(Logger::getRootLogger(), "Job");
 
85
 
 
86
  JobControllerPluginLoader Job::loader;
 
87
  
 
88
  DataHandle* Job::data_source = NULL;
 
89
  DataHandle* Job::data_destination = NULL;
 
90
 
 
91
  Job::Job()
 
92
    : ExitCode(-1),
 
93
      WaitingPosition(-1),
 
94
      RequestedTotalWallTime(-1),
 
95
      RequestedTotalCPUTime(-1),
 
96
      RequestedSlots(-1),
 
97
      UsedTotalWallTime(-1),
 
98
      UsedTotalCPUTime(-1),
 
99
      UsedMainMemory(-1),
 
100
      LocalSubmissionTime(-1),
 
101
      SubmissionTime(-1),
 
102
      ComputingManagerSubmissionTime(-1),
 
103
      StartTime(-1),
 
104
      ComputingManagerEndTime(-1),
 
105
      EndTime(-1),
 
106
      WorkingAreaEraseTime(-1),
 
107
      ProxyExpirationTime(-1),
 
108
      CreationTime(-1),
 
109
      Validity(-1),
 
110
      VirtualMachine(false),
 
111
      jc(NULL) {}
 
112
 
 
113
  Job::~Job() {}
 
114
 
 
115
  Job::Job(const Job& j)
 
116
    : ExitCode(-1),
 
117
      WaitingPosition(-1),
 
118
      RequestedTotalWallTime(-1),
 
119
      RequestedTotalCPUTime(-1),
 
120
      RequestedSlots(-1),
 
121
      UsedTotalWallTime(-1),
 
122
      UsedTotalCPUTime(-1),
 
123
      UsedMainMemory(-1),
 
124
      LocalSubmissionTime(-1),
 
125
      SubmissionTime(-1),
 
126
      ComputingManagerSubmissionTime(-1),
 
127
      StartTime(-1),
 
128
      ComputingManagerEndTime(-1),
 
129
      EndTime(-1),
 
130
      WorkingAreaEraseTime(-1),
 
131
      ProxyExpirationTime(-1),
 
132
      CreationTime(-1),
 
133
      Validity(-1),
 
134
      VirtualMachine(false),
 
135
      jc(NULL) {
 
136
    *this = j;
 
137
  }
 
138
 
 
139
  Job::Job(XMLNode j)
 
140
    : ExitCode(-1),
 
141
      WaitingPosition(-1),
 
142
      RequestedTotalWallTime(-1),
 
143
      RequestedTotalCPUTime(-1),
 
144
      RequestedSlots(-1),
 
145
      UsedTotalWallTime(-1),
 
146
      UsedTotalCPUTime(-1),
 
147
      UsedMainMemory(-1),
 
148
      LocalSubmissionTime(-1),
 
149
      SubmissionTime(-1),
 
150
      ComputingManagerSubmissionTime(-1),
 
151
      StartTime(-1),
 
152
      ComputingManagerEndTime(-1),
 
153
      EndTime(-1),
 
154
      WorkingAreaEraseTime(-1),
 
155
      ProxyExpirationTime(-1),
 
156
      CreationTime(-1),
 
157
      Validity(-1),
 
158
      VirtualMachine(false) {
 
159
    *this = j;
 
160
  }
 
161
 
 
162
  Job& Job::operator=(const Job& j) {
 
163
    jc = j.jc;
 
164
 
 
165
    JobID = j.JobID;
 
166
    Cluster = j.Cluster;
 
167
    InterfaceName = j.InterfaceName;
 
168
 
 
169
    Name = j.Name;
 
170
    Type = j.Type;
 
171
    IDFromEndpoint = j.IDFromEndpoint;
 
172
    LocalIDFromManager = j.LocalIDFromManager;
 
173
    JobDescription = j.JobDescription;
 
174
    JobDescriptionDocument = j.JobDescriptionDocument;
 
175
    State = j.State;
 
176
    RestartState = j.RestartState;
 
177
    ExitCode = j.ExitCode;
 
178
    ComputingManagerExitCode = j.ComputingManagerExitCode;
 
179
    Error = j.Error;
 
180
    WaitingPosition = j.WaitingPosition;
 
181
    UserDomain = j.UserDomain;
 
182
    Owner = j.Owner;
 
183
    LocalOwner = j.LocalOwner;
 
184
    RequestedTotalWallTime = j.RequestedTotalWallTime;
 
185
    RequestedTotalCPUTime = j.RequestedTotalCPUTime;
 
186
    RequestedSlots = j.RequestedSlots;
 
187
    RequestedApplicationEnvironment = j.RequestedApplicationEnvironment;
 
188
    StdIn = j.StdIn;
 
189
    StdOut = j.StdOut;
 
190
    StdErr = j.StdErr;
 
191
    LogDir = j.LogDir;
 
192
    ExecutionNode = j.ExecutionNode;
 
193
    Queue = j.Queue;
 
194
    UsedTotalWallTime = j.UsedTotalWallTime;
 
195
    UsedTotalCPUTime = j.UsedTotalCPUTime;
 
196
    UsedMainMemory = j.UsedMainMemory;
 
197
    RequestedApplicationEnvironment = j.RequestedApplicationEnvironment;
 
198
    RequestedSlots = j.RequestedSlots;
 
199
    LocalSubmissionTime = j.LocalSubmissionTime;
 
200
    SubmissionTime = j.SubmissionTime;
 
201
    ComputingManagerSubmissionTime = j.ComputingManagerSubmissionTime;
 
202
    StartTime = j.StartTime;
 
203
    ComputingManagerEndTime = j.ComputingManagerEndTime;
 
204
    EndTime = j.EndTime;
 
205
    WorkingAreaEraseTime = j.WorkingAreaEraseTime;
 
206
    ProxyExpirationTime = j.ProxyExpirationTime;
 
207
    SubmissionHost = j.SubmissionHost;
 
208
    SubmissionClientName = j.SubmissionClientName;
 
209
    CreationTime = j.CreationTime;
 
210
    Validity = j.Validity;
 
211
    OtherMessages = j.OtherMessages;
 
212
 
 
213
    ActivityOldID = j.ActivityOldID;
 
214
    LocalInputFiles = j.LocalInputFiles;
 
215
 
 
216
    VirtualMachine = j.VirtualMachine;
 
217
    UsedCPUType = j.UsedCPUType;
 
218
    UsedOSFamily = j.UsedOSFamily;
 
219
    UsedPlatform = j.UsedPlatform;
 
220
 
 
221
    return *this;
 
222
  }
 
223
 
 
224
  int Job::operator==(const Job& other) { return JobID == other.JobID; }
 
225
 
 
226
  Job& Job::operator=(XMLNode job) {
 
227
    jc = NULL;
 
228
 
 
229
    // Information specific to how job is stored in jobs list
 
230
    if (job["JobID"]) {
 
231
      JobID = URL((std::string)job["JobID"]);
 
232
    } else if (job["IDFromEndpoint"]) { // Backwardscompatibility: Pre 2.0.0 format.
 
233
      JobID = URL((std::string)job["IDFromEndpoint"]);
 
234
    }
 
235
    if (job["IDFromEndpoint"]
 
236
        /* If this is pre 2.0.0 format then JobID element would not
 
237
         * exist, and the usage of IDFromEndpoint element corresponded
 
238
         * to the current usage of the JobID element. Therefore only set
 
239
         * the IDFromEndpoint member if the JobID _does_ exist.
 
240
         */
 
241
        && job["JobID"]
 
242
        ) {
 
243
      IDFromEndpoint = (std::string)job["IDFromEndpoint"];
 
244
    }
 
245
 
 
246
    JXMLTOSTRING(Name)
 
247
    JXMLTOSTRING(Cluster)
 
248
    if (job["InterfaceName"]) {
 
249
      JXMLTOSTRING(InterfaceName)
 
250
    }
 
251
    else if (job["Flavour"]) {
 
252
      if      ((std::string)job["Flavour"] == "ARC0")  InterfaceName = "org.nordugrid.gridftpjob";
 
253
      else if ((std::string)job["Flavour"] == "BES")   InterfaceName = "org.ogf.bes";
 
254
      else if ((std::string)job["Flavour"] == "ARC1")  InterfaceName = "org.nordugrid.xbes";
 
255
      else if ((std::string)job["Flavour"] == "EMIES") InterfaceName = "org.ogf.emies";
 
256
      else if ((std::string)job["Flavour"] == "TEST")  InterfaceName = "org.nordugrid.test";
 
257
    }
 
258
 
 
259
    if (job["InfoEndpoint"] && job["Flavour"] && (std::string)job["Flavour"] == "ARC0") {
 
260
      IDFromEndpoint = (std::string)job["InfoEndpoint"];
 
261
    }
 
262
 
 
263
    if (job["JobDescription"]) {
 
264
      const std::string sjobdesc = job["JobDescription"];
 
265
      if (job["JobDescriptionDocument"] || job["State"] ||
 
266
          !job["LocalSubmissionTime"]) {
 
267
        // If the 'JobDescriptionDocument' or 'State' element is set assume that the 'JobDescription' element is the GLUE2 one.
 
268
        // Default is to assume it is the GLUE2 one.
 
269
        JobDescription = sjobdesc;
 
270
      }
 
271
      else {
 
272
        // If the 'LocalSubmissionTime' element is set assume that the 'JobDescription' element contains the actual job description.
 
273
        JobDescriptionDocument = sjobdesc;
 
274
      }
 
275
    }
 
276
 
 
277
    JXMLTOSTRING(JobDescriptionDocument)
 
278
    JXMLTOTIME(LocalSubmissionTime)
 
279
 
 
280
    if (job["Associations"]["ActivityOldID"]) {
 
281
      ActivityOldID.clear();
 
282
      for (XMLNode n = job["Associations"]["ActivityOldID"]; n; ++n) {
 
283
        ActivityOldID.push_back((std::string)n);
 
284
      }
 
285
    }
 
286
    else if (job["OldJobID"]) { // Included for backwards compatibility.
 
287
      ActivityOldID.clear();
 
288
      for (XMLNode n = job["OldJobID"]; n; ++n) {
 
289
        ActivityOldID.push_back((std::string)n);
 
290
      }
 
291
    }
 
292
 
 
293
    if (job["Associations"]["LocalInputFile"]) {
 
294
      LocalInputFiles.clear();
 
295
      for (XMLNode n = job["Associations"]["LocalInputFile"]; n; ++n) {
 
296
        if (n["Source"] && n["CheckSum"]) {
 
297
          LocalInputFiles[(std::string)n["Source"]] = (std::string)n["CheckSum"];
 
298
        }
 
299
      }
 
300
    }
 
301
    else if (job["LocalInputFiles"]["File"]) { // Included for backwards compatibility.
 
302
      LocalInputFiles.clear();
 
303
      for (XMLNode n = job["LocalInputFiles"]["File"]; n; ++n) {
 
304
        if (n["Source"] && n["CheckSum"]) {
 
305
          LocalInputFiles[(std::string)n["Source"]] = (std::string)n["CheckSum"];
 
306
        }
 
307
      }
 
308
    }
 
309
 
 
310
    // Pick generic GLUE2 information
 
311
    Update(job);
 
312
 
 
313
    return *this;
 
314
  }
 
315
 
 
316
  void Job::Update(XMLNode job) {
 
317
 
 
318
    JXMLTOSTRING(Type)
 
319
 
 
320
    // TODO: find out how to treat IDFromEndpoint in case of pure GLUE2
 
321
    
 
322
    JXMLTOSTRING(LocalIDFromManager)
 
323
 
 
324
    /* Earlier the 'JobDescription' element in a XMLNode representing a Job
 
325
     * object contained the actual job description, but in GLUE2 the name
 
326
     * 'JobDescription' specifies the job description language which was used to
 
327
     * describe the job. Due to the name clash we must guess what is meant when
 
328
     * parsing the 'JobDescription' element.
 
329
     */
 
330
 
 
331
    //  TODO: same for JobDescription
 
332
 
 
333
    // Parse libarcclient special state format.
 
334
    if (job["State"]["General"] && job["State"]["Specific"]) {
 
335
      State.state = (std::string)job["State"]["Specific"];
 
336
      State.type = JobState::GetStateType((std::string)job["State"]["General"]);
 
337
    }
 
338
    // Only use the first state. ACC modules should set the state them selves.
 
339
    else if (job["State"] && job["State"].Size() == 0) {
 
340
      State.state = (std::string)job["State"];
 
341
      State.type = JobState::OTHER;
 
342
    }
 
343
    if (job["RestartState"]["General"] && job["RestartState"]["Specific"]) {
 
344
      RestartState.state = (std::string)job["RestartState"]["Specific"];
 
345
      RestartState.type = JobState::GetStateType((std::string)job["RestartState"]["General"]);
 
346
    }
 
347
    // Only use the first state. ACC modules should set the state them selves.
 
348
    else if (job["RestartState"] && job["RestartState"].Size() == 0) {
 
349
      RestartState.state = (std::string)job["RestartState"];
 
350
      RestartState.type = JobState::OTHER;
 
351
    }
 
352
 
 
353
    JXMLSTRINGTO(int, ExitCode)
 
354
    JXMLTOSTRING(ComputingManagerExitCode)
 
355
    JXMLTOSTRINGLIST(Error)
 
356
    JXMLSTRINGTO(int, WaitingPosition)
 
357
    JXMLTOSTRING(UserDomain)
 
358
    JXMLTOSTRING(Owner)
 
359
    JXMLTOSTRING(LocalOwner)
 
360
    JXMLSTRINGTO(long, RequestedTotalWallTime)
 
361
    JXMLSTRINGTO(long, RequestedTotalCPUTime)
 
362
    JXMLSTRINGTO(int, RequestedSlots)
 
363
    JXMLTOSTRINGLIST(RequestedApplicationEnvironment)
 
364
    JXMLTOSTRING(StdIn)
 
365
    JXMLTOSTRING(StdOut)
 
366
    JXMLTOSTRING(StdErr)
 
367
    JXMLTOSTRING(LogDir)
 
368
    JXMLTOSTRINGLIST(ExecutionNode)
 
369
    JXMLTOSTRING(Queue)
 
370
    JXMLSTRINGTO(long, UsedTotalWallTime)
 
371
    JXMLSTRINGTO(long, UsedTotalCPUTime)
 
372
    JXMLSTRINGTO(int, UsedMainMemory)
 
373
    JXMLTOTIME(SubmissionTime)
 
374
    JXMLTOTIME(ComputingManagerSubmissionTime)
 
375
    JXMLTOTIME(StartTime)
 
376
    JXMLTOTIME(ComputingManagerEndTime)
 
377
    JXMLTOTIME(EndTime)
 
378
    JXMLTOTIME(WorkingAreaEraseTime)
 
379
    JXMLTOTIME(ProxyExpirationTime)
 
380
    JXMLTOSTRING(SubmissionHost)
 
381
    JXMLTOSTRING(SubmissionClientName)
 
382
    JXMLTOSTRINGLIST(OtherMessages)
 
383
  }
 
384
 
 
385
  void Job::ToXML(XMLNode node) const {
 
386
    URLTOXML(JobID)
 
387
    STRINGTOXML(Name)
 
388
    URLTOXML(Cluster)
 
389
    STRINGTOXML(InterfaceName)
 
390
    STRINGTOXML(Type)
 
391
    STRINGTOXML(IDFromEndpoint)
 
392
    STRINGTOXML(LocalIDFromManager)
 
393
    STRINGTOXML(JobDescription)
 
394
    STRINGTOXML(JobDescriptionDocument)
 
395
    if (State) {
 
396
      node.NewChild("State");
 
397
      node["State"].NewChild("Specific") = State();
 
398
      node["State"].NewChild("General") = State.GetGeneralState();
 
399
    }
 
400
    if (RestartState) {
 
401
      node.NewChild("RestartState");
 
402
      node["RestartState"].NewChild("Specific") = RestartState();
 
403
      node["RestartState"].NewChild("General") = RestartState.GetGeneralState();
 
404
    }
 
405
    INTTOXML(ExitCode)
 
406
    STRINGTOXML(ComputingManagerExitCode)
 
407
    STRINGLISTTOXML(Error)
 
408
    INTTOXML(WaitingPosition)
 
409
    STRINGTOXML(UserDomain)
 
410
    STRINGTOXML(Owner)
 
411
    STRINGTOXML(LocalOwner)
 
412
    PERIODTOSTRING(RequestedTotalWallTime)
 
413
    PERIODTOSTRING(RequestedTotalCPUTime)
 
414
    INTTOXML(RequestedSlots)
 
415
    STRINGLISTTOXML(RequestedApplicationEnvironment)
 
416
    STRINGTOXML(StdIn)
 
417
    STRINGTOXML(StdOut)
 
418
    STRINGTOXML(StdErr)
 
419
    STRINGTOXML(LogDir)
 
420
    STRINGLISTTOXML(ExecutionNode)
 
421
    STRINGTOXML(Queue)
 
422
    PERIODTOSTRING(UsedTotalWallTime)
 
423
    PERIODTOSTRING(UsedTotalCPUTime)
 
424
    INTTOXML(UsedMainMemory)
 
425
    TIMETOSTRING(LocalSubmissionTime)
 
426
    TIMETOSTRING(SubmissionTime)
 
427
    TIMETOSTRING(ComputingManagerSubmissionTime)
 
428
    TIMETOSTRING(StartTime)
 
429
    TIMETOSTRING(ComputingManagerEndTime)
 
430
    TIMETOSTRING(EndTime)
 
431
    TIMETOSTRING(WorkingAreaEraseTime)
 
432
    TIMETOSTRING(ProxyExpirationTime)
 
433
    STRINGTOXML(SubmissionHost)
 
434
    STRINGTOXML(SubmissionClientName)
 
435
    STRINGLISTTOXML(OtherMessages)
 
436
 
 
437
    if ((ActivityOldID.size() > 0 || LocalInputFiles.size() > 0) && !node["Associations"]) {
 
438
      node.NewChild("Associations");
 
439
    }
 
440
 
 
441
    for (std::list<std::string>::const_iterator it = ActivityOldID.begin();
 
442
         it != ActivityOldID.end(); it++) {
 
443
      node["Associations"].NewChild("ActivityOldID") = *it;
 
444
    }
 
445
 
 
446
    for (std::map<std::string, std::string>::const_iterator it = LocalInputFiles.begin();
 
447
         it != LocalInputFiles.end(); it++) {
 
448
      XMLNode lif = node["Associations"].NewChild("LocalInputFile");
 
449
      lif.NewChild("Source") = it->first;
 
450
      lif.NewChild("CheckSum") = it->second;
 
451
    }
 
452
  }
 
453
 
 
454
  void Job::SaveToStream(std::ostream& out, bool longlist) const {
 
455
    out << IString("Job: %s", JobID.fullstr()) << std::endl;
 
456
    if (!Name.empty())
 
457
      out << IString(" Name: %s", Name) << std::endl;
 
458
    if (!State().empty())
 
459
      out << IString(" State: %s (%s)", State.GetGeneralState(), State())
 
460
                << std::endl;
 
461
    if (State == JobState::QUEUING && WaitingPosition != -1) {
 
462
      out << IString(" Waiting Position: %d", WaitingPosition) << std::endl;
 
463
    }
 
464
 
 
465
    if (ExitCode != -1)
 
466
      out << IString(" Exit Code: %d", ExitCode) << std::endl;
 
467
    if (!Error.empty()) {
 
468
      for (std::list<std::string>::const_iterator it = Error.begin();
 
469
           it != Error.end(); it++)
 
470
        out << IString(" Job Error: %s", *it) << std::endl;
 
471
    }
 
472
 
 
473
    if (longlist) {
 
474
      if (!Owner.empty())
 
475
        out << IString(" Owner: %s", Owner) << std::endl;
 
476
      if (!OtherMessages.empty())
 
477
        for (std::list<std::string>::const_iterator it = OtherMessages.begin();
 
478
             it != OtherMessages.end(); it++)
 
479
          out << IString(" Other Messages: %s", *it)
 
480
                    << std::endl;
 
481
      if (!Queue.empty())
 
482
        out << IString(" Queue: %s", Queue) << std::endl;
 
483
      if (RequestedSlots != -1)
 
484
        out << IString(" Requested Slots: %d", RequestedSlots) << std::endl;
 
485
      if (WaitingPosition != -1)
 
486
        out << IString(" Waiting Position: %d", WaitingPosition)
 
487
                  << std::endl;
 
488
      if (!StdIn.empty())
 
489
        out << IString(" Stdin: %s", StdIn) << std::endl;
 
490
      if (!StdOut.empty())
 
491
        out << IString(" Stdout: %s", StdOut) << std::endl;
 
492
      if (!StdErr.empty())
 
493
        out << IString(" Stderr: %s", StdErr) << std::endl;
 
494
      if (!LogDir.empty())
 
495
        out << IString(" Grid Manager Log Directory: %s", LogDir)
 
496
                  << std::endl;
 
497
      if (SubmissionTime != -1)
 
498
        out << IString(" Submitted: %s",
 
499
                             (std::string)SubmissionTime) << std::endl;
 
500
      if (EndTime != -1)
 
501
        out << IString(" End Time: %s", (std::string)EndTime)
 
502
                  << std::endl;
 
503
      if (!SubmissionHost.empty())
 
504
        out << IString(" Submitted from: %s", SubmissionHost)
 
505
                  << std::endl;
 
506
      if (!SubmissionClientName.empty())
 
507
        out << IString(" Submitting client: %s",
 
508
                             SubmissionClientName) << std::endl;
 
509
      if (RequestedTotalCPUTime != -1)
 
510
        out << IString(" Requested CPU Time: %s",
 
511
                             RequestedTotalCPUTime.istr())
 
512
                  << std::endl;
 
513
      if (UsedTotalCPUTime != -1)
 
514
        out << IString(" Used CPU Time: %s",
 
515
                             UsedTotalCPUTime.istr()) << std::endl;
 
516
      if (UsedTotalWallTime != -1)
 
517
        out << IString(" Used Wall Time: %s",
 
518
                             UsedTotalWallTime.istr()) << std::endl;
 
519
      if (UsedMainMemory != -1)
 
520
        out << IString(" Used Memory: %d", UsedMainMemory)
 
521
                  << std::endl;
 
522
      if (WorkingAreaEraseTime != -1)
 
523
        out << IString((State == JobState::DELETED) ?
 
524
                             istring(" Results were deleted: %s") :
 
525
                             istring(" Results must be retrieved before: %s"),
 
526
                             (std::string)WorkingAreaEraseTime)
 
527
                  << std::endl;
 
528
      if (ProxyExpirationTime != -1)
 
529
        out << IString(" Proxy valid until: %s",
 
530
                             (std::string)ProxyExpirationTime)
 
531
                  << std::endl;
 
532
      if (CreationTime != -1)
 
533
        out << IString(" Entry valid from: %s",
 
534
                             (std::string)CreationTime) << std::endl;
 
535
      if (Validity != -1)
 
536
        out << IString(" Entry valid for: %s",
 
537
                             Validity.istr()) << std::endl;
 
538
 
 
539
      if (!ActivityOldID.empty()) {
 
540
        out << IString(" Old job IDs:") << std::endl;
 
541
        for (std::list<std::string>::const_iterator it = ActivityOldID.begin();
 
542
             it != ActivityOldID.end(); ++it) {
 
543
          out << "  " << *it << std::endl;
 
544
        }
 
545
      }
 
546
 
 
547
      out << IString(" Cluster: %s", Cluster.fullstr()) << std::endl;
 
548
      out << IString(" Management Interface: %s", InterfaceName) << std::endl;
 
549
    }
 
550
 
 
551
    out << std::endl;
 
552
  } // end Print
 
553
 
 
554
  bool Job::GetURLToResource(ResourceType resource, URL& url) const { return jc ? jc->GetURLToJobResource(*this, resource, url) : false; }
 
555
 
 
556
  bool Job::Retrieve(const UserConfig& uc, const URL& destination, bool force) const {
 
557
    if (!destination) {
 
558
      logger.msg(ERROR, "Invalid download destination path specified (%s)", destination.fullstr());
 
559
      return false;
 
560
    }
 
561
    
 
562
    if (jc == NULL) {
 
563
      logger.msg(DEBUG, "Unable to download job (%s), no JobControllerPlugin plugin was set to handle the job.", JobID.str());
 
564
      return false;
 
565
    }
 
566
 
 
567
    logger.msg(VERBOSE, "Downloading job: %s", JobID.str());
 
568
    
 
569
    URL src, dst(destination);
 
570
    if (!jc->GetURLToJobResource(*this, STAGEOUTDIR, src)) {
 
571
      logger.msg(ERROR, "Cant retrieve job files for job (%s) - unable to determine URL of stage out directory", JobID.fullstr());
 
572
      return false;
 
573
    }
 
574
 
 
575
    if (!src) {
 
576
      logger.msg(ERROR, "Invalid stage out path specified (%s)", src.fullstr());
 
577
      return false;
 
578
    }
 
579
 
 
580
    if (!force && Glib::file_test(dst.Path(), Glib::FILE_TEST_EXISTS)) {
 
581
      logger.msg(WARNING, "%s directory exist! Skipping job.", dst.Path());
 
582
      return false;
 
583
    }
 
584
 
 
585
    std::list<std::string> files;
 
586
    if (!ListFilesRecursive(uc, src, files)) {
 
587
      logger.msg(ERROR, "Unable to retrieve list of job files to download for job %s", JobID.fullstr());
 
588
      return false;
 
589
    }
 
590
 
 
591
    const std::string srcpath = src.Path() + (src.Path().empty() || *src.Path().rbegin() != '/' ? "/" : "");
 
592
    const std::string dstpath = dst.Path() + (dst.Path().empty() || *dst.Path().rbegin() != G_DIR_SEPARATOR ? G_DIR_SEPARATOR_S : "");
 
593
 
 
594
    bool ok = true;
 
595
    for (std::list<std::string>::const_iterator it = files.begin(); it != files.end(); ++it) {
 
596
      src.ChangePath(srcpath + *it);
 
597
      dst.ChangePath(dstpath + *it);
 
598
      if (!CopyJobFile(uc, src, dst)) {
 
599
        logger.msg(INFO, "Failed downloading %s to %s", src.str(), dst.str());
 
600
        ok = false;
 
601
      }
 
602
    }
 
603
 
 
604
    return ok;
 
605
  }
 
606
 
 
607
  bool Job::ListFilesRecursive(const UserConfig& uc, const URL& dir, std::list<std::string>& files, const std::string& prefix) {
 
608
    std::list<FileInfo> outputfiles;
 
609
 
 
610
    DataHandle handle(dir, uc);
 
611
    if (!handle) {
 
612
      logger.msg(INFO, "Unable to list files at %s", dir.str());
 
613
      return false;
 
614
    }
 
615
    if(!handle->List(outputfiles, (Arc::DataPoint::DataPointInfoType)
 
616
                                  (DataPoint::INFO_TYPE_NAME | DataPoint::INFO_TYPE_TYPE))) {
 
617
      logger.msg(INFO, "Unable to list files at %s", dir.str());
 
618
      return false;
 
619
    }
 
620
 
 
621
    for (std::list<FileInfo>::iterator i = outputfiles.begin();
 
622
         i != outputfiles.end(); i++) {
 
623
      if (i->GetName() == ".." || i->GetName() == ".") {
 
624
        continue;
 
625
      }
 
626
 
 
627
      if (i->GetType() == FileInfo::file_type_unknown ||
 
628
          i->GetType() == FileInfo::file_type_file) {
 
629
        files.push_back(prefix + i->GetName());
 
630
      }
 
631
      else if (i->GetType() == FileInfo::file_type_dir) {
 
632
        std::string path = dir.Path();
 
633
        if (path[path.size() - 1] != '/') {
 
634
          path += "/";
 
635
        }
 
636
        URL tmpdir(dir);
 
637
        tmpdir.ChangePath(path + i->GetName());
 
638
 
 
639
        std::string dirname = i->GetName();
 
640
        if (dirname[dirname.size() - 1] != '/') {
 
641
          dirname += "/";
 
642
        }
 
643
        if (!ListFilesRecursive(uc, tmpdir, files, dirname)) {
 
644
          return false;
 
645
        }
 
646
      }
 
647
    }
 
648
 
 
649
    return true;
 
650
  }
 
651
 
 
652
  bool Job::CopyJobFile(const UserConfig& uc, const URL& src, const URL& dst) {
 
653
    DataMover mover;
 
654
    mover.retry(true);
 
655
    mover.secure(false);
 
656
    mover.passive(true);
 
657
    mover.verbose(false);
 
658
 
 
659
    logger.msg(VERBOSE, "Now copying (from -> to)");
 
660
    logger.msg(VERBOSE, " %s -> %s", src.str(), dst.str());
 
661
 
 
662
    URL src_(src);
 
663
    URL dst_(dst);
 
664
    src_.AddOption("checksum=no");
 
665
    dst_.AddOption("checksum=no");
 
666
 
 
667
    if ((!data_source) || (!*data_source) ||
 
668
        (!(*data_source)->SetURL(src_))) {
 
669
      if(data_source) delete data_source;
 
670
      data_source = new DataHandle(src_, uc);
 
671
    }
 
672
    DataHandle& source = *data_source;
 
673
    if (!source) {
 
674
      logger.msg(ERROR, "Unable to initialise connection to source: %s", src.str());
 
675
      return false;
 
676
    }
 
677
 
 
678
    if ((!data_destination) || (!*data_destination) ||
 
679
        (!(*data_destination)->SetURL(dst_))) {
 
680
      if(data_destination) delete data_destination;
 
681
      data_destination = new DataHandle(dst_, uc);
 
682
    }
 
683
    DataHandle& destination = *data_destination;
 
684
    if (!destination) {
 
685
      logger.msg(ERROR, "Unable to initialise connection to destination: %s",
 
686
                 dst.str());
 
687
      return false;
 
688
    }
 
689
 
 
690
    // Set desired number of retries. Also resets any lost
 
691
    // tries from previous files.
 
692
    source->SetTries((src.Protocol() == "file")?1:3);
 
693
    destination->SetTries((dst.Protocol() == "file")?1:3);
 
694
 
 
695
    // Turn off all features we do not need
 
696
    source->SetAdditionalChecks(false);
 
697
    destination->SetAdditionalChecks(false);
 
698
 
 
699
    FileCache cache;
 
700
    DataStatus res =
 
701
      mover.Transfer(*source, *destination, cache, URLMap(), 0, 0, 0,
 
702
                     uc.Timeout());
 
703
    if (!res.Passed()) {
 
704
      if (!res.GetDesc().empty())
 
705
        logger.msg(ERROR, "File download failed: %s - %s", std::string(res), res.GetDesc());
 
706
      else
 
707
        logger.msg(ERROR, "File download failed: %s", std::string(res));
 
708
      // Reset connection because one can't be sure how failure
 
709
      // affects server and/or connection state.
 
710
      // TODO: Investigate/define DMC behavior in such case.
 
711
      delete data_source;
 
712
      data_source = NULL;
 
713
      delete data_destination;
 
714
      data_destination = NULL;
 
715
      return false;
 
716
    }
 
717
 
 
718
    return true;
 
719
  }
 
720
 
 
721
  bool Job::ReadAllJobsFromFile(const std::string& filename, std::list<Job>& jobs, unsigned nTries, unsigned tryInterval) {
 
722
    jobs.clear();
 
723
    Config jobstorage;
 
724
 
 
725
    FileLock lock(filename);
 
726
    bool acquired = false;
 
727
    for (int tries = (int)nTries; tries > 0; --tries) {
 
728
      acquired = lock.acquire();
 
729
      if (acquired) {
 
730
        if (!jobstorage.ReadFromFile(filename)) {
 
731
          lock.release();
 
732
          return false;
 
733
        }
 
734
        lock.release();
 
735
        break;
 
736
      }
 
737
 
 
738
      if (tries == 6) {
 
739
        logger.msg(VERBOSE, "Waiting for lock on job list file %s", filename);
 
740
      }
 
741
 
 
742
      Glib::usleep(tryInterval);
 
743
    }
 
744
 
 
745
    if (!acquired) {
 
746
      return false;
 
747
    }
 
748
 
 
749
    XMLNodeList xmljobs = jobstorage.Path("Job");
 
750
    for (XMLNodeList::iterator xit = xmljobs.begin(); xit != xmljobs.end(); ++xit) {
 
751
      jobs.push_back(*xit);
 
752
    }
 
753
 
 
754
    return true;
 
755
  }
 
756
 
 
757
  bool Job::ReadJobsFromFile(const std::string& filename, std::list<Job>& jobs, std::list<std::string>& jobIdentifiers, bool all, const std::list<std::string>& endpoints, const std::list<std::string>& rEndpoints, unsigned nTries, unsigned tryInterval) {
 
758
    if (!ReadAllJobsFromFile(filename, jobs, nTries, tryInterval)) { return false; }
 
759
 
 
760
    std::list<std::string> jobIdentifiersCopy = jobIdentifiers;
 
761
    for (std::list<Arc::Job>::iterator itJ = jobs.begin();
 
762
         itJ != jobs.end();) {
 
763
      // Check if the job (itJ) is selected by the job identifies, either by job ID or Name.
 
764
      std::list<std::string>::iterator itJIdentifier = jobIdentifiers.begin();
 
765
      for (;itJIdentifier != jobIdentifiers.end(); ++itJIdentifier) {
 
766
        if ((!itJ->Name.empty() && itJ->Name == *itJIdentifier) ||
 
767
            (itJ->JobID.fullstr() == URL(*itJIdentifier).fullstr())) {
 
768
          break;
 
769
        }
 
770
      }
 
771
      if (itJIdentifier != jobIdentifiers.end()) {
 
772
        // Job explicitly specified. Remove id from the copy list, in order to keep track of used identifiers.
 
773
        std::list<std::string>::iterator itJIdentifierCopy = std::find(jobIdentifiersCopy.begin(), jobIdentifiersCopy.end(), *itJIdentifier);
 
774
        if (itJIdentifierCopy != jobIdentifiersCopy.end()) {
 
775
          jobIdentifiersCopy.erase(itJIdentifierCopy);
 
776
        }
 
777
        ++itJ;
 
778
        continue;
 
779
      }
 
780
 
 
781
      if (!all) {
 
782
        // Check if the job (itJ) is selected by endpoints.
 
783
        std::list<std::string>::const_iterator itC = endpoints.begin();
 
784
        for (; itC != endpoints.end(); ++itC) {
 
785
          if (itJ->Cluster.StringMatches(*itC)) {
 
786
            break;
 
787
          }
 
788
        }
 
789
        if (itC != endpoints.end()) {
 
790
          // Cluster on which job reside is explicitly specified.
 
791
          ++itJ;
 
792
          continue;
 
793
        }
 
794
 
 
795
        // Job is not selected - remove it.
 
796
        itJ = jobs.erase(itJ);
 
797
      }
 
798
      else {
 
799
        ++itJ;
 
800
      }
 
801
    }
 
802
 
 
803
    // Filter jobs on rejected clusters.
 
804
    for (std::list<std::string>::const_iterator itC = rEndpoints.begin();
 
805
         itC != rEndpoints.end(); ++itC) {
 
806
      for (std::list<Arc::Job>::iterator itJ = jobs.begin(); itJ != jobs.end();) {
 
807
        if (itJ->Cluster.StringMatches(*itC)) {
 
808
          itJ = jobs.erase(itJ);
 
809
        }
 
810
        else {
 
811
          ++itJ;
 
812
        }
 
813
      }
 
814
    }
 
815
 
 
816
    jobIdentifiers = jobIdentifiersCopy;
 
817
 
 
818
    return true;
 
819
  }
 
820
 
 
821
  bool Job::WriteJobsToTruncatedFile(const std::string& filename, const std::list<Job>& jobs, unsigned nTries, unsigned tryInterval) {
 
822
    Config jobfile;
 
823
    std::map<std::string, XMLNode> jobIDXMLMap;
 
824
    for (std::list<Job>::const_iterator it = jobs.begin();
 
825
         it != jobs.end(); it++) {
 
826
      std::map<std::string, XMLNode>::iterator itJobXML = jobIDXMLMap.find(it->JobID.fullstr());
 
827
      if (itJobXML == jobIDXMLMap.end()) {
 
828
        XMLNode xJob = jobfile.NewChild("Job");
 
829
        it->ToXML(xJob);
 
830
        jobIDXMLMap[it->JobID.fullstr()] = xJob;
 
831
      }
 
832
      else {
 
833
        itJobXML->second.Replace(XMLNode(NS(), "Job"));
 
834
        it->ToXML(itJobXML->second);
 
835
      }
 
836
    }
 
837
 
 
838
    FileLock lock(filename);
 
839
    for (int tries = (int)nTries; tries > 0; --tries) {
 
840
      if (lock.acquire()) {
 
841
        if (!jobfile.SaveToFile(filename)) {
 
842
          lock.release();
 
843
          return false;
 
844
        }
 
845
        lock.release();
 
846
        return true;
 
847
      }
 
848
 
 
849
      if (tries == 6) {
 
850
        logger.msg(WARNING, "Waiting for lock on job list file %s", filename);
 
851
      }
 
852
 
 
853
      Glib::usleep(tryInterval);
 
854
    }
 
855
 
 
856
    return false;
 
857
  }
 
858
 
 
859
  bool Job::WriteJobsToFile(const std::string& filename, const std::list<Job>& jobs, unsigned nTries, unsigned tryInterval) {
 
860
    std::list<const Job*> newJobs;
 
861
    return WriteJobsToFile(filename, jobs, newJobs, nTries, tryInterval);
 
862
  }
 
863
 
 
864
  bool Job::WriteJobsToFile(const std::string& filename, const std::list<Job>& jobs, std::list<const Job*>& newJobs, unsigned nTries, unsigned tryInterval) {
 
865
    FileLock lock(filename);
 
866
    for (int tries = (int)nTries; tries > 0; --tries) {
 
867
      if (lock.acquire()) {
 
868
        Config jobfile;
 
869
        jobfile.ReadFromFile(filename);
 
870
 
 
871
        // Use std::map to store job IDs to be searched for duplicates.
 
872
        std::map<std::string, XMLNode> jobIDXMLMap;
 
873
        for (Arc::XMLNode j = jobfile["Job"]; j; ++j) {
 
874
          if (!((std::string)j["JobID"]).empty()) {
 
875
            jobIDXMLMap[(std::string)j["JobID"]] = j;
 
876
          }
 
877
        }
 
878
 
 
879
        std::map<std::string, const Job*> newJobsMap;
 
880
        for (std::list<Job>::const_iterator it = jobs.begin(); it != jobs.end(); ++it) {
 
881
          std::map<std::string, XMLNode>::iterator itJobXML = jobIDXMLMap.find(it->JobID.fullstr());
 
882
          if (itJobXML == jobIDXMLMap.end()) {
 
883
            XMLNode xJob = jobfile.NewChild("Job");
 
884
            it->ToXML(xJob);
 
885
            jobIDXMLMap[it->JobID.fullstr()] = xJob;
 
886
            newJobsMap[it->JobID.fullstr()] = &(*it);
 
887
          }
 
888
          else {
 
889
            // Duplicate found, replace it.
 
890
            itJobXML->second.Replace(XMLNode(NS(), "Job"));
 
891
            it->ToXML(itJobXML->second);
 
892
 
 
893
            // Only add to newJobsMap if this is a new job, i.e. not previous present in jobfile.
 
894
            std::map<std::string, const Job*>::iterator itNewJobsMap = newJobsMap.find(it->JobID.fullstr());
 
895
            if (itNewJobsMap != newJobsMap.end()) {
 
896
              itNewJobsMap->second = &(*it);
 
897
            }
 
898
          }
 
899
        }
 
900
 
 
901
        // Add pointers to new Job objects to the newJobs list.
 
902
        for (std::map<std::string, const Job*>::const_iterator it = newJobsMap.begin();
 
903
             it != newJobsMap.end(); ++it) {
 
904
          newJobs.push_back(it->second);
 
905
        }
 
906
 
 
907
        if (!jobfile.SaveToFile(filename)) {
 
908
          lock.release();
 
909
          return false;
 
910
        }
 
911
        lock.release();
 
912
        return true;
 
913
      }
 
914
 
 
915
      if (tries == 6) {
 
916
        logger.msg(WARNING, "Waiting for lock on job list file %s", filename);
 
917
      }
 
918
 
 
919
      Glib::usleep(tryInterval);
 
920
    }
 
921
 
 
922
    return false;
 
923
  }
 
924
 
 
925
  bool Job::RemoveJobsFromFile(const std::string& filename, const std::list<URL>& jobids, unsigned nTries, unsigned tryInterval) {
 
926
    if (jobids.empty()) {
 
927
      return true;
 
928
    }
 
929
 
 
930
    FileLock lock(filename);
 
931
    for (int tries = nTries; tries > 0; --tries) {
 
932
      if (lock.acquire()) {
 
933
        Config jobstorage;
 
934
        if (!jobstorage.ReadFromFile(filename)) {
 
935
          lock.release();
 
936
          return false;
 
937
        }
 
938
 
 
939
        XMLNodeList xmlJobs = jobstorage.Path("Job");
 
940
        for (std::list<URL>::const_iterator it = jobids.begin(); it != jobids.end(); ++it) {
 
941
          for (XMLNodeList::iterator xJIt = xmlJobs.begin(); xJIt != xmlJobs.end(); ++xJIt) {
 
942
            if ((*xJIt)["JobID"] == it->fullstr() ||
 
943
                (*xJIt)["IDFromEndpoint"] == it->fullstr() // Included for backwards compatibility.
 
944
                ) {
 
945
              xJIt->Destroy(); // Do not break, since for some reason there might be multiple identical jobs in the file.
 
946
            }
 
947
          }
 
948
        }
 
949
 
 
950
        if (!jobstorage.SaveToFile(filename)) {
 
951
          lock.release();
 
952
          return false;
 
953
        }
 
954
        lock.release();
 
955
        return true;
 
956
      }
 
957
 
 
958
      if (tries == 6) {
 
959
        logger.msg(VERBOSE, "Waiting for lock on job list file %s", filename);
 
960
      }
 
961
      Glib::usleep(tryInterval);
 
962
    }
 
963
 
 
964
    return false;
 
965
  }
 
966
 
 
967
  bool Job::ReadJobIDsFromFile(const std::string& filename, std::list<std::string>& jobids, unsigned nTries, unsigned tryInterval) {
 
968
    if (!Glib::file_test(filename, Glib::FILE_TEST_IS_REGULAR)) return false;
 
969
 
 
970
    FileLock lock(filename);
 
971
    for (int tries = (int)nTries; tries > 0; --tries) {
 
972
      if (lock.acquire()) {
 
973
        std::ifstream is(filename.c_str());
 
974
        if (!is.good()) {
 
975
          is.close();
 
976
          lock.release();
 
977
          return false;
 
978
        }
 
979
        std::string line;
 
980
        while (std::getline(is, line)) {
 
981
          line = Arc::trim(line, " \t");
 
982
          if (!line.empty() && line[0] != '#') {
 
983
            jobids.push_back(line);
 
984
          }
 
985
        }
 
986
        is.close();
 
987
        lock.release();
 
988
        return true;
 
989
      }
 
990
 
 
991
      if (tries == 6) {
 
992
        logger.msg(WARNING, "Waiting for lock on file %s", filename);
 
993
      }
 
994
 
 
995
      Glib::usleep(tryInterval);
 
996
    }
 
997
 
 
998
    return false;
 
999
  }
 
1000
 
 
1001
  bool Job::WriteJobIDToFile(const URL& jobid, const std::string& filename, unsigned nTries, unsigned tryInterval) {
 
1002
    if (Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) return false;
 
1003
 
 
1004
    FileLock lock(filename);
 
1005
    for (int tries = (int)nTries; tries > 0; --tries) {
 
1006
      if (lock.acquire()) {
 
1007
        std::ofstream os(filename.c_str(), std::ios::app);
 
1008
        if (!os.good()) {
 
1009
          os.close();
 
1010
          lock.release();
 
1011
          return false;
 
1012
        }
 
1013
        os << jobid.fullstr() << std::endl;
 
1014
        bool good = os.good();
 
1015
        os.close();
 
1016
        lock.release();
 
1017
        return good;
 
1018
      }
 
1019
 
 
1020
      if (tries == 6) {
 
1021
        logger.msg(WARNING, "Waiting for lock on file %s", filename);
 
1022
      }
 
1023
 
 
1024
      Glib::usleep(tryInterval);
 
1025
    }
 
1026
 
 
1027
    return false;
 
1028
  }
 
1029
 
 
1030
  bool Job::WriteJobIDsToFile(const std::list<URL>& jobids, const std::string& filename, unsigned nTries, unsigned tryInterval) {
 
1031
    if (Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) return false;
 
1032
    FileLock lock(filename);
 
1033
    for (int tries = (int)nTries; tries > 0; --tries) {
 
1034
      if (lock.acquire()) {
 
1035
        std::ofstream os(filename.c_str(), std::ios::app);
 
1036
        if (!os.good()) {
 
1037
          os.close();
 
1038
          lock.release();
 
1039
          return false;
 
1040
        }
 
1041
        for (std::list<URL>::const_iterator it = jobids.begin();
 
1042
             it != jobids.end(); ++it) {
 
1043
          os << it->fullstr() << std::endl;
 
1044
        }
 
1045
 
 
1046
        bool good = os.good();
 
1047
        os.close();
 
1048
        lock.release();
 
1049
        return good;
 
1050
      }
 
1051
 
 
1052
      if (tries == 6) {
 
1053
        logger.msg(WARNING, "Waiting for lock on file %s", filename);
 
1054
      }
 
1055
 
 
1056
      Glib::usleep(tryInterval);
 
1057
    }
 
1058
 
 
1059
    return false;
 
1060
  }
 
1061
 
 
1062
  bool Job::WriteJobIDsToFile(const std::list<Job>& jobs, const std::string& filename, unsigned nTries, unsigned tryInterval) {
 
1063
    if (Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) return false;
 
1064
 
 
1065
    FileLock lock(filename);
 
1066
    for (int tries = (int)nTries; tries > 0; --tries) {
 
1067
      if (lock.acquire()) {
 
1068
        std::ofstream os(filename.c_str(), std::ios::app);
 
1069
        if (!os.good()) {
 
1070
          os.close();
 
1071
          lock.release();
 
1072
          return false;
 
1073
        }
 
1074
        for (std::list<Job>::const_iterator it = jobs.begin();
 
1075
             it != jobs.end(); ++it) {
 
1076
          os << it->JobID.fullstr() << std::endl;
 
1077
        }
 
1078
 
 
1079
        bool good = os.good();
 
1080
        os.close();
 
1081
        lock.release();
 
1082
        return good;
 
1083
      }
 
1084
 
 
1085
      if (tries == 6) {
 
1086
        logger.msg(WARNING, "Waiting for lock on file %s", filename);
 
1087
      }
 
1088
 
 
1089
      Glib::usleep(tryInterval);
 
1090
    }
 
1091
 
 
1092
    return false;
 
1093
  }
 
1094
 
 
1095
} // namespace Arc