From 51e9fd8b02cdac164d0dd46d3b3fd953bf809233 Mon Sep 17 00:00:00 2001
From: Riccardo Maria Bianchi <riccardo.maria.bianchi@cern.ch>
Date: Tue, 17 May 2016 15:42:17 +0200
Subject: [PATCH] Fixed corrupted batch-produced single-event data files.
 Details: https://its.cern.ch/jira/browse/ATLASVPONE-316
 (VP1UtilsBase-00-00-06)

2016-05-17 Riccardo.Maria.Bianchi@cern.ch
    * Added removing of 'PoolFileCatalog.xml' after the copy of files,
      because it causes errors while accessing copied files later in the same Athena
      Details: https://its.cern.ch/jira/browse/ATLASVPONE-316
    * new tag: VP1UtilsBase-00-00-05

2016-02-17 Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch>
	* Added a hand-written CMakeLists.txt file to the package.
	* Removed the executable flag from the source files.
	* Tagging as VP1UtilsBase-00-00-05

2016-02-11 Riccardo.Maria.Bianchi@cern.ch
    * Added extra arguments to the VP1FileUtilities constructor, with default values:
      - outputDir = "",
      - bool forceMakeOutputDir = false,
      - bool removeInputFile = true

2014-11-06  Vakho Tsulaia  <tsulaia@cern.ch>

	* Remove the source file after copying
...
(Long ChangeLog diff - truncated)


Former-commit-id: d62c984f9ccbed43ed217f11b46dca4aab892f9b
---
 graphics/VP1/VP1UtilsBase/CMakeLists.txt      |  16 +++
 .../VP1UtilsBase/VP1FileUtilities.h           |  10 +-
 .../VP1/VP1UtilsBase/src/VP1FileUtilities.cxx | 115 ++++++++++++++++--
 3 files changed, 129 insertions(+), 12 deletions(-)
 create mode 100644 graphics/VP1/VP1UtilsBase/CMakeLists.txt
 mode change 100755 => 100644 graphics/VP1/VP1UtilsBase/VP1UtilsBase/VP1FileUtilities.h
 mode change 100755 => 100644 graphics/VP1/VP1UtilsBase/src/VP1FileUtilities.cxx

diff --git a/graphics/VP1/VP1UtilsBase/CMakeLists.txt b/graphics/VP1/VP1UtilsBase/CMakeLists.txt
new file mode 100644
index 000000000000..8c05f5d3cce6
--- /dev/null
+++ b/graphics/VP1/VP1UtilsBase/CMakeLists.txt
@@ -0,0 +1,16 @@
+################################################################################
+# Package: VP1UtilsBase
+################################################################################
+# Author: Riccardo Maria BIANCHI <rbianchi@cern.ch>
+################################################################################
+
+# Declare the package name:
+atlas_subdir( VP1UtilsBase )
+
+# External dependencies:
+find_package( Qt4 COMPONENTS QtCore )
+
+# Component(s) in the package:
+atlas_add_library( VP1UtilsBase src/*.cxx
+   PUBLIC_HEADERS VP1UtilsBase
+   PRIVATE_LINK_LIBRARIES Qt4::QtCore )
diff --git a/graphics/VP1/VP1UtilsBase/VP1UtilsBase/VP1FileUtilities.h b/graphics/VP1/VP1UtilsBase/VP1UtilsBase/VP1FileUtilities.h
old mode 100755
new mode 100644
index a9dfc312eaec..2f76de8d3229
--- a/graphics/VP1/VP1UtilsBase/VP1UtilsBase/VP1FileUtilities.h
+++ b/graphics/VP1/VP1UtilsBase/VP1UtilsBase/VP1FileUtilities.h
@@ -10,6 +10,9 @@
 //                                                         //
 //  Initial version: October 2007                          //
 //                                                         //
+//  Updates:                                               //
+//      Riccardo Maria BIANCHI <rbianchi@cern.ch>          //
+//                                                         //
 /////////////////////////////////////////////////////////////
 
 #ifndef VP1FILEUTILITIES_H
@@ -32,7 +35,7 @@ public:
   //    * Writing: maximum number of files to keep in 'inputDirectory'
   //    * Reading: maximum number of files to keep in 'copyDirectory' (see below)
   VP1FileUtilities(const std::string& inputDirectory,
-		   unsigned int fileLimit);
+		   unsigned int fileLimit, const std::string& outputDir = "", bool forceMakeOutputDir = false, bool removeInputFile = true);
   virtual ~VP1FileUtilities();
 
   //
@@ -62,7 +65,10 @@ private:
   void cleanUp();
 
   std::string m_inputDirectory;
-  unsigned int m_fileLimit;
+  int m_fileLimit;
+  std::string m_outputDirectory;
+  bool m_forceMakeOutputDir;
+  bool m_removeInputFile;
 };
 
 #endif
diff --git a/graphics/VP1/VP1UtilsBase/src/VP1FileUtilities.cxx b/graphics/VP1/VP1UtilsBase/src/VP1FileUtilities.cxx
old mode 100755
new mode 100644
index 5bb42f00e995..6ee33209a750
--- a/graphics/VP1/VP1UtilsBase/src/VP1FileUtilities.cxx
+++ b/graphics/VP1/VP1UtilsBase/src/VP1FileUtilities.cxx
@@ -25,11 +25,16 @@
 #include <iomanip>
 #include <iostream>
 #include <stdexcept>
+#include <thread>         // std::this_thread::sleep_for // C++11
+#include <chrono>         // std::chrono::seconds // C++11
 
 VP1FileUtilities::VP1FileUtilities(const std::string& inputDirectory,
-				   unsigned int fileLimit):
+				   unsigned int fileLimit, const std::string& outputDir, bool forceMakeOutputDir, bool removeInputFile):
   m_inputDirectory(inputDirectory),
-  m_fileLimit(fileLimit)
+  m_fileLimit(fileLimit),
+  m_outputDirectory(outputDir),
+  m_forceMakeOutputDir(forceMakeOutputDir),
+  m_removeInputFile(removeInputFile)
 {
   // Check if the input directory exists and is writable
   QFileInfo inpDir(m_inputDirectory.c_str());
@@ -37,6 +42,21 @@ VP1FileUtilities::VP1FileUtilities(const std::string& inputDirectory,
     std::string errMessage = std::string("VP1FileUtilities: ERROR!! The directory ") + inputDirectory + std::string(" either does not exist or is not writable");
     throw std::runtime_error(errMessage.c_str());
   }
+
+  // Check if the output directory exists and is writable
+  if (m_outputDirectory != "") {
+	  QFileInfo inpDir(m_outputDirectory.c_str());
+	  if(!inpDir.exists()||!inpDir.isDir()||!inpDir.isReadable()||!inpDir.isWritable()) {
+		  std::string errMessage = std::string("VP1FileUtilities: ERROR!! The directory ") + m_outputDirectory + std::string(" does not exist.");
+		  if (m_forceMakeOutputDir) {
+			  errMessage += "\nforceMakeOutputDir=True --> Creating the output folder now...";
+			  QDir().mkdir(m_outputDirectory.c_str());
+		  } else {
+			  throw std::runtime_error(errMessage.c_str());
+		  }
+	  }
+  }
+
 }
 
 VP1FileUtilities::~VP1FileUtilities()
@@ -56,30 +76,85 @@ void VP1FileUtilities::produceNewFile(const std::string& sourceFile,
     throw std::runtime_error("Source file does not exist!");
 
   QString inpDirName(m_inputDirectory.c_str());
+  QString outDirName(m_outputDirectory.c_str());
 
   // Construct new filename
   QString newFileName = inpDirName;
   std::ostringstream newFileStr;
 
   // if input directory name is empty don't add / to the file name
-  // also take into account a possibility od trailing slash in directory name
+  // also take into account a possibility of trailing slash in directory name
   if(m_inputDirectory!="" && m_inputDirectory.rfind("/")!=m_inputDirectory.size()-1)
     newFileStr << "/";
 
   QString latestEventFileName = inpDirName + QString(newFileStr.str().c_str()) + QString("latest_vp1event");
 
   if (textLabel != "" ) {
-    newFileStr << "vp1_" << runNumber << "_" << eventNumber << "_" << timeStamp << "_" << textLabel << ".pool.root";
+    newFileStr << "vp1_r" << runNumber << "_ev" << eventNumber << "_u" << timeStamp << "_t" << textLabel << ".pool.root";
   } else {
-    newFileStr << "vp1_" << runNumber << "_" << eventNumber << "_" << timeStamp << ".pool.root";
+    newFileStr << "vp1_r" << runNumber << "_ev" << eventNumber << "_u" << timeStamp << ".pool.root";
   }
 
   newFileName += QString(newFileStr.str().c_str());
 
+
+  // adding the output folder, if not empty
+  if (outDirName != "")
+	  newFileName = outDirName + QDir::separator() + newFileName;
+
   // do copy
+  std::cout << "copying '" <<  (srcFile.fileName()).toStdString() << "' to: '" << newFileName.toStdString() << "'..." << std::endl;
+
+
+    		  // get size of the file to be copied
+  qint64 inputSize = srcFile.size();
+    		  std::cout << "Size of the input file to be copied: " << inputSize << std::endl;
+
+
   if(!srcFile.copy(newFileName))
     throw std::runtime_error("Unable to produce new vp1 event file");
 
+
+
+      // the operation to time (for elapsed time)
+      char ch; std::cout << '?' && std::cin >> ch ;
+
+
+
+      // remove the input file (if not disabled by user)
+      if (m_removeInputFile) {
+    	  bool copyDone = false;
+    	  std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now() ;
+    	  typedef std::chrono::duration<int,std::milli> millisecs_t ;
+    	  while (!copyDone) {
+
+    		  // get handle on new file
+    		  QFileInfo checkFile(newFileName);
+
+
+    		  // check if file exists (and it is a file, and not a directory)
+    		  if (checkFile.exists() && checkFile.isFile() && (checkFile.size() == inputSize) )
+    		  {
+    			  std::cout << "Size of the copied file: " << checkFile.size() << std::endl;
+    			  copyDone = true;
+    			  if(!srcFile.remove())
+    				  std::cerr << "VP1FileUtilities WARNING! Unable to delete " << sourceFile << std::endl;
+    		  }
+    		  else
+    		  {
+    			  std::cout << "I could not find the output file, so probably the copy action is not finished yet. I'll wait for a short while and I will retry..." << std::endl;
+    			  std::this_thread::sleep_for(std::chrono::milliseconds(500)); //make the program waiting for 0.5 seconds
+    			  std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now() ;
+    			  millisecs_t duration( std::chrono::duration_cast<millisecs_t>(end-start) ) ;
+    			  if (duration.count() > 2000.0 )
+    			  {
+    				  std::cout << "WARNING!!! " << duration.count() << " milliseconds passed and still I cannot find the output file. Probably there was a problem. Giving up with the removal of the source file...\n" ;
+    				  copyDone = true;
+    			  }
+    		  }
+    	  }
+      }
+
   // create/update the latest event file
   QFile latestEvent(latestEventFileName);
   if(latestEvent.exists() && !latestEvent.remove())
@@ -90,25 +165,34 @@ void VP1FileUtilities::produceNewFile(const std::string& sourceFile,
   latestEvent.write(newFileName.toStdString().c_str());
   latestEvent.close();
 
-  // do cleanup if needed
-  cleanUp();
+  // do cleanup if requested. '-1' means 'KEEP ALL FILES'
+  if (m_fileLimit != -1) {
+	  std::cout << "VP1FileUtilities - cleaning up..." << std::endl;
+	  cleanUp();
+  }
 }
 
+// if the user set a "m_fileLimit" then clean the outputDirectory,
+// to only keep this predefined number of output files.
+// Please notice: default behaviours is: keep ALL output events.
 void VP1FileUtilities::cleanUp()
 {
+  //std::cout << "VP1FileUtilities::cleanUp()" << std::endl;
+
   QDir _dir;
-  _dir.setPath(QString(m_inputDirectory.c_str()));
+  _dir.setPath(QString(m_outputDirectory.c_str()));
 
   QStringList nameFilters;
   nameFilters << "vp1_*.pool.root";
 
-
   _dir.setFilter(QDir::Files);
   _dir.setNameFilters(nameFilters);
   _dir.setSorting(QDir::Time|QDir::Reversed);
   QFileInfoList list = _dir.entryInfoList();
 
-  if(unsigned(list.size()) > m_fileLimit)
+  //std::cout << "m_fileLimit: " << m_fileLimit << " - list.size(): " << list.size() << " - list: " << list << std::endl;
+
+  if(int(list.size()) > m_fileLimit)
   {
     QFileInfo fileInfo = list.at(0);
 
@@ -116,6 +200,17 @@ void VP1FileUtilities::cleanUp()
       throw std::runtime_error("VP1FileUtilities::cleanup() - WARNING: Unable to do the clean up!");
   }
 
+  QString poolCatalog("PoolFileCatalog.xml");
+  std::string poolCatalogStr = poolCatalog.toStdString();
+  std::cout << "looking for " << poolCatalogStr << " in " <<  QDir::currentPath().toStdString() << std::endl;
+  if ( QDir::current().entryList().contains( poolCatalog ) ) {
+	  std::cout << "VP1FileUtilities::cleanUp() - removing the file '" << poolCatalogStr << "' because it causes problems for subsequent Athena commands opening the copied file." << std::endl;
+	  QDir cwd = QDir::currentPath();
+	  if ( ! cwd.remove( poolCatalog ) )
+		std::cerr << "VP1FileUtilities WARNING! Unable to delete " << poolCatalogStr << std::endl;
+  }
+
+
   return;
 }
 
-- 
GitLab