ArchiveOpener.cpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2011
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 // Must be included before any other serialization headers
00030 #include <boost/archive/text_oarchive.hpp>
00031 #include <boost/archive/text_iarchive.hpp>
00032 
00033 #include <sstream>
00034 #include <iostream>
00035 
00036 #include "ArchiveOpener.hpp"
00037 #include "ArchiveLocationInfo.hpp"
00038 #include "ProcessSpecificArchive.hpp"
00039 #include "Exception.hpp"
00040 #include "OutputFileHandler.hpp"
00041 
00048 template<>
00049 ArchiveOpener<boost::archive::text_iarchive, std::ifstream>::ArchiveOpener(
00050         const FileFinder& rDirectory,
00051         const std::string& rFileNameBase,
00052         unsigned procId)
00053     : mpCommonStream(NULL),
00054       mpPrivateStream(NULL),
00055       mpCommonArchive(NULL),
00056       mpPrivateArchive(NULL)
00057 {
00058     // Figure out where things live
00059     ArchiveLocationInfo::SetArchiveDirectory(rDirectory);
00060     std::string private_path = ArchiveLocationInfo::GetProcessUniqueFilePath(rFileNameBase, procId);
00061     std::stringstream common_path;
00062     common_path << ArchiveLocationInfo::GetArchiveDirectory() << rFileNameBase;
00063 
00064     // Try to open the main archive for replicated data
00065     mpCommonStream = new std::ifstream(common_path.str().c_str(), std::ios::binary);
00066     if (!mpCommonStream->is_open())
00067     {
00068         delete mpCommonStream;
00069         EXCEPTION("Cannot load main archive file: " + common_path.str());
00070     }
00071 
00072     try
00073     {
00074         mpCommonArchive = new boost::archive::text_iarchive(*mpCommonStream);
00075     }
00076     catch (boost::archive::archive_exception& boost_exception)
00077     {
00078         if (boost_exception.code == boost::archive::archive_exception::unsupported_version)
00079         {
00080             // This is forward compatibility issue.  We can't open the archive because it's been written by a more recent Boost.
00081             delete mpCommonArchive;
00082             delete mpCommonStream;
00083             EXCEPTION("Could not open Boost archive '" + common_path.str() + "' because it was written by a more recent Boost.  Check process-specific archives too");
00084         }
00085         else
00086         {
00087             // We don't understand the exception, so we shouldn't continue
00088 #define COVERAGE_IGNORE
00089             throw boost_exception;
00090 #undef COVERAGE_IGNORE
00091         }
00092     }
00093 
00094     // Try to open the secondary archive for distributed data
00095     mpPrivateStream = new std::ifstream(private_path.c_str(), std::ios::binary);
00096     if (!mpPrivateStream->is_open())
00097     {
00098         delete mpPrivateStream;
00099         delete mpCommonArchive;
00100         delete mpCommonStream;
00101         EXCEPTION("Cannot load secondary archive file: " + private_path);
00102     }
00103     mpPrivateArchive = new boost::archive::text_iarchive(*mpPrivateStream);
00104     ProcessSpecificArchive<boost::archive::text_iarchive>::Set(mpPrivateArchive);
00105 }
00106 
00107 template<>
00108 ArchiveOpener<boost::archive::text_iarchive, std::ifstream>::~ArchiveOpener()
00109 {
00110     ProcessSpecificArchive<boost::archive::text_iarchive>::Set(NULL);
00111     delete mpPrivateArchive;
00112     delete mpPrivateStream;
00113     delete mpCommonArchive;
00114     delete mpCommonStream;
00115 }
00116 
00123 template<>
00124 ArchiveOpener<boost::archive::text_oarchive, std::ofstream>::ArchiveOpener(
00125         const FileFinder& rDirectory,
00126         const std::string& rFileNameBase,
00127         unsigned procId)
00128     : mpCommonStream(NULL),
00129       mpPrivateStream(NULL),
00130       mpCommonArchive(NULL),
00131       mpPrivateArchive(NULL)
00132 {
00133     // Check for user error
00134     if (procId != PetscTools::GetMyRank())
00135     {
00136         EXCEPTION("Specifying the secondary archive file ID doesn't make sense when writing.");
00137     }
00138 
00139     // Figure out where things live
00140     ArchiveLocationInfo::SetArchiveDirectory(rDirectory);
00141     if (ArchiveLocationInfo::GetIsDirRelativeToChasteTestOutput())
00142     {
00143         // Ensure the directory exists
00144         OutputFileHandler handler(ArchiveLocationInfo::GetArchiveRelativePath(), false);
00145     }
00146     std::string private_path = ArchiveLocationInfo::GetProcessUniqueFilePath(rFileNameBase);
00147     std::stringstream common_path;
00148     common_path << ArchiveLocationInfo::GetArchiveDirectory() << rFileNameBase;
00149 
00150     // Create master archive for replicated data
00151     if (PetscTools::AmMaster())
00152     {
00153         mpCommonStream = new std::ofstream(common_path.str().c_str());
00154         if (!mpCommonStream->is_open())
00155         {
00156             delete mpCommonStream;
00157             EXCEPTION("Failed to open main archive file for writing: " + common_path.str());
00158         }
00159     }
00160     else
00161     {
00162         // Non-master processes need to go through the serialization methods, but not write any data
00163         mpCommonStream = new std::ofstream("/dev/null");
00164         #define COVERAGE_IGNORE
00165         if (!mpCommonStream->is_open())
00166         {
00167             delete mpCommonStream;
00168             EXCEPTION("Failed to open dummy archive file '/dev/null' for writing");
00169         }
00170         #undef COVERAGE_IGNORE
00171     }
00172     mpCommonArchive = new boost::archive::text_oarchive(*mpCommonStream);
00173 
00174     // Create secondary archive for distributed data
00175     mpPrivateStream = new std::ofstream(private_path.c_str());
00176     if (!mpPrivateStream->is_open())
00177     {
00178         delete mpPrivateStream;
00179         delete mpCommonArchive;
00180         delete mpCommonStream;
00181         EXCEPTION("Failed to open secondary archive file for writing: " + private_path);
00182     }
00183     mpPrivateArchive = new boost::archive::text_oarchive(*mpPrivateStream);
00184     ProcessSpecificArchive<boost::archive::text_oarchive>::Set(mpPrivateArchive);
00185 }
00186 
00187 template<>
00188 ArchiveOpener<boost::archive::text_oarchive, std::ofstream>::~ArchiveOpener()
00189 {
00190     ProcessSpecificArchive<boost::archive::text_oarchive>::Set(NULL);
00191     delete mpPrivateArchive;
00192     delete mpPrivateStream;
00193     delete mpCommonArchive;
00194     delete mpCommonStream;
00195 
00196     /* In a parallel setting, make sure all processes have finished writing before
00197      * continuing, to avoid nasty race conditions.
00198      * For example, many tests will write an archive then immediately read it back
00199      * in, which could easily break without this.
00200      */
00201     PetscTools::Barrier("~ArchiveOpener");
00202 }
Generated on Thu Dec 22 13:00:05 2011 for Chaste by  doxygen 1.6.3