<commit_before>#include <cerrno>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>

#include <boost/filesystem.hpp>

#include <dbxml/DbXml.hpp>

#include <AlpinoCorpus/DbCorpusWriter.hh>
#include <AlpinoCorpus/Entry.hh>
#include <AlpinoCorpus/Error.hh>
#include <AlpinoCorpus/util/NonCopyable.hh>

namespace bf = boost::filesystem;
namespace db = DbXml;

namespace alpinocorpus {
    class DbCorpusWriterPrivate : public util::NonCopyable
    {
    public:
        /** Open path for writing. */
        DbCorpusWriterPrivate(std::string const &path, bool overwrite);
        DbXml::XmlUpdateContext &mkUpdateContext(DbXml::XmlUpdateContext &);
        void write(std::string const &, std::string const &, DbXml::XmlUpdateContext &);
        void writeFailFirst(CorpusReader const &, DbXml::XmlUpdateContext &);
        void writeFailSafe(CorpusReader const &, DbXml::XmlUpdateContext &);
    private:
        DbXml::XmlManager d_mgr;
        DbXml::XmlContainer d_container;        

    };
    
    DbCorpusWriter::DbCorpusWriter(std::string const &path, bool overwrite)
        : d_private(new DbCorpusWriterPrivate(path, overwrite))
    {}
    
    DbCorpusWriter::~DbCorpusWriter()
    {
        delete d_private;
    }
    
    void DbCorpusWriter::writeEntry(std::string const &name, std::string const &content)
    {
        db::XmlUpdateContext ctx;
        d_private->write(name, content, d_private->mkUpdateContext(ctx));
    }
    
    void DbCorpusWriter::writeEntry(CorpusReader const &corpus, bool fail_first)
    {
        db::XmlUpdateContext ctx;
        d_private->mkUpdateContext(ctx);
        
        if (fail_first)
            d_private->writeFailFirst(corpus, ctx);
        else
            d_private->writeFailSafe(corpus, ctx);
    }
    
    DbCorpusWriterPrivate::DbCorpusWriterPrivate(std::string const &path, bool overwrite)
        : d_mgr(), d_container()
    {
        try {
            db::XmlContainerConfig config;
            config.setReadOnly(false);


            if (overwrite) {
                if (std::remove(path.c_str()) != 0 && errno != ENOENT)
                    throw OpenError(path,
                                    std::string("cannot remove file: ") +
                                    std::strerror(errno));
                d_container = d_mgr.createContainer(path, config,
                                                    db::XmlContainer
                                                    ::NodeContainer);
            } else {
                if (bf::exists(path))
                    d_container = d_mgr.openContainer(path, config);
                else
                    d_container = d_mgr.createContainer(path, config,
                        db::XmlContainer::NodeContainer);
            }
        } catch (db::XmlException const &e) {
            throw OpenError(path, e.what());
        }
    }

    db::XmlUpdateContext &DbCorpusWriterPrivate::mkUpdateContext(
        db::XmlUpdateContext &ctx)
    {
        // Note: this function may be unnecessary; no exceptions are listed
        // for XmlManager::createUpdateContext() or the copy constructor,
        // but they don't have a no-throw guarantee either.
        try {
            return ctx = d_mgr.createUpdateContext();
        } catch (db::XmlException const &e) {
            std::string msg("cannot create XML database update context: ");
            msg += e.what();
            throw Error(msg);
        }
    }

    void DbCorpusWriterPrivate::writeFailFirst(CorpusReader const &corpus,
        db::XmlUpdateContext &ctx)
    {<commit_msg>Always sync on writer destruction.<commit_after>#include <cerrno>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <string>

#include <boost/filesystem.hpp>

#include <dbxml/DbXml.hpp>

#include <AlpinoCorpus/DbCorpusWriter.hh>
#include <AlpinoCorpus/Entry.hh>
#include <AlpinoCorpus/Error.hh>
#include <AlpinoCorpus/util/NonCopyable.hh>

namespace bf = boost::filesystem;
namespace db = DbXml;

namespace alpinocorpus {
    class DbCorpusWriterPrivate : public util::NonCopyable
    {
    public:
        /** Open path for writing. */
        DbCorpusWriterPrivate(std::string const &path, bool overwrite);
        ~DbCorpusWriterPrivate();
        DbXml::XmlUpdateContext &mkUpdateContext(DbXml::XmlUpdateContext &);
        void write(std::string const &, std::string const &, DbXml::XmlUpdateContext &);
        void writeFailFirst(CorpusReader const &, DbXml::XmlUpdateContext &);
        void writeFailSafe(CorpusReader const &, DbXml::XmlUpdateContext &);
    private:
        DbXml::XmlManager d_mgr;
        DbXml::XmlContainer d_container;        

    };
    
    DbCorpusWriter::DbCorpusWriter(std::string const &path, bool overwrite)
        : d_private(new DbCorpusWriterPrivate(path, overwrite))
    {}
    
    DbCorpusWriter::~DbCorpusWriter()
    {
        delete d_private;
    }
    
    void DbCorpusWriter::writeEntry(std::string const &name, std::string const &content)
    {
        db::XmlUpdateContext ctx;
        d_private->write(name, content, d_private->mkUpdateContext(ctx));
    }
    
    void DbCorpusWriter::writeEntry(CorpusReader const &corpus, bool fail_first)
    {
        db::XmlUpdateContext ctx;
        d_private->mkUpdateContext(ctx);
        
        if (fail_first)
            d_private->writeFailFirst(corpus, ctx);
        else
            d_private->writeFailSafe(corpus, ctx);
    }
    
    DbCorpusWriterPrivate::DbCorpusWriterPrivate(std::string const &path, bool overwrite)
        : d_mgr(), d_container()
    {
        try {
            db::XmlContainerConfig config;
            config.setReadOnly(false);


            if (overwrite) {
                if (std::remove(path.c_str()) != 0 && errno != ENOENT)
                    throw OpenError(path,
                                    std::string("cannot remove file: ") +
                                    std::strerror(errno));
                d_container = d_mgr.createContainer(path, config,
                                                    db::XmlContainer
                                                    ::NodeContainer);
            } else {
                if (bf::exists(path))
                    d_container = d_mgr.openContainer(path, config);
                else
                    d_container = d_mgr.createContainer(path, config,
                        db::XmlContainer::NodeContainer);
            }
        } catch (db::XmlException const &e) {
            throw OpenError(path, e.what());
        }
    }

    DbCorpusWriterPrivate::~DbCorpusWriterPrivate()
    {
      // Should not been necessary. But in some rare cases, the database
      // was not correctly written. Maybe a reference counting bug in
      // DB XML?
      d_container.sync();
    }

    db::XmlUpdateContext &DbCorpusWriterPrivate::mkUpdateContext(
        db::XmlUpdateContext &ctx)
    {
        // Note: this function may be unnecessary; no exceptions are listed
        // for XmlManager::createUpdateContext() or the copy constructor,
        // but they don't have a no-throw guarantee either.
        try {
            return ctx = d_mgr.createUpdateContext();
        } catch (db::XmlException const &e) {
            std::string msg("cannot create XML database update context: ");
            msg += e.what();
            throw Error(msg);
        }
    }

    void DbCorpusWriterPrivate::writeFailFirst(CorpusReader const &corpus,
        db::XmlUpdateContext &ctx)
    {
{'fraction_non_alphanumeric': 0.10510910058541778, 'fraction_numerical': 0.00026609898882384245, 'mean_word_length': 2.181125687685146, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1643607', 'n_tokens_mistral': 2129, 'n_tokens_neox': 2058, 'n_words': 438}