<commit_before>
// Note - python_bindings_common.h must be included before condor_common to avoid
// re-definition warnings.
#include "python_bindings_common.h"

#include <poll.h>

#include "condor_common.h"
#include "condor_config.h"
#include "read_user_log.h"
#include "file_lock.h"

#include <classad/operators.h>

#include <memory>

#include "old_boost.h"
#include "event.h"
#include "inotify_sentry.h"


EventIterator::EventIterator(FILE *source, bool is_xml)
  : m_blocking(false), m_is_xml(is_xml), m_step(1000), m_done(0), m_source(source), m_reader(new ReadUserLog(source, is_xml))
{}


bool
EventIterator::get_filename(std::string &fname)
{
    int fd = fileno(m_source);
    std::stringstream ss;
    ss << "/proc/self/fd/" << fd;
    std::string proc_fname = ss.str();
    std::vector<char> linkname; linkname.reserve(1024);
    ssize_t link_size;
    if (-1 == (link_size = readlink(proc_fname.c_str(), &linkname[0], 1023)))
    {
         return false;
    }
    linkname[link_size] = '\0';

    fname = &linkname[0];
    return true;
}


void
EventIterator::reset_to(off_t location)
{
    m_done = 0;
    fseek(m_source, location, SEEK_SET);
    m_reader.reset(new ReadUserLog(m_source, m_is_xml));
}


void
EventIterator::wait_internal(int timeout_ms)
{
    if (m_done == 0) {return;}
    off_t prev_done = m_done;
    if (timeout_ms == 0)
    {
        reset_to(prev_done);
        return;
    }
    int time_remaining = timeout_ms;
    int step = m_step;
    fflush(m_source);
    clearerr(m_source);
    int fd = fileno(m_source);
    struct stat result;
    while ((-1 != fstat(fd, &result)) && (result.st_size == m_done))
    {
        struct pollfd fd;
        fd.fd = watch();
        fd.events = POLLIN;
        Py_BEGIN_ALLOW_THREADS
        if (time_remaining > -1 && time_remaining < 1000) {step = time_remaining;}
        if (fd.fd == -1)
        {
            Sleep(step);
        }
        else
        {
            ::poll(&fd, 1, step);
        }
        Py_END_ALLOW_THREADS
        if (PyErr_CheckSignals() == -1)
        {
            boost::python::throw_error_already_set();
        }
        time_remaining -= step;
        if (time_remaining == 0)
        {
            errno = 0;
            break;
        }
    }
    if (errno)
    {
        THROW_EX(IOError, "Failure when checking file size of event log.");
    }
    reset_to(prev_done);
}


bool
EventIterator::useInotify()
{
#ifdef LOG_READER_USE_INOTIFY
    return true;
#else
    return false;
#endif
}


int
EventIterator::watch()
{
    if (!m_watch.get())
    {
        std::string fname;
        if (get_filename(fname))
        {
            m_watch.reset(new InotifySentry(fname));
        }<commit_msg>Fix bug in python bindings event log reader "watch" command<commit_after>
// Note - python_bindings_common.h must be included before condor_common to avoid
// re-definition warnings.
#include "python_bindings_common.h"

#include <poll.h>

#include "condor_common.h"
#include "condor_config.h"
#include "read_user_log.h"
#include "file_lock.h"

#include <classad/operators.h>

#include <memory>

#include "old_boost.h"
#include "event.h"
#include "inotify_sentry.h"


EventIterator::EventIterator(FILE *source, bool is_xml)
  : m_blocking(false), m_is_xml(is_xml), m_step(1000), m_done(0), m_source(source), m_reader(new ReadUserLog(source, is_xml))
{}


bool
EventIterator::get_filename(std::string &fname)
{
    int fd = fileno(m_source);
    std::stringstream ss;
    ss << "/proc/self/fd/" << fd;
    std::string proc_fname = ss.str();
    std::vector<char> linkname; linkname.reserve(1024);
    ssize_t link_size;
    if (-1 == (link_size = readlink(proc_fname.c_str(), &linkname[0], 1023)))
    {
         return false;
    }
    linkname[link_size] = '\0';

    fname = &linkname[0];
    return true;
}


void
EventIterator::reset_to(off_t location)
{
    m_done = 0;
    fseek(m_source, location, SEEK_SET);
    m_reader.reset(new ReadUserLog(m_source, m_is_xml));
}


void
EventIterator::wait_internal(int timeout_ms)
{
    if (m_done == 0) {return;}
    off_t prev_done = m_done;
    if (timeout_ms == 0)
    {
        reset_to(prev_done);
        return;
    }
    int time_remaining = timeout_ms;
    int step = m_step;
    fflush(m_source);
    clearerr(m_source);
    int fd = fileno(m_source);
    struct stat result;
	int r = 0;
    while ((-1 != (r = fstat(fd, &result))) && (result.st_size == m_done))
    {
        struct pollfd fd;
        fd.fd = watch();
        fd.events = POLLIN;
        Py_BEGIN_ALLOW_THREADS
        if (time_remaining > -1 && time_remaining < 1000) {step = time_remaining;}
        if (fd.fd == -1)
        {
            Sleep(step);
        }
        else
        {
            ::poll(&fd, 1, step);
        }
        Py_END_ALLOW_THREADS
        if (PyErr_CheckSignals() == -1)
        {
            boost::python::throw_error_already_set();
        }
        time_remaining -= step;
        if (time_remaining == 0)
        {
            break;
        }
    }
    if (r == -1)
    {
        THROW_EX(IOError, "Failure when checking file size of event log.");
    }
    reset_to(prev_done);
}


bool
EventIterator::useInotify()
{
#ifdef LOG_READER_USE_INOTIFY
    return true;
#else
    return false;
#endif
}


int
EventIterator::watch()
{
    if (!m_watch.get())
    {
        std::string fname;
        if (get_filename(fname))
        {
            m_watch.reset(new InotifySentry(fname));
        }
{'fraction_non_alphanumeric': 0.1345061389041598, 'fraction_numerical': 0.01154480483782298, 'mean_word_length': 2.6169648774022534, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 10}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7032982', 'n_tokens_mistral': 2027, 'n_tokens_neox': 1965, 'n_words': 398}