<commit_before>
#include <cstdint>

#include "component.h"
#include "entity.h"
#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "manager.h"

using ::testing::NiceMock;
using ::testing::Return;

// TODO move to shared testing file
class TestRenderer : public aronnax::Renderer {
  public:
    TestRenderer() { };
    ~TestRenderer() { };
    void render() { };
    void beforeRender() { };
    void afterRender() { };
};

// TODO move to shared testing file
class MockComponent : public aronnax::Component {
  public:
    MOCK_METHOD2(update, void(aronnax::Entity &entity, const uint32_t dt));
    MOCK_METHOD1(render, void(aronnax::Entity &entity));
    MOCK_METHOD0(getType, std::string());
};

class ManagerTest: public testing::Test {
  protected:
    virtual void SetUp() {
      std::shared_ptr<TestRenderer> tr = std::make_shared<TestRenderer>();
      testManager_ = new aronnax::Manager(tr, testEntities_);
    }

    virtual void TearDown() {
      delete testManager_;
    }

    aronnax::Manager* testManager_;
    aronnax::Entities testEntities_;
    aronnax::Components testComponentList_;
};

TEST(manager, Constructor) {
  std::shared_ptr<TestRenderer> testRenderer = std::make_shared<TestRenderer>();
  aronnax::Manager testManager(testRenderer);
}

TEST_F(ManagerTest, add) {
  NiceMock<MockComponent> testComponent;
  testComponentList_.push_back(&testComponent);

  ON_CALL(testComponent, getType())
      .WillByDefault(Return("TestComponentA"));

  auto actual = testManager_->add(testComponentList_);
  EXPECT_EQ(1, testManager_->getEntities().size());
  EXPECT_EQ(1, testManager_->getEntities().count(actual));

  auto actualComponent = actual.get()->getComponent("TestComponentA");
  EXPECT_EQ(actualComponent, &testComponent);

  actual = testManager_->add(testComponentList_);
  EXPECT_EQ(2, testManager_->getEntities().size());
  EXPECT_EQ(1, testManager_->getEntities().count(actual));
}

TEST_F(ManagerTest, getEntities) {
  aronnax::EntityPtr testEntity = std::make_shared<aronnax::Entity>(
      testComponentList_);
  testEntities_.insert(testEntity);

  std::shared_ptr<TestRenderer> tr = std::make_shared<TestRenderer>();
  auto testManager = new aronnax::Manager(tr, testEntities_);

  auto actual = testManager_->getEntities().size();
  //EXPECT_EQ(1, actual);
}
<commit_msg>Manager render test<commit_after>
#include <cstdint>

#include "component.h"
#include "entity.h"
#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "manager.h"

using ::testing::Mock;
using ::testing::NiceMock;
using ::testing::Return;

// TODO move to shared testing file
class TestRenderer : public aronnax::Renderer {
  public:
    TestRenderer() { };
    ~TestRenderer() { };
    void render() { };
    void beforeRender() { };
    void afterRender() { };
};

class MockRenderer: public TestRenderer {
  public:
    MOCK_METHOD0(render, void());
    MOCK_METHOD0(beforeRender, void());
    MOCK_METHOD0(afterRender, void());
};

// TODO move to shared testing file
class MockComponent : public aronnax::Component {
  public:
    MOCK_METHOD2(update, void(aronnax::Entity &entity, const uint32_t dt));
    MOCK_METHOD1(render, void(aronnax::Entity &entity));
    MOCK_METHOD0(getType, std::string());
};

class ManagerTest: public testing::Test {
  protected:
    virtual void SetUp() {
      std::shared_ptr<TestRenderer> tr = std::make_shared<TestRenderer>();
      testManager_ = new aronnax::Manager(tr, testEntities_);
    }

    virtual void TearDown() {
      delete testManager_;
    }

    aronnax::Manager* testManager_;
    aronnax::Entities testEntities_;
    aronnax::Components testComponentList_;
};

TEST(manager, Constructor) {
  std::shared_ptr<TestRenderer> testRenderer = std::make_shared<TestRenderer>();
  aronnax::Manager testManager(testRenderer);
}

TEST_F(ManagerTest, add) {
  NiceMock<MockComponent> testComponent;
  testComponentList_.push_back(&testComponent);

  ON_CALL(testComponent, getType())
      .WillByDefault(Return("TestComponentA"));

  auto actual = testManager_->add(testComponentList_);
  EXPECT_EQ(1, testManager_->getEntities().size());
  EXPECT_EQ(1, testManager_->getEntities().count(actual));

  auto actualComponent = actual.get()->getComponent("TestComponentA");
  EXPECT_EQ(actualComponent, &testComponent);

  actual = testManager_->add(testComponentList_);
  EXPECT_EQ(2, testManager_->getEntities().size());
  EXPECT_EQ(1, testManager_->getEntities().count(actual));
}

TEST_F(ManagerTest, getEntities) {
  aronnax::EntityPtr testEntity = std::make_shared<aronnax::Entity>(
      testComponentList_);
  testEntities_.insert(testEntity);

  std::shared_ptr<TestRenderer> tr = std::make_shared<TestRenderer>();
  auto testManager = new aronnax::Manager(tr, testEntities_);

  auto actual = testManager_->getEntities().size();
  //EXPECT_EQ(1, actual);
}

TEST_F(ManagerTest, render) {
  std::shared_ptr<MockRenderer> mockRenderer = std::make_shared<MockRenderer>();
  auto* testManager = new aronnax::Manager(mockRenderer, testEntities_);

  EXPECT_CALL(*mockRenderer, beforeRender()).Times(1);
  EXPECT_CALL(*mockRenderer, afterRender()).Times(1);

  testManager->render();
  Mock::AllowLeak(mockRenderer.get());
  Mock::VerifyAndClearExpectations(mockRenderer.get());
}
<|endoftext|>


<commit_before>#include "client.h"
#include "controller/taskcontroller.h"
#include "controller/reportcontroller.h"
#include "controller/logincontroller.h"
#include "controller/configcontroller.h"
#include "controller/crashcontroller.h"
#include "network/networkmanager.h"
#include "task/taskexecutor.h"
#include "scheduler/schedulerstorage.h"
#include "report/reportstorage.h"
#include "scheduler/scheduler.h"
#include "settings.h"
#include "log/logger.h"

#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QDebug>
#include <QHostInfo>

#ifdef Q_OS_UNIX
#include <QSocketNotifier>
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>
#endif // Q_OS_UNIX

#ifdef Q_OS_WIN
#include <Windows.h>
#include <stdio.h>
#endif // Q_OS_WIN

// TEST INCLUDES
#include "timing/immediatetiming.h"
#include "timing/timing.h"
#include "task/task.h"
#include "measurement/btc/btc_definition.h"
#include "measurement/http/httpdownload_definition.h"
#include "measurement/ping/ping_definition.h"
#include "measurement/dnslookup/dnslookup_definition.h"
#include "measurement/reverse_dnslookup/reverseDnslookup_definition.h"
#include "measurement/packettrains/packettrainsdefinition.h"
#include "measurement/udpping/udpping_definition.h"
#include "measurement/traceroute/traceroute_definition.h"

LOGGER(Client);

Q_GLOBAL_STATIC(Ntp, ntp)

class Client::Private : public QObject
{
    Q_OBJECT

public:
    Private(Client *q)
    : q(q)
    , status(Client::Unregistered)
    , networkAccessManager(new QNetworkAccessManager(q))
    , schedulerStorage(&scheduler)
    , reportStorage(&reportScheduler)
    {
        executor.setNetworkManager(&networkManager);
        scheduler.setExecutor(&executor);

        connect(&executor, SIGNAL(finished(TestDefinition, Result)), this, SLOT(taskFinished(TestDefinition,
                                                                                Result)));
        connect(&loginController, SIGNAL(finished()), this, SLOT(loginStatusChanged()));
    }

    Client *q;

    // Properties
    Client::Status status;
    QNetworkAccessManager *networkAccessManager;

    TaskExecutor executor;

    Scheduler scheduler;
    SchedulerStorage schedulerStorage;

    ReportScheduler reportScheduler;
    ReportStorage reportStorage;

    Settings settings;
    NetworkManager networkManager;

    TaskController taskController;
    ReportController reportController;
    LoginController loginController;
    ConfigController configController;
    CrashController crashController;

#ifdef Q_OS_UNIX
    static int sigintFd[2];
    static int sighupFd[2];
    static int sigtermFd[2];

    QSocketNotifier *snInt;
    QSocketNotifier *snHup;
    QSocketNotifier *snTerm;

    // Unix signal handlers.
    static void intSignalHandler(int unused);
    static void hupSignalHandler(int unused);
    static void termSignalHandler(int unused);
#endif // Q_OS_UNIX

    // Functions
    void setupUnixSignalHandlers();

#ifdef Q_OS_WIN
    static BOOL CtrlHandler(DWORD ctrlType);
#endif // Q_OS_WIN

public slots:
#ifdef Q_OS_UNIX
    void handleSigInt();
    void handleSigHup();
    void handleSigTerm();
#endif // Q_OS_UNIX
    void taskFinished(const TestDefinition &test, const Result &result);
    void loginStatusChanged();
};

#ifdef Q_OS_UNIX
int Client::Private::sigintFd[2];
int Client::Private::sighupFd[2];
int Client::Private::sigtermFd[2];

void Client::Private::intSignalHandler(int)
{
    char a = 1;
    ::write(sigintFd[0], &a, sizeof(a));
}

void Client::Private::hupSignalHandler(int)
{
    char a = 1;
    ::write(sighupFd[0], &a, sizeof(a));
}

void Client::Private::termSignalHandler(int)
{
    char a = 1;
    ::write(sigtermFd[0], &a, sizeof(a));
}
#endif // Q_OS_UNIX

void Client::Private::setupUnixSignalHandlers()
{
#ifdef Q_OS_UNIX
    struct sigaction Int, hup, term;

    Int.sa_handler = Client::Private::intSignalHandler;
    sigemptyset(&Int.sa_mask);
    Int.sa_flags = 0;
    Int.sa_flags |= SA_RESTART;

    if (sigaction(SIGINT, &Int, 0) > 0)
    {
        return;
    }

    hup.sa_handler = Client::Private::hupSignalHandler;
    sigemptyset(&hup.sa_mask);
    hup.sa_flags = 0;
    hup.sa_flags |= SA_RESTART;

    if (sigaction(SIGHUP, &hup, 0) > 0)
    {
        return;
    }

    term.sa_handler = Client::Private::termSignalHandler;
    sigemptyset(&term.sa_mask);
    term.sa_flags = 0;
    term.sa_flags |= SA_RESTART;

    if (sigaction(SIGTERM, &term, 0) > 0)
    {
        return;
    }

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
    {
        qFatal("Couldn't create INT socketpair");
    }

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
    {
        qFatal("Couldn't create HUP socketpair");
    }

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
    {
        qFatal("Couldn't create TERM socketpair");
    }

    snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
    connect(snInt, SIGNAL(activated(int)), this, SLOT(handleSigInt()));

    snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
    connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));

    snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
    connect(snTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
#elif defined(Q_OS_WIN)
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)Private::CtrlHandler, TRUE);
#endif
}

#ifdef Q_OS_WIN
BOOL Client::Private::CtrlHandler(DWORD ctrlType)
{
    switch (ctrlType)
    {
    case CTRL_C_EVENT:
    case CTRL_CLOSE_EVENT:
        LOG_INFO("Close requested, quitting.");
        qApp->quit();
        return TRUE;

    case CTRL_LOGOFF_EVENT:
    case CTRL_SHUTDOWN_EVENT:
        LOG_INFO("System shutdown or user logout, quitting.");
        qApp->quit();
        return FALSE;

    default:
        return FALSE;
    }
}
#endif // Q_OS_WIN

#ifdef Q_OS_UNIX
void Client::Private::handleSigInt()
{
    snInt->setEnabled(false);
    char tmp;
    ::read(sigintFd[1], &tmp, sizeof(tmp));

    LOG_INFO("Interrupt requested, quitting.");
    qApp->quit();

    snInt->setEnabled(true);
}

void Client::Private::handleSigTerm()
{
    snTerm->setEnabled(false);
    char tmp;
    ::read(sigtermFd[1], &tmp, sizeof(tmp));

    LOG_INFO("Termination requested, quitting.");
    qApp->quit();

    snTerm->setEnabled(true);
}

void Client::Private::handleSigHup()
{
    snHup->setEnabled(false);
    char tmp;
    ::read(sighupFd[1], &tmp, sizeof(tmp));

    LOG_INFO("Hangup detected, quitting.");
    qApp->quit();

    snHup->setEnabled(true);
}
#endif // Q_OS_UNIX

void Client::Private::taskFinished(const TestDefinition &test, const Result &result)
{
    Report report = reportScheduler.reportByTaskId(test.id());

    ResultList results = report.isNull() ? ResultList() : report.results();
    results.append(result);

    if (report.isNull())
    {
        report = Report(test.id(), QDateTime::currentDateTime(), Client::version(), results);
        reportScheduler.addReport(report);
    }
    else
    {
        report.setResults(results);
        reportScheduler.modifyReport(report);
    }
}

void Client::Private::loginStatusChanged()
{
    if (!settings.isPassive() && loginController.registeredDevice())
    {
        taskController.fetchTasks();
    }
}

Client::Client(QObject *parent)
: QObject(parent)
, d(new Private(this))
{
}

Client::~Client()
{
    d->schedulerStorage.storeData();
    d->reportStorage.storeData();
    delete d;
}

Client *Client::instance()
{
    static Client *ins = NULL;

    if (!ins)
    {
        ins = new Client();
    }

    return ins;
}

bool Client::init()
{
    qRegisterMetaType<TestDefinition>();
    qRegisterMetaType<Result>();

    // Get network time from ntp server
    QHostInfo hostInfo = QHostInfo::fromName("ptbtime1.ptb.de");

    if (!hostInfo.addresses().isEmpty())
    {
        QHostAddress ntpServer = hostInfo.addresses().first();
        ntp->sync(ntpServer);
    }
    else
    {
        LOG_WARNING("could not resolve ntp server");
    }

    d->setupUnixSignalHandlers();
    d->settings.init();

    // Initialize storages
    d->schedulerStorage.loadData();
    d->reportStorage.loadData();

    // Initialize controllers
    d->networkManager.init(&d->scheduler, &d->settings);
    d->configController.init(&d->networkManager, &d->settings);
    d->reportController.init(&d->reportScheduler, &d->settings);
    d->loginController.init(&d->networkManager, &d->settings);
    d->crashController.init(&d->networkManager, &d->settings);

    if (!d->settings.isPassive())
    {
        d->taskController.init(&d->networkManager, &d->scheduler, &d->settings);
    }

    return true;
}

bool Client::autoLogin()
{
    if (d->settings.hasLoginData())
    {
        // check if api key is still valid
        d->taskController.fetchTasks();

        return true;
    }

    return false;
}

void Client::btc(const QString &host)
{
    BulkTransportCapacityDefinition btcDef(host, 5106, 1024 * 1024);
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(9, "btc_ma", timing,
                                  btcDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::http(const QString &url)
{
    HTTPDownloadDefinition httpDef(url, false);
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(3, "httpdownload", timing,
                                  httpDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::upnp()
{
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(5, "upnp", timing,
                                  QVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::ping(const QString &host, quint16 count, quint32 timeout, quint32 interval)
{
    PingDefinition pingDef(host.isNull() ? "measure-it.de" : host, count, timeout, interval);
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(4, "ping", timing,
                                  pingDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::dnslookup()
{
    DnslookupDefinition dnslookupDef("www.google.com", "8.8.8.8");
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(8, "dnslookup", timing,
                                  dnslookupDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::reverseDnslookup()
{
    ReverseDnslookupDefinition reverseDnslookupDef("8.8.8.8");
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(9, "reverseDnslookup", timing,
                                  reverseDnslookupDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::packetTrains(QString host, quint16 port, quint16 packetSize, quint16 trainLength, quint8 iterations,
                          quint64 rateMin, quint64 rateMax, quint64 delay)
{
    PacketTrainsDefinition packetTrainsDef(host, port, packetSize, trainLength, iterations, rateMin, rateMax, delay);

    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(11, "packettrains_ma", timing,
                                  packetTrainsDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::udpPing(const QString &url, const quint32 &count, const quint32 &interval, const quint32 &receiveTimeout,
                     const int &ttl, const quint16 &destinationPort, const quint16 &sourcePort, const quint32 &payload)
{
    UdpPingDefinition udpPingDef(url, count, interval, receiveTimeout, ttl, destinationPort, sourcePort, payload);

    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(12, "udpping", timing,
                                  udpPingDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::traceroute(const QString &url,
                        const quint32 &count,
                        const quint32 &interval,
                        const quint32 &receiveTimeout,
                        const quint16 &destinationPort,
                        const quint16 &sourcePort,
                        const quint32 &payload)
{
    TracerouteDefinition tracerouteDef(url, count, interval, receiveTimeout, destinationPort, sourcePort, payload);

    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(13, "traceroute", timing,
                                  tracerouteDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::measureIt()
{
    // Ping
    d->scheduler.executeOnDemandTest(1);

    // BTC
    d->scheduler.executeOnDemandTest(2);

    // HTTP download
    d->scheduler.executeOnDemandTest(3);

    // PacketTrains
    d->scheduler.executeOnDemandTest(4);

    // UdpPing
    d->scheduler.executeOnDemandTest(5);

    // Traceroute
    d->scheduler.executeOnDemandTest(6);
}

void Client::setStatus(Client::Status status)
{
    if (d->status == status)
    {
        return;
    }

    d->status = status;
    emit statusChanged();
}

Client::Status Client::status() const
{
    return d->status;
}

QString Client::version()
{
    return QString("%1.%2.%3").arg(Client::versionMajor).arg(Client::versionMinor).arg(Client::versionPatch);
}

QNetworkAccessManager *Client::networkAccessManager() const
{
    return d->networkAccessManager;
}

Scheduler *Client::scheduler() const
{
    return &d->scheduler;
}

ReportScheduler *Client::reportScheduler() const
{
    return &d->reportScheduler;
}

NetworkManager *Client::networkManager() const
{
    return &d->networkManager;
}

TaskExecutor *Client::taskExecutor() const
{
    return &d->executor;
}

ConfigController *Client::configController() const
{
    return &d->configController;
}

LoginController *Client::loginController() const
{
    return &d->loginController;
}

ReportController *Client::reportController() const
{
    return &d->reportController;
}

TaskController *Client::taskController() const
{
    return &d->taskController;
}

CrashController *Client::crashController() const
{
    return &d->crashController;
}

Settings *Client::settings() const
{
    return &d->settings;
}

#include "client.moc"
<commit_msg>Fixed an evil bug which ignored results of each task on the first run.<commit_after>#include "client.h"
#include "controller/taskcontroller.h"
#include "controller/reportcontroller.h"
#include "controller/logincontroller.h"
#include "controller/configcontroller.h"
#include "controller/crashcontroller.h"
#include "network/networkmanager.h"
#include "task/taskexecutor.h"
#include "scheduler/schedulerstorage.h"
#include "report/reportstorage.h"
#include "scheduler/scheduler.h"
#include "settings.h"
#include "log/logger.h"

#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QDebug>
#include <QHostInfo>

#ifdef Q_OS_UNIX
#include <QSocketNotifier>
#include <sys/socket.h>
#include <signal.h>
#include <unistd.h>
#endif // Q_OS_UNIX

#ifdef Q_OS_WIN
#include <Windows.h>
#include <stdio.h>
#endif // Q_OS_WIN

// TEST INCLUDES
#include "timing/immediatetiming.h"
#include "timing/timing.h"
#include "task/task.h"
#include "measurement/btc/btc_definition.h"
#include "measurement/http/httpdownload_definition.h"
#include "measurement/ping/ping_definition.h"
#include "measurement/dnslookup/dnslookup_definition.h"
#include "measurement/reverse_dnslookup/reverseDnslookup_definition.h"
#include "measurement/packettrains/packettrainsdefinition.h"
#include "measurement/udpping/udpping_definition.h"
#include "measurement/traceroute/traceroute_definition.h"

LOGGER(Client);

Q_GLOBAL_STATIC(Ntp, ntp)

class Client::Private : public QObject
{
    Q_OBJECT

public:
    Private(Client *q)
    : q(q)
    , status(Client::Unregistered)
    , networkAccessManager(new QNetworkAccessManager(q))
    , schedulerStorage(&scheduler)
    , reportStorage(&reportScheduler)
    {
        executor.setNetworkManager(&networkManager);
        scheduler.setExecutor(&executor);

        connect(&executor, SIGNAL(finished(TestDefinition, Result)), this, SLOT(taskFinished(TestDefinition,
                                                                                Result)));
        connect(&loginController, SIGNAL(finished()), this, SLOT(loginStatusChanged()));
    }

    Client *q;

    // Properties
    Client::Status status;
    QNetworkAccessManager *networkAccessManager;

    TaskExecutor executor;

    Scheduler scheduler;
    SchedulerStorage schedulerStorage;

    ReportScheduler reportScheduler;
    ReportStorage reportStorage;

    Settings settings;
    NetworkManager networkManager;

    TaskController taskController;
    ReportController reportController;
    LoginController loginController;
    ConfigController configController;
    CrashController crashController;

#ifdef Q_OS_UNIX
    static int sigintFd[2];
    static int sighupFd[2];
    static int sigtermFd[2];

    QSocketNotifier *snInt;
    QSocketNotifier *snHup;
    QSocketNotifier *snTerm;

    // Unix signal handlers.
    static void intSignalHandler(int unused);
    static void hupSignalHandler(int unused);
    static void termSignalHandler(int unused);
#endif // Q_OS_UNIX

    // Functions
    void setupUnixSignalHandlers();

#ifdef Q_OS_WIN
    static BOOL CtrlHandler(DWORD ctrlType);
#endif // Q_OS_WIN

public slots:
#ifdef Q_OS_UNIX
    void handleSigInt();
    void handleSigHup();
    void handleSigTerm();
#endif // Q_OS_UNIX
    void taskFinished(const TestDefinition &test, const Result &result);
    void loginStatusChanged();
};

#ifdef Q_OS_UNIX
int Client::Private::sigintFd[2];
int Client::Private::sighupFd[2];
int Client::Private::sigtermFd[2];

void Client::Private::intSignalHandler(int)
{
    char a = 1;
    ::write(sigintFd[0], &a, sizeof(a));
}

void Client::Private::hupSignalHandler(int)
{
    char a = 1;
    ::write(sighupFd[0], &a, sizeof(a));
}

void Client::Private::termSignalHandler(int)
{
    char a = 1;
    ::write(sigtermFd[0], &a, sizeof(a));
}
#endif // Q_OS_UNIX

void Client::Private::setupUnixSignalHandlers()
{
#ifdef Q_OS_UNIX
    struct sigaction Int, hup, term;

    Int.sa_handler = Client::Private::intSignalHandler;
    sigemptyset(&Int.sa_mask);
    Int.sa_flags = 0;
    Int.sa_flags |= SA_RESTART;

    if (sigaction(SIGINT, &Int, 0) > 0)
    {
        return;
    }

    hup.sa_handler = Client::Private::hupSignalHandler;
    sigemptyset(&hup.sa_mask);
    hup.sa_flags = 0;
    hup.sa_flags |= SA_RESTART;

    if (sigaction(SIGHUP, &hup, 0) > 0)
    {
        return;
    }

    term.sa_handler = Client::Private::termSignalHandler;
    sigemptyset(&term.sa_mask);
    term.sa_flags = 0;
    term.sa_flags |= SA_RESTART;

    if (sigaction(SIGTERM, &term, 0) > 0)
    {
        return;
    }

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
    {
        qFatal("Couldn't create INT socketpair");
    }

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
    {
        qFatal("Couldn't create HUP socketpair");
    }

    if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
    {
        qFatal("Couldn't create TERM socketpair");
    }

    snInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
    connect(snInt, SIGNAL(activated(int)), this, SLOT(handleSigInt()));

    snHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
    connect(snHup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));

    snTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
    connect(snTerm, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
#elif defined(Q_OS_WIN)
    SetConsoleCtrlHandler((PHANDLER_ROUTINE)Private::CtrlHandler, TRUE);
#endif
}

#ifdef Q_OS_WIN
BOOL Client::Private::CtrlHandler(DWORD ctrlType)
{
    switch (ctrlType)
    {
    case CTRL_C_EVENT:
    case CTRL_CLOSE_EVENT:
        LOG_INFO("Close requested, quitting.");
        qApp->quit();
        return TRUE;

    case CTRL_LOGOFF_EVENT:
    case CTRL_SHUTDOWN_EVENT:
        LOG_INFO("System shutdown or user logout, quitting.");
        qApp->quit();
        return FALSE;

    default:
        return FALSE;
    }
}
#endif // Q_OS_WIN

#ifdef Q_OS_UNIX
void Client::Private::handleSigInt()
{
    snInt->setEnabled(false);
    char tmp;
    ::read(sigintFd[1], &tmp, sizeof(tmp));

    LOG_INFO("Interrupt requested, quitting.");
    qApp->quit();

    snInt->setEnabled(true);
}

void Client::Private::handleSigTerm()
{
    snTerm->setEnabled(false);
    char tmp;
    ::read(sigtermFd[1], &tmp, sizeof(tmp));

    LOG_INFO("Termination requested, quitting.");
    qApp->quit();

    snTerm->setEnabled(true);
}

void Client::Private::handleSigHup()
{
    snHup->setEnabled(false);
    char tmp;
    ::read(sighupFd[1], &tmp, sizeof(tmp));

    LOG_INFO("Hangup detected, quitting.");
    qApp->quit();

    snHup->setEnabled(true);
}
#endif // Q_OS_UNIX

void Client::Private::taskFinished(const TestDefinition &test, const Result &result)
{
    Report report = reportScheduler.reportByTaskId(test.id());

    ResultList results = report.isNull() ? ResultList() : report.results();
    results.append(result);

    if (report.isNull() || results.size() == 1)
    {
        report = Report(test.id(), QDateTime::currentDateTime(), Client::version(), results);
        reportScheduler.addReport(report);
    }
    else
    {
        report.setResults(results);
        reportScheduler.modifyReport(report);
    }
}

void Client::Private::loginStatusChanged()
{
    if (!settings.isPassive() && loginController.registeredDevice())
    {
        taskController.fetchTasks();
    }
}

Client::Client(QObject *parent)
: QObject(parent)
, d(new Private(this))
{
}

Client::~Client()
{
    d->schedulerStorage.storeData();
    d->reportStorage.storeData();
    delete d;
}

Client *Client::instance()
{
    static Client *ins = NULL;

    if (!ins)
    {
        ins = new Client();
    }

    return ins;
}

bool Client::init()
{
    qRegisterMetaType<TestDefinition>();
    qRegisterMetaType<Result>();

    // Get network time from ntp server
    QHostInfo hostInfo = QHostInfo::fromName("ptbtime1.ptb.de");

    if (!hostInfo.addresses().isEmpty())
    {
        QHostAddress ntpServer = hostInfo.addresses().first();
        ntp->sync(ntpServer);
    }
    else
    {
        LOG_WARNING("could not resolve ntp server");
    }

    d->setupUnixSignalHandlers();
    d->settings.init();

    // Initialize storages
    d->schedulerStorage.loadData();
    d->reportStorage.loadData();

    // Initialize controllers
    d->networkManager.init(&d->scheduler, &d->settings);
    d->configController.init(&d->networkManager, &d->settings);
    d->reportController.init(&d->reportScheduler, &d->settings);
    d->loginController.init(&d->networkManager, &d->settings);
    d->crashController.init(&d->networkManager, &d->settings);

    if (!d->settings.isPassive())
    {
        d->taskController.init(&d->networkManager, &d->scheduler, &d->settings);
    }

    return true;
}

bool Client::autoLogin()
{
    if (d->settings.hasLoginData())
    {
        // check if api key is still valid
        d->taskController.fetchTasks();

        return true;
    }

    return false;
}

void Client::btc(const QString &host)
{
    BulkTransportCapacityDefinition btcDef(host, 5106, 1024 * 1024);
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(9, "btc_ma", timing,
                                  btcDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::http(const QString &url)
{
    HTTPDownloadDefinition httpDef(url, false);
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(3, "httpdownload", timing,
                                  httpDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::upnp()
{
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(5, "upnp", timing,
                                  QVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::ping(const QString &host, quint16 count, quint32 timeout, quint32 interval)
{
    PingDefinition pingDef(host.isNull() ? "measure-it.de" : host, count, timeout, interval);
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(4, "ping", timing,
                                  pingDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::dnslookup()
{
    DnslookupDefinition dnslookupDef("www.google.com", "8.8.8.8");
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(8, "dnslookup", timing,
                                  dnslookupDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::reverseDnslookup()
{
    ReverseDnslookupDefinition reverseDnslookupDef("8.8.8.8");
    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(9, "reverseDnslookup", timing,
                                  reverseDnslookupDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::packetTrains(QString host, quint16 port, quint16 packetSize, quint16 trainLength, quint8 iterations,
                          quint64 rateMin, quint64 rateMax, quint64 delay)
{
    PacketTrainsDefinition packetTrainsDef(host, port, packetSize, trainLength, iterations, rateMin, rateMax, delay);

    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(11, "packettrains_ma", timing,
                                  packetTrainsDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::udpPing(const QString &url, const quint32 &count, const quint32 &interval, const quint32 &receiveTimeout,
                     const int &ttl, const quint16 &destinationPort, const quint16 &sourcePort, const quint32 &payload)
{
    UdpPingDefinition udpPingDef(url, count, interval, receiveTimeout, ttl, destinationPort, sourcePort, payload);

    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(12, "udpping", timing,
                                  udpPingDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::traceroute(const QString &url,
                        const quint32 &count,
                        const quint32 &interval,
                        const quint32 &receiveTimeout,
                        const quint16 &destinationPort,
                        const quint16 &sourcePort,
                        const quint32 &payload)
{
    TracerouteDefinition tracerouteDef(url, count, interval, receiveTimeout, destinationPort, sourcePort, payload);

    TimingPtr timing(new ImmediateTiming());
    TestDefinition testDefinition(13, "traceroute", timing,
                                  tracerouteDef.toVariant());
    d->scheduler.enqueue(testDefinition);
}

void Client::measureIt()
{
    // Ping
    d->scheduler.executeOnDemandTest(1);

    // BTC
    d->scheduler.executeOnDemandTest(2);

    // HTTP download
    d->scheduler.executeOnDemandTest(3);

    // PacketTrains
    d->scheduler.executeOnDemandTest(4);

    // UdpPing
    d->scheduler.executeOnDemandTest(5);

    // Traceroute
    d->scheduler.executeOnDemandTest(6);
}

void Client::setStatus(Client::Status status)
{
    if (d->status == status)
    {
        return;
    }

    d->status = status;
    emit statusChanged();
}

Client::Status Client::status() const
{
    return d->status;
}

QString Client::version()
{
    return QString("%1.%2.%3").arg(Client::versionMajor).arg(Client::versionMinor).arg(Client::versionPatch);
}

QNetworkAccessManager *Client::networkAccessManager() const
{
    return d->networkAccessManager;
}

Scheduler *Client::scheduler() const
{
    return &d->scheduler;
}

ReportScheduler *Client::reportScheduler() const
{
    return &d->reportScheduler;
}

NetworkManager *Client::networkManager() const
{
    return &d->networkManager;
}

TaskExecutor *Client::taskExecutor() const
{
    return &d->executor;
}

ConfigController *Client::configController() const
{
    return &d->configController;
}

LoginController *Client::loginController() const
{
    return &d->loginController;
}

ReportController *Client::reportController() const
{
    return &d->reportController;
}

TaskController *Client::taskController() const
{
    return &d->taskController;
}

CrashController *Client::crashController() const
{
    return &d->crashController;
}

Settings *Client::settings() const
{
    return &d->settings;
}

#include "client.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017-2018 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <boost/io/ios_state.hpp>
#include <vcf2multialign/check_overlapping_non_nested_variants.hh>
#include <vcf2multialign/check_ploidy.hh>
#include <vcf2multialign/read_single_fasta_seq.hh>
#include <vcf2multialign/generate_context_base.hh>
#include <vcf2multialign/variant_format.hh>

namespace lb	= libbio;
namespace v2m	= vcf2multialign;

namespace {

	bool compare_references(
		v2m::vector_type const &ref,
		std::string_view const &var_ref,
		std::size_t const var_pos,
		std::size_t /* out */ &idx
	)
	{
		char const *var_ref_data(var_ref.data());
		auto const var_ref_len(var_ref.size());

		char const *ref_data(ref.data());
		auto const ref_len(ref.size());

		if (! (var_pos + var_ref_len <= ref_len))
		{
			idx = 0;
			return false;
		}

		auto const var_ref_end(var_ref_data + var_ref_len);
		auto const p(std::mismatch(var_ref_data, var_ref_end, ref_data + var_pos));
		if (var_ref_end != p.first)
		{
			idx = p.first - var_ref_data;
			return false;
		}

		return true;
	}
}

namespace vcf2multialign {

	void generate_context_base::open_files(
		char const *reference_fname,
		char const *ref_seq_name,
		char const *variants_fname,
		char const *report_fname
	)
	{
		lb::mmap_handle <char> ref_handle;
		ref_handle.open(reference_fname);

		m_vcf_handle.open(variants_fname);
		m_vcf_input.reset_range();

		if (report_fname)
		{
			auto const mode(lb::make_writing_open_mode({
				lb::writing_open_mode::CREATE,
				(m_should_overwrite_files ? lb::writing_open_mode::OVERWRITE : lb::writing_open_mode::NONE)
			}));

			lb::open_file_for_writing(report_fname, m_error_logger.output_stream(), mode);
			m_error_logger.write_header();
		}

		lb::add_reserved_info_keys(m_vcf_reader.info_fields());
		lb::add_reserved_genotype_keys(m_vcf_reader.genotype_fields());

		m_vcf_reader.set_variant_format(new variant_format());
		m_vcf_reader.set_input(m_vcf_input);
		m_vcf_reader.fill_buffer();
		m_vcf_reader.read_header();

		// Read the reference file and place its contents into reference.
		read_single_fasta_seq(ref_handle, m_reference, ref_seq_name);
	}

	void generate_context_base::check_ploidy()
	{
		::vcf2multialign::check_ploidy(m_vcf_reader, m_ploidy);
	}

	void generate_context_base::check_ref()
	{
		m_vcf_reader.reset();
		m_vcf_reader.set_parsed_fields(lb::vcf_field::REF);
		bool found_mismatch(false);
		std::size_t i(0);

		bool should_continue(false);
		do {
			m_vcf_reader.fill_buffer();
			should_continue = m_vcf_reader.parse(
				[this, &found_mismatch, &i]
				(lb::transient_variant const &var)
				-> bool
			{
				if (0 == m_chromosome_name.size() || var.chrom_id() == m_chromosome_name)
				{
					auto const var_ref(var.ref());
					auto const var_pos(var.zero_based_pos());
					auto const lineno(var.lineno());
					std::size_t diff_pos{0};

					if (!compare_references(m_reference, var_ref, var_pos, diff_pos))
					{
						if (!found_mismatch)
						{
							found_mismatch = true;
							std::cerr
								<< "Reference differs from the variant file on line "
								<< lineno
								<< " (and possibly others)."
								<< std::endl;
						}

						m_error_logger.log_ref_mismatch(lineno, diff_pos);
					}
				}

				++i;
				if (0 == i % 100000)
					std::cerr << "Handled " << i << " variants…" << std::endl;

				return true;
			});
		} while (should_continue);
	}

	void generate_context_base::finish()
	{
		// Save the stream state.
		boost::io::ios_flags_saver ifs(std::cerr);

		// Change FP notation.
		std::cerr << std::fixed;

		auto const end_time(std::chrono::system_clock::now());
		std::chrono::duration <double> elapsed_seconds(end_time - m_start_time);
		std::cerr << "Sequence generation took " << (elapsed_seconds.count() / 60.0) << " minutes in total." << std::endl;

		// After calling cleanup *this is no longer valid.
		//std::cerr << "Calling cleanup" << std::endl;
		cleanup();

		//std::cerr << "Calling exit" << std::endl;
		exit(EXIT_SUCCESS);
	}

	void generate_context_base::load_and_generate(bool const should_check_ref)
	{
		// Check ploidy from the first record.
		std::cerr << "Checking ploidy…" << std::endl;
		check_ploidy();

		// Compare REF to the reference vector.
		if (should_check_ref)
		{
			std::cerr << "Comparing the REF column to the reference…" << std::endl;
			check_ref();
		}

		// List variants that conflict, i.e. overlap but are not nested.
		// Also mark structural variants that cannot be handled.
		{
			std::cerr << "Checking overlapping variants…" << std::endl;
			auto const conflict_count(check_overlapping_non_nested_variants(
				m_vcf_reader,
				m_chromosome_name,
				m_skipped_variants,
				m_error_logger
			));

			auto const skipped_count(m_skipped_variants.size());
			if (0 == skipped_count)
				std::cerr << "Found no conflicting variants." << std::endl;
			else
			{
				std::cerr << "Found " << conflict_count << " conflicts in total." << std::endl;
				std::cerr << "Number of variants to be skipped: " << m_skipped_variants.size() << std::endl;
			}
		}
	}
}
<commit_msg>Read the reference before starting to process the variant file<commit_after>/*
 * Copyright (c) 2017-2018 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <boost/io/ios_state.hpp>
#include <vcf2multialign/check_overlapping_non_nested_variants.hh>
#include <vcf2multialign/check_ploidy.hh>
#include <vcf2multialign/read_single_fasta_seq.hh>
#include <vcf2multialign/generate_context_base.hh>
#include <vcf2multialign/variant_format.hh>

namespace lb	= libbio;
namespace v2m	= vcf2multialign;

namespace {

	bool compare_references(
		v2m::vector_type const &ref,
		std::string_view const &var_ref,
		std::size_t const var_pos,
		std::size_t /* out */ &idx
	)
	{
		char const *var_ref_data(var_ref.data());
		auto const var_ref_len(var_ref.size());

		char const *ref_data(ref.data());
		auto const ref_len(ref.size());

		if (! (var_pos + var_ref_len <= ref_len))
		{
			idx = 0;
			return false;
		}

		auto const var_ref_end(var_ref_data + var_ref_len);
		auto const p(std::mismatch(var_ref_data, var_ref_end, ref_data + var_pos));
		if (var_ref_end != p.first)
		{
			idx = p.first - var_ref_data;
			return false;
		}

		return true;
	}
}

namespace vcf2multialign {

	void generate_context_base::open_files(
		char const *reference_fname,
		char const *ref_seq_name,
		char const *variants_fname,
		char const *report_fname
	)
	{
		lb::mmap_handle <char> ref_handle;
		ref_handle.open(reference_fname);

		// Read the reference file and place its contents into reference.
		read_single_fasta_seq(ref_handle, m_reference, ref_seq_name);

		// Open the variant file.
		m_vcf_handle.open(variants_fname);
		m_vcf_input.reset_range();

		if (report_fname)
		{
			auto const mode(lb::make_writing_open_mode({
				lb::writing_open_mode::CREATE,
				(m_should_overwrite_files ? lb::writing_open_mode::OVERWRITE : lb::writing_open_mode::NONE)
			}));

			lb::open_file_for_writing(report_fname, m_error_logger.output_stream(), mode);
			m_error_logger.write_header();
		}

		lb::add_reserved_info_keys(m_vcf_reader.info_fields());
		lb::add_reserved_genotype_keys(m_vcf_reader.genotype_fields());

		m_vcf_reader.set_variant_format(new variant_format());
		m_vcf_reader.set_input(m_vcf_input);
		m_vcf_reader.fill_buffer();
		m_vcf_reader.read_header();
	}

	void generate_context_base::check_ploidy()
	{
		::vcf2multialign::check_ploidy(m_vcf_reader, m_ploidy);
	}

	void generate_context_base::check_ref()
	{
		m_vcf_reader.reset();
		m_vcf_reader.set_parsed_fields(lb::vcf_field::REF);
		bool found_mismatch(false);
		std::size_t i(0);

		bool should_continue(false);
		do {
			m_vcf_reader.fill_buffer();
			should_continue = m_vcf_reader.parse(
				[this, &found_mismatch, &i]
				(lb::transient_variant const &var)
				-> bool
			{
				if (0 == m_chromosome_name.size() || var.chrom_id() == m_chromosome_name)
				{
					auto const var_ref(var.ref());
					auto const var_pos(var.zero_based_pos());
					auto const lineno(var.lineno());
					std::size_t diff_pos{0};

					if (!compare_references(m_reference, var_ref, var_pos, diff_pos))
					{
						if (!found_mismatch)
						{
							found_mismatch = true;
							std::cerr
								<< "Reference differs from the variant file on line "
								<< lineno
								<< " (and possibly others)."
								<< std::endl;
						}

						m_error_logger.log_ref_mismatch(lineno, diff_pos);
					}
				}

				++i;
				if (0 == i % 100000)
					std::cerr << "Handled " << i << " variants…" << std::endl;

				return true;
			});
		} while (should_continue);
	}

	void generate_context_base::finish()
	{
		// Save the stream state.
		boost::io::ios_flags_saver ifs(std::cerr);

		// Change FP notation.
		std::cerr << std::fixed;

		auto const end_time(std::chrono::system_clock::now());
		std::chrono::duration <double> elapsed_seconds(end_time - m_start_time);
		std::cerr << "Sequence generation took " << (elapsed_seconds.count() / 60.0) << " minutes in total." << std::endl;

		// After calling cleanup *this is no longer valid.
		//std::cerr << "Calling cleanup" << std::endl;
		cleanup();

		//std::cerr << "Calling exit" << std::endl;
		exit(EXIT_SUCCESS);
	}

	void generate_context_base::load_and_generate(bool const should_check_ref)
	{
		// Check ploidy from the first record.
		std::cerr << "Checking ploidy…" << std::endl;
		check_ploidy();

		// Compare REF to the reference vector.
		if (should_check_ref)
		{
			std::cerr << "Comparing the REF column to the reference…" << std::endl;
			check_ref();
		}

		// List variants that conflict, i.e. overlap but are not nested.
		// Also mark structural variants that cannot be handled.
		{
			std::cerr << "Checking overlapping variants…" << std::endl;
			auto const conflict_count(check_overlapping_non_nested_variants(
				m_vcf_reader,
				m_chromosome_name,
				m_skipped_variants,
				m_error_logger
			));

			auto const skipped_count(m_skipped_variants.size());
			if (0 == skipped_count)
				std::cerr << "Found no conflicting variants." << std::endl;
			else
			{
				std::cerr << "Found " << conflict_count << " conflicts in total." << std::endl;
				std::cerr << "Number of variants to be skipped: " << m_skipped_variants.size() << std::endl;
			}
		}
	}
}
<|endoftext|>


<commit_before>// File:  combinedLogger.cpp
// Date:  9/3/2013
// Auth:  K. Loux
// Copy:  (c) Kerry Loux 2013
// Desc:  Logging object that permits writing to multiple logs simultaneously
//        and from multiple threads.

// Standard C++ headers
#include <cassert>

// Local headers
#include "combinedLogger.h"

//==========================================================================
// Class:			CombinedLogger
// Function:		Add
//
// Description:		Adds a log sink to the vector.  Takes ownership of the log.
//
// Input Arguments:
//		log		= std::unique_ptr<std::ostream>
//
// Output Arguments:
//		None
//
// Return Value:
//		None
//
//==========================================================================
void CombinedLogger::Add(std::unique_ptr<std::ostream> log)
{
	assert(log);
	std::lock_guard<std::mutex> lock(logMutex);
	ownedLogs.push_back(std::move(log));
	allLogs.push_back(ownedLogs.back().get());
}

//==========================================================================
// Class:			CombinedLogger
// Function:		Add
//
// Description:		Adds a log sink to the vector.  Caller retains ownership.
//
// Input Arguments:
//		log		= std::ostream&
//
// Output Arguments:
//		None
//
// Return Value:
//		None
//
//==========================================================================
void CombinedLogger::Add(std::ostream& log)
{
	assert(log);
	std::lock_guard<std::mutex> lock(logMutex);
	allLogs.push_back(&log);
}

//==========================================================================
// Class:			CombinedLogger::CombinedStreamBuffer
// Function:		overflow
//
// Description:		Override of the standard overflow method.  Called when
//					new data is inserted into the stream.  This is overridden
//					so we can control which buffer the data is inserted into.
//					The buffers are controlled on a per-thread basis.
//
// Input Arguments:
//		c	= int
//
// Output Arguments:
//		None
//
// Return Value:
//		int
//
//==========================================================================
int CombinedLogger::CombinedStreamBuffer::overflow(int c)
{
	CreateThreadBuffer();
	if (c != traits_type::eof())
	{
		// Allow other threads to continue to buffer to the stream, even if
		// another thread is writing to the logs in sync() (so we don't lock
		// the buffer mutex here)
		const auto tb(threadBuffer);
		*tb.find(std::this_thread::get_id())->second << static_cast<char>(c);
	}

	return c;
}

//==========================================================================
// Class:			CombinedLogger::CombinedStreamBuffer
// Function:		sync
//
// Description:		Override of the standard sync method.  Called when an
//					endl object is passed to the stream.  This prints the
//					contents of the current thread's buffer to the output
//					stream, then clears the buffer.
//
// Input Arguments:
//		None
//
// Output Arguments:
//		None
//
// Return Value:
//		int
//
//==========================================================================
int CombinedLogger::CombinedStreamBuffer::sync()
{
	assert(log.allLogs.size() > 0);// Make sure we didn't forget to add logs

	int result(0);
	const std::thread::id id(std::this_thread::get_id());

	CreateThreadBuffer();// Before mutex locker, because this might lock the mutex, too
	std::lock_guard<std::mutex> lock(bufferMutex);

	{
		std::lock_guard<std::mutex> logLock(log.logMutex);

		for (auto& l : log.allLogs)
		{
			if ((*l << threadBuffer[id]->str()).fail())
				result = -1;
			l->flush();
		}
	}

	// Clear out the buffer
	threadBuffer[id]->str("");
	str("");

	return result;
}

//==========================================================================
// Class:			CombinedLogger::CombinedStreamBuffer
// Function:		CreateThreadBuffer
//
// Description:		Checks for existance of a buffer for the current thread,
//					and creates the buffer if it doesn't exist.
//
// Input Arguments:
//		None
//
// Output Arguments:
//		None
//
// Return Value:
//		None
//
//==========================================================================
void CombinedLogger::CombinedStreamBuffer::CreateThreadBuffer()
{
	const std::thread::id id(std::this_thread::get_id());
	if (threadBuffer.find(id) == threadBuffer.end())
	{
		std::lock_guard<std::mutex> lock(bufferMutex);
		if (threadBuffer.find(id) == threadBuffer.end())
			threadBuffer[id] = std::make_unique<std::ostringstream>();
	}
}
<commit_msg>CombinedLogger compiles again<commit_after>// File:  combinedLogger.cpp
// Date:  9/3/2013
// Auth:  K. Loux
// Copy:  (c) Kerry Loux 2013
// Desc:  Logging object that permits writing to multiple logs simultaneously
//        and from multiple threads.

// Standard C++ headers
#include <cassert>

// Local headers
#include "combinedLogger.h"

//==========================================================================
// Class:			CombinedLogger
// Function:		Add
//
// Description:		Adds a log sink to the vector.  Takes ownership of the log.
//
// Input Arguments:
//		log		= std::unique_ptr<std::ostream>
//
// Output Arguments:
//		None
//
// Return Value:
//		None
//
//==========================================================================
void CombinedLogger::Add(std::unique_ptr<std::ostream> log)
{
	assert(log);
	std::lock_guard<std::mutex> lock(logMutex);
	ownedLogs.push_back(std::move(log));
	allLogs.push_back(ownedLogs.back().get());
}

//==========================================================================
// Class:			CombinedLogger
// Function:		Add
//
// Description:		Adds a log sink to the vector.  Caller retains ownership.
//
// Input Arguments:
//		log		= std::ostream&
//
// Output Arguments:
//		None
//
// Return Value:
//		None
//
//==========================================================================
void CombinedLogger::Add(std::ostream& log)
{
	assert(log);
	std::lock_guard<std::mutex> lock(logMutex);
	allLogs.push_back(&log);
}

//==========================================================================
// Class:			CombinedLogger::CombinedStreamBuffer
// Function:		overflow
//
// Description:		Override of the standard overflow method.  Called when
//					new data is inserted into the stream.  This is overridden
//					so we can control which buffer the data is inserted into.
//					The buffers are controlled on a per-thread basis.
//
// Input Arguments:
//		c	= int
//
// Output Arguments:
//		None
//
// Return Value:
//		int
//
//==========================================================================
int CombinedLogger::CombinedStreamBuffer::overflow(int c)
{
	CreateThreadBuffer();
	if (c != traits_type::eof())
	{
		// Allow other threads to continue to buffer to the stream, even if
		// another thread is writing to the logs in sync() (so we don't lock
		// the buffer mutex here)
		const auto& tb(threadBuffer);
		*tb.find(std::this_thread::get_id())->second << static_cast<char>(c);
	}

	return c;
}

//==========================================================================
// Class:			CombinedLogger::CombinedStreamBuffer
// Function:		sync
//
// Description:		Override of the standard sync method.  Called when an
//					endl object is passed to the stream.  This prints the
//					contents of the current thread's buffer to the output
//					stream, then clears the buffer.
//
// Input Arguments:
//		None
//
// Output Arguments:
//		None
//
// Return Value:
//		int
//
//==========================================================================
int CombinedLogger::CombinedStreamBuffer::sync()
{
	assert(log.allLogs.size() > 0);// Make sure we didn't forget to add logs

	int result(0);
	const std::thread::id id(std::this_thread::get_id());

	CreateThreadBuffer();// Before mutex locker, because this might lock the mutex, too
	std::lock_guard<std::mutex> lock(bufferMutex);

	{
		std::lock_guard<std::mutex> logLock(log.logMutex);

		for (auto& l : log.allLogs)
		{
			if ((*l << threadBuffer[id]->str()).fail())
				result = -1;
			l->flush();
		}
	}

	// Clear out the buffer
	threadBuffer[id]->str("");
	str("");

	return result;
}

//==========================================================================
// Class:			CombinedLogger::CombinedStreamBuffer
// Function:		CreateThreadBuffer
//
// Description:		Checks for existance of a buffer for the current thread,
//					and creates the buffer if it doesn't exist.
//
// Input Arguments:
//		None
//
// Output Arguments:
//		None
//
// Return Value:
//		None
//
//==========================================================================
void CombinedLogger::CombinedStreamBuffer::CreateThreadBuffer()
{
	const std::thread::id id(std::this_thread::get_id());
	if (threadBuffer.find(id) == threadBuffer.end())
	{
		std::lock_guard<std::mutex> lock(bufferMutex);
		if (threadBuffer.find(id) == threadBuffer.end())
			threadBuffer[id] = std::make_unique<std::ostringstream>();
	}
}
<|endoftext|>


<commit_before>#include "eosio.system.hpp"
#include <eosiolib/dispatcher.hpp>

#include "delegate_bandwidth.cpp"
#include "producer_pay.cpp"
#include "voting.cpp"
#include "exchange_state.cpp"

namespace eosiosystem {

   system_contract::system_contract( account_name s )
   :native(s),
    _voters(_self,_self),
    _producers(_self,_self),
    _global(_self,_self),
    _rammarket(_self,_self)
   {
      //print( "construct system\n" );
      _gstate = _global.exists() ? _global.get() : get_default_parameters();

      auto itr = _rammarket.find(S(4,RAMCORE));

      if( itr == _rammarket.end() ) {
         auto system_token_supply   = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount;
         if( system_token_supply > 0 ) {
            itr = _rammarket.emplace( _self, [&]( auto& m ) {
               m.supply.amount = 100000000000000ll;
               m.supply.symbol = S(4,RAMCORE);
               m.base.balance.amount = int64_t(_gstate.free_ram());
               m.base.balance.symbol = S(0,RAM);
               m.quote.balance.amount = system_token_supply / 1000;
               m.quote.balance.symbol = CORE_SYMBOL;
            });
         }
      } else {
         //print( "ram market already created" );
      }
   }

   eosio_global_state system_contract::get_default_parameters() {
      eosio_global_state dp;
      get_blockchain_parameters(dp);
      return dp;
   }

   system_contract::~system_contract() {
      //print( "destruct system\n" );
      _global.set( _gstate, _self );
      //eosio_exit(0);
   }

   void system_contract::setram( uint64_t max_ram_size ) {
      require_auth( _self );

      eosio_assert( max_ram_size < 1024ll*1024*1024*1024*1024, "ram size is unrealistic" );
      eosio_assert( max_ram_size > _gstate.total_ram_bytes_reserved, "attempt to set max below reserved" );

      auto delta = int64_t(max_ram_size) - int64_t(_gstate.max_ram_size);
      auto itr = _rammarket.find(S(4,RAMCORE));

      /**
       *  Increase or decrease the amount of ram for sale based upon the change in max
       *  ram size.
       */
      _rammarket.modify( itr, 0, [&]( auto& m ) {
         m.base.balance.amount += delta;
      });

      _gstate.max_ram_size = max_ram_size;
      _global.set( _gstate, _self );
   }

   void system_contract::setpriv( account_name account, uint8_t ispriv ) {
      require_auth( _self );
      set_privileged( account, ispriv );
   }

   void system_contract::bidname( account_name bidder, account_name newname, asset bid ) {
      require_auth( bidder );
      eosio_assert( eosio::name_suffix(newname) == newname, "you can only bid on top-level suffix" );
      eosio_assert( !is_account( newname ), "account already exists" );
      eosio_assert( bid.symbol == asset().symbol, "asset must be system token" );
      eosio_assert( bid.amount > 0, "insufficient bid" );

      INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {bidder,N(active)},
                                                    { bidder, N(eosio), bid, std::string("bid name ")+(name{newname}).to_string()  } );

      name_bid_table bids(_self,_self);
      print( name{bidder}, " bid ", bid, " on ", name{newname}, "\n" );
      auto current = bids.find( newname );
      if( current == bids.end() ) {
         bids.emplace( bidder, [&]( auto& b ) {
            b.newname = newname;
            b.high_bidder = bidder;
            b.high_bid = bid.amount;
            b.last_bid_time = current_time();
         });
      } else {
         eosio_assert( current->high_bid > 0, "this auction has already closed" );
         eosio_assert( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" );
         eosio_assert( current->high_bidder != bidder, "account is already high bidder" );

         INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)},
                                                       { N(eosio), current->high_bidder, asset(current->high_bid),
                                                       std::string("refund bid on name ")+(name{newname}).to_string()  } );

         bids.modify( current, bidder, [&]( auto& b ) {
            b.high_bidder = bidder;
            b.high_bid = bid.amount;
            b.last_bid_time = current_time();
         });
      }
   }

   /**
    *  Called after a new account is created. This code enforces resource-limits rules
    *  for new accounts as well as new account naming conventions.
    *
    *  1. accounts cannot contain '.' symbols which forces all acccounts to be 12
    *  characters long without '.' until a future account auction process is implemented
    *  which prevents name squatting.
    *
    *  2. new accounts must stake a minimal number of tokens (as set in system parameters)
    *     therefore, this method will execute an inline buyram from receiver for newacnt in
    *     an amount equal to the current new account creation fee.
    */
   void native::newaccount( account_name     creator,
                            account_name     newact
                            /*  no need to parse authorites
                            const authority& owner,
                            const authority& active*/ ) {

      if( creator != _self ) {
         auto tmp = newact;
         bool has_dot = false;
         for( uint32_t i = 0; i < 13; ++i ) {
           has_dot |= (tmp >> 59);
           tmp <<= 5;
         }
         auto suffix = eosio::name_suffix(newact);
         if( has_dot ) {
            if( suffix == newact ) {
               name_bid_table bids(_self,_self);
               auto current = bids.find( newact );
               eosio_assert( current != bids.end(), "no active bid for name" );
               eosio_assert( current->high_bidder == creator, "only high bidder can claim" );
               eosio_assert( current->high_bid < 0, "auction for name is not closed yet" );
               bids.erase( current );
            } else {
               eosio_assert( creator == suffix, "only suffix may create this account" );
            }
         }
      }

      user_resources_table  userres( _self, newact);

      userres.emplace( newact, [&]( auto& res ) {
        res.owner = newact;
      });

      set_resource_limits( newact, 0, 0, 0 );
   }

} /// eosio.system

EOSIO_ABI( eosiosystem::system_contract,
     (setram)
     // delegate_bandwith.cpp
     (delegatebw)(undelegatebw)(refund)
     (buyram)(buyrambytes)(sellram)
     // voting.cpp
     // producer_pay.cpp
     (regproxy)(regproducer)(unregprod)(voteproducer)
     (claimrewards)
     // native.hpp
     (onblock)
     (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(postrecovery)(passrecovery)(vetorecovery)(onerror)(canceldelay)
     //this file
     (bidname)
     (setpriv)
)
<commit_msg>system contract should only allow producers to increase ram #3302<commit_after>#include "eosio.system.hpp"
#include <eosiolib/dispatcher.hpp>

#include "delegate_bandwidth.cpp"
#include "producer_pay.cpp"
#include "voting.cpp"
#include "exchange_state.cpp"

namespace eosiosystem {

   system_contract::system_contract( account_name s )
   :native(s),
    _voters(_self,_self),
    _producers(_self,_self),
    _global(_self,_self),
    _rammarket(_self,_self)
   {
      //print( "construct system\n" );
      _gstate = _global.exists() ? _global.get() : get_default_parameters();

      auto itr = _rammarket.find(S(4,RAMCORE));

      if( itr == _rammarket.end() ) {
         auto system_token_supply   = eosio::token(N(eosio.token)).get_supply(eosio::symbol_type(system_token_symbol).name()).amount;
         if( system_token_supply > 0 ) {
            itr = _rammarket.emplace( _self, [&]( auto& m ) {
               m.supply.amount = 100000000000000ll;
               m.supply.symbol = S(4,RAMCORE);
               m.base.balance.amount = int64_t(_gstate.free_ram());
               m.base.balance.symbol = S(0,RAM);
               m.quote.balance.amount = system_token_supply / 1000;
               m.quote.balance.symbol = CORE_SYMBOL;
            });
         }
      } else {
         //print( "ram market already created" );
      }
   }

   eosio_global_state system_contract::get_default_parameters() {
      eosio_global_state dp;
      get_blockchain_parameters(dp);
      return dp;
   }

   system_contract::~system_contract() {
      //print( "destruct system\n" );
      _global.set( _gstate, _self );
      //eosio_exit(0);
   }

   void system_contract::setram( uint64_t max_ram_size ) {
      require_auth( _self );

      eosio_assert( _gstate.max_ram_size < max_ram_size, "ram can only be increased" ); /// decreasing ram might result market maker issues
      eosio_assert( max_ram_size < 1024ll*1024*1024*1024*1024, "ram size is unrealistic" );
      eosio_assert( max_ram_size > _gstate.total_ram_bytes_reserved, "attempt to set max below reserved" );

      auto delta = int64_t(max_ram_size) - int64_t(_gstate.max_ram_size);
      auto itr = _rammarket.find(S(4,RAMCORE));

      /**
       *  Increase or decrease the amount of ram for sale based upon the change in max
       *  ram size.
       */
      _rammarket.modify( itr, 0, [&]( auto& m ) {
         m.base.balance.amount += delta;
      });

      _gstate.max_ram_size = max_ram_size;
      _global.set( _gstate, _self );
   }

   void system_contract::setpriv( account_name account, uint8_t ispriv ) {
      require_auth( _self );
      set_privileged( account, ispriv );
   }

   void system_contract::bidname( account_name bidder, account_name newname, asset bid ) {
      require_auth( bidder );
      eosio_assert( eosio::name_suffix(newname) == newname, "you can only bid on top-level suffix" );
      eosio_assert( !is_account( newname ), "account already exists" );
      eosio_assert( bid.symbol == asset().symbol, "asset must be system token" );
      eosio_assert( bid.amount > 0, "insufficient bid" );

      INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {bidder,N(active)},
                                                    { bidder, N(eosio), bid, std::string("bid name ")+(name{newname}).to_string()  } );

      name_bid_table bids(_self,_self);
      print( name{bidder}, " bid ", bid, " on ", name{newname}, "\n" );
      auto current = bids.find( newname );
      if( current == bids.end() ) {
         bids.emplace( bidder, [&]( auto& b ) {
            b.newname = newname;
            b.high_bidder = bidder;
            b.high_bid = bid.amount;
            b.last_bid_time = current_time();
         });
      } else {
         eosio_assert( current->high_bid > 0, "this auction has already closed" );
         eosio_assert( bid.amount - current->high_bid > (current->high_bid / 10), "must increase bid by 10%" );
         eosio_assert( current->high_bidder != bidder, "account is already high bidder" );

         INLINE_ACTION_SENDER(eosio::token, transfer)( N(eosio.token), {N(eosio),N(active)},
                                                       { N(eosio), current->high_bidder, asset(current->high_bid),
                                                       std::string("refund bid on name ")+(name{newname}).to_string()  } );

         bids.modify( current, bidder, [&]( auto& b ) {
            b.high_bidder = bidder;
            b.high_bid = bid.amount;
            b.last_bid_time = current_time();
         });
      }
   }

   /**
    *  Called after a new account is created. This code enforces resource-limits rules
    *  for new accounts as well as new account naming conventions.
    *
    *  1. accounts cannot contain '.' symbols which forces all acccounts to be 12
    *  characters long without '.' until a future account auction process is implemented
    *  which prevents name squatting.
    *
    *  2. new accounts must stake a minimal number of tokens (as set in system parameters)
    *     therefore, this method will execute an inline buyram from receiver for newacnt in
    *     an amount equal to the current new account creation fee.
    */
   void native::newaccount( account_name     creator,
                            account_name     newact
                            /*  no need to parse authorites
                            const authority& owner,
                            const authority& active*/ ) {

      if( creator != _self ) {
         auto tmp = newact;
         bool has_dot = false;
         for( uint32_t i = 0; i < 13; ++i ) {
           has_dot |= (tmp >> 59);
           tmp <<= 5;
         }
         auto suffix = eosio::name_suffix(newact);
         if( has_dot ) {
            if( suffix == newact ) {
               name_bid_table bids(_self,_self);
               auto current = bids.find( newact );
               eosio_assert( current != bids.end(), "no active bid for name" );
               eosio_assert( current->high_bidder == creator, "only high bidder can claim" );
               eosio_assert( current->high_bid < 0, "auction for name is not closed yet" );
               bids.erase( current );
            } else {
               eosio_assert( creator == suffix, "only suffix may create this account" );
            }
         }
      }

      user_resources_table  userres( _self, newact);

      userres.emplace( newact, [&]( auto& res ) {
        res.owner = newact;
      });

      set_resource_limits( newact, 0, 0, 0 );
   }

} /// eosio.system

EOSIO_ABI( eosiosystem::system_contract,
     (setram)
     // delegate_bandwith.cpp
     (delegatebw)(undelegatebw)(refund)
     (buyram)(buyrambytes)(sellram)
     // voting.cpp
     // producer_pay.cpp
     (regproxy)(regproducer)(unregprod)(voteproducer)
     (claimrewards)
     // native.hpp
     (onblock)
     (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(postrecovery)(passrecovery)(vetorecovery)(onerror)(canceldelay)
     //this file
     (bidname)
     (setpriv)
)
<|endoftext|>


<commit_before>/*
This file is part of cphVB and copyright (c) 2012 the cphVB team:
http://cphvb.bitbucket.org

cphVB 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 3
of the License, or (at your option) any later version.

cphVB 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 General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with cphVB.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <cphvb.h>
#include <cassert>
#include <map>
#include <set>
#include <StaticStore.hpp>
#include "cphvb_vem_cluster.h"
#include "dispatch.h"
#include "pgrid.h"
#include "exec.h"
#include "darray_extension.h"

//Local array information and storage
static std::map<cphvb_intp, cphvb_array*> map_dary2ary;
static std::map<cphvb_array*,darray*> map_ary2dary;
static StaticStore<darray> ary_store(512);

int main()
{
    dispatch_msg *msg;
    cphvb_error e;

    //Initiate the process grid
    if((e = pgrid_init()) != CPHVB_SUCCESS)
        return e;

    while(1)
    {
        if((e = dispatch_reset()) != CPHVB_SUCCESS)
            return e;

        if((e = dispatch_recv(&msg)) != CPHVB_SUCCESS)
            return e;

        switch(msg->type)
        {
            case CPHVB_CLUSTER_DISPATCH_INIT:
            {
                char *name = msg->payload;
                printf("Slave (rank %d) received INIT. name: %s\n", pgrid_myrank, name);
                if((e = exec_init(name)) != CPHVB_SUCCESS)
                    return e;
                break;
            }
            case CPHVB_CLUSTER_DISPATCH_SHUTDOWN:
            {
                printf("Slave (rank %d) received SHUTDOWN\n",pgrid_myrank);
                return exec_shutdown();
            }
            case CPHVB_CLUSTER_DISPATCH_UFUNC:
            {
                cphvb_intp *id = (cphvb_intp *)msg->payload;
                char *fun = msg->payload+sizeof(cphvb_intp);
                printf("Slave (rank %d) received UFUNC. fun: %s, id: %ld\n",pgrid_myrank, fun, *id);
                if((e = exec_reg_func(fun, id)) != CPHVB_SUCCESS)
                    return e;
                break;
            }
            case CPHVB_CLUSTER_DISPATCH_EXEC:
            {
                //The number of instructions
                cphvb_intp *noi = (cphvb_intp *)msg->payload;
                //The master-instruction list
                cphvb_instruction *master_list = (cphvb_instruction *)(noi+1);
                //The number of new arrays
                cphvb_intp *noa = (cphvb_intp *)(master_list + *noi);
                //The list of new arrays
                darray *darys = (darray*)(noa+1); //number of new arrays
                //The number of user-defined functions
                cphvb_intp *nou = (cphvb_intp *)(darys + *noa);
                //The list of user-defined functions
                cphvb_userfunc *ufunc = (cphvb_userfunc*)(nou+1); //number of new arrays

   printf("Slave (rank %d) received EXEC. noi: %ld, noa: %ld, nou: %ld\n",pgrid_myrank, *noi, *noa, *nou);

                //Insert the new array into the array store and the array maps
                std::set<darray*> base_darys;
                for(cphvb_intp i=0; i < *noa; ++i)
                {
                    darray *dary = ary_store.c_next();
                    *dary = darys[i];
                    assert(map_dary2ary.count(dary->id) == 0);
                    assert(map_ary2dary.count(&dary->global_ary) == 0);
                    map_dary2ary[dary->id] = &dary->global_ary;
                    map_ary2dary[&dary->global_ary] = dary;
                    if(dary->global_ary.base == NULL)//This is a base array.
                        base_darys.insert(dary);
                }

                //Update the base-array-pointers
                for(cphvb_intp i=0; i < *noa; ++i)
                {
                    cphvb_array *ary = map_dary2ary[darys[i].id];
                    if(ary->base != NULL)//This is NOT a base array
                    {
                        assert(map_dary2ary.count((cphvb_intp)ary->base) == 1);
                        ary->base = map_dary2ary[(cphvb_intp)ary->base];
                    }
                }

                //Receive the dispatched array-data from the master-process
                if((e = dispatch_array_data(base_darys)) != CPHVB_SUCCESS)
                    return e;

                //Allocate the local instruction list that should reference local arrays
                cphvb_instruction *local_list = (cphvb_instruction *)malloc(*noi*sizeof(cphvb_instruction));
                if(local_list == NULL)
                    return CPHVB_OUT_OF_MEMORY;
                memcpy(local_list, master_list, (*noi)*sizeof(cphvb_instruction));

                //De-serialize all user-defined function pointers.
                for(cphvb_intp i=0; i < *noi; ++i)
                {
                    cphvb_instruction *inst = &local_list[i];
                    if(inst->opcode == CPHVB_USERFUNC)
                    {
                        inst->userfunc = (cphvb_userfunc*) malloc(ufunc->struct_size);
                        if(inst->userfunc == NULL)
                            return CPHVB_OUT_OF_MEMORY;
                        //Save a local copy of the user-defined function
                        memcpy(inst->userfunc, ufunc, ufunc->struct_size);
                        //Iterate to the next user-defined function
                        ufunc = (cphvb_userfunc*)(((char*)ufunc) + ufunc->struct_size);
                    }
                }

                //Update all instruction to reference local arrays
                for(cphvb_intp i=0; i < *noi; ++i)
                {
                    cphvb_instruction *inst = &local_list[i];
                    int nop = cphvb_operands_in_instruction(inst);
                    cphvb_array **ops;
                    if(inst->opcode == CPHVB_USERFUNC)
                        ops = inst->userfunc->operand;
                    else
                        ops = inst->operand;

                    //Convert all instructon operands
                    for(cphvb_intp j=0; j<nop; ++j)
                    {
                        if(cphvb_is_constant(ops[j]))
                            continue;
                        assert(map_dary2ary.count((cphvb_intp)ops[j]) == 1);
                        ops[j] = map_dary2ary[(cphvb_intp)ops[j]];
                        assert(map_ary2dary.count(ops[j]) == 1);
                    }
                }

//                cphvb_pprint_instr_list(local_list, *noi, "SLAVE");

                if((e = exec_execute(*noi, local_list)) != CPHVB_SUCCESS)
                    return e;
                free(local_list);
                break;
            }
            default:
                fprintf(stderr, "[VEM-CLUSTER] Slave (rank %d) "
                        "received unknown message type\n", pgrid_myrank);
                MPI_Abort(MPI_COMM_WORLD,CPHVB_ERROR);
        }
    }
    return CPHVB_SUCCESS;
}
<commit_msg>Implemented error checking by the slave process<commit_after>/*
This file is part of cphVB and copyright (c) 2012 the cphVB team:
http://cphvb.bitbucket.org

cphVB 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 3
of the License, or (at your option) any later version.

cphVB 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 General Public License for more details.

You should have received a copy of the
GNU Lesser General Public License along with cphVB.

If not, see <http://www.gnu.org/licenses/>.
*/

#include <cphvb.h>
#include <cassert>
#include <map>
#include <set>
#include <StaticStore.hpp>
#include "cphvb_vem_cluster.h"
#include "dispatch.h"
#include "pgrid.h"
#include "exec.h"
#include "darray_extension.h"

//Local array information and storage
static std::map<cphvb_intp, cphvb_array*> map_dary2ary;
static std::map<cphvb_array*,darray*> map_ary2dary;
static StaticStore<darray> ary_store(512);

//Check for error. Will exit on error.
static void check_error(cphvb_error err, const char *file, int line)
{
    if(err != CPHVB_SUCCESS)
    {
        fprintf(stderr, "[VEM-CLUSTER] Slave (rank %d) encountered the error %s at %s:%d\n",
                pgrid_myrank, cphvb_error_text(err), file, line);
        MPI_Abort(MPI_COMM_WORLD,-1);
    }
}

//Check for execution error. Will exit on error.
static void check_exec_error(cphvb_error err, const char *file, int line,
                             cphvb_intp count, cphvb_instruction inst_list[])
{
    if(err == CPHVB_PARTIAL_SUCCESS)//Only partial success
    {
        char msg[count+4096];
        sprintf(msg, "[VEM-CLUSTER] Slave (rank %d) encountered error in instruction batch: %s\n",
                pgrid_myrank, cphvb_error_text(err));
        for(cphvb_intp i=0; i<count; ++i)
        {
            cphvb_instruction *ist = &inst_list[i];
            sprintf(msg+strlen(msg),"\tOpcode: %s", cphvb_opcode_text(ist->opcode));
            if(ist->opcode == CPHVB_USERFUNC)
            {
                sprintf(msg+strlen(msg),", Operand types:");
                for(cphvb_intp j=0; j<cphvb_operands_in_instruction(ist); ++j)
                    sprintf(msg+strlen(msg)," %s", cphvb_type_text(cphvb_type_operand(ist,j)));
            }
            else
            {
                sprintf(msg+strlen(msg),", Operand types:");
                for(cphvb_intp j=0; j<cphvb_operands_in_instruction(ist); ++j)
                    sprintf(msg+strlen(msg)," %s", cphvb_type_text(cphvb_type_operand(ist,j)));
            }
            sprintf(msg+strlen(msg),", Status: %s\n", cphvb_error_text(ist->status));
        }
        fprintf(stderr,"%s", msg);
        MPI_Abort(MPI_COMM_WORLD,-1);
    }
    check_error(err, file, line);
}

int main()
{
    dispatch_msg *msg;

    //Initiate the process grid
    check_error(pgrid_init(),__FILE__,__LINE__);

    while(1)
    {
        //Receive the dispatch message from the master-process
        check_error(dispatch_reset(),__FILE__,__LINE__);
        check_error(dispatch_recv(&msg),__FILE__,__LINE__);

        //Handle the message
        switch(msg->type)
        {
            case CPHVB_CLUSTER_DISPATCH_INIT:
            {
                char *name = msg->payload;
                printf("Slave (rank %d) received INIT. name: %s\n", pgrid_myrank, name);
                check_error(exec_init(name),__FILE__,__LINE__);
                break;
            }
            case CPHVB_CLUSTER_DISPATCH_SHUTDOWN:
            {
                printf("Slave (rank %d) received SHUTDOWN\n",pgrid_myrank);
                return exec_shutdown();
            }
            case CPHVB_CLUSTER_DISPATCH_UFUNC:
            {
                cphvb_intp *id = (cphvb_intp *)msg->payload;
                char *fun = msg->payload+sizeof(cphvb_intp);
                printf("Slave (rank %d) received UFUNC. fun: %s, id: %ld\n",pgrid_myrank, fun, *id);
                check_error(exec_reg_func(fun, id),__FILE__,__LINE__);
                break;
            }
            case CPHVB_CLUSTER_DISPATCH_EXEC:
            {
                //The number of instructions
                cphvb_intp *noi = (cphvb_intp *)msg->payload;
                //The master-instruction list
                cphvb_instruction *master_list = (cphvb_instruction *)(noi+1);
                //The number of new arrays
                cphvb_intp *noa = (cphvb_intp *)(master_list + *noi);
                //The list of new arrays
                darray *darys = (darray*)(noa+1); //number of new arrays
                //The number of user-defined functions
                cphvb_intp *nou = (cphvb_intp *)(darys + *noa);
                //The list of user-defined functions
                cphvb_userfunc *ufunc = (cphvb_userfunc*)(nou+1); //number of new arrays

   printf("Slave (rank %d) received EXEC. noi: %ld, noa: %ld, nou: %ld\n",pgrid_myrank, *noi, *noa, *nou);

                //Insert the new array into the array store and the array maps
                std::set<darray*> base_darys;
                for(cphvb_intp i=0; i < *noa; ++i)
                {
                    darray *dary = ary_store.c_next();
                    *dary = darys[i];
                    assert(map_dary2ary.count(dary->id) == 0);
                    assert(map_ary2dary.count(&dary->global_ary) == 0);
                    map_dary2ary[dary->id] = &dary->global_ary;
                    map_ary2dary[&dary->global_ary] = dary;
                    if(dary->global_ary.base == NULL)//This is a base array.
                        base_darys.insert(dary);
                }

                //Update the base-array-pointers
                for(cphvb_intp i=0; i < *noa; ++i)
                {
                    cphvb_array *ary = map_dary2ary[darys[i].id];
                    if(ary->base != NULL)//This is NOT a base array
                    {
                        assert(map_dary2ary.count((cphvb_intp)ary->base) == 1);
                        ary->base = map_dary2ary[(cphvb_intp)ary->base];
                    }
                }

                //Receive the dispatched array-data from the master-process
                check_error(dispatch_array_data(base_darys),__FILE__,__LINE__);

                //Allocate the local instruction list that should reference local arrays
                cphvb_instruction *local_list = (cphvb_instruction *)malloc(*noi*sizeof(cphvb_instruction));
                if(local_list == NULL)
                    return CPHVB_OUT_OF_MEMORY;
                memcpy(local_list, master_list, (*noi)*sizeof(cphvb_instruction));

                //De-serialize all user-defined function pointers.
                for(cphvb_intp i=0; i < *noi; ++i)
                {
                    cphvb_instruction *inst = &local_list[i];
                    if(inst->opcode == CPHVB_USERFUNC)
                    {
                        inst->userfunc = (cphvb_userfunc*) malloc(ufunc->struct_size);
                        if(inst->userfunc == NULL)
                            return CPHVB_OUT_OF_MEMORY;
                        //Save a local copy of the user-defined function
                        memcpy(inst->userfunc, ufunc, ufunc->struct_size);
                        //Iterate to the next user-defined function
                        ufunc = (cphvb_userfunc*)(((char*)ufunc) + ufunc->struct_size);
                    }
                }

                //Update all instruction to reference local arrays
                for(cphvb_intp i=0; i < *noi; ++i)
                {
                    cphvb_instruction *inst = &local_list[i];
                    int nop = cphvb_operands_in_instruction(inst);
                    cphvb_array **ops;
                    if(inst->opcode == CPHVB_USERFUNC)
                        ops = inst->userfunc->operand;
                    else
                        ops = inst->operand;

                    //Convert all instructon operands
                    for(cphvb_intp j=0; j<nop; ++j)
                    {
                        if(cphvb_is_constant(ops[j]))
                            continue;
                        assert(map_dary2ary.count((cphvb_intp)ops[j]) == 1);
                        ops[j] = map_dary2ary[(cphvb_intp)ops[j]];
                        assert(map_ary2dary.count(ops[j]) == 1);
                    }
                }

//                cphvb_pprint_instr_list(local_list, *noi, "SLAVE");

                check_exec_error(exec_execute(*noi, local_list),__FILE__,__LINE__, *noi, local_list);
                free(local_list);
                break;
            }
            default:
                fprintf(stderr, "[VEM-CLUSTER] Slave (rank %d) "
                        "received unknown message type\n", pgrid_myrank);
                MPI_Abort(MPI_COMM_WORLD,CPHVB_ERROR);
        }
    }
    return CPHVB_SUCCESS;
}
<|endoftext|>


<commit_before>#pragma once

#include <map>
#include <list>
#include <optional>

namespace nix {

/* A simple least-recently used cache. Not thread-safe. */
template<typename Key, typename Value>
class LRUCache
{
private:

    size_t capacity;

    // Stupid wrapper to get around circular dependency between Data
    // and LRU.
    struct LRUIterator;

    using Data = std::map<Key, std::pair<LRUIterator, Value>>;
    using LRU = std::list<typename Data::iterator>;

    struct LRUIterator { typename LRU::iterator it; };

    Data data;
    LRU lru;

public:

    LRUCache(size_t capacity) : capacity(capacity) { }

    /* Insert or upsert an item in the cache. */
    void upsert(const Key & key, const Value & value)
    {
        if (capacity == 0) return;

        erase(key);

        if (data.size() >= capacity) {
            /* Retire the oldest item. */
            auto oldest = lru.begin();
            data.erase(*oldest);
            lru.erase(oldest);
        }

        auto res = data.emplace(key, std::make_pair(LRUIterator(), value));
        assert(res.second);
        auto & i(res.first);

        auto j = lru.insert(lru.end(), i);

        i->second.first.it = j;
    }

    bool erase(const Key & key)
    {
        auto i = data.find(key);
        if (i == data.end()) return false;
        lru.erase(i->second.first.it);
        data.erase(i);
        return true;
    }

    /* Look up an item in the cache. If it exists, it becomes the most
       recently used item. */
    std::optional<Value> get(const Key & key)
    {
        auto i = data.find(key);
        if (i == data.end()) return {};

        /* Move this item to the back of the LRU list. */
        lru.erase(i->second.first.it);
        auto j = lru.insert(lru.end(), i);
        i->second.first.it = j;

        return i->second.second;
    }

    size_t size()
    {
        return data.size();
    }

    void clear()
    {
        data.clear();
        lru.clear();
    }
};

}
<commit_msg>Missing `#include <cassert>` in `lru-cache.hh` (#3654)<commit_after>#pragma once

#include <cassert>
#include <map>
#include <list>
#include <optional>

namespace nix {

/* A simple least-recently used cache. Not thread-safe. */
template<typename Key, typename Value>
class LRUCache
{
private:

    size_t capacity;

    // Stupid wrapper to get around circular dependency between Data
    // and LRU.
    struct LRUIterator;

    using Data = std::map<Key, std::pair<LRUIterator, Value>>;
    using LRU = std::list<typename Data::iterator>;

    struct LRUIterator { typename LRU::iterator it; };

    Data data;
    LRU lru;

public:

    LRUCache(size_t capacity) : capacity(capacity) { }

    /* Insert or upsert an item in the cache. */
    void upsert(const Key & key, const Value & value)
    {
        if (capacity == 0) return;

        erase(key);

        if (data.size() >= capacity) {
            /* Retire the oldest item. */
            auto oldest = lru.begin();
            data.erase(*oldest);
            lru.erase(oldest);
        }

        auto res = data.emplace(key, std::make_pair(LRUIterator(), value));
        assert(res.second);
        auto & i(res.first);

        auto j = lru.insert(lru.end(), i);

        i->second.first.it = j;
    }

    bool erase(const Key & key)
    {
        auto i = data.find(key);
        if (i == data.end()) return false;
        lru.erase(i->second.first.it);
        data.erase(i);
        return true;
    }

    /* Look up an item in the cache. If it exists, it becomes the most
       recently used item. */
    std::optional<Value> get(const Key & key)
    {
        auto i = data.find(key);
        if (i == data.end()) return {};

        /* Move this item to the back of the LRU list. */
        lru.erase(i->second.first.it);
        auto j = lru.insert(lru.end(), i);
        i->second.first.it = j;

        return i->second.second;
    }

    size_t size()
    {
        return data.size();
    }

    void clear()
    {
        data.clear();
        lru.clear();
    }
};

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sprite.hxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 08:15:11 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CPPCANVAS_SPRITE_HXX
#define _CPPCANVAS_SPRITE_HXX

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif

#ifndef BOOST_SHARED_PTR_HPP_INCLUDED
#include <boost/shared_ptr.hpp>
#endif

namespace basegfx
{
    class B2DHomMatrix;
    class B2DPolyPolygon;
    class B2DPoint;
}

namespace com { namespace sun { namespace star { namespace rendering
{
    class  XSprite;
} } } }

/* Definition of Sprite class */

namespace cppcanvas
{

    class Sprite
    {
    public:
        virtual ~Sprite() {}

        virtual void setAlpha( const double& rAlpha ) = 0;

        /** Set the sprite position on screen

            This method differs from the XSprite::move() insofar, as
            no viewstate/renderstate transformations are applied to
            the specified position. The given position is interpreted
            in device coordinates (i.e. screen pixel)
         */
        virtual void movePixel( const ::basegfx::B2DPoint& rNewPos ) = 0;

        /** Set the sprite position on screen

            This method sets the sprite position in the view
            coordinate system of the parent canvas
         */
        virtual void move( const ::basegfx::B2DPoint& rNewPos ) = 0;

        virtual void transform( const ::basegfx::B2DHomMatrix& rMatrix ) = 0;

        /** Set output clipping

            This method differs from the XSprite::clip() insofar, as
            no viewstate/renderstate transformations are applied to
            the specified clip polygon. The given polygon is
            interpreted in device coordinates (i.e. screen pixel)
         */
        virtual void setClipPixel( const ::basegfx::B2DPolyPolygon& rClipPoly ) = 0;

        /** Set output clipping

            This method applies the clip poly-polygon interpreted in
            the view coordinate system of the parent canvas.
         */
        virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) = 0;

        virtual void show() = 0;
        virtual void hide() = 0;

        virtual ::com::sun::star::uno::Reference<
            ::com::sun::star::rendering::XSprite > getUNOSprite() const = 0;
    };

    typedef ::boost::shared_ptr< ::cppcanvas::Sprite > SpriteSharedPtr;
}

#endif /* _CPPCANVAS_SPRITE_HXX */
<commit_msg>INTEGRATION: CWS canvas02 (1.6.4); FILE MERGED 2005/10/24 16:27:46 thb 1.6.4.1: #i48939# Providing the sprite priority also on the cppcanvas wrapper<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: sprite.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: kz $ $Date: 2005-11-02 13:38:52 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _CPPCANVAS_SPRITE_HXX
#define _CPPCANVAS_SPRITE_HXX

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif

#ifndef BOOST_SHARED_PTR_HPP_INCLUDED
#include <boost/shared_ptr.hpp>
#endif

namespace basegfx
{
    class B2DHomMatrix;
    class B2DPolyPolygon;
    class B2DPoint;
}

namespace com { namespace sun { namespace star { namespace rendering
{
    class  XSprite;
} } } }

/* Definition of Sprite class */

namespace cppcanvas
{

    class Sprite
    {
    public:
        virtual ~Sprite() {}

        virtual void setAlpha( const double& rAlpha ) = 0;

        /** Set the sprite position on screen

            This method differs from the XSprite::move() insofar, as
            no viewstate/renderstate transformations are applied to
            the specified position. The given position is interpreted
            in device coordinates (i.e. screen pixel)
         */
        virtual void movePixel( const ::basegfx::B2DPoint& rNewPos ) = 0;

        /** Set the sprite position on screen

            This method sets the sprite position in the view
            coordinate system of the parent canvas
         */
        virtual void move( const ::basegfx::B2DPoint& rNewPos ) = 0;

        virtual void transform( const ::basegfx::B2DHomMatrix& rMatrix ) = 0;

        /** Set output clipping

            This method differs from the XSprite::clip() insofar, as
            no viewstate/renderstate transformations are applied to
            the specified clip polygon. The given polygon is
            interpreted in device coordinates (i.e. screen pixel)
         */
        virtual void setClipPixel( const ::basegfx::B2DPolyPolygon& rClipPoly ) = 0;

        /** Set output clipping

            This method applies the clip poly-polygon interpreted in
            the view coordinate system of the parent canvas.
         */
        virtual void setClip( const ::basegfx::B2DPolyPolygon& rClipPoly ) = 0;

        virtual void show() = 0;
        virtual void hide() = 0;

        /** Change the sprite priority

            @param fPriority
            New sprite priority. The higher the priority, the further
            towards the viewer the sprite appears. That is, sprites
            with higher priority appear before ones with lower
            priority.
         */
        virtual void setPriority( double fPriority ) = 0;

        virtual ::com::sun::star::uno::Reference<
            ::com::sun::star::rendering::XSprite > getUNOSprite() const = 0;
    };

    typedef ::boost::shared_ptr< ::cppcanvas::Sprite > SpriteSharedPtr;
}

#endif /* _CPPCANVAS_SPRITE_HXX */
<|endoftext|>