Skip to content
Snippets Groups Projects
Select Git revision
  • 6e4da982f7fc310551a3e2917c644ee1df9b58e5
  • master default protected
  • fix_Makefile.mingw#2
  • update_Makefile.mingw
  • fix_Makefile.mingw
  • fix_API_for_C_apps
  • fix_procinfo_mac
  • boinccmd_gpu_mode_always_until_sigterm
  • fgrp_osx_hotfix
  • fix_boinc_master@f8250782
  • eah_wrapper_improvements
  • diagnostics_win-hotfix
  • diagnostics_win-hotfix-old
  • current_fgrp_apps
  • testing_gw_apps
  • gw_app_darwin_15
  • current_brp_apps
  • current_brp_apps_android10
  • current_gfx_apps
  • current_server
  • current_gw_apps
  • previous_fgrp_apps
  • previous_gw_apps
  • testing_brp_apps
  • apps_FGRP3_1.07
  • apps_FGRP3_1.08
26 results

boinc_checkpoint.C

Blame
  • user avatar
    Eric J. Korpela authored
    without a -include command line option.
    
    svn path=/trunk/boinc/; revision=8896
    d9ee4260
    History
    boinc_checkpoint.C 7.73 KiB
    // Berkeley Open Infrastructure for Network Computing
    // http://boinc.berkeley.edu
    // Copyright (C) 2005 University of California
    //
    // This is free software; you can redistribute it and/or
    // modify it under the terms of the GNU Lesser General Public
    // License as published by the Free Software Foundation;
    // either version 2.1 of the License, or (at your option) any later version.
    //
    // This software is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    // See the GNU Lesser General Public License for more details.
    //
    // To view the GNU Lesser General Public License visit
    // http://www.gnu.org/copyleft/lesser.html
    // or write to the Free Software Foundation, Inc.,
    // 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    
    // Untested and unsupported code for checkpointing multiple files.
    
    #include "config.h"
    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <vector>
    #include <cstdarg>
    
    using namespace std;
    
    // abstract interface - derive classes from this base class
    class BoincCheckpointFile
    {
    public:
        // these functions should set error on f on failure
    
        // this is only called once each time an application is resumed
        virtual void input(istream& f) = 0;
    
        // this is called at every checkpoint
        virtual void output(ostream& f) = 0;
    };
    
    // checkpoint class good for binary dump of struct as a state file
    class BoincRawDataCheckpointFile : public BoincCheckpointFile {
        void* data;
        size_t length;
    public:
        BoincRawDataCheckpointFile(void* data_, size_t length_)
            :data(data_), length(length_)
        {
        }
    
        virtual void input(istream& f)
        {
            f.read((char*) data, length);
            if (!f.eof())
                f.clear(ios::badbit);
        }
    
        virtual void output(ostream& f)
        {
            f.write((char const*) data, length);
        }
    };
    
    // Class that is good for writing or appending (text or binary) data.
    // Use standard C++ iostream operators to output, or printf
    class BoincStreamCheckpointFile : public BoincCheckpointFile, public stringstream
    {
    public:
        virtual void input(istream& f)
        {
            // read entire file into memory buffer (which is a stringbuf)
            f >> rdbuf();
        }
    
        virtual void output(ostream& f)
        {
            // write entire memory buffer to file
            seekg(0);
            f << rdbuf();
        }
    
        void printf(const char* format, ...)
        {
            va_list ap;
            char buf[20000];
    
            va_start(ap, format);
            vsprintf(buf, format, ap);
            va_end(ap);
            *this << buf;
        }
    };
    
    // AtomicFileSet defines a set of files which are written/read atomically.  If
    // the system crashes within a write(), the next read() will read what was
    // written by the previous write().  Assumes that writing a single integer is
    // atomic - a much safer assumption than just writing an arbitrary number of
    // files of arbitrary length.
    class AtomicFileSet
    {
        struct NamedCheckpointFile {
            const char* filename;
            BoincCheckpointFile* file;
            bool keep;
        };
    
        int current_checkpoint_number;
        typedef vector<NamedCheckpointFile> FilesList;
        FilesList files;
    
        // returns true on success
        bool read_checkpoint_number()
        {
            ifstream f("boinc_checkpoint.dat");
            return (bool) (void*) (f >> current_checkpoint_number);
        }
    
        void write_checkpoint_number() const
        {
            ofstream f("boinc_checkpoint.dat");
            f << current_checkpoint_number;
        }
    
        string format_checkpointed_filename(const char* filename, int checkpoint_number)
        {
            char buf[1024];
            sprintf(buf, "%s.%d", filename, checkpoint_number);
            return buf;
        }
    
        void delete_files(int checkpoint_number)
        {
            for (FilesList::const_iterator i = files.begin(); i != files.end(); ++i) {
                string cp_filename =
                    format_checkpointed_filename(i->filename, checkpoint_number);
                if (unlink(cp_filename.c_str())) {
                    cerr << "Couldn't unlink \"" << cp_filename << "\": " << strerror(errno) << endl;
                }
            }
        }
    
    public:
        AtomicFileSet() : current_checkpoint_number(0) {}
    
        // add a file to the set of files to atomically write.  if keep, then the
        // file exists as 'filename' after Finish(); else it is deleted after
        // Finish().
        void add(const char* filename,
                 BoincCheckpointFile* file,
                 bool keep = true)
        {
            NamedCheckpointFile namedfile;
            namedfile.filename = filename;
            namedfile.file = file;
            namedfile.keep = keep;
            files.push_back(namedfile);
        }
    
        // call when resuming. returns true on success of all files, false on failure.
        bool read()
        {
            if (!read_checkpoint_number()) return false;
    
            for (FilesList::const_iterator i = files.begin(); i != files.end(); ++i) {
                string cp_filename =
                    format_checkpointed_filename(i->filename, current_checkpoint_number);
                ifstream f(cp_filename.c_str(), ios::binary);
                if (!f) {
                    cerr << "Error opening for input \"" << cp_filename << "\"\n";
                    return false;
                }
                i->file->input(f);
                if (!f) {
                    cerr << "Error reading \"" << cp_filename << "\"\n";
                    return false;
                }
            }
            // success
            return true;
        }
    
        void write()
        {
            // strategy:
            //   1. write *.N
            //   2. write N to checkpoint file
            //   3. delete *.(N-1)
    
            for (FilesList::const_iterator i = files.begin(); i != files.end(); ++i) {
                string cp_filename =
                    format_checkpointed_filename(i->filename, current_checkpoint_number);
                ofstream f(cp_filename.c_str(), ios::binary);
                if (!f) {
                    cerr << "Couldn't open output \"" << cp_filename << "\"\n";
                    exit(101);
                }
                i->file->output(f);
                if (!f) {
                    cerr << "Error writing \"" << cp_filename << "\"\n";
                    exit(102);
                }
            }
    
            write_checkpoint_number();
    
            delete_files(current_checkpoint_number-1);
            ++current_checkpoint_number;
        }
    
        // NOTE: you must call write() yourself, if there is any data to be written.
        void finish()
        {
            // delete files that are no longer needed, and rename the ones we
            // want to keep.
            int checkpoint_number = current_checkpoint_number-1;
            for (FilesList::const_iterator i = files.begin(); i != files.end(); ++i) {
                string cp_filename =
                    format_checkpointed_filename(i->filename, checkpoint_number);
                if (i->keep) {
                    if (unlink(cp_filename.c_str())) {
                        cerr << "Warning: Couldn't unlink \"" << cp_filename
                             << "\": " << strerror(errno) << endl;
                    }
                } else {
                    if (rename(cp_filename.c_str(), i->filename)) {
                        cerr << "Fatal error: Couldn't rename \"" << cp_filename
                             << "\" to \"" << i->filename << "\": "
                             << strerror(errno) << endl;
                        exit(100);
                    }
                }
            }
        }
    };
    
    /* usage in astropulse:
    
    AtomicFileSet files;
    ostream* output;
    
    void init()
    {
        files.add("ap_state.dat",
                  new BoincRawDataCheckpointFile(client.state, sizeof(client.state)));
        files.add("pulse.out", (output=new BoincStreamCheckpointFile));
        if (files.read()) {
            // resuming
        } else {
            *output << "<astropulse> ...";
        }
    }
    
    void output_pulse()
    {
        *output << "<pulse> ... </pulse>";
    }
    
    void checkpoint()
    {
        files.write();
    }
    
    */
    
    const char *BOINC_RCSID_f3d3fb27ca = "$Id$";