<commit_before>/** Copyright (c) 2012, 2013
 *    Ares Programming Language Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. All advertising materials mentioning features or use of this software
 *     must display the following acknowledgement:
 *     This product includes software developed by Ares Programming Language
 *     Project and its contributors.
 *  4. Neither the name of the Ares Programming Language Project 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 ARES PROGRAMMING LANGUAGE PROJECT 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.
 *
 *****************************************************************************
 * main.cpp - Utilities
 *
 * Implements the main entry point of program, treating the program flags and
 * source code.
 *
 */

#include <string>
#include <vector>
#include <boost/program_options.hpp>
#include "enum.h"
#include "util.h"
#include "driver.h"
#include "version.h"

using namespace std;
using namespace LANG_NAMESPACE;
using namespace LANG_NAMESPACE::Enum;
using namespace LANG_NAMESPACE::Util;
namespace programOptions = boost::program_options;

#ifndef STATS
#define STATS(print_exec_time) \
if (driver.verboseMode >= VerboseMode::Low) { \
    string errors = driver.resumeMessages(); \
    if (!errors.empty()) \
        output << "=> " << errors; \
    if (driver.totalLines > 0) \
        output << statistics(filesProcessed, driver.totalLines, colorized, print_exec_time); \
    if (driver.verboseMode >= VerboseMode::High) { \
        output << "=> Elapsed miliseconds: " << getMili() << endl; \
    } \
}
#endif

int
main(int argc, char ** argv)
{
    unsigned maxErrors = 3, filesProcessed = 0;
    InteractionMode::Mode mode = InteractionMode::None;
    vector<string> files, messages;
    string outputFilename(LANG_SHELL_NAME ".out"), line;
    std::ostream & output = std::cout;
    bool echo = true, colorized = LANG_COLORIZED;

    programOptions::options_description desc("Usage: " LANG_SHELL_NAME " [Options] files\n\nOptions");
    desc.add_options()
        ("check-only,c", "Enable check only")
        ("colorized,l", programOptions::value<bool>()->default_value(true), "Set colorized output to console")
        ("echo,z", programOptions::value<bool>()->default_value(true), "Set echo for console")
        ("eval,e", programOptions::value<string>(), "Read-eval-print <arg>")
        ("help,h", "Print this message")
        ("input-file,i", programOptions::value<vector<string> >(), "[Optional] Use <arg> as input file(s).")
        // ("output-file,o", programOptions::value<vector<string> >(), "[Optional] Set <arg> as output file(s).")
        ("verbose,x", programOptions::value<int>()->default_value(0), "Set the verbose mode [0..3]")
        ("version,v", "Print version information")
        ;
    programOptions::positional_options_description positional_input;
    positional_input.add("input-file", -1);

    programOptions::variables_map options;
    try {
        programOptions::store(programOptions::command_line_parser(argc, argv)
            .options(desc).positional(positional_input).run(), options);
        notify(options);
    } catch(programOptions::unknown_option & e) {
        output << "Unknown option: " << e.get_option_name() << endl;
        output << desc << endl;
        return 1;
    }

    if (LANG_COLORIZED && options.count("colorized"))
        colorized = options ["colorized"].as<bool>();

    VirtualEngine::Driver driver(output, colorized);

    if (options.count("check-only")) {
        driver.checkOnly = true;
    }

    if (options.count("eval")) {
        mode = InteractionMode::LineEval;
        line = options ["eval"].as<string>();
        if (!line.empty()) {
            bool parse_result = driver.parseString(line, "line eval");
            if (parse_result) {
                if (driver.errors > maxErrors) return 1;
                driver.produce((driver.checkOnly ? FinallyAction::None : FinallyAction::PrintOnConsole), output);
            }
            STATS(false)
        }
    }

    if (options.count("help")) {
        output << desc << endl;
        return 0;
    }

    if (options.count("input-file")) {
        vector<string> input_files = options ["input-file"].as<vector<string> >();
        for (auto file = input_files.begin(); file < input_files.end(); file++) {
            files.push_back(*file);
        }
    }

    if (options.count("verbose")) {
        driver.verboseMode =(VerboseMode::Mode) options ["verbose"].as<int>();
    }

    if (options.count("version")) {
        output << langVersionInfo() << endl;
        return 0;
    }

    if (options.count("echo"))
        echo = options ["echo"].as<bool>();

    if (driver.verboseMode >= VerboseMode::High) {
        output << langVersionInfo() << endl;
        if (!messages.empty())
            for (auto message = messages.begin(); message < messages.end(); message++)
                output << *message << endl;
    }

    // TODO Transpor código para Driver
    if (!files.empty()) {
        mode = InteractionMode::FileParse;
        for (auto file = files.begin(); file < files.end(); file++) {
            bool parse_ok = driver.parseFile(*file);
            if (parse_ok) {
                filesProcessed++;
                if (driver.errors > maxErrors) return 1;
                driver.produce((driver.checkOnly ? FinallyAction::None : FinallyAction::PrintOnConsole), output);
            } else
                break;
        }
        STATS(true)
    } else if (mode == InteractionMode::None) mode = InteractionMode::Shell;

    if (mode == InteractionMode::Shell) {
        string guide(">>> ");
        int blanks = 0;
        string echo_shell = "";
        if (echo)
            if (colorized)
                echo_shell = COLOR_BGREEN LANG_SHELL_NAME COLOR_RESET + guide;
            else
                echo_shell = LANG_SHELL_NAME + guide;
        while(output << echo_shell && getline(cin, line))
            if (!line.empty()) {
                bool parse_ok = driver.parseString(line, LANG_SHELL_NAME);
                if (parse_ok) {
                    if (driver.errors > maxErrors) break;
                    driver.produce((driver.checkOnly ? FinallyAction::None : FinallyAction::PrintOnConsole), output);
                }
                blanks = 0; line.clear();
            } else if (++blanks && blanks >= 3) break;
        STATS(false)
    }

    return 0;
}
<commit_msg>Incluido o código para tratamento das linhas de comando, mas ainda não parece estar funcionando corretamente<commit_after>/** Copyright (c) 2012, 2013
 *    Ares Programming Language Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. All advertising materials mentioning features or use of this software
 *     must display the following acknowledgement:
 *     This product includes software developed by Ares Programming Language
 *     Project and its contributors.
 *  4. Neither the name of the Ares Programming Language Project 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 ARES PROGRAMMING LANGUAGE PROJECT 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.
 *
 *****************************************************************************
 * main.cpp - Utilities
 *
 * Implements the main entry point of program, treating the program flags and
 * source code.
 *
 */

#include <string>
#include <vector>
#include <boost/program_options.hpp>
#include "enum.h"
#include "util.h"
#include "driver.h"
#include "version.h"

using namespace std;
using namespace LANG_NAMESPACE;
using namespace LANG_NAMESPACE::Enum;
using namespace LANG_NAMESPACE::Util;
namespace po = boost::program_options;

#ifndef STATS
#define STATS(print_exec_time) \
if (driver.verboseMode >= VerboseMode::Low) { \
    string errors = driver.resumeMessages(); \
    if (!errors.empty()) \
        output << "=> " << errors; \
    if (driver.totalLines > 0) \
        output << statistics(filesProcessed, driver.totalLines, colorized, print_exec_time); \
    if (driver.verboseMode >= VerboseMode::High) { \
        output << "=> Elapsed miliseconds: " << getMili() << endl; \
    } \
}
#endif

vector<string>
split_string (string str);

int
main(int argc, char ** argv)
{
    unsigned maxErrors = 3, filesProcessed = 0;
    InteractionMode::Mode mode = InteractionMode::None;
    vector<string> files, messages;
    string outputFilename(LANG_SHELL_NAME ".out"), line;
    std::ostream & output = std::cout;
    bool echo = true, colorized = LANG_COLORIZED;

    po::options_description desc("Usage: " LANG_SHELL_NAME " [Options] files\n\nOptions");
    desc.add_options()
        ("check-only,c", "Enable check only")
        ("colorized,l", po::value<bool>()->default_value(true), "Set colorized output to console")
        ("echo,z", po::value<bool>()->default_value(true), "Set echo for console")
        ("eval,e", po::value<string>(), "Read-eval-print <arg>")
        ("help,h", "Print this message")
        ("input-file,i", po::value<vector<string> >(), "[Optional] Use <arg> as input file(s).")
        // ("output-file,o", po::value<vector<string> >(), "[Optional] Set <arg> as output file(s).")
        ("verbose,x", po::value<int>()->default_value(0), "Set the verbose mode [0..3]")
        ("version,v", "Print version information")
        ;
    po::positional_options_description positional_input;
    positional_input.add("input-file", -1);

    po::variables_map options;
    try {
        po::store(po::command_line_parser(argc, argv)
            .options(desc).positional(positional_input).run(), options);
        po::notify(options);
    } catch(po::unknown_option & e) {
        output << "Unknown option: " << e.get_option_name() << endl;
        output << desc << endl;
        return 1;
    }

    if (LANG_COLORIZED && options.count("colorized"))
        colorized = options ["colorized"].as<bool>();

    VirtualEngine::Driver driver(output, colorized);

    if (options.count("check-only")) {
        driver.checkOnly = true;
    }

    if (options.count("eval")) {
        mode = InteractionMode::LineEval;
        line = options ["eval"].as<string>();
        if (!line.empty()) {
            bool parse_result = driver.parseString(line, "line eval");
            if (parse_result) {
                if (driver.errors > maxErrors) return 1;
                driver.produce((driver.checkOnly ? FinallyAction::None : FinallyAction::PrintOnConsole), output);
            }
            STATS(false)
        }
    }

    if (options.count("help")) {
        output << desc << endl;
        return 0;
    }

    if (options.count("input-file")) {
        vector<string> input_files = options ["input-file"].as<vector<string> >();
        for (auto file = input_files.begin(); file < input_files.end(); file++) {
            files.push_back(*file);
        }
    }

    if (options.count("verbose")) {
        driver.verboseMode =(VerboseMode::Mode) options ["verbose"].as<int>();
    }

    if (options.count("version")) {
        output << langVersionInfo() << endl;
        return 0;
    }

    if (options.count("echo"))
        echo = options ["echo"].as<bool>();

    if (driver.verboseMode >= VerboseMode::High) {
        output << langVersionInfo() << endl;
        if (!messages.empty())
            for (auto message = messages.begin(); message < messages.end(); message++)
                output << *message << endl;
    }

    // TODO Transpor código para Driver
    if (!files.empty()) {
        mode = InteractionMode::FileParse;
        for (auto file = files.begin(); file < files.end(); file++) {
            bool parse_ok = driver.parseFile(*file);
            if (parse_ok) {
                filesProcessed++;
                if (driver.errors > maxErrors) return 1;
                driver.produce((driver.checkOnly ? FinallyAction::None : FinallyAction::PrintOnConsole), output);
            } else
                break;
        }
        STATS(true)
    } else if (mode == InteractionMode::None) mode = InteractionMode::Shell;

    if (mode == InteractionMode::Shell) {

        vector<string> args;

        po::options_description shell("Interactive shell");
        shell.add_options()
            ("\\q", "Quit")
            ("\\h", "Print this help message")
            ("\\c", "Clear the buffer")
            ("\\l", "List the buffer")
            ("/", "Execute the command buffer")
            ;
        po::variables_map commands;

        string guide(">>> "), prompt = "", buffer = "";
        if (echo)
            if (colorized)
                prompt = COLOR_BGREEN LANG_SHELL_NAME COLOR_RESET + guide;
            else
                prompt = LANG_SHELL_NAME + guide;
        while(output << prompt && getline(cin, line))
            if (!line.empty()) {

                try
                {
                    args = split_string(string("--") + line);
                    po::store(po::command_line_parser(args).options(shell).run(), commands);
                    po::notify(commands);

                    if (commands.count("\\q"))
                        break;

                    if (commands.count("\\h"))
                        output << shell << endl;

                    if (commands.count("\\l"))
                        output << buffer << endl;

                    if (commands.count("\\c"))
                        buffer.clear();

                    if (commands.count("/"))
                    {
                        bool parse_ok = driver.parseString(buffer, LANG_SHELL_NAME);
                        if (parse_ok) {
                            if (driver.errors > maxErrors) break;
                            driver.produce((driver.checkOnly ? FinallyAction::None : FinallyAction::PrintOnConsole), output);
                        }
                    }

                }
                catch (po::unknown_option & e)
                {
                    buffer.append(line);
                    buffer.append("\n");
                }

                commands.clear();
                line.clear();
            }
        STATS(false)
    }

    return 0;
}

vector<string>
split_string (string str)
{
    vector<string> result;

    string::const_iterator i = str.begin(), e = str.end();
    for(;i != e; ++i)
    if (!isspace((unsigned char)*i))
        break;

    if (i != e)
    {
        string current;
        bool inside_quoted = false;
        int backslash_count = 0;

        for(; i != e; ++i)
        {
            if (*i == '"')
            {
                // '"' preceded by even number (n) of backslashes generates
                // n/2 backslashes and is a quoted block delimiter
                if (backslash_count % 2 == 0)
                {
                    current.append(backslash_count / 2, '\\');
                    inside_quoted = !inside_quoted;
                    // '"' preceded by odd number (n) of backslashes generates
                    // (n-1)/2 backslashes and is literal quote.
                }
                else
                {
                    current.append(backslash_count / 2, '\\');
                    current += '"';
                }

                backslash_count = 0;

            }
            else if (*i == '\\')
                ++backslash_count;
            else
            {
                // Not quote or backslash. All accumulated backslashes should be
                // added
                if (backslash_count)
                {
                    current.append(backslash_count, '\\');
                    backslash_count = 0;
                }

                if (isspace((unsigned char)*i) && !inside_quoted)
                {
                    // Space outside quoted section terminate the current argument
                    result.push_back(current);
                    current.resize(0);
                    for(;i != e && isspace((unsigned char)*i); ++i)
                    ;
                    --i;
                }
                else
                    current += *i;
            }
        }

        // If we have trailing backslashes, add them
        if (backslash_count)
            current.append(backslash_count, '\\');

        // If we have non-empty 'current' or we're still in quoted
        // section (even if 'current' is empty), add the last token.
        if (!current.empty() || inside_quoted)
            result.push_back(current);
    }

    return result;
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2011, Wesley Moore http://www.wezm.net/
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 the node-genx Project, Wesley Moore, 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 <node.h>
#include <node_events.h>
#include <iostream>
extern "C" {
#include "genx.h"
}

using namespace v8;
using namespace node;
using namespace std;

static Persistent<String> sym_data;

class Writer: public EventEmitter
{
private:
  genxWriter writer;
  genxSender sender;
  Persistent<Object> stream;
public:

  static void Initialize(Handle<Object> target)
  {
    HandleScope scope;

    Local<FunctionTemplate> t = FunctionTemplate::New(New);
    t->Inherit(EventEmitter::constructor_template);
    t->InstanceTemplate()->SetInternalFieldCount(1);
    t->SetClassName(String::NewSymbol("Writer"));

    NODE_SET_PROTOTYPE_METHOD(t, "startDocument", StartDoc);
    NODE_SET_PROTOTYPE_METHOD(t, "endDocument", EndDocument);

    NODE_SET_PROTOTYPE_METHOD(t, "startElementLiteral", StartElementLiteral);
    NODE_SET_PROTOTYPE_METHOD(t, "endElement", EndElement);

    target->Set(String::NewSymbol("Writer"), t->GetFunction());

    sym_data = NODE_PSYMBOL("data");
  }

  Writer()
  {
    // alloc, free, userData
    writer = genxNew(NULL, NULL, this);
    sender.send = sender_send;
    sender.sendBounded = sender_sendBounded;
    sender.flush = sender_flush;
    stream = Persistent<Object>::Persistent();
  }

  ~Writer()
  {
    if(!stream.IsEmpty()) stream.Dispose(); // or Clear?
    genxDispose(writer);
  }

protected:

  static Handle<Value> New(const Arguments& args)
  {
    HandleScope scope;
    Writer* writer = new Writer();
    writer->Wrap(args.This());
    return args.This();
  }

  static Handle<Value> StartDoc(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    // if (args.Length() <1 ||
    //     !args[0]->IsObject()) {
    //   return ThrowException(Exception::Error(String::New(
    //     "First argument must be a WriteStream")));
    // }
    //
    // Local<String> sym_writable = String::NewSymbol("writable");
    //
    // Local<Object> stream = args[0]->ToObject();
    // // Check that the argument has the expected properties
    // if (!stream->Has(String::NewSymbol("write"))) {
    //   return ThrowException(Exception::Error(String::New(
    //     "Stream does not have write property")));
    // }
    // if (!stream->Has(String::NewSymbol("flush"))) {
    //   return ThrowException(Exception::Error(String::New(
    //     "Stream does not have flush property")));
    // }
    // if (stream->Has(sym_writable)) {
    //   Local<Value> writable = stream->Get(sym_writable);
    //   bool isWritable = writable->BooleanValue();
    //   if (!isWritable) {
    //     return ThrowException(Exception::Error(String::New(
    //       "Stream is not writable")));
    //   }
    // }
    // else {
    //   return ThrowException(Exception::Error(String::New(
    //     "Stream does not have writable property")));
    // }

    w->startDoc();

    return args.This();
  }

  genxStatus startDoc()
  {
    cout << "startDoc" << endl;
    return genxStartDocSender(writer, &sender);
  }

  static Handle<Value> EndDocument(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->endDocument();
    return args.This();
  }

  genxStatus endDocument()
  {
    cout << "endDocument" << endl;
    return genxEndDocument(writer);
  }

  static Handle<Value> StartElementLiteral(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 type = NULL;

    if (args.Length() <1 ||
        !args[0]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "First argument must be a String")));
    }

    Local<String> Type = args[0]->ToString();

    // Get the raw UTF-8 element type
    int length = Type->Utf8Length();
    type = new unsigned char[length];

    Type->WriteUtf8((char *)type, length);

    w->startElementLiteral(type);
    return Undefined();
  }

  genxStatus startElementLiteral(constUtf8 type)
  {
    HandleScope scope;
    return genxStartElementLiteral(writer, NULL, type);
  }

  static Handle<Value> EndElement(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->endElement();
    return args.This();
  }

  genxStatus endElement()
  {
    cout << "endElement" << endl;
    return genxEndElement(writer);
  }

private:
  static genxStatus sender_send(void * userData, constUtf8 s)
  {
    cout << "sender_send: " << s << endl;

    // Deliver the data event

  	return GENX_SUCCESS;
  }

  static genxStatus sender_sendBounded(void * userData, constUtf8 start, constUtf8 end)
  {
    cout << "sender_sendBounded" << endl;
  	return GENX_SUCCESS;
  }

  static genxStatus sender_flush(void * userData)
  {
    cout << "sender_flush" << endl;
  	return GENX_SUCCESS;
  }

};

extern "C" {
  static void init (Handle<Object> target)
  {
    Writer::Initialize(target);
  }

  NODE_MODULE(genx, init);
}
<commit_msg>Remove debugging code<commit_after>/*
Copyright (c) 2011, Wesley Moore http://www.wezm.net/
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 the node-genx Project, Wesley Moore, 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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 <node.h>
#include <node_events.h>
#include <iostream>
extern "C" {
#include "genx.h"
}

using namespace v8;
using namespace node;
using namespace std;

static Persistent<String> sym_data;

class Writer: public EventEmitter
{
private:
  genxWriter writer;
  genxSender sender;
  Persistent<Object> stream;
public:

  static void Initialize(Handle<Object> target)
  {
    HandleScope scope;

    Local<FunctionTemplate> t = FunctionTemplate::New(New);
    t->Inherit(EventEmitter::constructor_template);
    t->InstanceTemplate()->SetInternalFieldCount(1);
    t->SetClassName(String::NewSymbol("Writer"));

    NODE_SET_PROTOTYPE_METHOD(t, "startDocument", StartDoc);
    NODE_SET_PROTOTYPE_METHOD(t, "endDocument", EndDocument);

    NODE_SET_PROTOTYPE_METHOD(t, "startElementLiteral", StartElementLiteral);
    NODE_SET_PROTOTYPE_METHOD(t, "endElement", EndElement);

    target->Set(String::NewSymbol("Writer"), t->GetFunction());

    sym_data = NODE_PSYMBOL("data");
  }

  Writer()
  {
    // alloc, free, userData
    writer = genxNew(NULL, NULL, this);
    sender.send = sender_send;
    sender.sendBounded = sender_sendBounded;
    sender.flush = sender_flush;
    stream = Persistent<Object>::Persistent();
  }

  ~Writer()
  {
    if(!stream.IsEmpty()) stream.Dispose(); // or Clear?
    genxDispose(writer);
  }

protected:

  static Handle<Value> New(const Arguments& args)
  {
    HandleScope scope;
    Writer* writer = new Writer();
    writer->Wrap(args.This());
    return args.This();
  }

  static Handle<Value> StartDoc(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->startDoc();
    return args.This();
  }

  genxStatus startDoc()
  {
    return genxStartDocSender(writer, &sender);
  }

  static Handle<Value> EndDocument(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->endDocument();
    return args.This();
  }

  genxStatus endDocument()
  {
    return genxEndDocument(writer);
  }

  static Handle<Value> StartElementLiteral(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());
    utf8 type = NULL;

    if (args.Length() <1 ||
        !args[0]->IsString()) {
      return ThrowException(Exception::Error(String::New(
        "First argument must be a String")));
    }

    Local<String> Type = args[0]->ToString();

    // Get the raw UTF-8 element type
    int length = Type->Utf8Length();
    type = new unsigned char[length];

    Type->WriteUtf8((char *)type, length);

    w->startElementLiteral(type);
    return Undefined();
  }

  genxStatus startElementLiteral(constUtf8 type)
  {
    HandleScope scope;
    return genxStartElementLiteral(writer, NULL, type);
  }

  static Handle<Value> EndElement(const Arguments& args)
  {
    HandleScope scope;
    Writer* w = ObjectWrap::Unwrap<Writer>(args.This());

    w->endElement();
    return args.This();
  }

  genxStatus endElement()
  {
    return genxEndElement(writer);
  }

private:
  static genxStatus sender_send(void * userData, constUtf8 s)
  {

    // Deliver the data event

  	return GENX_SUCCESS;
  }

  static genxStatus sender_sendBounded(void * userData, constUtf8 start, constUtf8 end)
  {
  	return GENX_SUCCESS;
  }

  static genxStatus sender_flush(void * userData)
  {
  	return GENX_SUCCESS;
  }

};

extern "C" {
  static void init (Handle<Object> target)
  {
    Writer::Initialize(target);
  }

  NODE_MODULE(genx, init);
}
<|endoftext|>


<commit_before>#include <avro/BinaryEncoder.hh>
#include <avro/Compiler.hh>
#include <avro/Decoder.hh>
#include <avro/Encoder.hh>
#include <avro/Generic.hh>
#include <avro/Specific.hh>
#include <avro/Symbol.hh>
#include <avro/ValidSchema.hh>
#include <avro/buffer/Buffer.hh>
#include <avro/buffer/BufferStream.hh>
#include <avro/json/JsonEncoder.hh>
#include <node.h>
#include <node_buffer.h>
#include <v8.h>

using namespace std;
using namespace v8;

Persistent<ObjectTemplate> avroSchemaTemplate;

Handle<ObjectTemplate> MakeAvroSchemaTemplate() {
  HandleScope handle_scope;
  Handle<ObjectTemplate> result = ObjectTemplate::New();
  result->SetInternalFieldCount(1);
  return handle_scope.Close(result);
}

/*
  Wraps a parsed schema in a V8 schema object.
*/
Handle<Object> WrapAvroSchema(avro::ValidSchema *schema) {
  HandleScope handle_scope;
  if (avroSchemaTemplate.IsEmpty()) {
    Handle<ObjectTemplate> rawTemplate = MakeAvroSchemaTemplate();
    avroSchemaTemplate = Persistent<ObjectTemplate>::New(rawTemplate);
  }
  Handle<ObjectTemplate> templ = avroSchemaTemplate;
  Handle<Object> result = templ->NewInstance();
  Handle<External> schemaPtr = External::New(schema);
  result->SetInternalField(0, schemaPtr);
  return handle_scope.Close(result);
}

/*
  Extracts the wrapped schema from a V8 schema object.
*/
avro::ValidSchema *UnwrapAvroSchema(Handle<Object> obj) {
  Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
  void* ptr = field->Value();
  return static_cast<avro::ValidSchema*>(ptr);
}

/*
  Takes a JSON schema as input and returns a V8 schema object.
*/
static Handle<Value> ParseAvroSchema(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  Handle<Value> schemaString = args[0];

  if (!schemaString->IsString()) {
    ThrowException(Exception::TypeError(String::New("Schema must be a string")));
    return scope.Close(Undefined());
  }

  String::Utf8Value schemaUtf8Value(schemaString);
  uint8_t *schemaBytes = (uint8_t *) *schemaUtf8Value;

  avro::ValidSchema schema = avro::compileJsonSchemaFromMemory(schemaBytes, schemaUtf8Value.length());

  return WrapAvroSchema(&schema);
}

/*
  Takes two arguments, an Avro schema as a JSON string, and an Avro
  value as a JSON string, and returns a buffer containing the encoded
  data.
*/
static Handle<Value> JsonStringToAvroBuffer(const Arguments& args) {
  HandleScope scope;

  // Check arguments

  if (args.Length() != 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  Handle<Object> schemaObject = args[0]->ToObject();
  Handle<Value> jsonString = args[1];

  if (!jsonString->IsString()) {
    ThrowException(Exception::TypeError(String::New("JSON must be a string")));
    return scope.Close(Undefined());
  }

  // Get schema

  avro::ValidSchema schema = *UnwrapAvroSchema(schemaObject);

  // Decode JSON from string

  String::Utf8Value jsonUtf8Value(jsonString);
  uint8_t *jsonBytes = (uint8_t *) *jsonUtf8Value;
  auto_ptr<avro::InputStream> in = avro::memoryInputStream(jsonBytes, jsonUtf8Value.length());
  avro::DecoderPtr decoder = avro::jsonDecoder(schema);
  decoder->init(*in);
  avro::GenericDatum datum(schema);
  avro::decode(*decoder, datum);

  // Encode datum to output stream backed by stringstream

  stringstream ss(stringstream::out);
  auto_ptr<avro::OutputStream> out = avro::ostreamOutputStream(ss);
  avro::EncoderPtr encoder = avro::binaryEncoder();
  encoder->init(*out);
  avro::encode(*encoder, datum);
  encoder->flush();
  out->flush();
  string s = ss.str();

  // Copy data to buffer and return it

  avro::BinaryEncoder *binaryEncoder = (avro::BinaryEncoder *) &(*encoder);
  avro::StreamWriter &sw = binaryEncoder->getStreamWriter();

  Handle<Value> buffer = node::Buffer::New((char *) s.data(), sw.getBytesWritten())->handle_;
  return scope.Close(buffer);
}

/*
  Takes two arguments, an Avro schema as a JSON string, and a buffer
  containing encoded data, and returns a JSON string containing the
  decoded Avro value.
*/
static Handle<Value> AvroBufferToJsonString(const Arguments& args) {
  HandleScope scope;

  // Check arguments

  if (args.Length() != 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  Handle<Object> schemaObject = args[0]->ToObject();
  Handle<Value> avroBuffer = args[1];

  if (!node::Buffer::HasInstance(avroBuffer)) {
    ThrowException(Exception::TypeError(String::New("Not a buffer")));
    return scope.Close(Undefined());
  }

  // Get schema

  avro::ValidSchema schema = *UnwrapAvroSchema(schemaObject);

  // Decode data from buffer

  auto_ptr<avro::InputStream> in =
    avro::memoryInputStream((uint8_t *) node::Buffer::Data(avroBuffer->ToObject()),
                            node::Buffer::Length(avroBuffer->ToObject()));
  avro::DecoderPtr decoder = avro::binaryDecoder();
  decoder->init(*in);
  avro::GenericDatum datum(schema);
  avro::decode(*decoder, datum);

  // Encode data to JSON

  stringstream ss(stringstream::out);
  auto_ptr<avro::OutputStream> out = avro::ostreamOutputStream(ss);
  avro::EncoderPtr encoder = avro::jsonEncoder(schema);
  encoder->init(*out);
  avro::encode(*encoder, datum);
  encoder->flush();
  out->flush();
  string s = ss.str();

  avro::parsing::JsonEncoder<avro::parsing::SimpleParser<avro::parsing::JsonHandler> >  *jsonEncoder =
    (avro::parsing::JsonEncoder<avro::parsing::SimpleParser<avro::parsing::JsonHandler> > *) &(*encoder);
  avro::StreamWriter &sw = jsonEncoder->getStreamWriter();

  return scope.Close(String::New((char *) s.data(), sw.getBytesWritten()));
}

void init(Handle<Object> target) {
  target->Set(String::NewSymbol("jsonStringToAvroBuffer"),
              FunctionTemplate::New(JsonStringToAvroBuffer)->GetFunction());
  target->Set(String::NewSymbol("avroBufferToJsonString"),
              FunctionTemplate::New(AvroBufferToJsonString)->GetFunction());
  target->Set(String::NewSymbol("parseSchema"),
              FunctionTemplate::New(ParseAvroSchema)->GetFunction());
}

NODE_MODULE(avro, init)
<commit_msg>Add trick from neckbeard hacker friend that makes heap allocation of schemas possible.<commit_after>#include <avro/BinaryEncoder.hh>
#include <avro/Compiler.hh>
#include <avro/Decoder.hh>
#include <avro/Encoder.hh>
#include <avro/Generic.hh>
#include <avro/Specific.hh>
#include <avro/Symbol.hh>
#include <avro/ValidSchema.hh>
#include <avro/buffer/Buffer.hh>
#include <avro/buffer/BufferStream.hh>
#include <avro/json/JsonEncoder.hh>
#include <node.h>
#include <node_buffer.h>
#include <v8.h>

using namespace std;
using namespace v8;

Persistent<ObjectTemplate> avroSchemaTemplate;

Handle<ObjectTemplate> MakeAvroSchemaTemplate() {
  HandleScope handle_scope;
  Handle<ObjectTemplate> result = ObjectTemplate::New();
  result->SetInternalFieldCount(1);
  return handle_scope.Close(result);
}

/*
  Wraps a parsed schema in a V8 schema object.
*/
Handle<Object> WrapAvroSchema(avro::ValidSchema *schema) {
  HandleScope handle_scope;
  if (avroSchemaTemplate.IsEmpty()) {
    Handle<ObjectTemplate> rawTemplate = MakeAvroSchemaTemplate();
    avroSchemaTemplate = Persistent<ObjectTemplate>::New(rawTemplate);
  }
  Handle<ObjectTemplate> templ = avroSchemaTemplate;
  Handle<Object> result = templ->NewInstance();
  Handle<External> schemaPtr = External::New(schema);
  result->SetInternalField(0, schemaPtr);
  return handle_scope.Close(result);
}

/*
  Extracts the wrapped schema from a V8 schema object.
*/
avro::ValidSchema *UnwrapAvroSchema(Handle<Object> obj) {
  Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
  void* ptr = field->Value();
  return static_cast<avro::ValidSchema*>(ptr);
}

/*
  Takes a JSON schema as input and returns a V8 schema object.
*/
static Handle<Value> ParseAvroSchema(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  Handle<Value> schemaString = args[0];

  if (!schemaString->IsString()) {
    ThrowException(Exception::TypeError(String::New("Schema must be a string")));
    return scope.Close(Undefined());
  }

  String::Utf8Value schemaUtf8Value(schemaString);
  uint8_t *schemaBytes = (uint8_t *) *schemaUtf8Value;

  avro::ValidSchema *schema =
    new avro::ValidSchema(avro::compileJsonSchemaFromMemory(schemaBytes, schemaUtf8Value.length()));

  return WrapAvroSchema(schema);
}

/*
  Takes two arguments, an Avro schema as a JSON string, and an Avro
  value as a JSON string, and returns a buffer containing the encoded
  data.
*/
static Handle<Value> JsonStringToAvroBuffer(const Arguments& args) {
  HandleScope scope;

  // Check arguments

  if (args.Length() != 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  Handle<Object> schemaObject = args[0]->ToObject();
  Handle<Value> jsonString = args[1];

  if (!jsonString->IsString()) {
    ThrowException(Exception::TypeError(String::New("JSON must be a string")));
    return scope.Close(Undefined());
  }

  // Get schema

  avro::ValidSchema schema = *UnwrapAvroSchema(schemaObject);

  // Decode JSON from string

  String::Utf8Value jsonUtf8Value(jsonString);
  uint8_t *jsonBytes = (uint8_t *) *jsonUtf8Value;
  auto_ptr<avro::InputStream> in = avro::memoryInputStream(jsonBytes, jsonUtf8Value.length());
  avro::DecoderPtr decoder = avro::jsonDecoder(schema);
  decoder->init(*in);
  avro::GenericDatum datum(schema);
  avro::decode(*decoder, datum);

  // Encode datum to output stream backed by stringstream

  stringstream ss(stringstream::out);
  auto_ptr<avro::OutputStream> out = avro::ostreamOutputStream(ss);
  avro::EncoderPtr encoder = avro::binaryEncoder();
  encoder->init(*out);
  avro::encode(*encoder, datum);
  encoder->flush();
  out->flush();
  string s = ss.str();

  // Copy data to buffer and return it

  avro::BinaryEncoder *binaryEncoder = (avro::BinaryEncoder *) &(*encoder);
  avro::StreamWriter &sw = binaryEncoder->getStreamWriter();

  Handle<Value> buffer = node::Buffer::New((char *) s.data(), sw.getBytesWritten())->handle_;
  return scope.Close(buffer);
}

/*
  Takes two arguments, an Avro schema as a JSON string, and a buffer
  containing encoded data, and returns a JSON string containing the
  decoded Avro value.
*/
static Handle<Value> AvroBufferToJsonString(const Arguments& args) {
  HandleScope scope;

  // Check arguments

  if (args.Length() != 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  Handle<Object> schemaObject = args[0]->ToObject();
  Handle<Value> avroBuffer = args[1];

  if (!node::Buffer::HasInstance(avroBuffer)) {
    ThrowException(Exception::TypeError(String::New("Not a buffer")));
    return scope.Close(Undefined());
  }

  // Get schema

  avro::ValidSchema schema = *UnwrapAvroSchema(schemaObject);

  // Decode data from buffer

  auto_ptr<avro::InputStream> in =
    avro::memoryInputStream((uint8_t *) node::Buffer::Data(avroBuffer->ToObject()),
                            node::Buffer::Length(avroBuffer->ToObject()));
  avro::DecoderPtr decoder = avro::binaryDecoder();
  decoder->init(*in);
  avro::GenericDatum datum(schema);
  avro::decode(*decoder, datum);

  // Encode data to JSON

  stringstream ss(stringstream::out);
  auto_ptr<avro::OutputStream> out = avro::ostreamOutputStream(ss);
  avro::EncoderPtr encoder = avro::jsonEncoder(schema);
  encoder->init(*out);
  avro::encode(*encoder, datum);
  encoder->flush();
  out->flush();
  string s = ss.str();

  avro::parsing::JsonEncoder<avro::parsing::SimpleParser<avro::parsing::JsonHandler> >  *jsonEncoder =
    (avro::parsing::JsonEncoder<avro::parsing::SimpleParser<avro::parsing::JsonHandler> > *) &(*encoder);
  avro::StreamWriter &sw = jsonEncoder->getStreamWriter();

  return scope.Close(String::New((char *) s.data(), sw.getBytesWritten()));
}

void init(Handle<Object> target) {
  target->Set(String::NewSymbol("jsonStringToAvroBuffer"),
              FunctionTemplate::New(JsonStringToAvroBuffer)->GetFunction());
  target->Set(String::NewSymbol("avroBufferToJsonString"),
              FunctionTemplate::New(AvroBufferToJsonString)->GetFunction());
  target->Set(String::NewSymbol("parseSchema"),
              FunctionTemplate::New(ParseAvroSchema)->GetFunction());
}

NODE_MODULE(avro, init)
<|endoftext|>


<commit_before>/*
 *
 * Copyright (C) 1999 Kevin Fu (fubob@mit.edu)
 * and Frans Kaashoek (kaashoek@mit.edu)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 *
 * This program 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 General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 */

#include "sfsrodb_core.h"
#include "sfsrodb.h"
#include "dhash.h"
#include "dhash_prot.h"
#include "arpc.h"
#include "sys/time.h"

#define mytimespecsub(vvp, uvp)						\
	do {								\
		(vvp)->tv_sec -= (uvp)->tv_sec;				\
		(vvp)->tv_nsec -= (uvp)->tv_nsec;			\
		if ((vvp)->tv_nsec < 0) {				\
			(vvp)->tv_sec--;				\
			(vvp)->tv_nsec += 1000000000;			\
		}							\
	} while (0)

long out=0;
long blkcnt = 0;

#define SMTU MTU

bool usr1 = false;

void
sfsrodb_core_sigusr1 ()
{
  usr1 = !usr1;  // toggle
}

static void
check_cbs ()
{
  while (out >= 100)
    acheck();
}

bigint
fh2mpz(const void *keydata, size_t keylen)
{
  bigint n;
  mpz_set_rawmag_be(&n, (const char *)keydata, keylen);
  return n;
}

/*
  Requires: You have at some point called random_init();
  Given: A filled buffer and allocated fh
  Return: A file handle in fh.  Generate random bytes for the first
  SFSRO_IVSIZE bytes in the opaque fh.  Add fh to fh_list
*/

void
create_sfsrofh (sfs_hash *fh, char *buf, size_t buflen)
{
  bzero(fh->base (), fh->size ());
  sha1_hash (fh->base (), buf, buflen);
}

str
t()
{
  str buf ("");
  timespec ts;
  clock_gettime (CLOCK_REALTIME, &ts);
  buf = strbuf (" %d:%06d", int (ts.tv_sec), int (ts.tv_nsec/1000));
  return buf;
}

static timespec periodic;

static void
sfsrodb_put_cb (timespec ts, dhash_stat status, ptr<insert_info> i)
{
  if (blkcnt % 1000 == 0) {
    static timespec diff;
    clock_gettime (CLOCK_REALTIME, &diff);
    mytimespecsub(&diff, &periodic);
    warn << blkcnt << ", sec/1k " << diff.tv_sec << "\n";
    clock_gettime (CLOCK_REALTIME, &periodic);
  }

  blkcnt++;

  if (usr1) {
    timespec ts2;
    clock_gettime (CLOCK_REALTIME, &ts2);
    timespec diff = ts2;
    mytimespecsub(&diff, &ts);

    uint32 ms = 1000 * diff.tv_sec  + diff.tv_nsec / 1000000;
    //warn ("ts2  %ld:%09ld\n", ts2.tv_sec, ts2.tv_nsec);
    //warn ("ts   %ld:%09ld\n", ts.tv_sec, ts.tv_nsec);
    //warn ("df   %ld:%09ld\n", diff.tv_sec, diff.tv_nsec);
    warn << ms << " ms (" << blkcnt << ")\n";
    //  warnx << ms << "\n";
  }

  out--;
  if (status != DHASH_OK)
    warn << "Could not store block " << i->key << "\n";
}

sfs_hash
sfsrodb_put (void *data, size_t len)
{
  if (blkcnt == 0)  clock_gettime (CLOCK_REALTIME, &periodic);

  sfs_hash h;
  create_sfsrofh (&h, (char *)data, len);
  check_cbs ();
  out++;

  //warn << t() << " -- INSERT (" << blkcnt << ")\n";
  timespec ts;
  clock_gettime (CLOCK_REALTIME, &ts);
  dhash_cli->insert ((char *)data, len, wrap (sfsrodb_put_cb, ts));

  return h;
}

void
sfsrodb_put (ptr<sfspriv> sk, void *data, size_t len)
{
  if (blkcnt == 0) clock_gettime (CLOCK_REALTIME, &periodic);

  check_cbs ();
  out++;

  //warn << t() << " -- INSERT\n";
  timespec ts;
  clock_gettime (CLOCK_REALTIME, &ts);
  dhash_cli->insert (sk, (char *)data, len, wrap (sfsrodb_put_cb, ts));
}

static bool get_done;
static ptr<sfsro_data> get_result;

static void
sfsrodb_get_cb (ptr<dhash_block> blk)
{
  ///warn << "---------------------- get_cb\n";

  get_done = true;
  get_result = NULL;

  if (blk) {
    ptr<sfsro_data> data = New refcounted<sfsro_data>;
    xdrmem x (blk->data, blk->len, XDR_DECODE);
    if (xdr_sfsro_data (x.xdrp (), data))
      get_result = data;
    else
      warn << "Couldn't unmarshall data\n";
  } else {
    warn << "No such block\n";
  }
}

ptr<sfsro_data>
sfsrodb_get (bigint key)
{
  get_done = false; // reset

  //warn << "---------------------- get: " << key << "\n";
  dhash_cli->retrieve (key, wrap (&sfsrodb_get_cb));

  while (!get_done)
    acheck ();

  return get_result;
}

// 53300 - 54300:                       (107 sec/1k)
// 71000 = Mon Mar 25 17:54:35 EST 2002
// 74000 = Mon Mar 25 18:01:17 EST 2002 (134 sec/1k)
// 86000 = Mon Mar 25 18:27:12 EST 2002 (129 sec/1k)
// 93000 = Mon Mar 25 18:43:34 EST 2002 (140 sec/1k)
// 98000 = Mon Mar 25 18:59:46 EST 2002 (194 sec/1k)
// 136000 - 140000                         (380 sec/1k)
<commit_msg>update for new dhash callback<commit_after>/*
 *
 * Copyright (C) 1999 Kevin Fu (fubob@mit.edu)
 * and Frans Kaashoek (kaashoek@mit.edu)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 *
 * This program 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 General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 */

#include "sfsrodb_core.h"
#include "sfsrodb.h"
#include "dhash.h"
#include "dhash_prot.h"
#include "arpc.h"
#include "sys/time.h"

#define mytimespecsub(vvp, uvp)						\
	do {								\
		(vvp)->tv_sec -= (uvp)->tv_sec;				\
		(vvp)->tv_nsec -= (uvp)->tv_nsec;			\
		if ((vvp)->tv_nsec < 0) {				\
			(vvp)->tv_sec--;				\
			(vvp)->tv_nsec += 1000000000;			\
		}							\
	} while (0)

long out=0;
long blkcnt = 0;

#define SMTU MTU

bool usr1 = false;

void
sfsrodb_core_sigusr1 ()
{
  usr1 = !usr1;  // toggle
}

static void
check_cbs ()
{
  while (out >= 100)
    acheck();
}

bigint
fh2mpz(const void *keydata, size_t keylen)
{
  bigint n;
  mpz_set_rawmag_be(&n, (const char *)keydata, keylen);
  return n;
}

/*
  Requires: You have at some point called random_init();
  Given: A filled buffer and allocated fh
  Return: A file handle in fh.  Generate random bytes for the first
  SFSRO_IVSIZE bytes in the opaque fh.  Add fh to fh_list
*/

void
create_sfsrofh (sfs_hash *fh, char *buf, size_t buflen)
{
  bzero(fh->base (), fh->size ());
  sha1_hash (fh->base (), buf, buflen);
}

str
t()
{
  str buf ("");
  timespec ts;
  clock_gettime (CLOCK_REALTIME, &ts);
  buf = strbuf (" %d:%06d", int (ts.tv_sec), int (ts.tv_nsec/1000));
  return buf;
}

static timespec periodic;

static void
sfsrodb_put_cb (timespec ts, dhash_stat status, ptr<insert_info> i)
{
  if (blkcnt % 1000 == 0) {
    static timespec diff;
    clock_gettime (CLOCK_REALTIME, &diff);
    mytimespecsub(&diff, &periodic);
    warn << blkcnt << ", sec/1k " << diff.tv_sec << "\n";
    clock_gettime (CLOCK_REALTIME, &periodic);
  }

  blkcnt++;

  if (usr1) {
    timespec ts2;
    clock_gettime (CLOCK_REALTIME, &ts2);
    timespec diff = ts2;
    mytimespecsub(&diff, &ts);

    uint32 ms = 1000 * diff.tv_sec  + diff.tv_nsec / 1000000;
    //warn ("ts2  %ld:%09ld\n", ts2.tv_sec, ts2.tv_nsec);
    //warn ("ts   %ld:%09ld\n", ts.tv_sec, ts.tv_nsec);
    //warn ("df   %ld:%09ld\n", diff.tv_sec, diff.tv_nsec);
    warn << ms << " ms (" << blkcnt << ")\n";
    //  warnx << ms << "\n";
  }

  out--;
  if (status != DHASH_OK)
    warn << "Could not store block " << i->key << "\n";
}

sfs_hash
sfsrodb_put (void *data, size_t len)
{
  if (blkcnt == 0)  clock_gettime (CLOCK_REALTIME, &periodic);

  sfs_hash h;
  create_sfsrofh (&h, (char *)data, len);
  check_cbs ();
  out++;

  //warn << t() << " -- INSERT (" << blkcnt << ")\n";
  timespec ts;
  clock_gettime (CLOCK_REALTIME, &ts);
  dhash_cli->insert ((char *)data, len, wrap (sfsrodb_put_cb, ts));

  return h;
}

void
sfsrodb_put (ptr<sfspriv> sk, void *data, size_t len)
{
  if (blkcnt == 0) clock_gettime (CLOCK_REALTIME, &periodic);

  check_cbs ();
  out++;

  //warn << t() << " -- INSERT\n";
  timespec ts;
  clock_gettime (CLOCK_REALTIME, &ts);
  dhash_cli->insert (sk, (char *)data, len, wrap (sfsrodb_put_cb, ts));
}

static bool get_done;
static ptr<sfsro_data> get_result;

static void
sfsrodb_get_cb (dhash_stat stat, ptr<dhash_block> blk, route path)
{
  ///warn << "---------------------- get_cb\n";

  get_done = true;
  get_result = NULL;

  if (blk) {
    ptr<sfsro_data> data = New refcounted<sfsro_data>;
    xdrmem x (blk->data, blk->len, XDR_DECODE);
    if (xdr_sfsro_data (x.xdrp (), data))
      get_result = data;
    else
      warn << "Couldn't unmarshall data\n";
  } else {
    warn << "No such block\n";
  }
}

ptr<sfsro_data>
sfsrodb_get (bigint key)
{
  get_done = false; // reset

  //warn << "---------------------- get: " << key << "\n";
  dhash_cli->retrieve (key, wrap (&sfsrodb_get_cb));

  while (!get_done)
    acheck ();

  return get_result;
}

// 53300 - 54300:                       (107 sec/1k)
// 71000 = Mon Mar 25 17:54:35 EST 2002
// 74000 = Mon Mar 25 18:01:17 EST 2002 (134 sec/1k)
// 86000 = Mon Mar 25 18:27:12 EST 2002 (129 sec/1k)
// 93000 = Mon Mar 25 18:43:34 EST 2002 (140 sec/1k)
// 98000 = Mon Mar 25 18:59:46 EST 2002 (194 sec/1k)
// 136000 - 140000                         (380 sec/1k)
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <iostream>
#include <fstream>
#include <iterator>
#include <iomanip>

#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>

using namespace boost::filesystem;
using namespace libtorrent;

void add_files(
	torrent_info& t
	, path const& p
	, path const& l)
{
	path f(p / l);
	if (is_directory(f))
	{
		for (directory_iterator i(f), end; i != end; ++i)
			add_files(t, p, l / i->leaf());
	}
	else
	{
		file f(f, file::in);
		f.seek(0, file::end);
		libtorrent::size_type size = f.tell();
		t.add_file(l, size);
	}
}

int main(int argc, char* argv[])
{
	using namespace libtorrent;
	using namespace boost::filesystem;

	if (argc != 4)
	{
		std::cerr << "usage: make_torrent <output torrent-file> <announce url> <file or directory to create torrent from>\n\n"
			"the torrent file will be written to stdout.\n";
		return 1;
	}

	path::default_name_check(native);

	try
	{
		torrent_info t;
		path full_path = initial_path() / path(argv[3]);
		ofstream out(initial_path() / path(argv[1]), std::ios_base::binary);

		int piece_size = 256 * 1024;
		char const* creator_str = "libtorrent";

		add_files(t, full_path.branch_path(), full_path.leaf());
		t.set_piece_size(piece_size);

		storage st(t, full_path.branch_path());
		t.add_tracker(argv[2]);

		// calculate the hash for all pieces
		int num = t.num_pieces();
		std::vector<char> buf(piece_size);
		for (int i = 0; i < num; ++i)
		{
			st.read(&buf[0], i, 0, t.piece_size(i));
			hasher h(&buf[0], t.piece_size(i));
			t.set_hash(i, h.final());
			std::cerr << (i+1) << "/" << num << "\r";
		}

		t.set_creator(creator_str);

		// create the torrent and print it to stdout
		entry e = t.create_torrent();
		libtorrent::bencode(std::ostream_iterator<char>(out), e);
	}
	catch (std::exception& e)
	{
  		std::cerr << e.what() << "\n";
	}

	return 0;
}

<commit_msg>spyhole test cygwin develop context<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 the author 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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 <iostream>
#include <fstream>
#include <iterator>
#include <iomanip>

#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/file.hpp"
#include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>

using namespace boost::filesystem;
using namespace libtorrent;

void add_files(
	torrent_info& t
	, path const& p
	, path const& l)
{
	path f(p / l);
	if (is_directory(f))
	{
		for (directory_iterator i(f), end; i != end; ++i)
			add_files(t, p, l / i->leaf());
	}
	else
	{
		file f(f, file::in);
		f.seek(0, file::end);
		libtorrent::size_type size = f.tell();
		t.add_file(l, size);
	}
}

int main(int argc, char* argv[])
{
	using namespace libtorrent;
	using namespace boost::filesystem;

	if (argc != 4)
	{
		std::cerr << "usage: make_torrent <output torrent-file> <announce url> <file or directory to create torrent from>\n\n"
			"the torrent file will be written to stdout.\n";
		return 1;
	}

	boost::filesystem::path::default_name_check(native);

	try
	{
		torrent_info t;
		path full_path = initial_path() / path(argv[3]);
		ofstream out(initial_path() / path(argv[1]), std::ios_base::binary);

		int piece_size = 256 * 1024;
		char const* creator_str = "libtorrent";

		add_files(t, full_path.branch_path(), full_path.leaf());
		t.set_piece_size(piece_size);

		storage st(t, full_path.branch_path());
		t.add_tracker(argv[2]);

		// calculate the hash for all pieces
		int num = t.num_pieces();
		std::vector<char> buf(piece_size);
		for (int i = 0; i < num; ++i)
		{
			st.read(&buf[0], i, 0, t.piece_size(i));
			hasher h(&buf[0], t.piece_size(i));
			t.set_hash(i, h.final());
			std::cerr << (i+1) << "/" << num << "\r";
		}

		t.set_creator(creator_str);

		// create the torrent and print it to stdout
		entry e = t.create_torrent();
		libtorrent::bencode(std::ostream_iterator<char>(out), e);
	}
	catch (std::exception& e)
	{
  		std::cerr << e.what() << "\n";
	}

	return 0;
}

<|endoftext|>


<commit_before>#ifndef ALEPH_TOPOLOGY_IO_VTK_HH__
#define ALEPH_TOPOLOGY_IO_VTK_HH__

#include <cstddef>

#include <fstream>
#include <regex>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>

#include "utilities/String.hh"

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class VTKStructuredGridReader
  @brief Simple reader class for VTK structured grids

  This class is a simple parser for VTK files in 'legacy format'. It is
  capable of parsing a structured grid and converting it to a simplicial
  complex. Data and weights of the simplicial complex will be taken from
  the VTK file.
*/

class VTKStructuredGridReader
{
public:
  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    std::ifstream in( filename );
    if( !in )
      throw std::runtime_error( "Unable to read input file" );

    this->operator()( in, K );
  }

  template <class SimplicialComplex> void operator()( std::ifstream& in, SimplicialComplex& /* K */ )
  {
    using namespace aleph::utilities;

    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;
    using VertexType = typename Simplex::VertexType;

    std::string line;

    // Parse header first ----------------------------------------------

    std::size_t nx, ny, nz,
                n,
                s;

    bool parsedHeader = this->parseHeader( in, nx, ny, nz, n, s );
    if( !parsedHeader )
      return;

    // TODO: Check data type size against 's' and report if there are
    // issues such as insufficient storage space

    // Parse body ------------------------------------------------------
    //
    // The body contains coordinates for each of the points, which are
    // dutifully ignored for now, and attributes. For now, point-based
    // attributes are supported.

    std::vector<DataType> values;
    values.reserve( n );

    while( std::getline( in, line ) )
    {
      line         = trim( line );
      auto strings = split( line );

      for( auto&& value : strings )
        values.push_back( convert<DataType>( value ) );
    }

    VertexType v;
    (void) v;

    // Create topology -------------------------------------------------
    //
    // The first dimension (x) is increasing fastest. We first need some
    // mapping functions that assign indices based on x,y,z offsets.
    //
    // nx = 3
    // ny = 3
    // nz = 3
    //
    // [0,0,0] [1,0,0] [2,0,0] |  0, 1, 2
    // [0,1,0] [1,1,0] [2,1,0] |  3, 4, 5
    // [0,2,0] [1,2,0] [2,2,0] |  6, 7, 8
    // [0,0,1] [1,0,1] [2,0,1] |  9,10,11
    // [0,1,1] [1,1,1] [2,1,1] | 12,13,14
    // [0,2,1] [1,2,1] [2,2,1] | 15,16,17
    // [0,0,2] [1,0,2] [2,0,2] | 18,19,20
    // [0,1,2] [1,1,2] [2,1,2] | 21,22,23
    // [0,2,2] [1,2,2] [2,2,2] | 24,25,26
    //
    // nx = 1
    // ny = 2
    // nz = 3
    //
    // [0,0,0] [0,1,0] | 0,1
    // [0,0,1] [0,1,1] | 2,3
    // [0,0,2] [0,1,2] | 4,5
    //
    // [0,0,0] | 0
    // [0,1,0] | 1
    // [0,0,1] | 2
    // [0,1,1] | 3
    // [0,0,2] | 4
    // [0,1,2] | 5

#if 0
    auto indexToCoordinates = [nx,ny] ( std::size_t i, std::size_t& x, std::size_t& y, std::size_t& z )
    {
      x = i % nx;
      y = static_cast<std::size_t>( i / (nx)    ) % ny;
      z = static_cast<std::size_t>( i / (nx*ny) );
    };

    auto coordinatesToIndex = [nx,ny] ( std::size_t x, std::size_t y, std::size_t z )
    {
      return z * nx*ny + x % nx + y * nx;
    };
#endif

  }

private:

  /**
    Converts x,y,z coordinates to the corresponding index in the array
    of values.
  */

  static std::size_t coordinatesToIndex( const std::size_t nx, const std::size_t ny,
                                         const std::size_t x , const std::size_t  y, const std::size_t z ) noexcept
  {
   return z * nx*ny + x % nx + y * nx;
  }

  /**
    Enumerates all valid neighbours of a vertex and returns their
    indices. A valid neighbour is a neighbour whose index doesn't
    exceed the bounds of the grid. At present, the diagonal isn't
    used.
  */

  static std::vector<std::size_t> neighbours( const std::size_t nx, const std::size_t ny, const std::size_t nz,
                                              std::size_t x, std::size_t y, std::size_t z )
  {
    std::vector<std::size_t> neighbours;
    neighbours.reserve( 6 );

    // left
    if( x > 0 )
      neighbours.push_back( coordinatesToIndex(nx, ny, x-1, y, z) );
    // right
    else if( x+1 < nx )
      neighbours.push_back( coordinatesToIndex(nx, ny, x+1, y, z) );

    // bottom
    if( y > 0 )
      neighbours.push_back( coordinatesToIndex(nx, ny, x, y-1, z) );
    // top
    else if( y+1 < ny )
      neighbours.push_back( coordinatesToIndex(nx, ny, x, y+1, z) );

    // back
    if( z > 0 )
      neighbours.push_back( coordinatesToIndex(nx, ny, x, y, z-1) );
    // front
    else if( z+1 < nz )
      neighbours.push_back( coordinatesToIndex(nx, ny, x, y, z+1) );

    return neighbours;
  }

  /**
    Attempts parsing the header of a structured VTK file. If successful,
    returns true and sets all output variables:

    - x: x dimension
    - y: y dimension
    - z: z dimension
    - n: number of data points

    This function expects the header to conform to the VTK legacy file
    format.
  */

  bool parseHeader( std::ifstream& in,
                    std::size_t& x, std::size_t& y, std::size_t& z,
                    std::size_t& n,
                    std::size_t& s )
  {
    using namespace aleph::utilities;

    std::string identifier; // e.g. '# vtk DataFile Version 3.0'
    std::string header;     // e.g. 'VTK Output'
    std::string format;     // e.g. 'ASCII'
    std::string structure;  // e.g. 'DATASET STRUCTURED_GRID'
    std::string dimensions; // e.g. 'DIMENSIONS 100 10 1'
    std::string points;     // e.g. 'POINTS 1000 float'

    std::getline( in, identifier );
    std::getline( in, header );
    std::getline( in, format );

    if( !in )
      return false;

    identifier = trim( identifier );
    format     = trim( format );

    // This identifier is a little bit more lenient than the original
    // documentation requires: it will also accept if some fields are
    // joined by multiple spaces.
    std::regex reIdentifier( "#[[:space:]]+vtk[[:space:]]+DataFile[[:space:]]+Version[[:space:]]+([[:digit:]]+)\\.([[:digit:]]+)" );

    if( !std::regex_match( identifier, reIdentifier ) )
      return false;

    if( format != "ASCII" )
      throw std::runtime_error( "Binary file parsing is not yet supported" );

    std::getline( in, structure );
    std::getline( in, dimensions );
    std::getline( in, points );

    if( !in )
      return false;

    structure  = trim( structure );
    dimensions = trim( dimensions );
    points     = trim( points );

    std::regex reStructure( "DATASET[[:space:]]+STRUCTURED_GRID" );
    if( !std::regex_match( structure, reStructure ) )
      return false;

    std::regex reDimensions( "DIMENSIONS[[:space:]]+([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:digit:]]+)" );
    std::smatch matches;

    if( !std::regex_match( dimensions, matches, reDimensions ) )
      return false;

    auto sx = matches[1];
    auto sy = matches[2];
    auto sz = matches[3];

    x = std::size_t( std::stoull( sx ) );
    y = std::size_t( std::stoull( sy ) );
    z = std::size_t( std::stoull( sz ) );

    std::regex rePoints( "POINTS[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]+)" );
    if( !std::regex_match( points, matches, rePoints ) )
      return false;

    auto sn = matches[1];
    auto st = matches[2];

    n = std::size_t( std::stoull( sn ) );

    if( st == "double" )
      s = sizeof(double);
    else if( st == "float" )
      s = sizeof(float);
    else if( st == "long" )
      s = sizeof(long);
    else if( st == "unsigned_long" )
      s = sizeof(unsigned long);
    else if( st == "int" )
      s = sizeof(int);
    else if( st == "unsigned_int" )
      s = sizeof(unsigned int);
    else if( st == "short" )
      s = sizeof(short);
    else if( st == "unsigned_short" )
      s = sizeof(unsigned short);
    else if( st == "char" )
      s = sizeof(char);
    else if( st == "unsigned char" )
      s = sizeof(unsigned char);
    else if( st == "bit" )
      s = sizeof(bool);

    return true;
  }
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<commit_msg>Implemented point data parsing<commit_after>#ifndef ALEPH_TOPOLOGY_IO_VTK_HH__
#define ALEPH_TOPOLOGY_IO_VTK_HH__

#include <cstddef>

#include <fstream>
#include <regex>
#include <stdexcept>
#include <sstream>
#include <string>
#include <vector>

#include "utilities/String.hh"

namespace aleph
{

namespace topology
{

namespace io
{

/**
  @class VTKStructuredGridReader
  @brief Simple reader class for VTK structured grids

  This class is a simple parser for VTK files in 'legacy format'. It is
  capable of parsing a structured grid and converting it to a simplicial
  complex. Data and weights of the simplicial complex will be taken from
  the VTK file.
*/

class VTKStructuredGridReader
{
public:
  template <class SimplicialComplex> void operator()( const std::string& filename, SimplicialComplex& K )
  {
    std::ifstream in( filename );
    if( !in )
      throw std::runtime_error( "Unable to read input file" );

    this->operator()( in, K );
  }

  template <class SimplicialComplex> void operator()( std::ifstream& in, SimplicialComplex& /* K */ )
  {
    using namespace aleph::utilities;

    using Simplex    = typename SimplicialComplex::ValueType;
    using DataType   = typename Simplex::DataType;
    using VertexType = typename Simplex::VertexType;

    std::string line;

    // Parse header first ----------------------------------------------

    std::size_t nx, ny, nz,
                n,
                s;

    bool parsedHeader = this->parseHeader( in, nx, ny, nz, n, s );
    if( !parsedHeader )
      return;

    // TODO: Check data type size against 's' and report if there are
    // issues such as insufficient storage space

    // Parse body ------------------------------------------------------
    //
    // The body contains coordinates for each of the points, which are
    // dutifully ignored for now, and attributes. For now, point-based
    // attributes are supported.

    std::regex rePointData( "POINT_DATA[[:space:]]+([[:digit:]]+)" );
    std::regex reScalars( "SCALARS[[:space:]]+([[:alnum:]]+)[[:space:]]+([[:alnum:]]+)[[:space:]]*([[:digit:]]*)" );
    std::regex reLookupTable( "LOOKUP_TABLE[[:space:]]+([[:alnum:]]+)" );

    std::vector<DataType> coordinates;
    coordinates.reserve( n*3 );

    while( std::getline( in, line ) )
    {
      line         = trim( line );
      auto strings = split( line );

      for( auto&& coordinate : strings )
        coordinates.push_back( convert<DataType>( coordinate ) );

      if( coordinates.size() == n*3 )
        break;
    }

    std::vector<DataType> values;
    values.reserve( n );

    {
      std::smatch matches;

      while( std::getline( in, line ) )
      {
        if( std::regex_match( line, matches, rePointData ) )
        {
          auto sn = matches[1];
          if( static_cast<std::size_t>( std::stoull( sn ) ) != n )
            throw std::runtime_error( "Format error: number of point data attributes does not match number of points" );
        }
        else if( std::regex_match( line, matches, reScalars ) )
        {
          auto name       = matches[1];
          auto type       = matches[2];
          auto components = matches[3];

          // TODO:
          //  - Use name
          //  - Check type
          //  - Check number of components (if present)

          (void) name;
          (void) type;
          (void) components;
        }
        else if( std::regex_match( line, matches, reLookupTable ) )
        {
          auto name = matches[1];
          if( name != "default" )
            throw std::runtime_error( "Handling non-default lookup tables is not yet implemented" );
        }
        else
        {
          line         = trim( line );
          auto strings = split( line );

          for( auto&& value : strings )
            values.push_back( convert<DataType>( value ) );
        }
      }
    }

    VertexType v;
    (void) v;

    // Create topology -------------------------------------------------
    //
    // The first dimension (x) is increasing fastest. We first need some
    // mapping functions that assign indices based on x,y,z offsets.
    //
    // nx = 3
    // ny = 3
    // nz = 3
    //
    // [0,0,0] [1,0,0] [2,0,0] |  0, 1, 2
    // [0,1,0] [1,1,0] [2,1,0] |  3, 4, 5
    // [0,2,0] [1,2,0] [2,2,0] |  6, 7, 8
    // [0,0,1] [1,0,1] [2,0,1] |  9,10,11
    // [0,1,1] [1,1,1] [2,1,1] | 12,13,14
    // [0,2,1] [1,2,1] [2,2,1] | 15,16,17
    // [0,0,2] [1,0,2] [2,0,2] | 18,19,20
    // [0,1,2] [1,1,2] [2,1,2] | 21,22,23
    // [0,2,2] [1,2,2] [2,2,2] | 24,25,26
    //
    // nx = 1
    // ny = 2
    // nz = 3
    //
    // [0,0,0] [0,1,0] | 0,1
    // [0,0,1] [0,1,1] | 2,3
    // [0,0,2] [0,1,2] | 4,5
    //
    // [0,0,0] | 0
    // [0,1,0] | 1
    // [0,0,1] | 2
    // [0,1,1] | 3
    // [0,0,2] | 4
    // [0,1,2] | 5

#if 0
    auto indexToCoordinates = [nx,ny] ( std::size_t i, std::size_t& x, std::size_t& y, std::size_t& z )
    {
      x = i % nx;
      y = static_cast<std::size_t>( i / (nx)    ) % ny;
      z = static_cast<std::size_t>( i / (nx*ny) );
    };

    auto coordinatesToIndex = [nx,ny] ( std::size_t x, std::size_t y, std::size_t z )
    {
      return z * nx*ny + x % nx + y * nx;
    };
#endif

  }

private:

  /**
    Converts x,y,z coordinates to the corresponding index in the array
    of values.
  */

  static std::size_t coordinatesToIndex( const std::size_t nx, const std::size_t ny,
                                         const std::size_t x , const std::size_t  y, const std::size_t z ) noexcept
  {
   return z * nx*ny + x % nx + y * nx;
  }

  /**
    Enumerates all valid neighbours of a vertex and returns their
    indices. A valid neighbour is a neighbour whose index doesn't
    exceed the bounds of the grid. At present, the diagonal isn't
    used.
  */

  static std::vector<std::size_t> neighbours( const std::size_t nx, const std::size_t ny, const std::size_t nz,
                                              std::size_t x, std::size_t y, std::size_t z )
  {
    std::vector<std::size_t> neighbours;
    neighbours.reserve( 6 );

    // left
    if( x > 0 )
      neighbours.push_back( coordinatesToIndex(nx, ny, x-1, y, z) );
    // right
    else if( x+1 < nx )
      neighbours.push_back( coordinatesToIndex(nx, ny, x+1, y, z) );

    // bottom
    if( y > 0 )
      neighbours.push_back( coordinatesToIndex(nx, ny, x, y-1, z) );
    // top
    else if( y+1 < ny )
      neighbours.push_back( coordinatesToIndex(nx, ny, x, y+1, z) );

    // back
    if( z > 0 )
      neighbours.push_back( coordinatesToIndex(nx, ny, x, y, z-1) );
    // front
    else if( z+1 < nz )
      neighbours.push_back( coordinatesToIndex(nx, ny, x, y, z+1) );

    return neighbours;
  }

  /**
    Attempts parsing the header of a structured VTK file. If successful,
    returns true and sets all output variables:

    - x: x dimension
    - y: y dimension
    - z: z dimension
    - n: number of data points

    This function expects the header to conform to the VTK legacy file
    format.
  */

  bool parseHeader( std::ifstream& in,
                    std::size_t& x, std::size_t& y, std::size_t& z,
                    std::size_t& n,
                    std::size_t& s )
  {
    using namespace aleph::utilities;

    std::string identifier; // e.g. '# vtk DataFile Version 3.0'
    std::string header;     // e.g. 'VTK Output'
    std::string format;     // e.g. 'ASCII'
    std::string structure;  // e.g. 'DATASET STRUCTURED_GRID'
    std::string dimensions; // e.g. 'DIMENSIONS 100 10 1'
    std::string points;     // e.g. 'POINTS 1000 float'

    std::getline( in, identifier );
    std::getline( in, header );
    std::getline( in, format );

    if( !in )
      return false;

    identifier = trim( identifier );
    format     = trim( format );

    // This identifier is a little bit more lenient than the original
    // documentation requires: it will also accept if some fields are
    // joined by multiple spaces.
    std::regex reIdentifier( "#[[:space:]]+vtk[[:space:]]+DataFile[[:space:]]+Version[[:space:]]+([[:digit:]]+)\\.([[:digit:]]+)" );

    if( !std::regex_match( identifier, reIdentifier ) )
      return false;

    if( format != "ASCII" )
      throw std::runtime_error( "Binary file parsing is not yet supported" );

    std::getline( in, structure );
    std::getline( in, dimensions );
    std::getline( in, points );

    if( !in )
      return false;

    structure  = trim( structure );
    dimensions = trim( dimensions );
    points     = trim( points );

    std::regex reStructure( "DATASET[[:space:]]+STRUCTURED_GRID" );
    if( !std::regex_match( structure, reStructure ) )
      return false;

    std::regex reDimensions( "DIMENSIONS[[:space:]]+([[:digit:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:digit:]]+)" );
    std::smatch matches;

    if( !std::regex_match( dimensions, matches, reDimensions ) )
      return false;

    auto sx = matches[1];
    auto sy = matches[2];
    auto sz = matches[3];

    x = std::size_t( std::stoull( sx ) );
    y = std::size_t( std::stoull( sy ) );
    z = std::size_t( std::stoull( sz ) );

    std::regex rePoints( "POINTS[[:space:]]+([[:digit:]]+)[[:space:]]+([[:alpha:]]+)" );
    if( !std::regex_match( points, matches, rePoints ) )
      return false;

    auto sn = matches[1];
    auto st = matches[2];

    n = std::size_t( std::stoull( sn ) );

    if( st == "double" )
      s = sizeof(double);
    else if( st == "float" )
      s = sizeof(float);
    else if( st == "long" )
      s = sizeof(long);
    else if( st == "unsigned_long" )
      s = sizeof(unsigned long);
    else if( st == "int" )
      s = sizeof(int);
    else if( st == "unsigned_int" )
      s = sizeof(unsigned int);
    else if( st == "short" )
      s = sizeof(short);
    else if( st == "unsigned_short" )
      s = sizeof(unsigned short);
    else if( st == "char" )
      s = sizeof(char);
    else if( st == "unsigned char" )
      s = sizeof(unsigned char);
    else if( st == "bit" )
      s = sizeof(bool);

    return true;
  }
};

} // namespace io

} // namespace topology

} // namespace aleph

#endif
<|endoftext|>


<commit_before>#include "сomplex_t.hpp"
complex_t::complex_t() : a(0.0), b(0.0)
{}
complex_t::complex_t(double x, double y) : a(x), b(y)
{}
complex_t::complex_t(const complex_t&cop)
{
	a = cop.a;
	b = cop.b;
}
double complex_t::a_() const
{
	return a;
}

double complex_t::b_() const
{
	return b;
}
bool complex_t::operator == (const complex_t& c2) const
{
	if ((a == c2.a) && (b == c2.b))
		return true;
}

complex_t complex_t::operator = (const complex_t& result) const
{
	if (this == &result) {
		return *this;
	}
	a = result.a;
	b = result.b;
	return *this;
}
istream& operator >> (istream&cin, complex_t& result)
{
	cout << "Please enter real complex part:" << endl;
	cin >> result.a;
	cout << "Please enter imaginary complex part:" << endl;
	cin >> result.b;
	cout << endl;
	return cin;
}

ostream& operator << (ostream&cout, complex_t& result)
{
	if (result.b < 0)
	{
		cout << result.a << result.b << "i" << endl;
	}
	else
		cout << result.a << "+" << result.b << "i" << endl;
	return cout;
}
complex_t complex_t::operator * (const complex_t& c2) const
{
	return complex_t(a*c2.a - b*c2.b, a*c2.b + c2.a*b);
}

complex_t complex_t::operator / (const complex_t& c2) const
{
	return complex_t((a*c2.a + b*c2.b) / (c2.a*c2.a + c2.b*c2.b), (c2.a*b - a*c2.b) / (c2.a*c2.a + c2.b*c2.b));
}

complex_t complex_t::operator += (const complex_t& c2) const
{
	a += c2.a;
	b += c2.b;
	return *this;
}

complex_t complex_t::operator -= (const complex_t& c2) const
{
	a -= c2.a;
	b -= c2.b;
	return *this;
}
complex_t complex_t::operator /= (const complex_t& c2) const
{
	float a_ = (a*c2.a + b*c2.b) / (c2.a*c2.a + c2.b*c2.b);
	b = (c2.a*b - a*c2.b) / (c2.a*c2.a + c2.b*c2.b);
	a = a_;
	return *this;
}

complex_t complex_t::operator *= (const complex_t& c2) const
{
	float a_ = a*c2.a - b*c2.b;
	b = a*c2.b + c2.a*b;
	a = a_;
	return *this;
}
<commit_msg>Update сomplex_t.cpp<commit_after>#include "сomplex_t.hpp"
complex_t::complex_t() : a(0.0), b(0.0)
{}
complex_t::complex_t(double x, double y) : a(x), b(y)
{}
complex_t::complex_t(const complex_t&cop)
{
	a = cop.a;
	b = cop.b;
}
double complex_t::a_()
{
	return a;
}

double complex_t::b_()
{
	return b;
}
bool complex_t::operator == (const complex_t& c2) const
{
	if ((a == c2.a) && (b == c2.b))
		return true;
}

complex_t complex_t::operator = (const complex_t& result) const
{
	if (this == &result) {
		return *this;
	}
	a = result.a;
	b = result.b;
	return *this;
}
istream& operator >> (istream&cin, complex_t& result)
{
	cout << "Please enter real complex part:" << endl;
	cin >> result.a;
	cout << "Please enter imaginary complex part:" << endl;
	cin >> result.b;
	cout << endl;
	return cin;
}

ostream& operator << (ostream&cout, complex_t& result)
{
	if (result.b < 0)
	{
		cout << result.a << result.b << "i" << endl;
	}
	else
		cout << result.a << "+" << result.b << "i" << endl;
	return cout;
}
complex_t complex_t::operator * (const complex_t& c2) const
{
	return complex_t(a*c2.a - b*c2.b, a*c2.b + c2.a*b);
}

complex_t complex_t::operator / (const complex_t& c2) const
{
	return complex_t((a*c2.a + b*c2.b) / (c2.a*c2.a + c2.b*c2.b), (c2.a*b - a*c2.b) / (c2.a*c2.a + c2.b*c2.b));
}

complex_t complex_t::operator += (const complex_t& c2) const
{
	a += c2.a;
	b += c2.b;
	return *this;
}

complex_t complex_t::operator -= (const complex_t& c2) const
{
	a -= c2.a;
	b -= c2.b;
	return *this;
}
complex_t complex_t::operator /= (const complex_t& c2) const
{
	float a_ = (a*c2.a + b*c2.b) / (c2.a*c2.a + c2.b*c2.b);
	b = (c2.a*b - a*c2.b) / (c2.a*c2.a + c2.b*c2.b);
	a = a_;
	return *this;
}

complex_t complex_t::operator *= (const complex_t& c2) const
{
	float a_ = a*c2.a - b*c2.b;
	b = a*c2.b + c2.a*b;
	a = a_;
	return *this;
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright (C) 2016 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "tracing/tracing.hh"
#include "utils/class_registrator.hh"
#include "tracing/trace_state.hh"

namespace tracing {

static logging::logger logger("tracing");
const gc_clock::duration tracing::tracing::write_period = std::chrono::seconds(2);

std::vector<sstring> trace_type_names = {
    "NONE",
    "QUERY",
    "REPAIR"
};

tracing::tracing(const sstring& tracing_backend_helper_class_name)
        : _write_timer([this] { write_timer_callback(); })
        , _thread_name(to_sstring(engine().cpu_id()))
        , _registrations{
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "total_operations", "max_sessions_threshold_hits")
                    , scollectd::make_typed(scollectd::data_type::DERIVE, stats.max_sessions_threshold_hits)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "total_operations", "max_traces_threshold_hits")
                    , scollectd::make_typed(scollectd::data_type::DERIVE, stats.max_traces_threshold_hits)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "total_operations", "trace_events_count")
                    , scollectd::make_typed(scollectd::data_type::DERIVE, stats.trace_events_count)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "total_operations", "trace_errors")
                    , scollectd::make_typed(scollectd::data_type::DERIVE, stats.trace_errors)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "queue_length", "active_sessions")
                    , scollectd::make_typed(scollectd::data_type::GAUGE, _active_sessions)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "queue_length", "pending_for_write_sessions")
                    , scollectd::make_typed(scollectd::data_type::GAUGE, _pending_for_write_sessions)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "queue_length", "flushing_sessions")
                    , scollectd::make_typed(scollectd::data_type::GAUGE, _flushing_sessions))}
        , _gen(std::random_device()()) {
    try {
        _tracing_backend_helper_ptr = create_object<i_tracing_backend_helper>(tracing_backend_helper_class_name, *this);
    } catch (no_such_class& e) {
        logger.error("Can't create tracing backend helper {}: not supported", tracing_backend_helper_class_name);
        throw;
    } catch (...) {
        throw;
    }
}

future<> tracing::create_tracing(const sstring& tracing_backend_class_name) {
    return tracing_instance().start(tracing_backend_class_name).then([] {
        return tracing_instance().invoke_on_all([] (tracing& local_tracing) {
            return local_tracing.start();
        });
    });
}

trace_state_ptr tracing::create_session(trace_type type, bool write_on_close, const std::experimental::optional<utils::UUID>& session_id) {
    trace_state_ptr tstate;
    try {
        if (_active_sessions + _pending_for_write_sessions + _flushing_sessions > 2 * max_pending_for_write_sessions) {
            if (session_id) {
                logger.trace("{}: Maximum sessions count is reached. Dropping a secondary session", session_id);
            } else {
                logger.trace("Maximum sessions count is reached. Dropping a primary session");
            }

            if (++stats.max_sessions_threshold_hits % tracing::max_threshold_hits_warning_period == 1) {
                logger.warn("Maximum sessions limit is hit {} times: open_sessions {}, pending_for_flush_sessions {}, flushing_sessions {}",
                            stats.max_sessions_threshold_hits, _active_sessions, _pending_for_write_sessions, _flushing_sessions);
            }

            return trace_state_ptr();
        }

        ++_active_sessions;
        return make_lw_shared<trace_state>(type, write_on_close, session_id);
    } catch (...) {
        // return an uninitialized state in case of any error (OOM?)
        return trace_state_ptr();
    }
}

future<> tracing::start() {
    return _tracing_backend_helper_ptr->start().then([this] {
        _write_timer.arm(write_period);
    });
}

void tracing::write_timer_callback() {
    if (_down) {
        return;
    }

    logger.trace("Timer kicks in: {}", _pending_for_write_sessions ? "writing" : "not writing");
    write_pending_records();
    _write_timer.arm(write_period);
}

future<> tracing::shutdown() {
    logger.info("Asked to shut down");
    write_pending_records();
    _down = true;
    _write_timer.cancel();
    return _tracing_backend_helper_ptr->stop().then([] {
        logger.info("Tracing is down");
    });
}

future<> tracing::stop() {
    if (!_down) {
        throw std::logic_error("tracing: stop() called before shutdown()");
    }

    return make_ready_future<>();
}

void tracing::set_trace_probability(double p) {
    if (p < 0 || p > 1) {
        throw std::invalid_argument("trace probability must be in a [0,1] range");
    }

    _trace_probability = p;
    _normalized_trace_probability = std::llround(_trace_probability * (_gen.max() + 1));

    logger.info("Setting tracing probability to {} (normalized {})", _trace_probability, _normalized_trace_probability);
}
}

<commit_msg>tracing: add a word "shard" to a "thread" value<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*
 * Copyright (C) 2016 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla 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 General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "tracing/tracing.hh"
#include "utils/class_registrator.hh"
#include "tracing/trace_state.hh"

namespace tracing {

static logging::logger logger("tracing");
const gc_clock::duration tracing::tracing::write_period = std::chrono::seconds(2);

std::vector<sstring> trace_type_names = {
    "NONE",
    "QUERY",
    "REPAIR"
};

tracing::tracing(const sstring& tracing_backend_helper_class_name)
        : _write_timer([this] { write_timer_callback(); })
        , _thread_name(seastar::format("shard {:d}", engine().cpu_id()))
        , _registrations{
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "total_operations", "max_sessions_threshold_hits")
                    , scollectd::make_typed(scollectd::data_type::DERIVE, stats.max_sessions_threshold_hits)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "total_operations", "max_traces_threshold_hits")
                    , scollectd::make_typed(scollectd::data_type::DERIVE, stats.max_traces_threshold_hits)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "total_operations", "trace_events_count")
                    , scollectd::make_typed(scollectd::data_type::DERIVE, stats.trace_events_count)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "total_operations", "trace_errors")
                    , scollectd::make_typed(scollectd::data_type::DERIVE, stats.trace_errors)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "queue_length", "active_sessions")
                    , scollectd::make_typed(scollectd::data_type::GAUGE, _active_sessions)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "queue_length", "pending_for_write_sessions")
                    , scollectd::make_typed(scollectd::data_type::GAUGE, _pending_for_write_sessions)),
            scollectd::add_polled_metric(scollectd::type_instance_id("tracing"
                    , scollectd::per_cpu_plugin_instance
                    , "queue_length", "flushing_sessions")
                    , scollectd::make_typed(scollectd::data_type::GAUGE, _flushing_sessions))}
        , _gen(std::random_device()()) {
    try {
        _tracing_backend_helper_ptr = create_object<i_tracing_backend_helper>(tracing_backend_helper_class_name, *this);
    } catch (no_such_class& e) {
        logger.error("Can't create tracing backend helper {}: not supported", tracing_backend_helper_class_name);
        throw;
    } catch (...) {
        throw;
    }
}

future<> tracing::create_tracing(const sstring& tracing_backend_class_name) {
    return tracing_instance().start(tracing_backend_class_name).then([] {
        return tracing_instance().invoke_on_all([] (tracing& local_tracing) {
            return local_tracing.start();
        });
    });
}

trace_state_ptr tracing::create_session(trace_type type, bool write_on_close, const std::experimental::optional<utils::UUID>& session_id) {
    trace_state_ptr tstate;
    try {
        if (_active_sessions + _pending_for_write_sessions + _flushing_sessions > 2 * max_pending_for_write_sessions) {
            if (session_id) {
                logger.trace("{}: Maximum sessions count is reached. Dropping a secondary session", session_id);
            } else {
                logger.trace("Maximum sessions count is reached. Dropping a primary session");
            }

            if (++stats.max_sessions_threshold_hits % tracing::max_threshold_hits_warning_period == 1) {
                logger.warn("Maximum sessions limit is hit {} times: open_sessions {}, pending_for_flush_sessions {}, flushing_sessions {}",
                            stats.max_sessions_threshold_hits, _active_sessions, _pending_for_write_sessions, _flushing_sessions);
            }

            return trace_state_ptr();
        }

        ++_active_sessions;
        return make_lw_shared<trace_state>(type, write_on_close, session_id);
    } catch (...) {
        // return an uninitialized state in case of any error (OOM?)
        return trace_state_ptr();
    }
}

future<> tracing::start() {
    return _tracing_backend_helper_ptr->start().then([this] {
        _write_timer.arm(write_period);
    });
}

void tracing::write_timer_callback() {
    if (_down) {
        return;
    }

    logger.trace("Timer kicks in: {}", _pending_for_write_sessions ? "writing" : "not writing");
    write_pending_records();
    _write_timer.arm(write_period);
}

future<> tracing::shutdown() {
    logger.info("Asked to shut down");
    write_pending_records();
    _down = true;
    _write_timer.cancel();
    return _tracing_backend_helper_ptr->stop().then([] {
        logger.info("Tracing is down");
    });
}

future<> tracing::stop() {
    if (!_down) {
        throw std::logic_error("tracing: stop() called before shutdown()");
    }

    return make_ready_future<>();
}

void tracing::set_trace_probability(double p) {
    if (p < 0 || p > 1) {
        throw std::invalid_argument("trace probability must be in a [0,1] range");
    }

    _trace_probability = p;
    _normalized_trace_probability = std::llround(_trace_probability * (_gen.max() + 1));

    logger.info("Setting tracing probability to {} (normalized {})", _trace_probability, _normalized_trace_probability);
}
}

<|endoftext|>


<commit_before>#include "np/child.hxx"
#include "np/testnode.hxx"
#include "np/job.hxx"
#include "np/event.hxx"
#include "np/proxy_listener.hxx"
#include "np_priv.h"

namespace np {

child_t::child_t(pid_t pid, int fd, job_t *j)
 :  pid_(pid),
    event_pipe_(fd),
    job_(j),
    result_(R_UNKNOWN),
    state_(RUNNING),
    deadline_(j->get_start() + 30 * NANOSEC_PER_SEC)
{
}

child_t::~child_t()
{
    close(event_pipe_);
    delete job_;
}

void
child_t::handle_input()
{
    if (state_ == FINISHED)
	return;
    if (!proxy_listener_t::handle_call(event_pipe_, job_, &result_))
	state_ = FINISHED;
}

void
child_t::handle_timeout(int64_t end)
{
    switch (state_)
    {
    case RUNNING:
	if (deadline_ <= end)
	{
	    event_t ev(EV_TIMEOUT, "Child timed out");
	    merge_result(np::runner_t::running()->raise_event(job_, &ev));

	    kill(pid_, SIGTERM);
	    state_ = TIMEOUT1;
	    deadline_ = end + 3 * NANOSEC_PER_SEC;
	}
	break;
    case TIMEOUT1:
	kill(pid_, SIGKILL);
	state_ = TIMEOUT2;
	deadline_ = 0;
	break;
    default:
	break;
    }
}

void
child_t::merge_result(result_t r)
{
    result_ = merge(result_, r);
}

// close the namespace
};
<commit_msg>Bump up test timeout to 45 sec<commit_after>#include "np/child.hxx"
#include "np/testnode.hxx"
#include "np/job.hxx"
#include "np/event.hxx"
#include "np/proxy_listener.hxx"
#include "np_priv.h"

namespace np {

child_t::child_t(pid_t pid, int fd, job_t *j)
 :  pid_(pid),
    event_pipe_(fd),
    job_(j),
    result_(R_UNKNOWN),
    state_(RUNNING),
    deadline_(j->get_start() + 45 * NANOSEC_PER_SEC)
{
}

child_t::~child_t()
{
    close(event_pipe_);
    delete job_;
}

void
child_t::handle_input()
{
    if (state_ == FINISHED)
	return;
    if (!proxy_listener_t::handle_call(event_pipe_, job_, &result_))
	state_ = FINISHED;
}

void
child_t::handle_timeout(int64_t end)
{
    switch (state_)
    {
    case RUNNING:
	if (deadline_ <= end)
	{
	    event_t ev(EV_TIMEOUT, "Child timed out");
	    merge_result(np::runner_t::running()->raise_event(job_, &ev));

	    kill(pid_, SIGTERM);
	    state_ = TIMEOUT1;
	    deadline_ = end + 3 * NANOSEC_PER_SEC;
	}
	break;
    case TIMEOUT1:
	kill(pid_, SIGKILL);
	state_ = TIMEOUT2;
	deadline_ = 0;
	break;
    default:
	break;
    }
}

void
child_t::merge_result(result_t r)
{
    result_ = merge(result_, r);
}

// close the namespace
};
<|endoftext|>