<commit_before>/**
 * Copyright (c) 2014, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "auto_mem.hh"
#include "lnav_log.hh"
#include "sql_util.hh"
#include "environ_vtab.hh"

using namespace std;

extern char **environ;

const char *ENVIRON_CREATE_STMT = "\
-- Access lnav's environment variables through this table.\n\
CREATE TABLE environ (\n\
    name text PRIMARY KEY,\n\
    value text\n\
);\n\
";

struct vtab {
    sqlite3_vtab        base;
    sqlite3 *           db;
};

struct vtab_cursor {
    sqlite3_vtab_cursor        base;
    char **env_cursor;
};

static int vt_destructor(sqlite3_vtab *p_svt);

static int vt_create(sqlite3 *db,
                     void *pAux,
                     int argc, const char *const *argv,
                     sqlite3_vtab **pp_vt,
                     char **pzErr)
{
    vtab *p_vt;

    /* Allocate the sqlite3_vtab/vtab structure itself */
    p_vt = (vtab *)sqlite3_malloc(sizeof(*p_vt));

    if (p_vt == NULL) {
        return SQLITE_NOMEM;
    }

    memset(&p_vt->base, 0, sizeof(sqlite3_vtab));
    p_vt->db = db;

    *pp_vt = &p_vt->base;

    int rc = sqlite3_declare_vtab(db, ENVIRON_CREATE_STMT);

    return rc;
}

static int vt_destructor(sqlite3_vtab *p_svt)
{
    vtab *p_vt = (vtab *)p_svt;

    /* Free the SQLite structure */
    sqlite3_free(p_vt);

    return SQLITE_OK;
}

static int vt_connect(sqlite3 *db, void *p_aux,
                      int argc, const char *const *argv,
                      sqlite3_vtab **pp_vt, char **pzErr)
{
    return vt_create(db, p_aux, argc, argv, pp_vt, pzErr);
}

static int vt_disconnect(sqlite3_vtab *pVtab)
{
    return vt_destructor(pVtab);
}

static int vt_destroy(sqlite3_vtab *p_vt)
{
    return vt_destructor(p_vt);
}

static int vt_next(sqlite3_vtab_cursor *cur);

static int vt_open(sqlite3_vtab *p_svt, sqlite3_vtab_cursor **pp_cursor)
{
    vtab *p_vt = (vtab *)p_svt;

    p_vt->base.zErrMsg = NULL;

    vtab_cursor *p_cur = (vtab_cursor *)new vtab_cursor();

    *pp_cursor = (sqlite3_vtab_cursor *)p_cur;

    p_cur->base.pVtab = p_svt;
    p_cur->env_cursor = environ;

    vt_next((sqlite3_vtab_cursor *)p_cur);

    return p_cur ? SQLITE_OK : SQLITE_NOMEM;
}

static int vt_close(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *p_cur = (vtab_cursor *)cur;

    /* Free cursor struct. */
    delete p_cur;

    return SQLITE_OK;
}

static int vt_eof(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *vc = (vtab_cursor *)cur;

    return vc->env_cursor[0] == NULL;
}

static int vt_next(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *vc   = (vtab_cursor *)cur;

    if (vc->env_cursor[0] != NULL) {
        vc->env_cursor += 1;
    }

    return SQLITE_OK;
}

static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
{
    vtab_cursor *vc = (vtab_cursor *)cur;
    const char *eq = strchr(vc->env_cursor[0], '=');

    switch (col) {
    case 0:
        sqlite3_result_text(ctx,
            vc->env_cursor[0], eq - vc->env_cursor[0],
            SQLITE_TRANSIENT);
        break;
    case 1:
        sqlite3_result_text(ctx, eq + 1, -1, SQLITE_TRANSIENT);
        break;
    }

    return SQLITE_OK;
}

static int vt_rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *p_rowid)
{
    vtab_cursor *p_cur = (vtab_cursor *)cur;

    *p_rowid = (int64_t)p_cur->env_cursor[0];

    return SQLITE_OK;
}

static int vt_best_index(sqlite3_vtab *tab, sqlite3_index_info *p_info)
{
    return SQLITE_OK;
}

static int vt_filter(sqlite3_vtab_cursor *p_vtc,
                     int idxNum, const char *idxStr,
                     int argc, sqlite3_value **argv)
{
    return SQLITE_OK;
}

static int vt_update(sqlite3_vtab *tab,
                     int argc,
                     sqlite3_value **argv,
                     sqlite_int64 *rowid)
{
    const char *name = (
        argc > 2 ? (const char *)sqlite3_value_text(argv[2]) : NULL);
    vtab *p_vt = (vtab *)tab;
    int retval;

    if (argc != 1 &&
        (argc < 3 ||
         sqlite3_value_type(argv[2]) == SQLITE_NULL ||
         sqlite3_value_type(argv[3]) == SQLITE_NULL ||
         sqlite3_value_text(argv[2])[0] == '\0')) {
        tab->zErrMsg = sqlite3_mprintf(
            "A non-empty name and value must be provided when inserting an "
            "environment variable");

        return SQLITE_ERROR;
    }
    if (name != NULL && strchr(name, '=') != NULL) {
        tab->zErrMsg = sqlite3_mprintf(
            "Environment variable names cannot contain an equals sign (=)");

        return SQLITE_ERROR;
    }

    if (sqlite3_value_type(argv[0]) != SQLITE_NULL) {
        int64_t index = sqlite3_value_int64(argv[0]);
        const char *var = (const char *)index;
        const char *eq = strchr(var, '=');
        size_t namelen = eq - var;
        char name[namelen + 1];

        memcpy(name, var, namelen);
        name[namelen] = '\0';
        unsetenv(name);

        retval = SQLITE_OK;
    } else if (getenv(name) != NULL) {
#ifdef SQLITE_FAIL
        int rc;

        rc = sqlite3_vtab_on_conflict(p_vt->db);
        // fprintf(stderr, "got rc %d\n", rc);
        switch (rc) {
        case SQLITE_FAIL:
        case SQLITE_ABORT:
            tab->zErrMsg = sqlite3_mprintf(
                "An environment variable with the name '%s' already exists",
                name);
            return rc;
        case SQLITE_IGNORE:
            return SQLITE_OK;
        case SQLITE_REPLACE:
            break;
        default:
            return rc;
        }
#endif
    }

    if (argc == 4) {
        const unsigned char *value = sqlite3_value_text(argv[3]);

        setenv((const char *)name, (const char *)value, 1);

        retval = SQLITE_OK;
    }

    return retval;
}

static sqlite3_module vtab_module = {
    0,              /* iVersion */
    vt_create,      /* xCreate       - create a vtable */
    vt_connect,     /* xConnect      - associate a vtable with a connection */
    vt_best_index,  /* xBestIndex    - best index */
    vt_disconnect,  /* xDisconnect   - disassociate a vtable with a connection */
    vt_destroy,     /* xDestroy      - destroy a vtable */
    vt_open,        /* xOpen         - open a cursor */
    vt_close,       /* xClose        - close a cursor */
    vt_filter,      /* xFilter       - configure scan constraints */
    vt_next,        /* xNext         - advance a cursor */
    vt_eof,         /* xEof          - inidicate end of result set*/
    vt_column,      /* xColumn       - read data */
    vt_rowid,       /* xRowid        - read data */
    vt_update,      /* xUpdate       - write data */
    NULL,           /* xBegin        - begin transaction */
    NULL,           /* xSync         - sync transaction */
    NULL,           /* xCommit       - commit transaction */
    NULL,           /* xRollback     - rollback transaction */
    NULL,           /* xFindFunction - function overloading */
};

int register_environ_vtab(sqlite3 *db)
{
    auto_mem<char, sqlite3_free> errmsg;
    int rc;

    rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, NULL);
    assert(rc == SQLITE_OK);
    if ((rc = sqlite3_exec(db,
             "CREATE VIRTUAL TABLE environ USING environ_vtab_impl()",
             NULL, NULL, errmsg.out())) != SQLITE_OK) {
        fprintf(stderr, "wtf %s\n", errmsg.in());
    }
    return rc;
}
<commit_msg>[Coverity] Fixes an 'Uninitialized variables' error.<commit_after>/**
 * Copyright (c) 2014, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include "auto_mem.hh"
#include "lnav_log.hh"
#include "sql_util.hh"
#include "environ_vtab.hh"

using namespace std;

extern char **environ;

const char *ENVIRON_CREATE_STMT = "\
-- Access lnav's environment variables through this table.\n\
CREATE TABLE environ (\n\
    name text PRIMARY KEY,\n\
    value text\n\
);\n\
";

struct vtab {
    sqlite3_vtab        base;
    sqlite3 *           db;
};

struct vtab_cursor {
    sqlite3_vtab_cursor        base;
    char **env_cursor;
};

static int vt_destructor(sqlite3_vtab *p_svt);

static int vt_create(sqlite3 *db,
                     void *pAux,
                     int argc, const char *const *argv,
                     sqlite3_vtab **pp_vt,
                     char **pzErr)
{
    vtab *p_vt;

    /* Allocate the sqlite3_vtab/vtab structure itself */
    p_vt = (vtab *)sqlite3_malloc(sizeof(*p_vt));

    if (p_vt == NULL) {
        return SQLITE_NOMEM;
    }

    memset(&p_vt->base, 0, sizeof(sqlite3_vtab));
    p_vt->db = db;

    *pp_vt = &p_vt->base;

    int rc = sqlite3_declare_vtab(db, ENVIRON_CREATE_STMT);

    return rc;
}

static int vt_destructor(sqlite3_vtab *p_svt)
{
    vtab *p_vt = (vtab *)p_svt;

    /* Free the SQLite structure */
    sqlite3_free(p_vt);

    return SQLITE_OK;
}

static int vt_connect(sqlite3 *db, void *p_aux,
                      int argc, const char *const *argv,
                      sqlite3_vtab **pp_vt, char **pzErr)
{
    return vt_create(db, p_aux, argc, argv, pp_vt, pzErr);
}

static int vt_disconnect(sqlite3_vtab *pVtab)
{
    return vt_destructor(pVtab);
}

static int vt_destroy(sqlite3_vtab *p_vt)
{
    return vt_destructor(p_vt);
}

static int vt_next(sqlite3_vtab_cursor *cur);

static int vt_open(sqlite3_vtab *p_svt, sqlite3_vtab_cursor **pp_cursor)
{
    vtab *p_vt = (vtab *)p_svt;

    p_vt->base.zErrMsg = NULL;

    vtab_cursor *p_cur = (vtab_cursor *)new vtab_cursor();

    *pp_cursor = (sqlite3_vtab_cursor *)p_cur;

    p_cur->base.pVtab = p_svt;
    p_cur->env_cursor = environ;

    vt_next((sqlite3_vtab_cursor *)p_cur);

    return p_cur ? SQLITE_OK : SQLITE_NOMEM;
}

static int vt_close(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *p_cur = (vtab_cursor *)cur;

    /* Free cursor struct. */
    delete p_cur;

    return SQLITE_OK;
}

static int vt_eof(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *vc = (vtab_cursor *)cur;

    return vc->env_cursor[0] == NULL;
}

static int vt_next(sqlite3_vtab_cursor *cur)
{
    vtab_cursor *vc   = (vtab_cursor *)cur;

    if (vc->env_cursor[0] != NULL) {
        vc->env_cursor += 1;
    }

    return SQLITE_OK;
}

static int vt_column(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int col)
{
    vtab_cursor *vc = (vtab_cursor *)cur;
    const char *eq = strchr(vc->env_cursor[0], '=');

    switch (col) {
    case 0:
        sqlite3_result_text(ctx,
            vc->env_cursor[0], eq - vc->env_cursor[0],
            SQLITE_TRANSIENT);
        break;
    case 1:
        sqlite3_result_text(ctx, eq + 1, -1, SQLITE_TRANSIENT);
        break;
    }

    return SQLITE_OK;
}

static int vt_rowid(sqlite3_vtab_cursor *cur, sqlite_int64 *p_rowid)
{
    vtab_cursor *p_cur = (vtab_cursor *)cur;

    *p_rowid = (int64_t)p_cur->env_cursor[0];

    return SQLITE_OK;
}

static int vt_best_index(sqlite3_vtab *tab, sqlite3_index_info *p_info)
{
    return SQLITE_OK;
}

static int vt_filter(sqlite3_vtab_cursor *p_vtc,
                     int idxNum, const char *idxStr,
                     int argc, sqlite3_value **argv)
{
    return SQLITE_OK;
}

static int vt_update(sqlite3_vtab *tab,
                     int argc,
                     sqlite3_value **argv,
                     sqlite_int64 *rowid)
{
    const char *name = (
        argc > 2 ? (const char *)sqlite3_value_text(argv[2]) : NULL);
    vtab *p_vt = (vtab *)tab;
    int retval = SQLITE_ERROR;

    if (argc != 1 &&
        (argc < 3 ||
         sqlite3_value_type(argv[2]) == SQLITE_NULL ||
         sqlite3_value_type(argv[3]) == SQLITE_NULL ||
         sqlite3_value_text(argv[2])[0] == '\0')) {
        tab->zErrMsg = sqlite3_mprintf(
            "A non-empty name and value must be provided when inserting an "
            "environment variable");

        return SQLITE_ERROR;
    }
    if (name != NULL && strchr(name, '=') != NULL) {
        tab->zErrMsg = sqlite3_mprintf(
            "Environment variable names cannot contain an equals sign (=)");

        return SQLITE_ERROR;
    }

    if (sqlite3_value_type(argv[0]) != SQLITE_NULL) {
        int64_t index = sqlite3_value_int64(argv[0]);
        const char *var = (const char *)index;
        const char *eq = strchr(var, '=');
        size_t namelen = eq - var;
        char name[namelen + 1];

        memcpy(name, var, namelen);
        name[namelen] = '\0';
        unsetenv(name);

        retval = SQLITE_OK;
    } else if (getenv(name) != NULL) {
#ifdef SQLITE_FAIL
        int rc;

        rc = sqlite3_vtab_on_conflict(p_vt->db);
        // fprintf(stderr, "got rc %d\n", rc);
        switch (rc) {
        case SQLITE_FAIL:
        case SQLITE_ABORT:
            tab->zErrMsg = sqlite3_mprintf(
                "An environment variable with the name '%s' already exists",
                name);
            return rc;
        case SQLITE_IGNORE:
            return SQLITE_OK;
        case SQLITE_REPLACE:
            break;
        default:
            return rc;
        }
#endif
    }

    if (argc == 4) {
        const unsigned char *value = sqlite3_value_text(argv[3]);

        setenv((const char *)name, (const char *)value, 1);

        retval = SQLITE_OK;
    }

    return retval;
}

static sqlite3_module vtab_module = {
    0,              /* iVersion */
    vt_create,      /* xCreate       - create a vtable */
    vt_connect,     /* xConnect      - associate a vtable with a connection */
    vt_best_index,  /* xBestIndex    - best index */
    vt_disconnect,  /* xDisconnect   - disassociate a vtable with a connection */
    vt_destroy,     /* xDestroy      - destroy a vtable */
    vt_open,        /* xOpen         - open a cursor */
    vt_close,       /* xClose        - close a cursor */
    vt_filter,      /* xFilter       - configure scan constraints */
    vt_next,        /* xNext         - advance a cursor */
    vt_eof,         /* xEof          - inidicate end of result set*/
    vt_column,      /* xColumn       - read data */
    vt_rowid,       /* xRowid        - read data */
    vt_update,      /* xUpdate       - write data */
    NULL,           /* xBegin        - begin transaction */
    NULL,           /* xSync         - sync transaction */
    NULL,           /* xCommit       - commit transaction */
    NULL,           /* xRollback     - rollback transaction */
    NULL,           /* xFindFunction - function overloading */
};

int register_environ_vtab(sqlite3 *db)
{
    auto_mem<char, sqlite3_free> errmsg;
    int rc;

    rc = sqlite3_create_module(db, "environ_vtab_impl", &vtab_module, NULL);
    assert(rc == SQLITE_OK);
    if ((rc = sqlite3_exec(db,
             "CREATE VIRTUAL TABLE environ USING environ_vtab_impl()",
             NULL, NULL, errmsg.out())) != SQLITE_OK) {
        fprintf(stderr, "wtf %s\n", errmsg.in());
    }
    return rc;
}
<|endoftext|>


<commit_before>// Copyright © 2018-2019 Dmitriy Khaustov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Dmitriy Khaustov aka xDimon
// Contacts: khaustov.dm@gmail.com
// File created on: 2018.01.23

// LpsContext.hpp

#pragma once

#include <queue>
#include "../utils/Context.hpp"
#include "../sessions/Session.hpp"
#include "../serialization/SArr.hpp"
#include "../utils/Timer.hpp"
#include "TransportContext.hpp"

class LpsContext: public Context
{
private:
	mutable std::recursive_mutex _mutex;
	std::weak_ptr<ServicePart> _service;
	std::shared_ptr<TransportContext> _context;
	std::weak_ptr<Session> _session;
	std::queue<SVal> _output;
	std::shared_ptr<Timer> _timeout;
	bool _aggregation;
	bool _compression;
	bool _close;
	bool _closed;

public:
	LpsContext() = delete; // Default-constructor
	LpsContext(const LpsContext&) = delete; // Copy-constructor
	LpsContext& operator=(LpsContext const&) = delete; // Copy-assignment
	LpsContext(LpsContext&&) noexcept = delete; // Move-constructor
	LpsContext& operator=(LpsContext&&) noexcept = delete; // Move-assignment

	LpsContext(
		const std::shared_ptr<ServicePart>& servicePart,
		const std::shared_ptr<TransportContext>& context,
		bool aggregation = false,
		bool compression = false
	);

	~LpsContext() override;

	void assignContext(const std::shared_ptr<TransportContext>& context)
	{
		_context = context;
	}
	std::shared_ptr<TransportContext> getContext() const
	{
		return _context;
	}

	void assignSession(const std::shared_ptr<Session>& session);
	std::shared_ptr<Session> getSession();
	void resetSession();

	virtual std::string tag()
	{
		return "";
	}

	SVal recv();

	void send();

	void out(SVal value, bool close = false);
};
<commit_msg>refactoring: tags for LpsContext<commit_after>// Copyright © 2018-2019 Dmitriy Khaustov
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: Dmitriy Khaustov aka xDimon
// Contacts: khaustov.dm@gmail.com
// File created on: 2018.01.23

// LpsContext.hpp

#pragma once

#include <queue>
#include "../utils/Context.hpp"
#include "../sessions/Session.hpp"
#include "../serialization/SArr.hpp"
#include "../utils/Timer.hpp"
#include "TransportContext.hpp"

class LpsContext: public Context
{
private:
	mutable std::recursive_mutex _mutex;
	std::weak_ptr<ServicePart> _service;
	std::shared_ptr<TransportContext> _context;
	std::weak_ptr<Session> _session;
	std::queue<SVal> _output;
	std::shared_ptr<Timer> _timeout;
	bool _aggregation;
	bool _compression;
	bool _close;
	bool _closed;

protected:
	mutable std::string _tag;

public:
	LpsContext() = delete; // Default-constructor
	LpsContext(const LpsContext&) = delete; // Copy-constructor
	LpsContext& operator=(LpsContext const&) = delete; // Copy-assignment
	LpsContext(LpsContext&&) noexcept = delete; // Move-constructor
	LpsContext& operator=(LpsContext&&) noexcept = delete; // Move-assignment

	LpsContext(
		const std::shared_ptr<ServicePart>& servicePart,
		const std::shared_ptr<TransportContext>& context,
		bool aggregation = false,
		bool compression = false
	);

	~LpsContext() override;

	void assignContext(const std::shared_ptr<TransportContext>& context)
	{
		_context = context;
	}
	std::shared_ptr<TransportContext> getContext() const
	{
		return _context;
	}

	void assignSession(const std::shared_ptr<Session>& session);
	std::shared_ptr<Session> getSession() const;
	void resetSession();

	virtual std::string tag() const
	{
		return _tag;
	}

	SVal recv();

	void send();

	void out(SVal value, bool close = false);
};
<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(n)

class TwoSum {
public:

    // Add the number to an internal data structure.
	void add(int number) {
	    ++lookup_[number];
	}

    // Find if there exists any pair of numbers which sum is equal to the value.
	bool find(int value) {
	    for (const auto& kvp : lookup_) {
	        const auto num = value - kvp.first;
	        if (lookup_.count(num) && (num != kvp.first || kvp.second > 1)) {
	            return true;
	        }
	    }
	    return false;
	}

private:
    unordered_map<int, int> lookup_;
};

// Your TwoSum object will be instantiated and called as such:
// TwoSum twoSum;
// twoSum.add(number);
// twoSum.find(value);
<commit_msg>Update two-sum-iii-data-structure-design.cpp<commit_after>// Time:  O(n)
// Space: O(n)

class TwoSum {
public:

    // Add the number to an internal data structure.
    void add(int number) {
        ++lookup_[number];
    }

    // Find if there exists any pair of numbers which sum is equal to the value.
    bool find(int value) {
        for (const auto& kvp : lookup_) {
            const auto num = value - kvp.first;
            if (lookup_.count(num) && (num != kvp.first || kvp.second > 1)) {
                return true;
            }
        }
        return false;
    }

private:
    unordered_map<int, int> lookup_;
};

// Your TwoSum object will be instantiated and called as such:
// TwoSum twoSum;
// twoSum.add(number);
// twoSum.find(value);
<|endoftext|>


<commit_before>/*
 * Copyright 2014 The Imaging Source Europe GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "formats.h"

#include <iostream>
#include <iomanip>

#include "gsttcambase.h"

void list_formats (const std::vector<VideoFormatDescription>& available_formats)
{
    std::cout << "Available format settings:" << std::endl;
    for (const VideoFormatDescription& f : available_formats)
    {
        auto desc = f.get_struct();

        std::cout << "Format: " << desc.description << " - Fourcc(" << desc.fourcc << ")" << std::endl;

        for (const auto& s : f.get_resolutions())
        {
            if (s.type == TCAM_RESOLUTION_TYPE_RANGE)
            {
                std::cout << "\tResolutionrange: "
                          << s.min_size.width << "x" << s.min_size.height << " - "
                          << s.max_size.width << "x" << s.max_size.height << std::endl;
            }
            else
            {
                std::cout << "\tResolution: " << s.min_size.width << "x" << s.min_size.height << std::endl;
            }
            for (const auto& fps : f.get_frame_rates(s))
            {
                std::cout << "\t\t" << std::setw(8) << std::fixed << std::setprecision(4)<< fps << " fps" << std::endl;
            }
        }

        std::cout << std::endl;
    }
}

void list_gstreamer_1_0_formats (const std::vector<VideoFormatDescription>& available_formats)
{
    std::cout << "Available gstreamer-1.0 caps:" << std::endl;
    for (const auto& f : available_formats)
    {
        const char* tmp = tcam_fourcc_to_gst_1_0_caps_string(f.get_fourcc());

        if (tmp == nullptr)
        {
            continue;
        }

        std::string format = tmp;

        for (const auto& res : f.get_resolutions())
        {

            std::string fps_string = ", fps={ ";
            for (const auto& fps : f.get_framerates(res.min_size))
            {
                fps_string += std::to_string(fps) + " ";
            }

            fps_string += "}";

            std::string output = format
                + ", width=" + std::to_string(res.min_size.width)
                + ", height=" + std::to_string(res.min_size.height)
                + fps_string;

            std::cout << output << std::endl;
        }
    }
}

void print_active_format (const VideoFormat& format)
{
    std::cout << "Active format:\n"
              << "Format: \t" << fourcc_to_description(format.get_fourcc())
              << "\nResolution: \t" << format.get_size().width << "x" << format.get_size().height
              << "\nFramerate: \t" << format.get_framerate() << "\n" << std::endl;
}

bool set_active_format (std::shared_ptr<CaptureDevice> dev, const std::string& new_format)
{
    VideoFormat v;

    bool ret = v.from_string(new_format);

    if (ret)
    {
        return dev->set_video_format(v);
    }
    else
    {
        std::cout << "Invalid string description!" << std::endl;
    }
    return false;
}
<commit_msg>Add handling of range resolutions to tcam-ctrl -c<commit_after>/*
 * Copyright 2014 The Imaging Source Europe GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "formats.h"

#include <iostream>
#include <iomanip>

#include "gsttcambase.h"

void list_formats (const std::vector<VideoFormatDescription>& available_formats)
{
    std::cout << "Available format settings:" << std::endl;
    for (const VideoFormatDescription& f : available_formats)
    {
        auto desc = f.get_struct();

        std::cout << "Format: " << desc.description << " - Fourcc(" << desc.fourcc << ")" << std::endl;

        for (const auto& s : f.get_resolutions())
        {
            if (s.type == TCAM_RESOLUTION_TYPE_RANGE)
            {
                std::cout << "\tResolutionrange: "
                          << s.min_size.width << "x" << s.min_size.height << " - "
                          << s.max_size.width << "x" << s.max_size.height << std::endl;
            }
            else
            {
                std::cout << "\tResolution: " << s.min_size.width << "x" << s.min_size.height << std::endl;
            }
            for (const auto& fps : f.get_frame_rates(s))
            {
                std::cout << "\t\t" << std::setw(8) << std::fixed << std::setprecision(4)<< fps << " fps" << std::endl;
            }
        }

        std::cout << std::endl;
    }
}

void list_gstreamer_1_0_formats (const std::vector<VideoFormatDescription>& available_formats)
{
    std::cout << "Available gstreamer-1.0 caps:" << std::endl;
    for (const auto& f : available_formats)
    {
        const char* tmp = tcam_fourcc_to_gst_1_0_caps_string(f.get_fourcc());

        if (tmp == nullptr)
        {
            continue;
        }

        std::string format = tmp;

        for (const auto& res : f.get_resolutions())
        {
            if (res.type == TCAM_RESOLUTION_TYPE_FIXED)
            {
                std::string fps_string = ", fps={ ";
                for (const auto& fps : f.get_framerates(res.min_size))
                {
                    fps_string += std::to_string(fps) + " ";
                }

                fps_string += "}";

                std::string output = format
                    + ", width=" + std::to_string(res.min_size.width)
                    + ", height=" + std::to_string(res.min_size.height)
                    + fps_string;

                std::cout << output << std::endl;
            }
            else
            {
                auto resolutions = tcam::get_standard_resolutions(res.min_size, res.max_size);

                for (const auto& r: resolutions)
                {
                    std::string fps_string = ", fps={ ";
                    for (const auto& fps : f.get_framerates(r))
                    {
                        fps_string += std::to_string(fps) + " ";
                    }

                    fps_string += "}";

                    std::string output = format
                        + ", width=" + std::to_string(r.width)
                        + ", height=" + std::to_string(r.height)
                        + fps_string;

                    std::cout << output << std::endl;
                }

            }
        }
    }
}

void print_active_format (const VideoFormat& format)
{
    std::cout << "Active format:\n"
              << "Format: \t" << fourcc_to_description(format.get_fourcc())
              << "\nResolution: \t" << format.get_size().width << "x" << format.get_size().height
              << "\nFramerate: \t" << format.get_framerate() << "\n" << std::endl;
}

bool set_active_format (std::shared_ptr<CaptureDevice> dev, const std::string& new_format)
{
    VideoFormat v;

    bool ret = v.from_string(new_format);

    if (ret)
    {
        return dev->set_video_format(v);
    }
    else
    {
        std::cout << "Invalid string description!" << std::endl;
    }
    return false;
}
<|endoftext|>


<commit_before>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "errors.hpp"
#include <boost/make_shared.hpp>

#include "buffer_cache/buffer_cache.hpp"
#include "clustering/administration/metadata.hpp"
#include "containers/iterators.hpp"
#include "memcached/protocol.hpp"
#include "rdb_protocol/proto_utils.hpp"
#include "rdb_protocol/protocol.hpp"
#include "rpc/directory/read_manager.hpp"
#include "rpc/semilattice/semilattice_manager.hpp"
#include "serializer/config.hpp"
#include "serializer/translator.hpp"
#include "unittest/dummy_namespace_interface.hpp"
#include "unittest/gtest.hpp"

namespace unittest {
namespace {

void run_with_namespace_interface(boost::function<void(namespace_interface_t<rdb_protocol_t> *, order_source_t *)> fun) {

    order_source_t order_source;

    /* Pick shards */
    std::vector<rdb_protocol_t::region_t> shards;
    shards.push_back(rdb_protocol_t::region_t(key_range_t(key_range_t::none,   store_key_t(),  key_range_t::open, store_key_t("n"))));
    shards.push_back(rdb_protocol_t::region_t(key_range_t(key_range_t::closed, store_key_t("n"), key_range_t::none, store_key_t() )));

    boost::ptr_vector<mock::temp_file_t> temp_files;
    for (size_t i = 0; i < shards.size(); ++i) {
        temp_files.push_back(new mock::temp_file_t("/tmp/rdb_unittest.XXXXXX"));
    }

    scoped_ptr_t<io_backender_t> io_backender;
    make_io_backender(aio_default, &io_backender);

    scoped_array_t<scoped_ptr_t<serializer_t> > serializers(shards.size());
    for (size_t i = 0; i < shards.size(); ++i) {
        filepath_file_opener_t file_opener(temp_files[i].name(), io_backender.get());
        standard_serializer_t::create(&file_opener,
                                      standard_serializer_t::static_config_t());
        serializers[i].init(new standard_serializer_t(standard_serializer_t::dynamic_config_t(),
                                                      &file_opener,
                                                      &get_global_perfmon_collection()));
    }

    boost::ptr_vector<rdb_protocol_t::store_t> underlying_stores;

    /* Create some structures for the rdb_protocol_t::context_t, warning some
     * boilerplate is about to follow, avert your eyes if you have a weak
     * stomach for such things. */
    extproc::spawner_t::info_t spawner_info;
    extproc::spawner_t::create(&spawner_info);
    extproc::pool_group_t pool_group(&spawner_info, extproc::pool_group_t::DEFAULTS);

    int port = mock::randport();
    connectivity_cluster_t c;
    semilattice_manager_t<cluster_semilattice_metadata_t> slm(&c, cluster_semilattice_metadata_t());
    connectivity_cluster_t::run_t cr(&c, mock::get_unittest_addresses(), port, &slm, 0, NULL);

    int port2 = mock::randport();
    connectivity_cluster_t c2;
    directory_read_manager_t<cluster_directory_metadata_t> read_manager(&c2);
    connectivity_cluster_t::run_t cr2(&c2, mock::get_unittest_addresses(), port2, &read_manager, 0, NULL);

    rdb_protocol_t::context_t ctx(&pool_group, NULL, slm.get_root_view(), &read_manager, generate_uuid());

    for (size_t i = 0; i < shards.size(); ++i) {
        underlying_stores.push_back(new rdb_protocol_t::store_t(serializers[i].get(), temp_files[i].name(), GIGABYTE, true, &get_global_perfmon_collection(), &ctx));
    }

    boost::ptr_vector<store_view_t<rdb_protocol_t> > stores;
    for (size_t i = 0; i < shards.size(); ++i) {
        stores.push_back(new store_subview_t<rdb_protocol_t>(&underlying_stores[i], shards[i]));
    }

    /* Set up namespace interface */
    dummy_namespace_interface_t<rdb_protocol_t> nsi(shards, stores.c_array(), &order_source, &ctx);

    fun(&nsi, &order_source);
}

void run_in_thread_pool_with_namespace_interface(boost::function<void(namespace_interface_t<rdb_protocol_t> *, order_source_t*)> fun) {
    mock::run_in_thread_pool(boost::bind(&run_with_namespace_interface, fun));
}

}   /* anonymous namespace */

/* `SetupTeardown` makes sure that it can start and stop without anything going
horribly wrong */
void run_setup_teardown_test(UNUSED namespace_interface_t<rdb_protocol_t> *nsi, order_source_t *) {
    /* Do nothing */
}
TEST(RDBProtocol, SetupTeardown) {
    run_in_thread_pool_with_namespace_interface(&run_setup_teardown_test);
}

/* `GetSet` tests basic get and set operations */
void run_get_set_test(namespace_interface_t<rdb_protocol_t> *nsi, order_source_t *osource) {
    boost::shared_ptr<scoped_cJSON_t> data(new scoped_cJSON_t(cJSON_CreateNull()));
    {
        rdb_protocol_t::write_t write(rdb_protocol_t::point_write_t(store_key_t("a"), data));
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_get_set_test(rdb_protocol.cc-A)"), &interruptor);

        if (rdb_protocol_t::point_write_response_t *maybe_point_write_response_t = boost::get<rdb_protocol_t::point_write_response_t>(&response.response)) {
            ASSERT_EQ(maybe_point_write_response_t->result, STORED);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        rdb_protocol_t::read_t read(rdb_protocol_t::point_read_t(store_key_t("a")));
        rdb_protocol_t::read_response_t response;

        cond_t interruptor;
        nsi->read(read, &response, osource->check_in("unittest::run_get_set_test(rdb_protocol.cc-B)"), &interruptor);

        if (rdb_protocol_t::point_read_response_t *maybe_point_read_response = boost::get<rdb_protocol_t::point_read_response_t>(&response.response)) {
            ASSERT_TRUE(maybe_point_read_response->data->get() != NULL);
            ASSERT_TRUE(cJSON_Equal(data->get(), maybe_point_read_response->data->get()));
        } else {
            ADD_FAILURE() << "got wrong result back";
        }
    }
}

TEST(RDBProtocol, GetSet) {
    run_in_thread_pool_with_namespace_interface(&run_get_set_test);
}

void run_create_drop_sindex_test(namespace_interface_t<rdb_protocol_t> *nsi, order_source_t *osource) {
    uuid_u id = generate_uuid();
    {
        /* Create a secondary index. */
        Mapping m;
        *m.mutable_arg() = "row";
        m.mutable_body()->set_type(Term::CALL);
        *m.mutable_body()->mutable_call() = Term::Call();
        m.mutable_body()->mutable_call()->mutable_builtin()->set_type(Builtin::GETATTR);
        *m.mutable_body()->mutable_call()->mutable_builtin()->mutable_attr() = "sid";

        Term *arg = m.mutable_body()->mutable_call()->add_args();
        arg->set_type(Term::VAR);
        *arg->mutable_var() = "row";

        rdb_protocol_t::write_t write(rdb_protocol_t::sindex_create_t(id, m));
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (!boost::get<rdb_protocol_t::sindex_create_response_t>(&response.response)) {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    boost::shared_ptr<scoped_cJSON_t> data(new scoped_cJSON_t(cJSON_Parse("{\"id\" : 0, \"sid\" : 1}")));
    ASSERT_TRUE(data->get());
    {
        debugf("insert\n");
        /* Insert a piece of data (it will be indexed using the secondary
         * index). */
        query_language::backtrace_t b;
        rdb_protocol_t::write_t write(rdb_protocol_t::point_write_t(store_key_t(cJSON_print_primary(cJSON_GetObjectItem(data->get(), "id"), b)), data));
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (rdb_protocol_t::point_write_response_t *maybe_point_write_response = boost::get<rdb_protocol_t::point_write_response_t>(&response.response)) {
            ASSERT_EQ(maybe_point_write_response->result, STORED);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        debugf("read\n");
        /* Access the data using the secondary index. */
        query_language::backtrace_t b;
        rdb_protocol_t::read_t read(rdb_protocol_t::rget_read_t(store_key_t(cJSON_print_primary(scoped_cJSON_t(cJSON_CreateNumber(1)).get(), b)), id));
        rdb_protocol_t::read_response_t response;

        cond_t interruptor;
        nsi->read(read, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (rdb_protocol_t::rget_read_response_t *rget_resp = boost::get<rdb_protocol_t::rget_read_response_t>(&response.response)) {
            rdb_protocol_t::rget_read_response_t::stream_t *stream = boost::get<rdb_protocol_t::rget_read_response_t::stream_t>(&rget_resp->result);
            ASSERT_TRUE(stream != NULL);
            ASSERT_TRUE(stream->size() == 1);
            ASSERT_TRUE(query_language::json_cmp(stream->at(0).second->get(), data->get()) == 0);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        debugf("delete\n");
        /* Delete the data. */
        query_language::backtrace_t b;
        rdb_protocol_t::write_t write(rdb_protocol_t::point_delete_t(store_key_t(cJSON_print_primary(cJSON_GetObjectItem(data->get(), "id"), b))));
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (rdb_protocol_t::point_delete_response_t *maybe_point_delete_response = boost::get<rdb_protocol_t::point_delete_response_t>(&response.response)) {
            ASSERT_EQ(maybe_point_delete_response->result, DELETED);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        rdb_protocol_t::sindex_drop_t d(id);
        rdb_protocol_t::write_t write(d);
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (!boost::get<rdb_protocol_t::sindex_drop_response_t>(&response.response)) {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }
}

TEST(RDBProtocol, SindexCreateDrop) {
    run_in_thread_pool_with_namespace_interface(&run_create_drop_sindex_test);
}

}   /* namespace unittest */

<commit_msg>Extends the rdb protocol to include a delete of the indexed key.<commit_after>// Copyright 2010-2012 RethinkDB, all rights reserved.
#include "errors.hpp"
#include <boost/make_shared.hpp>

#include "buffer_cache/buffer_cache.hpp"
#include "clustering/administration/metadata.hpp"
#include "containers/iterators.hpp"
#include "memcached/protocol.hpp"
#include "rdb_protocol/proto_utils.hpp"
#include "rdb_protocol/protocol.hpp"
#include "rpc/directory/read_manager.hpp"
#include "rpc/semilattice/semilattice_manager.hpp"
#include "serializer/config.hpp"
#include "serializer/translator.hpp"
#include "unittest/dummy_namespace_interface.hpp"
#include "unittest/gtest.hpp"

namespace unittest {
namespace {

void run_with_namespace_interface(boost::function<void(namespace_interface_t<rdb_protocol_t> *, order_source_t *)> fun) {

    order_source_t order_source;

    /* Pick shards */
    std::vector<rdb_protocol_t::region_t> shards;
    shards.push_back(rdb_protocol_t::region_t(key_range_t(key_range_t::none,   store_key_t(),  key_range_t::open, store_key_t("n"))));
    shards.push_back(rdb_protocol_t::region_t(key_range_t(key_range_t::closed, store_key_t("n"), key_range_t::none, store_key_t() )));

    boost::ptr_vector<mock::temp_file_t> temp_files;
    for (size_t i = 0; i < shards.size(); ++i) {
        temp_files.push_back(new mock::temp_file_t("/tmp/rdb_unittest.XXXXXX"));
    }

    scoped_ptr_t<io_backender_t> io_backender;
    make_io_backender(aio_default, &io_backender);

    scoped_array_t<scoped_ptr_t<serializer_t> > serializers(shards.size());
    for (size_t i = 0; i < shards.size(); ++i) {
        filepath_file_opener_t file_opener(temp_files[i].name(), io_backender.get());
        standard_serializer_t::create(&file_opener,
                                      standard_serializer_t::static_config_t());
        serializers[i].init(new standard_serializer_t(standard_serializer_t::dynamic_config_t(),
                                                      &file_opener,
                                                      &get_global_perfmon_collection()));
    }

    boost::ptr_vector<rdb_protocol_t::store_t> underlying_stores;

    /* Create some structures for the rdb_protocol_t::context_t, warning some
     * boilerplate is about to follow, avert your eyes if you have a weak
     * stomach for such things. */
    extproc::spawner_t::info_t spawner_info;
    extproc::spawner_t::create(&spawner_info);
    extproc::pool_group_t pool_group(&spawner_info, extproc::pool_group_t::DEFAULTS);

    int port = mock::randport();
    connectivity_cluster_t c;
    semilattice_manager_t<cluster_semilattice_metadata_t> slm(&c, cluster_semilattice_metadata_t());
    connectivity_cluster_t::run_t cr(&c, mock::get_unittest_addresses(), port, &slm, 0, NULL);

    int port2 = mock::randport();
    connectivity_cluster_t c2;
    directory_read_manager_t<cluster_directory_metadata_t> read_manager(&c2);
    connectivity_cluster_t::run_t cr2(&c2, mock::get_unittest_addresses(), port2, &read_manager, 0, NULL);

    rdb_protocol_t::context_t ctx(&pool_group, NULL, slm.get_root_view(), &read_manager, generate_uuid());

    for (size_t i = 0; i < shards.size(); ++i) {
        underlying_stores.push_back(new rdb_protocol_t::store_t(serializers[i].get(), temp_files[i].name(), GIGABYTE, true, &get_global_perfmon_collection(), &ctx));
    }

    boost::ptr_vector<store_view_t<rdb_protocol_t> > stores;
    for (size_t i = 0; i < shards.size(); ++i) {
        stores.push_back(new store_subview_t<rdb_protocol_t>(&underlying_stores[i], shards[i]));
    }

    /* Set up namespace interface */
    dummy_namespace_interface_t<rdb_protocol_t> nsi(shards, stores.c_array(), &order_source, &ctx);

    fun(&nsi, &order_source);
}

void run_in_thread_pool_with_namespace_interface(boost::function<void(namespace_interface_t<rdb_protocol_t> *, order_source_t*)> fun) {
    mock::run_in_thread_pool(boost::bind(&run_with_namespace_interface, fun));
}

}   /* anonymous namespace */

/* `SetupTeardown` makes sure that it can start and stop without anything going
horribly wrong */
void run_setup_teardown_test(UNUSED namespace_interface_t<rdb_protocol_t> *nsi, order_source_t *) {
    /* Do nothing */
}
TEST(RDBProtocol, SetupTeardown) {
    run_in_thread_pool_with_namespace_interface(&run_setup_teardown_test);
}

/* `GetSet` tests basic get and set operations */
void run_get_set_test(namespace_interface_t<rdb_protocol_t> *nsi, order_source_t *osource) {
    boost::shared_ptr<scoped_cJSON_t> data(new scoped_cJSON_t(cJSON_CreateNull()));
    {
        rdb_protocol_t::write_t write(rdb_protocol_t::point_write_t(store_key_t("a"), data));
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_get_set_test(rdb_protocol.cc-A)"), &interruptor);

        if (rdb_protocol_t::point_write_response_t *maybe_point_write_response_t = boost::get<rdb_protocol_t::point_write_response_t>(&response.response)) {
            ASSERT_EQ(maybe_point_write_response_t->result, STORED);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        rdb_protocol_t::read_t read(rdb_protocol_t::point_read_t(store_key_t("a")));
        rdb_protocol_t::read_response_t response;

        cond_t interruptor;
        nsi->read(read, &response, osource->check_in("unittest::run_get_set_test(rdb_protocol.cc-B)"), &interruptor);

        if (rdb_protocol_t::point_read_response_t *maybe_point_read_response = boost::get<rdb_protocol_t::point_read_response_t>(&response.response)) {
            ASSERT_TRUE(maybe_point_read_response->data->get() != NULL);
            ASSERT_TRUE(cJSON_Equal(data->get(), maybe_point_read_response->data->get()));
        } else {
            ADD_FAILURE() << "got wrong result back";
        }
    }
}

TEST(RDBProtocol, GetSet) {
    run_in_thread_pool_with_namespace_interface(&run_get_set_test);
}

void run_create_drop_sindex_test(namespace_interface_t<rdb_protocol_t> *nsi, order_source_t *osource) {
    uuid_u id = generate_uuid();
    query_language::backtrace_t b;
    {
        /* Create a secondary index. */
        Mapping m;
        *m.mutable_arg() = "row";
        m.mutable_body()->set_type(Term::CALL);
        *m.mutable_body()->mutable_call() = Term::Call();
        m.mutable_body()->mutable_call()->mutable_builtin()->set_type(Builtin::GETATTR);
        *m.mutable_body()->mutable_call()->mutable_builtin()->mutable_attr() = "sid";

        Term *arg = m.mutable_body()->mutable_call()->add_args();
        arg->set_type(Term::VAR);
        *arg->mutable_var() = "row";

        rdb_protocol_t::write_t write(rdb_protocol_t::sindex_create_t(id, m));
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (!boost::get<rdb_protocol_t::sindex_create_response_t>(&response.response)) {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    boost::shared_ptr<scoped_cJSON_t> data(new scoped_cJSON_t(cJSON_Parse("{\"id\" : 0, \"sid\" : 1}")));
    store_key_t pk = store_key_t(cJSON_print_primary(cJSON_GetObjectItem(data->get(), "id"), b));
    ASSERT_TRUE(data->get());
    {
        /* Insert a piece of data (it will be indexed using the secondary
         * index). */
        rdb_protocol_t::write_t write(rdb_protocol_t::point_write_t(pk, data));
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (rdb_protocol_t::point_write_response_t *maybe_point_write_response = boost::get<rdb_protocol_t::point_write_response_t>(&response.response)) {
            ASSERT_EQ(maybe_point_write_response->result, STORED);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        /* Access the data using the secondary index. */
        rdb_protocol_t::read_t read(rdb_protocol_t::rget_read_t(store_key_t(cJSON_print_primary(scoped_cJSON_t(cJSON_CreateNumber(1)).get(), b)), id));
        rdb_protocol_t::read_response_t response;

        cond_t interruptor;
        nsi->read(read, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (rdb_protocol_t::rget_read_response_t *rget_resp = boost::get<rdb_protocol_t::rget_read_response_t>(&response.response)) {
            rdb_protocol_t::rget_read_response_t::stream_t *stream = boost::get<rdb_protocol_t::rget_read_response_t::stream_t>(&rget_resp->result);
            ASSERT_TRUE(stream != NULL);
            ASSERT_TRUE(stream->size() == 1);
            ASSERT_TRUE(query_language::json_cmp(stream->at(0).second->get(), data->get()) == 0);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        /* Delete the data. */
        rdb_protocol_t::point_delete_t d(pk);
        rdb_protocol_t::write_t write(d);
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (rdb_protocol_t::point_delete_response_t *maybe_point_delete_response = boost::get<rdb_protocol_t::point_delete_response_t>(&response.response)) {
            ASSERT_EQ(maybe_point_delete_response->result, DELETED);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        /* Access the data using the secondary index. */
        rdb_protocol_t::read_t read(rdb_protocol_t::rget_read_t(store_key_t(cJSON_print_primary(scoped_cJSON_t(cJSON_CreateNumber(1)).get(), b)), id));
        rdb_protocol_t::read_response_t response;

        cond_t interruptor;
        nsi->read(read, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (rdb_protocol_t::rget_read_response_t *rget_resp = boost::get<rdb_protocol_t::rget_read_response_t>(&response.response)) {
            rdb_protocol_t::rget_read_response_t::stream_t *stream = boost::get<rdb_protocol_t::rget_read_response_t::stream_t>(&rget_resp->result);
            ASSERT_TRUE(stream != NULL);
            ASSERT_TRUE(stream->size() == 0);
        } else {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }

    {
        rdb_protocol_t::sindex_drop_t d(id);
        rdb_protocol_t::write_t write(d);
        rdb_protocol_t::write_response_t response;

        cond_t interruptor;
        nsi->write(write, &response, osource->check_in("unittest::run_create_drop_sindex_test(rdb_protocol_t.cc-A"), &interruptor);

        if (!boost::get<rdb_protocol_t::sindex_drop_response_t>(&response.response)) {
            ADD_FAILURE() << "got wrong type of result back";
        }
    }
}

TEST(RDBProtocol, SindexCreateDrop) {
    run_in_thread_pool_with_namespace_interface(&run_create_drop_sindex_test);
}

}   /* namespace unittest */

<|endoftext|>


<commit_before>#pragma once
#include <map>
#include <set>
#include <tuple>
#include <regex>
#include <string>
#include <thread>
#include "net/acceptor.hpp"
#include "http/headers.hpp"

namespace http {

using namespace std::literals;

class controller
{
public:

    using callback = std::function<std::string(std::string_view,std::string_view)>;

    void text(const std::string& content)
    {
        m_content_type = "text/plain"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void html(const std::string& content)
    {
        m_content_type = "text/html"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void css(const std::string& content)
    {
        m_content_type = "text/css"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void script(const std::string& content)
    {
        m_content_type = "application/javascript"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void json(const std::string& content)
    {
        m_content_type = "application/json"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void xml(const std::string& content)
    {
        m_content_type = "application/xml"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void response(std::string_view content_type, callback cb)
    {
        m_content_type = content_type;
        m_callback = cb;
    }

    std::tuple<std::string,std::string> render(std::string_view request = "", std::string_view body = "") const
    {
        return {m_callback(request,body),m_content_type};
    }

    void content_type(std::string_view type)
    {
        m_content_type = type;
    }

    const std::string& content_type() const
    {
        return m_content_type;
    }

private:

    std::string m_content_type = "*/*"s;

    callback m_callback = [](std::string_view, std::string_view){return "Not Found"s;};
};

class server
{
public:

    controller& get(const std::string& path)
    {
        m_methods.insert("GET"s);
        return m_router[path]["GET"s];
    }

    controller& head(const std::string& path)
    {
        m_methods.insert("HEAD"s);
        return m_router[path]["HEAD"s];
    }

    controller& post(const std::string& path)
    {
        m_methods.insert("POST"s);
        return m_router[path]["POST"s];
    }

    controller& put(const std::string& path)
    {
        m_methods.insert("PUT"s);
        return m_router[path]["PUT"s];
    }

    controller& patch(const std::string& path)
    {
        m_methods.insert("PATCH"s);
        return m_router[path]["PATCH"s];
    }

    controller& destroy(const std::string& path)
    {
        m_methods.insert("DELETE"s);
        return m_router[path]["DELETE"s];
    }

    void listen(std::string_view serice_or_port = "http")
    {
        auto endpoint = net::acceptor{"localhost"sv, serice_or_port};
        endpoint.timeout(0s); // no timeout
        slog << notice << "Started up at " << endpoint.host() << ":" << endpoint.service_or_port() << flush;
        while(true)
        {
            auto host = ""s, port = ""s;
            auto client = endpoint.accept(host, port);
            slog << notice << "Accepted connection from " << host << ":" << port << flush;
            auto worker = std::thread{[&]{handle(std::move(client));}};
            worker.detach();
            std::this_thread::sleep_for(1ms);
        }
    }

    void public_paths(std::string_view regex)
    {
        m_public_paths = regex;
    }

    void credentials(std::initializer_list<std::string> tokens)
    {
        m_credentials.insert(tokens);
    }

private:

    auto date() const
    {
        return ext::to_rfc1123(std::chrono::system_clock::now());
    }

    const auto& host() const
    {
        static auto s_host = syslog::gethostname();
        return s_host;
    }

    auto methods() const
    {
        auto tmp = ""s;
        for(const auto&  m : m_methods)
        {
            if(not tmp.empty()) tmp += ", "s;
            tmp += m;
        }
        return tmp;
    }

    const auto& content_type() const
    {
        return m_content_type;
    }

    void handle(endpointstream client)
    try
    {
        while(client)
        {
            auto method = ""s, uri = ""s, version = ""s;
            client >> method >> uri >> version;

            if(not client.good()) break;

            slog << info << "HTTP request \"" << method << ' ' << uri << ' ' << version << "\"" << flush;

            client >> std::ws;

            auto headers = http::headers{};
            client >> headers;
            // headers object will do the logging into syslog

            client.ignore(2); // crlf

            auto content_length = 0ull;
            if(headers.contains("content-length"))
                content_length = std::stoll(headers["content-length"]);

            auto authorization = ""s;
            if(headers.contains("authorization"))
                authorization = headers["authorization"];

            auto body = std::string(content_length,' ');

            for(auto& c : body)
                c = client.get();

            slog << debug << "HTTP request body \"" << body << "\"" << flush;

            if(version != "HTTP/1.1")
            {
                client << "HTTP/1.1 505 HTTP Version Not Supported" << crlf
                       << "Date: "         << date()                << crlf
                       << "Server: "       << host()                << crlf
                       << "Content-Type: " << content_type()        << crlf
                       << "Content-Length: 0"                       << crlf
                       << crlf << flush;
            }
            else if(not m_methods.contains(method))
            {
                client << "HTTP/1.1 400 Bad Request"                    << crlf
                       << "Date: "         << date()                    << crlf
                       << "Server: "       << host()                    << crlf
                       << "Content-Type: " << content_type()            << crlf
                       << "Content-Length: 0"                           << crlf
                       << "Access-Control-Allow-Methods: " << methods() << crlf
                       << crlf << flush;
            }
            else if(uri == "/favicon.ico")
            {
                client << "HTTP/1.1 404 Not Found"           << crlf
                       << "Date: "         << date()         << crlf
                       << "Server: "       << host()         << crlf
                       << "Content-Type: " << content_type() << crlf
                       << "Content-Length: 0"                << crlf
                       << crlf << flush;
            }
            else if(not std::regex_match(uri,std::regex(m_public_paths)) and not m_credentials.contains(authorization))
            {
                client << "HTTP/1.1 401 Unauthorized status"                     << crlf
                       << "Date: "         << date()                             << crlf
                       << "Server: "       << host()                             << crlf
                       << "Content-Type: " << content_type()                     << crlf
                       << "Content-Length: 0"                                    << crlf
                       << "WWW-Authenticate: Basic realm=\"User Visible Realm\"" << crlf
                       << crlf << flush;
            }
            else
            {
                auto content = ""s,  type = ""s;

                for(auto& [path,controller] : m_router)
                    if(std::regex_match(uri,std::regex(path)))
                        std::tie(content,type) = controller[method].render(uri,body);

                if(not type.empty())
                    client << "HTTP/1.1 200 OK"                                           << crlf
                           << "Date: " << date()                                          << crlf
                           << "Server: " << host()                                        << crlf
                           << "Content-Type: " << type                                    << crlf
                           << "Content-Length: " << content.length()                      << crlf
                           << "Access-Control-Allow-Methods: " << methods()               << crlf
                           << "Cache-Control: private"                                    << crlf
                           << "Access-Control-Allow-Origin: http://localhost:8080"        << crlf // FIXME
                           << "Access-Control-Allow-Headers: Content-Type, Authorization" << crlf
                           << "Access-Control-Allow-Credentials: true"                    << crlf
                           << crlf
                           << (method != "HEAD"s ? content : ""s) << flush;
                else
                    client << "HTTP/1.0 404 Not Found"                                    << crlf
                           << "Date: " << date()                                          << crlf
                           << "Server: " << host()                                        << crlf
                           << "Content-Type: " << content_type()                          << crlf
                           << "Content-Length: 0"                                         << crlf
                           << crlf << flush;
            }
        }
        slog << info << "connection closed" << flush;
    }
    catch(const std::exception& e)
    {
        client << "HTTP/1.0 500 Internal Server Error" << crlf
               << "Date: " << date()                   << crlf
               << "Server: " << host()                 << crlf
               << "Content-Type: " << content_type()   << crlf
               << "Content-Length: 0"                  << crlf
               << crlf << flush;

        net::slog << net::error << e.what() << net::flush;
    }

    using router = std::map<std::string,std::map<std::string,controller>, std::less<>>;

    router m_router = {};

    std::string m_content_type = "*/*"s;

    std::set<std::string> m_methods = {"HEAD"s, "OPTIONS"s};

    std::string m_public_paths = ".*";

    std::set<std::string> m_credentials = {};
};

} // namespace http
<commit_msg>Dockers do not listen localhost<commit_after>#pragma once
#include <map>
#include <set>
#include <tuple>
#include <regex>
#include <string>
#include <thread>
#include "net/acceptor.hpp"
#include "http/headers.hpp"

namespace http {

using namespace std::literals;

class controller
{
public:

    using callback = std::function<std::string(std::string_view,std::string_view)>;

    void text(const std::string& content)
    {
        m_content_type = "text/plain"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void html(const std::string& content)
    {
        m_content_type = "text/html"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void css(const std::string& content)
    {
        m_content_type = "text/css"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void script(const std::string& content)
    {
        m_content_type = "application/javascript"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void json(const std::string& content)
    {
        m_content_type = "application/json"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void xml(const std::string& content)
    {
        m_content_type = "application/xml"s;
        m_callback = [&](std::string_view,std::string_view){return content;};
    }

    void response(std::string_view content_type, callback cb)
    {
        m_content_type = content_type;
        m_callback = cb;
    }

    std::tuple<std::string,std::string> render(std::string_view request = "", std::string_view body = "") const
    {
        return {m_callback(request,body),m_content_type};
    }

    void content_type(std::string_view type)
    {
        m_content_type = type;
    }

    const std::string& content_type() const
    {
        return m_content_type;
    }

private:

    std::string m_content_type = "*/*"s;

    callback m_callback = [](std::string_view, std::string_view){return "Not Found"s;};
};

class server
{
public:

    controller& get(const std::string& path)
    {
        m_methods.insert("GET"s);
        return m_router[path]["GET"s];
    }

    controller& head(const std::string& path)
    {
        m_methods.insert("HEAD"s);
        return m_router[path]["HEAD"s];
    }

    controller& post(const std::string& path)
    {
        m_methods.insert("POST"s);
        return m_router[path]["POST"s];
    }

    controller& put(const std::string& path)
    {
        m_methods.insert("PUT"s);
        return m_router[path]["PUT"s];
    }

    controller& patch(const std::string& path)
    {
        m_methods.insert("PATCH"s);
        return m_router[path]["PATCH"s];
    }

    controller& destroy(const std::string& path)
    {
        m_methods.insert("DELETE"s);
        return m_router[path]["DELETE"s];
    }

    void listen(std::string_view serice_or_port = "http")
    {
        auto endpoint = net::acceptor{"0.0.0.0", serice_or_port};
        endpoint.timeout(0s); // no timeout
        slog << notice << "Started up at " << endpoint.host() << ":" << endpoint.service_or_port() << flush;
        while(true)
        {
            auto host = ""s, port = ""s;
            auto client = endpoint.accept(host, port);
            slog << notice << "Accepted connection from " << host << ":" << port << flush;
            auto worker = std::thread{[&]{handle(std::move(client));}};
            worker.detach();
            std::this_thread::sleep_for(1ms);
        }
    }

    void public_paths(std::string_view regex)
    {
        m_public_paths = regex;
    }

    void credentials(std::initializer_list<std::string> tokens)
    {
        m_credentials.insert(tokens);
    }

private:

    auto date() const
    {
        return ext::to_rfc1123(std::chrono::system_clock::now());
    }

    const auto& host() const
    {
        static auto s_host = syslog::gethostname();
        return s_host;
    }

    auto methods() const
    {
        auto tmp = ""s;
        for(const auto&  m : m_methods)
        {
            if(not tmp.empty()) tmp += ", "s;
            tmp += m;
        }
        return tmp;
    }

    const auto& content_type() const
    {
        return m_content_type;
    }

    void handle(endpointstream client)
    try
    {
        while(client)
        {
            auto method = ""s, uri = ""s, version = ""s;
            client >> method >> uri >> version;

            if(not client.good()) break;

            slog << info << "HTTP request \"" << method << ' ' << uri << ' ' << version << "\"" << flush;

            client >> std::ws;

            auto headers = http::headers{};
            client >> headers;
            // headers object will do the logging into syslog

            client.ignore(2); // crlf

            auto content_length = 0ull;
            if(headers.contains("content-length"))
                content_length = std::stoll(headers["content-length"]);

            auto authorization = ""s;
            if(headers.contains("authorization"))
                authorization = headers["authorization"];

            auto body = std::string(content_length,' ');

            for(auto& c : body)
                c = client.get();

            slog << debug << "HTTP request body \"" << body << "\"" << flush;

            if(version != "HTTP/1.1")
            {
                client << "HTTP/1.1 505 HTTP Version Not Supported" << crlf
                       << "Date: "         << date()                << crlf
                       << "Server: "       << host()                << crlf
                       << "Content-Type: " << content_type()        << crlf
                       << "Content-Length: 0"                       << crlf
                       << crlf << flush;
            }
            else if(not m_methods.contains(method))
            {
                client << "HTTP/1.1 400 Bad Request"                    << crlf
                       << "Date: "         << date()                    << crlf
                       << "Server: "       << host()                    << crlf
                       << "Content-Type: " << content_type()            << crlf
                       << "Content-Length: 0"                           << crlf
                       << "Access-Control-Allow-Methods: " << methods() << crlf
                       << crlf << flush;
            }
            else if(uri == "/favicon.ico")
            {
                client << "HTTP/1.1 404 Not Found"           << crlf
                       << "Date: "         << date()         << crlf
                       << "Server: "       << host()         << crlf
                       << "Content-Type: " << content_type() << crlf
                       << "Content-Length: 0"                << crlf
                       << crlf << flush;
            }
            else if(not std::regex_match(uri,std::regex(m_public_paths)) and not m_credentials.contains(authorization))
            {
                client << "HTTP/1.1 401 Unauthorized status"                     << crlf
                       << "Date: "         << date()                             << crlf
                       << "Server: "       << host()                             << crlf
                       << "Content-Type: " << content_type()                     << crlf
                       << "Content-Length: 0"                                    << crlf
                       << "WWW-Authenticate: Basic realm=\"User Visible Realm\"" << crlf
                       << crlf << flush;
            }
            else
            {
                auto content = ""s,  type = ""s;

                for(auto& [path,controller] : m_router)
                    if(std::regex_match(uri,std::regex(path)))
                        std::tie(content,type) = controller[method].render(uri,body);

                if(not type.empty())
                    client << "HTTP/1.1 200 OK"                                           << crlf
                           << "Date: " << date()                                          << crlf
                           << "Server: " << host()                                        << crlf
                           << "Content-Type: " << type                                    << crlf
                           << "Content-Length: " << content.length()                      << crlf
                           << "Access-Control-Allow-Methods: " << methods()               << crlf
                           << "Cache-Control: private"                                    << crlf
                           << "Access-Control-Allow-Origin: http://localhost:8080"        << crlf // FIXME
                           << "Access-Control-Allow-Headers: Content-Type, Authorization" << crlf
                           << "Access-Control-Allow-Credentials: true"                    << crlf
                           << crlf
                           << (method != "HEAD"s ? content : ""s) << flush;
                else
                    client << "HTTP/1.0 404 Not Found"                                    << crlf
                           << "Date: " << date()                                          << crlf
                           << "Server: " << host()                                        << crlf
                           << "Content-Type: " << content_type()                          << crlf
                           << "Content-Length: 0"                                         << crlf
                           << crlf << flush;
            }
        }
        slog << info << "connection closed" << flush;
    }
    catch(const std::exception& e)
    {
        client << "HTTP/1.0 500 Internal Server Error" << crlf
               << "Date: " << date()                   << crlf
               << "Server: " << host()                 << crlf
               << "Content-Type: " << content_type()   << crlf
               << "Content-Length: 0"                  << crlf
               << crlf << flush;

        net::slog << net::error << e.what() << net::flush;
    }

    using router = std::map<std::string,std::map<std::string,controller>, std::less<>>;

    router m_router = {};

    std::string m_content_type = "*/*"s;

    std::set<std::string> m_methods = {"HEAD"s, "OPTIONS"s};

    std::string m_public_paths = ".*";

    std::set<std::string> m_credentials = {};
};

} // namespace http
<|endoftext|>


<commit_before>#include "computing_unit_manager.hpp"

#include "computing_unit.hpp"

namespace TaskDistribution {
#if ENABLE_MPI
  ComputingUnitManager::ComputingUnitManager(boost::mpi::communicator& world,
      MPIObjectArchive<ArchiveKey>& archive):
    ComputingUnitManager(Tags(), world, archive) { }

  ComputingUnitManager::ComputingUnitManager(Tags const& tags,
      boost::mpi::communicator& world, MPIObjectArchive<ArchiveKey>& archive):
    world_(world),
    tags_(tags),
    archive_(archive) { }
#else
  ComputingUnitManager::ComputingUnitManager(
      ObjectArchive<ArchiveKey>& archive):
    archive_(archive) { }
#endif

  void ComputingUnitManager::process_local(TaskEntry& task) {
    if (task.should_save) {
#if ENABLE_MPI
      task.result_key = ArchiveKey::new_key(world_);
#else
      task.result_key = ArchiveKey::new_key();
#endif
    }

    // Gets the correct computing unit and executes it
    std::string computing_unit_id;
    archive_.load(task.computing_unit_id_key, computing_unit_id);
    BaseComputingUnit const* unit =
      BaseComputingUnit::get_by_id(computing_unit_id);
    unit->execute(archive_, task, *this);

    archive_.insert(task.task_key, task);
  }

#if ENABLE_MPI
  void ComputingUnitManager::process_remote() {
    archive_.mpi_process();

    bool stop = false;
    while (!stop) {
      // Probes world and, if something is found, check if it's a tag it can
      // deal right here. Otherwise, stops.
      auto status_opt = world_.iprobe();
      if (status_opt) {
        auto status = status_opt.get();

        if (status.tag() == tags_.task_begin) {
          TaskEntry task;
          world_.recv(status.source(), status.tag(), task);

          process_local(task);

          world_.isend(status.source(), tags_.task_end, task.task_key);
        }
        else if (status.tag() == tags_.task_end) {
          ArchiveKey task_key;
          world_.recv(status.source(), status.tag(), task_key);

          tasks_ended_.push_back(task_key);
        }
        else
          stop = true;
      }
      else
        stop = true;
    }
  }

  void ComputingUnitManager::send_remote(TaskEntry const& task, int remote) {
    world_.isend(remote, tags_.task_begin, task);
  }

  std::list<ArchiveKey> const& ComputingUnitManager::get_tasks_ended() const {
    return tasks_ended_;
  }

  void ComputingUnitManager::clear_tasks_ended() {
    tasks_ended_.clear();
  }
#endif
}
<commit_msg>Manager now avoids recomputing if the result is valid.<commit_after>#include "computing_unit_manager.hpp"

#include "computing_unit.hpp"

namespace TaskDistribution {
#if ENABLE_MPI
  ComputingUnitManager::ComputingUnitManager(boost::mpi::communicator& world,
      MPIObjectArchive<ArchiveKey>& archive):
    ComputingUnitManager(Tags(), world, archive) { }

  ComputingUnitManager::ComputingUnitManager(Tags const& tags,
      boost::mpi::communicator& world, MPIObjectArchive<ArchiveKey>& archive):
    world_(world),
    tags_(tags),
    archive_(archive) { }
#else
  ComputingUnitManager::ComputingUnitManager(
      ObjectArchive<ArchiveKey>& archive):
    archive_(archive) { }
#endif

  void ComputingUnitManager::process_local(TaskEntry& task) {
    if (task.result_key.is_valid())
      return;

    if (task.should_save) {
#if ENABLE_MPI
      task.result_key = ArchiveKey::new_key(world_);
#else
      task.result_key = ArchiveKey::new_key();
#endif
    }

    // Gets the correct computing unit and executes it
    std::string computing_unit_id;
    archive_.load(task.computing_unit_id_key, computing_unit_id);
    BaseComputingUnit const* unit =
      BaseComputingUnit::get_by_id(computing_unit_id);
    unit->execute(archive_, task, *this);

    archive_.insert(task.task_key, task);
  }

#if ENABLE_MPI
  void ComputingUnitManager::process_remote() {
    archive_.mpi_process();

    bool stop = false;
    while (!stop) {
      // Probes world and, if something is found, check if it's a tag it can
      // deal right here. Otherwise, stops.
      auto status_opt = world_.iprobe();
      if (status_opt) {
        auto status = status_opt.get();

        if (status.tag() == tags_.task_begin) {
          TaskEntry task;
          world_.recv(status.source(), status.tag(), task);

          process_local(task);

          world_.isend(status.source(), tags_.task_end, task.task_key);
        }
        else if (status.tag() == tags_.task_end) {
          ArchiveKey task_key;
          world_.recv(status.source(), status.tag(), task_key);

          tasks_ended_.push_back(task_key);
        }
        else
          stop = true;
      }
      else
        stop = true;
    }
  }

  void ComputingUnitManager::send_remote(TaskEntry const& task, int remote) {
    world_.isend(remote, tags_.task_begin, task);
  }

  std::list<ArchiveKey> const& ComputingUnitManager::get_tasks_ended() const {
    return tasks_ended_;
  }

  void ComputingUnitManager::clear_tasks_ended() {
    tasks_ended_.clear();
  }
#endif
}
<|endoftext|>