changeset 2648:e1893d31652a jobs

serialization of JobHandler
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 31 May 2018 18:44:05 +0200
parents 73d7d95dd75e
children 193ef9c1b731
files Core/JobsEngine/GenericJobUnserializer.cpp Core/JobsEngine/GenericJobUnserializer.h Core/JobsEngine/IJob.h Core/JobsEngine/IJobUnserializer.cpp Core/JobsEngine/IJobUnserializer.h Core/JobsEngine/JobStatus.cpp Core/JobsEngine/JobStatus.h Core/JobsEngine/JobsRegistry.cpp Core/JobsEngine/JobsRegistry.h Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp Core/JobsEngine/Operations/SequenceOfOperationsJob.h Core/JobsEngine/SetOfInstancesJob.cpp Core/JobsEngine/SetOfInstancesJob.h OrthancServer/ServerJobs/ArchiveJob.cpp OrthancServer/ServerJobs/ArchiveJob.h OrthancServer/ServerJobs/OrthancJobUnserializer.cpp OrthancServer/ServerJobs/OrthancJobUnserializer.h OrthancServer/ServerJobs/ResourceModificationJob.cpp OrthancServer/ServerJobs/ResourceModificationJob.h UnitTestsSources/MultiThreadingTests.cpp
diffstat 20 files changed, 134 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/Core/JobsEngine/GenericJobUnserializer.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/GenericJobUnserializer.cpp	Thu May 31 18:44:05 2018 +0200
@@ -43,10 +43,9 @@
 
 namespace Orthanc
 {
-  IJob* GenericJobUnserializer::UnserializeJob(const Json::Value& source)
+  IJob* GenericJobUnserializer::UnserializeJob(const std::string& type,
+                                               const Json::Value& source)
   {
-    const std::string type = GetString(source, "Type");
-    JobState state = StringToJobState(GetString(source, "State"));
 
     LOG(ERROR) << "Cannot unserialize job of type: " << type;
     throw OrthancException(ErrorCode_BadFileFormat);
--- a/Core/JobsEngine/GenericJobUnserializer.h	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/GenericJobUnserializer.h	Thu May 31 18:44:05 2018 +0200
@@ -40,10 +40,11 @@
   class GenericJobUnserializer : public IJobUnserializer
   {
   public:
-    virtual IJob* UnserializeJob(const Json::Value& source);
+    virtual IJob* UnserializeJob(const std::string& type,
+                                 const Json::Value& value);
 
-    virtual IJobOperation* UnserializeOperation(const Json::Value& source);
+    virtual IJobOperation* UnserializeOperation(const Json::Value& value);
 
-    virtual JobOperationValue* UnserializeValue(const Json::Value& source);
+    virtual JobOperationValue* UnserializeValue(const Json::Value& value);
   };
 }
--- a/Core/JobsEngine/IJob.h	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/IJob.h	Thu May 31 18:44:05 2018 +0200
@@ -63,6 +63,6 @@
     
     virtual void GetPublicContent(Json::Value& value) = 0;
 
-    virtual void GetInternalContent(Json::Value& value) = 0;
+    virtual void Serialize(Json::Value& value) = 0;
   };
 }
--- a/Core/JobsEngine/IJobUnserializer.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/IJobUnserializer.cpp	Thu May 31 18:44:05 2018 +0200
@@ -38,58 +38,43 @@
 
 namespace Orthanc
 {
-  void IJobUnserializer::CheckType(const Json::Value& source,
-                                   const std::string& expectedType)
-  {
-    static const char* TYPE = "Type";
-
-    if (source.type() != Json::objectValue ||
-        !source.isMember(TYPE) ||
-        source[TYPE].type() != Json::stringValue ||
-        source[TYPE].asString() != expectedType)
-    {
-      throw OrthancException(ErrorCode_BadFileFormat);
-    }
-  }
-
-
-  std::string IJobUnserializer::GetString(const Json::Value& source,
+  std::string IJobUnserializer::GetString(const Json::Value& value,
                                           const std::string& name)
   {
-    if (source.type() != Json::objectValue ||
-        !source.isMember(name.c_str()) ||
-        source[name.c_str()].type() != Json::stringValue)
+    if (value.type() != Json::objectValue ||
+        !value.isMember(name.c_str()) ||
+        value[name.c_str()].type() != Json::stringValue)
     {
       throw OrthancException(ErrorCode_BadFileFormat);
     }
     else
     {
-      return source[name.c_str()].asString();
+      return value[name.c_str()].asString();
     }
   }
 
 
-  int IJobUnserializer::GetInteger(const Json::Value& source,
+  int IJobUnserializer::GetInteger(const Json::Value& value,
                                    const std::string& name)
   {
-    if (source.type() != Json::objectValue ||
-        !source.isMember(name.c_str()) ||
-        (source[name.c_str()].type() != Json::intValue &&
-         source[name.c_str()].type() != Json::uintValue))
+    if (value.type() != Json::objectValue ||
+        !value.isMember(name.c_str()) ||
+        (value[name.c_str()].type() != Json::intValue &&
+         value[name.c_str()].type() != Json::uintValue))
     {
       throw OrthancException(ErrorCode_BadFileFormat);
     }
     else
     {
-      return source[name.c_str()].asInt();
+      return value[name.c_str()].asInt();
     }    
   }
 
 
-  unsigned int IJobUnserializer::GetUnsignedInteger(const Json::Value& source,
+  unsigned int IJobUnserializer::GetUnsignedInteger(const Json::Value& value,
                                                     const std::string& name)
   {
-    int tmp = GetInteger(source, name);
+    int tmp = GetInteger(value, name);
 
     if (tmp < 0)
     {
--- a/Core/JobsEngine/IJobUnserializer.h	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/IJobUnserializer.h	Thu May 31 18:44:05 2018 +0200
@@ -46,22 +46,20 @@
     {
     }
 
-    virtual IJob* UnserializeJob(const Json::Value& source) = 0;
-
-    virtual IJobOperation* UnserializeOperation(const Json::Value& source) = 0;
+    virtual IJob* UnserializeJob(const std::string& jobType,
+                                 const Json::Value& value) = 0;
 
-    virtual JobOperationValue* UnserializeValue(const Json::Value& source) = 0;
+    virtual IJobOperation* UnserializeOperation(const Json::Value& value) = 0;
 
-    static void CheckType(const Json::Value& source,
-                          const std::string& expectedType);
+    virtual JobOperationValue* UnserializeValue(const Json::Value& value) = 0;
 
-    static std::string GetString(const Json::Value& source,
+    static std::string GetString(const Json::Value& value,
                                  const std::string& name);
 
-    static int GetInteger(const Json::Value& source,
+    static int GetInteger(const Json::Value& value,
                           const std::string& name);
 
-    static unsigned int GetUnsignedInteger(const Json::Value& source,
+    static unsigned int GetUnsignedInteger(const Json::Value& value,
                                            const std::string& name);
   };
 }
--- a/Core/JobsEngine/JobStatus.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/JobStatus.cpp	Thu May 31 18:44:05 2018 +0200
@@ -40,7 +40,8 @@
     errorCode_(ErrorCode_InternalError),
     progress_(0),
     jobType_("Invalid"),
-    publicContent_(Json::objectValue)
+    publicContent_(Json::objectValue),
+    serialized_(Json::objectValue)
   {
   }
 
@@ -63,5 +64,6 @@
 
     job.GetJobType(jobType_);
     job.GetPublicContent(publicContent_);
+    job.Serialize(serialized_);
   }
 }
--- a/Core/JobsEngine/JobStatus.h	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/JobStatus.h	Thu May 31 18:44:05 2018 +0200
@@ -44,6 +44,7 @@
     float          progress_;
     std::string    jobType_;
     Json::Value    publicContent_;
+    Json::Value    serialized_;
 
   public:
     JobStatus();
@@ -75,5 +76,10 @@
     {
       return publicContent_;
     }
+
+    const Json::Value& GetSerialized() const
+    {
+      return serialized_;
+    }
   };
 }
--- a/Core/JobsEngine/JobsRegistry.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/JobsRegistry.cpp	Thu May 31 18:44:05 2018 +0200
@@ -45,6 +45,7 @@
   private:
     std::string                       id_;
     JobState                          state_;
+    std::string                       jobType_;
     std::auto_ptr<IJob>               job_;
     int                               priority_;  // "+inf()" means highest priority
     boost::posix_time::ptime          creationTime_;
@@ -94,9 +95,10 @@
         throw OrthancException(ErrorCode_NullPointer);
       }
 
+      job->GetJobType(jobType_);
       job->Start();
 
-      lastStatus_ = JobStatus(ErrorCode_Success, *job);
+      lastStatus_ = JobStatus(ErrorCode_Success, *job_);
     }
 
     const std::string& GetId() const
@@ -231,6 +233,65 @@
     {
       lastStatus_.SetErrorCode(code);
     }
+
+    void Serialize(Json::Value& target) const
+    {
+      target["State"] = EnumerationToString(state_);
+      target["JobType"] = jobType_;
+      target["Priority"] = priority_;
+      target["CreationTime"] = boost::posix_time::to_iso_string(creationTime_);
+      target["Runtime"] = static_cast<unsigned int>(runtime_.total_milliseconds());
+
+      if (state_ == JobState_Running)
+      {
+        // WARNING: Cannot directly access the "job_" member, as long
+        // as a "RunningJob" instance is running. We do not use a
+        // mutex at the "JobHandler" level, as serialization would be
+        // blocked while a step in the job is running. Instead, we
+        // save a snapshot of the serialized job.
+        target["Job"] = lastStatus_.GetSerialized();
+      }
+      else
+      {
+        job_->Serialize(target["Job"]);
+      }
+    }
+
+    JobHandler(IJobUnserializer& unserializer,
+               const std::string& id,
+               const Json::Value& serialized) :
+      id_(id),
+      lastStateChangeTime_(boost::posix_time::microsec_clock::universal_time()),
+      pauseScheduled_(false),
+      cancelScheduled_(false)
+    {
+      state_ = StringToJobState(IJobUnserializer::GetString(serialized, "State"));
+      jobType_ = IJobUnserializer::GetString(serialized, "Type");
+      priority_ = IJobUnserializer::GetInteger(serialized, "Priority");
+      creationTime_ = boost::posix_time::from_iso_string
+        (IJobUnserializer::GetString(serialized, "CreationTime"));
+      runtime_ = boost::posix_time::milliseconds(IJobUnserializer::GetInteger(serialized, "Runtime"));
+
+      retryTime_ = creationTime_;
+
+      if (state_ == JobState_Retry ||
+          state_ == JobState_Running) 
+      {
+        state_ = JobState_Pending;
+      }
+
+      job_.reset(unserializer.UnserializeJob(jobType_, serialized["Job"]));
+
+      std::string s;
+      job_->GetJobType(s);
+      if (s != jobType_)
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+
+      job_->Start();
+      lastStatus_ = JobStatus(ErrorCode_Success, *job_);
+    }
   };
 
 
@@ -501,6 +562,22 @@
   }
 
 
+  void JobsRegistry::Serialize(Json::Value& target)
+  {
+    boost::mutex::scoped_lock lock(mutex_);
+    CheckInvariants();
+
+    target = Json::objectValue;
+
+    for (JobsIndex::const_iterator it = jobsIndex_.begin(); 
+         it != jobsIndex_.end(); ++it)
+    {
+      Json::Value& v = target[it->first];
+      it->second->Serialize(v);
+    }
+  }
+
+
   void JobsRegistry::Submit(std::string& id,
                             IJob* job,        // Takes ownership
                             int priority)
--- a/Core/JobsEngine/JobsRegistry.h	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/JobsRegistry.h	Thu May 31 18:44:05 2018 +0200
@@ -42,6 +42,7 @@
 #endif
 
 #include "JobInfo.h"
+#include "IJobUnserializer.h"
 
 #include <list>
 #include <set>
@@ -126,6 +127,8 @@
 
     bool GetJobInfo(JobInfo& target,
                     const std::string& id);
+
+    void Serialize(Json::Value& target);
     
     void Submit(std::string& id,
                 IJob* job,        // Takes ownership
--- a/Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/Operations/SequenceOfOperationsJob.cpp	Thu May 31 18:44:05 2018 +0200
@@ -361,7 +361,7 @@
   }
 
 
-  void SequenceOfOperationsJob::GetInternalContent(Json::Value& value)
+  void SequenceOfOperationsJob::Serialize(Json::Value& value)
   {
     boost::mutex::scoped_lock lock(mutex_);
 
--- a/Core/JobsEngine/Operations/SequenceOfOperationsJob.h	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/Operations/SequenceOfOperationsJob.h	Thu May 31 18:44:05 2018 +0200
@@ -138,7 +138,7 @@
 
     virtual void GetPublicContent(Json::Value& value);
 
-    virtual void GetInternalContent(Json::Value& value);
+    virtual void Serialize(Json::Value& value);
 
     void AwakeTrailingSleep()
     {
--- a/Core/JobsEngine/SetOfInstancesJob.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/SetOfInstancesJob.cpp	Thu May 31 18:44:05 2018 +0200
@@ -186,7 +186,7 @@
   }    
 
 
-  void SetOfInstancesJob::GetInternalContent(Json::Value& value)
+  void SetOfInstancesJob::Serialize(Json::Value& value)
   {
     Json::Value v = Json::arrayValue;
       
--- a/Core/JobsEngine/SetOfInstancesJob.h	Thu May 31 17:45:09 2018 +0200
+++ b/Core/JobsEngine/SetOfInstancesJob.h	Thu May 31 18:44:05 2018 +0200
@@ -109,6 +109,6 @@
     
     virtual void GetPublicContent(Json::Value& value);
     
-    virtual void GetInternalContent(Json::Value& value);
+    virtual void Serialize(Json::Value& value);
   };
 }
--- a/OrthancServer/ServerJobs/ArchiveJob.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/OrthancServer/ServerJobs/ArchiveJob.cpp	Thu May 31 18:44:05 2018 +0200
@@ -903,7 +903,7 @@
   }
 
   
-  void ArchiveJob::GetInternalContent(Json::Value& value)
+  void ArchiveJob::Serialize(Json::Value& value)
   {
     // TODO
   }
--- a/OrthancServer/ServerJobs/ArchiveJob.h	Thu May 31 17:45:09 2018 +0200
+++ b/OrthancServer/ServerJobs/ArchiveJob.h	Thu May 31 18:44:05 2018 +0200
@@ -97,6 +97,6 @@
     
     virtual void GetPublicContent(Json::Value& value);
 
-    virtual void GetInternalContent(Json::Value& value);
+    virtual void Serialize(Json::Value& value);
   };
 }
--- a/OrthancServer/ServerJobs/OrthancJobUnserializer.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/OrthancServer/ServerJobs/OrthancJobUnserializer.cpp	Thu May 31 18:44:05 2018 +0200
@@ -41,11 +41,10 @@
 
 namespace Orthanc
 {
-  IJob* OrthancJobUnserializer::UnserializeJob(const Json::Value& source)
+  IJob* OrthancJobUnserializer::UnserializeJob(const std::string& type,
+                                               const Json::Value& source)
   {
-    const std::string type = GetString(source, "Type");
-
-    return GenericJobUnserializer::UnserializeJob(source);
+    return GenericJobUnserializer::UnserializeJob(type, source);
   }
 
 
--- a/OrthancServer/ServerJobs/OrthancJobUnserializer.h	Thu May 31 17:45:09 2018 +0200
+++ b/OrthancServer/ServerJobs/OrthancJobUnserializer.h	Thu May 31 18:44:05 2018 +0200
@@ -49,10 +49,11 @@
     {
     }
 
-    virtual IJob* UnserializeJob(const Json::Value& source);
+    virtual IJob* UnserializeJob(const std::string& type,
+                                 const Json::Value& value);
 
-    virtual IJobOperation* UnserializeOperation(const Json::Value& source);
+    virtual IJobOperation* UnserializeOperation(const Json::Value& value);
 
-    virtual JobOperationValue* UnserializeValue(const Json::Value& source);
+    virtual JobOperationValue* UnserializeValue(const Json::Value& value);
   };
 }
--- a/OrthancServer/ServerJobs/ResourceModificationJob.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/OrthancServer/ServerJobs/ResourceModificationJob.cpp	Thu May 31 18:44:05 2018 +0200
@@ -273,9 +273,9 @@
   }
 
   
-  void ResourceModificationJob::GetInternalContent(Json::Value& value)
+  void ResourceModificationJob::Serialize(Json::Value& value)
   {
-    SetOfInstancesJob::GetInternalContent(value);
+    SetOfInstancesJob::Serialize(value);
 
     Json::Value tmp;
     modification_->Serialize(tmp);
--- a/OrthancServer/ServerJobs/ResourceModificationJob.h	Thu May 31 17:45:09 2018 +0200
+++ b/OrthancServer/ServerJobs/ResourceModificationJob.h	Thu May 31 18:44:05 2018 +0200
@@ -104,6 +104,6 @@
 
     virtual void GetPublicContent(Json::Value& value);
     
-    virtual void GetInternalContent(Json::Value& value);
+    virtual void Serialize(Json::Value& value);
   };
 }
--- a/UnitTestsSources/MultiThreadingTests.cpp	Thu May 31 17:45:09 2018 +0200
+++ b/UnitTestsSources/MultiThreadingTests.cpp	Thu May 31 18:44:05 2018 +0200
@@ -167,7 +167,7 @@
     type = "DummyJob";
   }
 
-  virtual void GetInternalContent(Json::Value& value)
+  virtual void Serialize(Json::Value& value)
   {
   }