<commit_before>/* Copyright (c) 2010-2014 Stanford University
 * Copyright (c) 2015 Diego Ongaro
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <cassert>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include "Core/Debug.h"
#include "Core/Endian.h"
#include "Event/Loop.h"
#include "RPC/MessageSocket.h"

namespace LogCabin {
namespace RPC {

namespace {

/// Wrapper for dup().
int
dupOrPanic(int oldfd)
{
    int newfd = dup(oldfd);
    if (newfd < 0)
        PANIC("Failed to dup(%d): %s", oldfd, strerror(errno));
    return newfd;
}

} // anonymous namespace

////////// MessageSocket::SendSocket //////////

MessageSocket::SendSocket::SendSocket(int fd,
                                      MessageSocket& messageSocket)
    : Event::File(fd)
    , messageSocket(messageSocket)
{
    int flag = 1;
    int r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
    if (r < 0) {
        // This should be a warning, but some unit tests pass weird types of
        // file descriptors in here. It's not very important, anyhow.
        NOTICE("Could not set TCP_NODELAY flag on sending socket %d: %s",
               fd, strerror(errno));
    }
}

MessageSocket::SendSocket::~SendSocket()
{
}

void
MessageSocket::SendSocket::handleFileEvent(uint32_t events)
{
    messageSocket.writable();
}

////////// MessageSocket::ReceiveSocket //////////

MessageSocket::ReceiveSocket::ReceiveSocket(int fd,
                                            MessageSocket& messageSocket)
    : Event::File(fd)
    , messageSocket(messageSocket)
{
    // I don't know that TCP_NODELAY has any effect if we're only reading from
    // this file descriptor, but I guess it can't hurt.
    int flag = 1;
    int r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
    if (r < 0) {
        // This should be a warning, but some unit tests pass weird types of
        // file descriptors in here. It's not very important, anyhow.
        NOTICE("Could not set TCP_NODELAY flag on receiving socket %d: %s",
                fd, strerror(errno));
    }
}

MessageSocket::ReceiveSocket::~ReceiveSocket()
{
}

void
MessageSocket::ReceiveSocket::handleFileEvent(uint32_t events)
{
    messageSocket.readable();
}

////////// MessageSocket::Header //////////

void
MessageSocket::Header::fromBigEndian()
{
    fixed = be16toh(fixed);
    version = be16toh(version);
    payloadLength = be32toh(payloadLength);
    messageId = be64toh(messageId);
}

void
MessageSocket::Header::toBigEndian()
{
    fixed = htobe16(fixed);
    version = htobe16(version);
    payloadLength = htobe32(payloadLength);
    messageId = htobe64(messageId);
}

////////// MessageSocket::Inbound //////////

MessageSocket::Inbound::Inbound()
    : bytesRead(0)
    , header()
    , message()
{
}

////////// MessageSocket::Outbound //////////

MessageSocket::Outbound::Outbound()
    : bytesSent(0)
    , header()
    , message()
{
}

MessageSocket::Outbound::Outbound(Outbound&& other)
    : bytesSent(other.bytesSent)
    , header(other.header)
    , message(std::move(other.message))
{
}

MessageSocket::Outbound::Outbound(MessageId messageId,
                                  Core::Buffer message)
    : bytesSent(0)
    , header()
    , message(std::move(message))
{
    header.fixed = 0xdaf4;
    header.version = 1;
    header.payloadLength = uint32_t(this->message.getLength());
    header.messageId = messageId;
    header.toBigEndian();
}

MessageSocket::Outbound&
MessageSocket::Outbound::operator=(Outbound&& other)
{
    bytesSent = other.bytesSent;
    header = other.header;
    message = std::move(other.message);
    return *this;
}

////////// MessageSocket //////////

MessageSocket::MessageSocket(Handler& handler,
                             Event::Loop& eventLoop, int fd,
                             uint32_t maxMessageLength)
    : maxMessageLength(maxMessageLength)
    , handler(handler)
    , eventLoop(eventLoop)
    , inbound()
    , outboundQueueMutex()
    , outboundQueue()
    , receiveSocket(dupOrPanic(fd), *this)
    , sendSocket(fd, *this)
    , receiveSocketMonitor(eventLoop, receiveSocket, EPOLLIN)
    , sendSocketMonitor(eventLoop, sendSocket, 0)
{
}

MessageSocket::~MessageSocket()
{
}

void
MessageSocket::close()
{
    receiveSocketMonitor.disableForever();
    sendSocketMonitor.disableForever();

    // Take an Event::Loop::Lock in case the handler assumes it's being
    // executed on the event loop thread.
    Event::Loop::Lock lock(eventLoop);
    handler.handleDisconnect();
}

void
MessageSocket::sendMessage(MessageId messageId, Core::Buffer contents)
{
    // Check the message length.
    if (contents.getLength() > maxMessageLength) {
        PANIC("Message of length %lu bytes is too long to send "
              "(limit is %u bytes)",
              contents.getLength(), maxMessageLength);
    }

    bool kick;
    { // Place the message on the outbound queue.
        std::lock_guard<Core::Mutex> lock(outboundQueueMutex);
        kick = outboundQueue.empty();
        outboundQueue.emplace_back(messageId, std::move(contents));
    }
    // Make sure the SendSocket is set up to call writable().
    if (kick)
        sendSocketMonitor.setEvents(EPOLLOUT|EPOLLONESHOT);
}

void
MessageSocket::disconnect()
{
    receiveSocketMonitor.disableForever();
    sendSocketMonitor.disableForever();
    // TODO(ongaro): to make it safe for epoll_wait to return multiple events,
    // need to somehow queue the handleDisconnect for later.
    handler.handleDisconnect();
}

void
MessageSocket::readable()
{
    // Try to read data from the kernel until there is no more left.
    while (true) {
        if (inbound.bytesRead < sizeof(Header)) {
            // Receiving header
            ssize_t bytesRead = read(
                reinterpret_cast<char*>(&inbound.header) + inbound.bytesRead,
                sizeof(Header) - inbound.bytesRead);
            if (bytesRead == -1) {
                disconnect();
                return;
            }
            inbound.bytesRead += size_t(bytesRead);
            if (inbound.bytesRead < sizeof(Header))
                return;
            // Transition to receiving data
            inbound.header.fromBigEndian();
            if (inbound.header.fixed != 0xdaf4) {
                WARNING("Disconnecting since message doesn't start with magic "
                        "0xdaf4 (first two bytes are 0x%02x)",
                        inbound.header.fixed);
                disconnect();
            }
            if (inbound.header.version != 1) {
                WARNING("Disconnecting since message uses version %u, but "
                        "this code only understands version 1",
                        inbound.header.version);
                disconnect();
            }
            if (inbound.header.payloadLength > maxMessageLength) {
                WARNING("Disconnecting since message is too long to receive "
                        "(message is %u bytes, limit is %u bytes)",
                        inbound.header.payloadLength, maxMessageLength);
                disconnect();
                return;
            }
            inbound.message.setData(new char[inbound.header.payloadLength],
                                    inbound.header.payloadLength,
                                    Core::Buffer::deleteArrayFn<char>);
        }
        // Don't use 'else' here; we want to check this branch for two reasons:
        // First, if there is a header with a length of 0, the socket won't be
        // readable, but we still need to process the message. Second, most of
        // the time the header will arrive with at least some data. It makes
        // sense to go ahead and try a non-blocking read, rather than going
        // back to the event loop.
        if (inbound.bytesRead >= sizeof(Header)) {
            // Receiving data
            size_t payloadBytesRead = inbound.bytesRead - sizeof(Header);
            ssize_t bytesRead = read(
                (static_cast<char*>(inbound.message.getData()) +
                 payloadBytesRead),
                inbound.header.payloadLength - payloadBytesRead);
            if (bytesRead == -1) {
                disconnect();
                return;
            }
            inbound.bytesRead += size_t(bytesRead);
            if (inbound.bytesRead < (sizeof(Header) +
                                     inbound.header.payloadLength)) {
                return;
            }
            handler.handleReceivedMessage(inbound.header.messageId,
                                          std::move(inbound.message));
            // Transition to receiving header
            inbound.bytesRead = 0;
        }
    }
}

ssize_t
MessageSocket::read(void* buf, size_t maxBytes)
{
    ssize_t actual = recv(receiveSocket.fd, buf, maxBytes, MSG_DONTWAIT);
    if (actual > 0)
        return actual;
    if (actual == 0 || // peer performed orderly shutdown.
        errno == ECONNRESET || errno == ETIMEDOUT || errno == EHOSTUNREACH) {
        return -1;
    }
    if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
        return 0;
    PANIC("Error while reading from socket: %s", strerror(errno));
}

void
MessageSocket::writable()
{
    // Each iteration of this loop tries to write one message
    // from outboundQueue.
    while (true) {

        // Get the next outbound message.
        Outbound outbound;
        int flags = MSG_DONTWAIT | MSG_NOSIGNAL;
        {
            std::lock_guard<Core::Mutex> lock(outboundQueueMutex);
            if (outboundQueue.empty())
                return;
            outbound = std::move(outboundQueue.front());
            outboundQueue.pop_front();
            if (!outboundQueue.empty())
                flags |= MSG_MORE;
        }

        // Use an iovec to send everything in one kernel call: one iov for the
        // header, another for the payload.
        enum { IOV_LEN = 2 };
        struct iovec iov[IOV_LEN];
        iov[0].iov_base = &outbound.header;
        iov[0].iov_len = sizeof(Header);
        iov[1].iov_base = outbound.message.getData();
        iov[1].iov_len = outbound.message.getLength();

        { // Skip the parts of the iovec that have already been sent.
            size_t bytesSent = outbound.bytesSent;
            for (uint32_t i = 0; i < IOV_LEN; ++i) {
                iov[i].iov_base = (static_cast<char*>(iov[i].iov_base) +
                                   bytesSent);
                if (bytesSent < iov[i].iov_len) {
                    iov[i].iov_len -= bytesSent;
                    break;
                } else {
                    bytesSent -= iov[i].iov_len;
                    iov[i].iov_len = 0;
                }
            }
        }

        struct msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = iov;
        msg.msg_iovlen = IOV_LEN;

        // Do the actual send
        ssize_t bytesSent = sendmsg(sendSocket.fd, &msg, flags);
        if (bytesSent < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
                // Wasn't able to send, try again later.
                bytesSent = 0;
            } else if (errno == ECONNRESET || errno == EPIPE) {
                // Connection closed; disconnect this end.
                // This must be the last line to touch this object, in case
                // handleDisconnect() deletes this object.
                disconnect();
                return;
            } else {
                // Unexpected error.
                PANIC("Error while writing to socket %d: %s",
                      sendSocket.fd, strerror(errno));
            }
        }

        // Sent successfully.
        outbound.bytesSent += size_t(bytesSent);
        if (outbound.bytesSent != (sizeof(Header) +
                                   outbound.message.getLength())) {
            sendSocketMonitor.setEvents(EPOLLOUT|EPOLLONESHOT);
            std::lock_guard<Core::Mutex> lockGuard(outboundQueueMutex);
            outboundQueue.emplace_front(std::move(outbound));
            return;
        }
    }
}

} // namespace LogCabin::RPC
} // namespace LogCabin
<commit_msg>MessageSocket: Add missing returns after disconnect()<commit_after>/* Copyright (c) 2010-2014 Stanford University
 * Copyright (c) 2015 Diego Ongaro
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <cassert>
#include <errno.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

#include "Core/Debug.h"
#include "Core/Endian.h"
#include "Event/Loop.h"
#include "RPC/MessageSocket.h"

namespace LogCabin {
namespace RPC {

namespace {

/// Wrapper for dup().
int
dupOrPanic(int oldfd)
{
    int newfd = dup(oldfd);
    if (newfd < 0)
        PANIC("Failed to dup(%d): %s", oldfd, strerror(errno));
    return newfd;
}

} // anonymous namespace

////////// MessageSocket::SendSocket //////////

MessageSocket::SendSocket::SendSocket(int fd,
                                      MessageSocket& messageSocket)
    : Event::File(fd)
    , messageSocket(messageSocket)
{
    int flag = 1;
    int r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
    if (r < 0) {
        // This should be a warning, but some unit tests pass weird types of
        // file descriptors in here. It's not very important, anyhow.
        NOTICE("Could not set TCP_NODELAY flag on sending socket %d: %s",
               fd, strerror(errno));
    }
}

MessageSocket::SendSocket::~SendSocket()
{
}

void
MessageSocket::SendSocket::handleFileEvent(uint32_t events)
{
    messageSocket.writable();
}

////////// MessageSocket::ReceiveSocket //////////

MessageSocket::ReceiveSocket::ReceiveSocket(int fd,
                                            MessageSocket& messageSocket)
    : Event::File(fd)
    , messageSocket(messageSocket)
{
    // I don't know that TCP_NODELAY has any effect if we're only reading from
    // this file descriptor, but I guess it can't hurt.
    int flag = 1;
    int r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(flag));
    if (r < 0) {
        // This should be a warning, but some unit tests pass weird types of
        // file descriptors in here. It's not very important, anyhow.
        NOTICE("Could not set TCP_NODELAY flag on receiving socket %d: %s",
                fd, strerror(errno));
    }
}

MessageSocket::ReceiveSocket::~ReceiveSocket()
{
}

void
MessageSocket::ReceiveSocket::handleFileEvent(uint32_t events)
{
    messageSocket.readable();
}

////////// MessageSocket::Header //////////

void
MessageSocket::Header::fromBigEndian()
{
    fixed = be16toh(fixed);
    version = be16toh(version);
    payloadLength = be32toh(payloadLength);
    messageId = be64toh(messageId);
}

void
MessageSocket::Header::toBigEndian()
{
    fixed = htobe16(fixed);
    version = htobe16(version);
    payloadLength = htobe32(payloadLength);
    messageId = htobe64(messageId);
}

////////// MessageSocket::Inbound //////////

MessageSocket::Inbound::Inbound()
    : bytesRead(0)
    , header()
    , message()
{
}

////////// MessageSocket::Outbound //////////

MessageSocket::Outbound::Outbound()
    : bytesSent(0)
    , header()
    , message()
{
}

MessageSocket::Outbound::Outbound(Outbound&& other)
    : bytesSent(other.bytesSent)
    , header(other.header)
    , message(std::move(other.message))
{
}

MessageSocket::Outbound::Outbound(MessageId messageId,
                                  Core::Buffer message)
    : bytesSent(0)
    , header()
    , message(std::move(message))
{
    header.fixed = 0xdaf4;
    header.version = 1;
    header.payloadLength = uint32_t(this->message.getLength());
    header.messageId = messageId;
    header.toBigEndian();
}

MessageSocket::Outbound&
MessageSocket::Outbound::operator=(Outbound&& other)
{
    bytesSent = other.bytesSent;
    header = other.header;
    message = std::move(other.message);
    return *this;
}

////////// MessageSocket //////////

MessageSocket::MessageSocket(Handler& handler,
                             Event::Loop& eventLoop, int fd,
                             uint32_t maxMessageLength)
    : maxMessageLength(maxMessageLength)
    , handler(handler)
    , eventLoop(eventLoop)
    , inbound()
    , outboundQueueMutex()
    , outboundQueue()
    , receiveSocket(dupOrPanic(fd), *this)
    , sendSocket(fd, *this)
    , receiveSocketMonitor(eventLoop, receiveSocket, EPOLLIN)
    , sendSocketMonitor(eventLoop, sendSocket, 0)
{
}

MessageSocket::~MessageSocket()
{
}

void
MessageSocket::close()
{
    receiveSocketMonitor.disableForever();
    sendSocketMonitor.disableForever();

    // Take an Event::Loop::Lock in case the handler assumes it's being
    // executed on the event loop thread.
    Event::Loop::Lock lock(eventLoop);
    handler.handleDisconnect();
}

void
MessageSocket::sendMessage(MessageId messageId, Core::Buffer contents)
{
    // Check the message length.
    if (contents.getLength() > maxMessageLength) {
        PANIC("Message of length %lu bytes is too long to send "
              "(limit is %u bytes)",
              contents.getLength(), maxMessageLength);
    }

    bool kick;
    { // Place the message on the outbound queue.
        std::lock_guard<Core::Mutex> lock(outboundQueueMutex);
        kick = outboundQueue.empty();
        outboundQueue.emplace_back(messageId, std::move(contents));
    }
    // Make sure the SendSocket is set up to call writable().
    if (kick)
        sendSocketMonitor.setEvents(EPOLLOUT|EPOLLONESHOT);
}

void
MessageSocket::disconnect()
{
    receiveSocketMonitor.disableForever();
    sendSocketMonitor.disableForever();
    // TODO(ongaro): to make it safe for epoll_wait to return multiple events,
    // need to somehow queue the handleDisconnect for later.
    handler.handleDisconnect();
}

void
MessageSocket::readable()
{
    // Try to read data from the kernel until there is no more left.
    while (true) {
        if (inbound.bytesRead < sizeof(Header)) {
            // Receiving header
            ssize_t bytesRead = read(
                reinterpret_cast<char*>(&inbound.header) + inbound.bytesRead,
                sizeof(Header) - inbound.bytesRead);
            if (bytesRead == -1) {
                disconnect();
                return;
            }
            inbound.bytesRead += size_t(bytesRead);
            if (inbound.bytesRead < sizeof(Header))
                return;
            // Transition to receiving data
            inbound.header.fromBigEndian();
            if (inbound.header.fixed != 0xdaf4) {
                WARNING("Disconnecting since message doesn't start with magic "
                        "0xdaf4 (first two bytes are 0x%02x)",
                        inbound.header.fixed);
                disconnect();
                return;
            }
            if (inbound.header.version != 1) {
                WARNING("Disconnecting since message uses version %u, but "
                        "this code only understands version 1",
                        inbound.header.version);
                disconnect();
                return;
            }
            if (inbound.header.payloadLength > maxMessageLength) {
                WARNING("Disconnecting since message is too long to receive "
                        "(message is %u bytes, limit is %u bytes)",
                        inbound.header.payloadLength, maxMessageLength);
                disconnect();
                return;
            }
            inbound.message.setData(new char[inbound.header.payloadLength],
                                    inbound.header.payloadLength,
                                    Core::Buffer::deleteArrayFn<char>);
        }
        // Don't use 'else' here; we want to check this branch for two reasons:
        // First, if there is a header with a length of 0, the socket won't be
        // readable, but we still need to process the message. Second, most of
        // the time the header will arrive with at least some data. It makes
        // sense to go ahead and try a non-blocking read, rather than going
        // back to the event loop.
        if (inbound.bytesRead >= sizeof(Header)) {
            // Receiving data
            size_t payloadBytesRead = inbound.bytesRead - sizeof(Header);
            ssize_t bytesRead = read(
                (static_cast<char*>(inbound.message.getData()) +
                 payloadBytesRead),
                inbound.header.payloadLength - payloadBytesRead);
            if (bytesRead == -1) {
                disconnect();
                return;
            }
            inbound.bytesRead += size_t(bytesRead);
            if (inbound.bytesRead < (sizeof(Header) +
                                     inbound.header.payloadLength)) {
                return;
            }
            handler.handleReceivedMessage(inbound.header.messageId,
                                          std::move(inbound.message));
            // Transition to receiving header
            inbound.bytesRead = 0;
        }
    }
}

ssize_t
MessageSocket::read(void* buf, size_t maxBytes)
{
    ssize_t actual = recv(receiveSocket.fd, buf, maxBytes, MSG_DONTWAIT);
    if (actual > 0)
        return actual;
    if (actual == 0 || // peer performed orderly shutdown.
        errno == ECONNRESET || errno == ETIMEDOUT || errno == EHOSTUNREACH) {
        return -1;
    }
    if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
        return 0;
    PANIC("Error while reading from socket: %s", strerror(errno));
}

void
MessageSocket::writable()
{
    // Each iteration of this loop tries to write one message
    // from outboundQueue.
    while (true) {

        // Get the next outbound message.
        Outbound outbound;
        int flags = MSG_DONTWAIT | MSG_NOSIGNAL;
        {
            std::lock_guard<Core::Mutex> lock(outboundQueueMutex);
            if (outboundQueue.empty())
                return;
            outbound = std::move(outboundQueue.front());
            outboundQueue.pop_front();
            if (!outboundQueue.empty())
                flags |= MSG_MORE;
        }

        // Use an iovec to send everything in one kernel call: one iov for the
        // header, another for the payload.
        enum { IOV_LEN = 2 };
        struct iovec iov[IOV_LEN];
        iov[0].iov_base = &outbound.header;
        iov[0].iov_len = sizeof(Header);
        iov[1].iov_base = outbound.message.getData();
        iov[1].iov_len = outbound.message.getLength();

        { // Skip the parts of the iovec that have already been sent.
            size_t bytesSent = outbound.bytesSent;
            for (uint32_t i = 0; i < IOV_LEN; ++i) {
                iov[i].iov_base = (static_cast<char*>(iov[i].iov_base) +
                                   bytesSent);
                if (bytesSent < iov[i].iov_len) {
                    iov[i].iov_len -= bytesSent;
                    break;
                } else {
                    bytesSent -= iov[i].iov_len;
                    iov[i].iov_len = 0;
                }
            }
        }

        struct msghdr msg;
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = iov;
        msg.msg_iovlen = IOV_LEN;

        // Do the actual send
        ssize_t bytesSent = sendmsg(sendSocket.fd, &msg, flags);
        if (bytesSent < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
                // Wasn't able to send, try again later.
                bytesSent = 0;
            } else if (errno == ECONNRESET || errno == EPIPE) {
                // Connection closed; disconnect this end.
                // This must be the last line to touch this object, in case
                // handleDisconnect() deletes this object.
                disconnect();
                return;
            } else {
                // Unexpected error.
                PANIC("Error while writing to socket %d: %s",
                      sendSocket.fd, strerror(errno));
            }
        }

        // Sent successfully.
        outbound.bytesSent += size_t(bytesSent);
        if (outbound.bytesSent != (sizeof(Header) +
                                   outbound.message.getLength())) {
            sendSocketMonitor.setEvents(EPOLLOUT|EPOLLONESHOT);
            std::lock_guard<Core::Mutex> lockGuard(outboundQueueMutex);
            outboundQueue.emplace_front(std::move(outbound));
            return;
        }
    }
}

} // namespace LogCabin::RPC
} // namespace LogCabin
<|endoftext|>


<commit_before>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <iostream>
#include "core/ast.h"
#include "core/codegen.h"
#include "core/scope.h"
#include "core/compiler.h"

namespace clever { namespace ast {

static inline void _prepare_operand(Operand& op, Node* node)
{
	if (node->isLiteral()) {
		op = Operand(FETCH_CONST, static_cast<Literal*>(node)->getConstId());
	} else if (node->getScope()) {
		op = Operand(FETCH_VAR, node->getValueId(),	node->getScope()->getId());
	} else {
		op = Operand(FETCH_TMP, node->getValueId());
	}
}

void Codegen::visit(IntLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(DoubleLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(StringLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(Ident* node)
{
	Symbol* sym = m_scope->getAny(node->getName());

	if (!sym) {
		Compiler::errorf(node->getLocation(),
			"Variable `%S' not found!", node->getName());
	}

	node->setValueId(sym->value_id);
	node->setScope(sym->scope);
}

void Codegen::visit(Block* node)
{
	m_scope = node->getScope();

	Visitor::visit(static_cast<NodeArray*>(node));

	m_scope = m_scope->getParent();
}

void Codegen::visit(VariableDecl* node)
{
	node->getAssignment()->accept(*this);
}

void Codegen::visit(Assignment* node)
{
	// TODO: allow assignment of any possible left hand side.
	Symbol* sym = static_cast<Ident*>(node->getLhs())->getSymbol();
	Node* rhs = node->getRhs();

	clever_assert_not_null(sym);

	if (node->isConditional()) {
		m_ir.push_back(IR(OP_JMPNZ,
			Operand(FETCH_VAR, sym->value_id, sym->scope->getId()),
			Operand(JMP_ADDR, m_ir.size() + 2)));
	}

	if (rhs) {
		rhs->accept(*this);
	}
	m_ir.push_back(IR(OP_ASSIGN,
			Operand(FETCH_VAR, sym->value_id, sym->scope->getId())));

	if (!rhs) {
		m_ir.back().op2 = Operand(FETCH_TMP, m_compiler->getTempValue());
	} else {
		if (rhs->isLiteral()) {
			m_ir.back().op2 = Operand(FETCH_CONST,
				static_cast<Literal*>(rhs)->getConstId());
		} else if (rhs->getScope()) {
			m_ir.back().op2 = Operand(FETCH_VAR, rhs->getValueId(),
				rhs->getScope()->getId());
		} else {
			m_ir.back().op2 = Operand(FETCH_TMP, rhs->getValueId());
		}
	}
}

void Codegen::visit(FunctionCall* node)
{
	// TODO: allow call for any possible callee
	Symbol* sym = static_cast<Ident*>(node->getCallee())->getSymbol();

	clever_assert_not_null(sym);

	if (node->hasArgs()) {
		NodeList& args = node->getArgs()->getNodes();
		NodeList::const_iterator it = args.begin(), end = args.end();

		while (it != end) {
			Operand operand;

			(*it)->accept(*this);

			if ((*it)->isLiteral()) {
				operand.op_type = FETCH_CONST;
				operand.value_id = static_cast<Literal*>(*it)->getConstId();
			} else {
				operand.op_type = (*it)->isEvaluable() ? FETCH_TMP : FETCH_VAR;
				operand.value_id = (*it)->getValueId();
				if ((*it)->getScope()) {
					operand.scope_id = (*it)->getScope()->getId();
				}
			}
			m_ir.push_back(IR(OP_SEND_VAL, operand));
			++it;
		}
	}

	m_ir.push_back(IR(OP_FCALL,
		Operand(FETCH_VAR, sym->value_id, sym->scope->getId())));

	size_t tmp_id = m_compiler->getTempValue();

	m_ir.back().result = Operand(FETCH_TMP, tmp_id);

	node->setValueId(tmp_id);
}

void Codegen::visit(FunctionDecl* node)
{
	size_t start_func = m_ir.size();

	m_ir.push_back(IR(OP_JMP, Operand(JMP_ADDR, 0)));

	Symbol* sym = node->getIdent()->getSymbol();
	Value* funcval = sym->scope->getValue(sym->value_id);
	Function* func = static_cast<Function*>(funcval->getObj());
	func->setAddr(m_ir.size());

	m_scope = node->getScope();

	if (node->hasArgs()) {
		node->getArgs()->accept(*this);
	}

	node->getBlock()->accept(*this);

	m_scope = m_scope->getParent();

	m_ir.push_back(IR(OP_LEAVE));

	m_ir[start_func].op1.value_id = m_ir.size();

	if (node->isAnonymous()) {
		node->setValueId(sym->value_id);
		node->setScope(sym->scope);
	}
}

void Codegen::visit(Return* node)
{
	if (node->hasValue()) {
		Node* value = node->getValue();

		value->accept(*this);

		m_ir.push_back(IR(OP_RET));

		if (value->isLiteral()) {
			m_ir.back().op1 = Operand(FETCH_CONST,
				static_cast<Literal*>(value)->getConstId());
		} else if (value->getScope()) {
			m_ir.back().op1 = Operand(FETCH_VAR,
				value->getValueId(), value->getScope()->getId());
		} else {
			m_ir.back().op1 = Operand(FETCH_TMP, value->getValueId());
		}
	} else {
		m_ir.push_back(IR(OP_RET));
	}
}

void Codegen::visit(While* node)
{
	size_t start_while = m_ir.size();
	Node* cond = node->getCondition();

	cond->accept(*this);

	if (cond->isLiteral()) {
		m_ir.push_back(IR(OP_JMPZ,
			Operand(FETCH_CONST, static_cast<Literal*>(cond)->getConstId())));
	} else if (cond->getScope()) {
		m_ir.push_back(IR(OP_JMPZ,
			Operand(FETCH_VAR, cond->getValueId(), cond->getScope()->getId())));
	} else {
		m_ir.push_back(IR(OP_JMPZ,	Operand(FETCH_TMP, cond->getValueId())));
	}

	node->getBlock()->accept(*this);

	m_ir.push_back(IR(OP_JMP, Operand(JMP_ADDR, start_while)));

	m_ir[start_while].op2.value_id = m_ir.size();
}

void Codegen::visit(IncDec* node)
{
	Opcode op;

	node->getVar()->accept(*this);

	switch (node->getOperator()) {
		case IncDec::PRE_INC: op = OP_PRE_INC; break;
		case IncDec::PRE_DEC: op = OP_PRE_DEC; break;
		case IncDec::POS_INC: op = OP_POS_INC; break;
		case IncDec::POS_DEC: op = OP_POS_DEC; break;
	}

	m_ir.push_back(IR(op,
		Operand(FETCH_VAR, node->getVar()->getValueId(),
			node->getVar()->getScope()->getId())));

	size_t tmp_id = m_compiler->getTempValue();

	m_ir.back().result = Operand(FETCH_TMP, tmp_id);

	node->setValueId(tmp_id);
}

void Codegen::visit(Arithmetic* node)
{
	Node* lhs = node->getLhs();
	Node* rhs = node->getRhs();
	Opcode op;

	switch (node->getOperator()) {
		case Arithmetic::MOP_ADD: op = OP_ADD; break;
		case Arithmetic::MOP_SUB: op = OP_SUB; break;
		case Arithmetic::MOP_MUL: op = OP_MUL; break;
		case Arithmetic::MOP_DIV: op = OP_DIV; break;
		case Arithmetic::MOP_MOD: op = OP_MOD; break;
	}

	lhs->accept(*this);
	rhs->accept(*this);

	m_ir.push_back(IR(op));

	_prepare_operand(m_ir.back().op1, lhs);
	_prepare_operand(m_ir.back().op2, rhs);

	size_t tmp_id = m_compiler->getTempValue();

	m_ir.back().result = Operand(FETCH_TMP, tmp_id);

	node->setValueId(tmp_id);
}

void Codegen::visit(Logic* node)
{
	Node* lhs = node->getLhs();
	Node* rhs = node->getRhs();
	Opcode op;

	switch (node->getOperator()) {
		case Logic::LOP_EQUALS: op = OP_EQUAL; break;
		case Logic::LOP_AND:    op = OP_AND;   break;
		case Logic::LOP_OR:     op = OP_OR;    break;
	}

	lhs->accept(*this);
	rhs->accept(*this);

	m_ir.push_back(IR(op));

	_prepare_operand(m_ir.back().op1, lhs);
	_prepare_operand(m_ir.back().op2, rhs);

	size_t tmp_id = m_compiler->getTempValue();

	m_ir.back().result = Operand(FETCH_TMP, tmp_id);

	node->setValueId(tmp_id);
}

void Codegen::visit(If* node)
{
	size_t last_jmpz = 0;
	std::vector<std::pair<Node*, Node*> >& branches = node->getConditionals();
	std::vector<std::pair<Node*, Node*> >::const_iterator it(branches.begin()),
		end(branches.end());

	m_jmps.push(AddrVector());

	while (it != end) {
		Node* cond  = (*it).first;
		Node* block = (*it).second;

		cond->accept(*this);

		last_jmpz = m_ir.size();
		m_ir.push_back(IR(OP_JMPZ));

		if (cond->isLiteral()) {
			m_ir.back().op1 = Operand(FETCH_CONST, static_cast<Literal*>(cond)->getConstId());
		} else if (cond->getScope()) {
			m_ir.back().op1 = Operand(FETCH_VAR, cond->getValueId(), cond->getScope()->getId());
		} else {
			m_ir.back().op1 = Operand(FETCH_TMP, cond->getValueId());
		}

		block->accept(*this);

		m_jmps.top().push_back(m_ir.size());
		m_ir.push_back(IR(OP_JMP)); // JMP to outside if-elseif-else

		m_ir[last_jmpz].op2 = Operand(JMP_ADDR, m_ir.size());

		++it;
	}

	if (node->getElseNode()) {
		node->getElseNode()->accept(*this);
	}

	AddrVector& vec = m_jmps.top();
	for (size_t i = 0, j = vec.size(); i < j; ++i) {
		m_ir[vec[i]].op1 = Operand(JMP_ADDR, m_ir.size());
	}

	m_jmps.pop();
}

}} // clever::ast
<commit_msg>- Reuse code!<commit_after>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include <iostream>
#include "core/ast.h"
#include "core/codegen.h"
#include "core/scope.h"
#include "core/compiler.h"

namespace clever { namespace ast {

static inline void _prepare_operand(Operand& op, Node* node)
{
	if (node->isLiteral()) {
		op = Operand(FETCH_CONST, static_cast<Literal*>(node)->getConstId());
	} else if (node->getScope()) {
		op = Operand(FETCH_VAR, node->getValueId(),	node->getScope()->getId());
	} else {
		op = Operand(FETCH_TMP, node->getValueId());
	}
}

void Codegen::visit(IntLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(DoubleLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(StringLit* node)
{
	node->setConstId(m_compiler->addConstant(new Value(node->getValue())));
}

void Codegen::visit(Ident* node)
{
	Symbol* sym = m_scope->getAny(node->getName());

	if (!sym) {
		Compiler::errorf(node->getLocation(),
			"Variable `%S' not found!", node->getName());
	}

	node->setValueId(sym->value_id);
	node->setScope(sym->scope);
}

void Codegen::visit(Block* node)
{
	m_scope = node->getScope();

	Visitor::visit(static_cast<NodeArray*>(node));

	m_scope = m_scope->getParent();
}

void Codegen::visit(VariableDecl* node)
{
	node->getAssignment()->accept(*this);
}

void Codegen::visit(Assignment* node)
{
	// TODO: allow assignment of any possible left hand side.
	Symbol* sym = static_cast<Ident*>(node->getLhs())->getSymbol();
	Node* rhs = node->getRhs();

	clever_assert_not_null(sym);

	if (node->isConditional()) {
		m_ir.push_back(IR(OP_JMPNZ,
			Operand(FETCH_VAR, sym->value_id, sym->scope->getId()),
			Operand(JMP_ADDR, m_ir.size() + 2)));
	}

	if (rhs) {
		rhs->accept(*this);
	}
	m_ir.push_back(IR(OP_ASSIGN,
			Operand(FETCH_VAR, sym->value_id, sym->scope->getId())));

	if (!rhs) {
		m_ir.back().op2 = Operand(FETCH_TMP, m_compiler->getTempValue());
	} else {
		_prepare_operand(m_ir.back().op2, rhs);
	}
}

void Codegen::visit(FunctionCall* node)
{
	// TODO: allow call for any possible callee
	Symbol* sym = static_cast<Ident*>(node->getCallee())->getSymbol();

	clever_assert_not_null(sym);

	if (node->hasArgs()) {
		NodeList& args = node->getArgs()->getNodes();
		NodeList::const_iterator it = args.begin(), end = args.end();

		while (it != end) {
			(*it)->accept(*this);

			m_ir.push_back(IR(OP_SEND_VAL));

			_prepare_operand(m_ir.back().op1, *it);
			++it;
		}
	}

	m_ir.push_back(IR(OP_FCALL,
		Operand(FETCH_VAR, sym->value_id, sym->scope->getId())));

	size_t tmp_id = m_compiler->getTempValue();

	m_ir.back().result = Operand(FETCH_TMP, tmp_id);

	node->setValueId(tmp_id);
}

void Codegen::visit(FunctionDecl* node)
{
	size_t start_func = m_ir.size();

	m_ir.push_back(IR(OP_JMP, Operand(JMP_ADDR, 0)));

	Symbol* sym = node->getIdent()->getSymbol();
	Value* funcval = sym->scope->getValue(sym->value_id);
	Function* func = static_cast<Function*>(funcval->getObj());
	func->setAddr(m_ir.size());

	m_scope = node->getScope();

	if (node->hasArgs()) {
		node->getArgs()->accept(*this);
	}

	node->getBlock()->accept(*this);

	m_scope = m_scope->getParent();

	m_ir.push_back(IR(OP_LEAVE));

	m_ir[start_func].op1.value_id = m_ir.size();

	if (node->isAnonymous()) {
		node->setValueId(sym->value_id);
		node->setScope(sym->scope);
	}
}

void Codegen::visit(Return* node)
{
	if (node->hasValue()) {
		Node* value = node->getValue();

		value->accept(*this);

		m_ir.push_back(IR(OP_RET));

		_prepare_operand(m_ir.back().op1, value);
	} else {
		m_ir.push_back(IR(OP_RET));
	}
}

void Codegen::visit(While* node)
{
	size_t start_while = m_ir.size();
	Node* cond = node->getCondition();

	cond->accept(*this);

	m_ir.push_back(IR(OP_JMPZ));

	_prepare_operand(m_ir.back().op1, cond);

	node->getBlock()->accept(*this);

	m_ir.push_back(IR(OP_JMP, Operand(JMP_ADDR, start_while)));

	m_ir[start_while].op2.value_id = m_ir.size();
}

void Codegen::visit(IncDec* node)
{
	Opcode op;

	node->getVar()->accept(*this);

	switch (node->getOperator()) {
		case IncDec::PRE_INC: op = OP_PRE_INC; break;
		case IncDec::PRE_DEC: op = OP_PRE_DEC; break;
		case IncDec::POS_INC: op = OP_POS_INC; break;
		case IncDec::POS_DEC: op = OP_POS_DEC; break;
	}

	m_ir.push_back(IR(op,
		Operand(FETCH_VAR, node->getVar()->getValueId(),
			node->getVar()->getScope()->getId())));

	size_t tmp_id = m_compiler->getTempValue();

	m_ir.back().result = Operand(FETCH_TMP, tmp_id);

	node->setValueId(tmp_id);
}

void Codegen::visit(Arithmetic* node)
{
	Node* lhs = node->getLhs();
	Node* rhs = node->getRhs();
	Opcode op;

	switch (node->getOperator()) {
		case Arithmetic::MOP_ADD: op = OP_ADD; break;
		case Arithmetic::MOP_SUB: op = OP_SUB; break;
		case Arithmetic::MOP_MUL: op = OP_MUL; break;
		case Arithmetic::MOP_DIV: op = OP_DIV; break;
		case Arithmetic::MOP_MOD: op = OP_MOD; break;
	}

	lhs->accept(*this);
	rhs->accept(*this);

	m_ir.push_back(IR(op));

	_prepare_operand(m_ir.back().op1, lhs);
	_prepare_operand(m_ir.back().op2, rhs);

	size_t tmp_id = m_compiler->getTempValue();

	m_ir.back().result = Operand(FETCH_TMP, tmp_id);

	node->setValueId(tmp_id);
}

void Codegen::visit(Logic* node)
{
	Node* lhs = node->getLhs();
	Node* rhs = node->getRhs();
	Opcode op;

	switch (node->getOperator()) {
		case Logic::LOP_EQUALS: op = OP_EQUAL; break;
		case Logic::LOP_AND:    op = OP_AND;   break;
		case Logic::LOP_OR:     op = OP_OR;    break;
	}

	lhs->accept(*this);
	rhs->accept(*this);

	m_ir.push_back(IR(op));

	_prepare_operand(m_ir.back().op1, lhs);
	_prepare_operand(m_ir.back().op2, rhs);

	size_t tmp_id = m_compiler->getTempValue();

	m_ir.back().result = Operand(FETCH_TMP, tmp_id);

	node->setValueId(tmp_id);
}

void Codegen::visit(If* node)
{
	size_t last_jmpz = 0;
	std::vector<std::pair<Node*, Node*> >& branches = node->getConditionals();
	std::vector<std::pair<Node*, Node*> >::const_iterator it(branches.begin()),
		end(branches.end());

	m_jmps.push(AddrVector());

	while (it != end) {
		Node* cond  = (*it).first;
		Node* block = (*it).second;

		cond->accept(*this);

		last_jmpz = m_ir.size();
		m_ir.push_back(IR(OP_JMPZ));

		_prepare_operand(m_ir.back().op1, cond);

		block->accept(*this);

		m_jmps.top().push_back(m_ir.size());
		m_ir.push_back(IR(OP_JMP)); // JMP to outside if-elseif-else

		m_ir[last_jmpz].op2 = Operand(JMP_ADDR, m_ir.size());

		++it;
	}

	if (node->getElseNode()) {
		node->getElseNode()->accept(*this);
	}

	AddrVector& vec = m_jmps.top();
	for (size_t i = 0, j = vec.size(); i < j; ++i) {
		m_ir[vec[i]].op1 = Operand(JMP_ADDR, m_ir.size());
	}

	m_jmps.pop();
}

}} // clever::ast
<|endoftext|>


<commit_before>/*
    This file is part of KDE-PIM.

    Copyright (c) 2007 Tobias Koenig <tokoe@kde.org>

    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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "vcfendanalyzer.h"

#include <kabc/vcardconverter.h>

#include <strigi/fieldtypes.h>
#include <strigi/analysisresult.h>
#include <strigi/streamendanalyzer.h>

VcfEndAnalyzer::VcfEndAnalyzer( const VcfEndAnalyzerFactory *factory )
  : m_factory( factory )
{
}

bool VcfEndAnalyzer::checkHeader( const char* header, int32_t headersize ) const
{
  const char* magic = "BEGIN:VCARD";
  int32_t magicLength = strlen( magic );

  return headersize >= magicLength && !strncmp( magic, header, magicLength );
}

/**
 * It's easier to use KABC::VCardConverter to extract the single fields from the vCard
 * than doing it manually.
 */
char VcfEndAnalyzer::analyze( Strigi::AnalysisResult& idx, Strigi::InputStream* in )
{
  const char* data;
  if ( in->read( data, 1, in->size() ) < 0 )
    return Strigi::Error;

  const QByteArray text( data, in->size() );

  KABC::VCardConverter converter;
  KABC::Addressee addr = converter.parseVCard( text );

  if ( addr.isEmpty() )
    return Strigi::Error;

  idx.addValue( m_factory->field( Name ), addr.assembledName().toUtf8().data() );
  idx.addValue( m_factory->field( Email ), addr.preferredEmail().toUtf8().data() );
  idx.addValue( m_factory->field( Telephone ), addr.phoneNumbers().first().number().toUtf8().data() );

  return Strigi::Ok;
}

const Strigi::RegisteredField* VcfEndAnalyzerFactory::field( VcfEndAnalyzer::Field field ) const
{
  switch ( field ) {
    default:
    case VcfEndAnalyzer::Name:
      return nameField;
      break;
    case VcfEndAnalyzer::Email:
      return emailField;
      break;
    case VcfEndAnalyzer::Telephone:
      return telephoneField;
      break;
  }
}

void VcfEndAnalyzerFactory::registerFields( Strigi::FieldRegister& reg )
{
  nameField = reg.registerField( "vcf.name", Strigi::FieldRegister::stringType, 1, 0 );
  emailField = reg.registerField( "vcf.email", Strigi::FieldRegister::stringType, 1, 0 );
  telephoneField = reg.registerField( "vcf.telephone", Strigi::FieldRegister::stringType, 1, 0 );
}

<commit_msg>fix bug that causes crash when telephone list is empty.<commit_after>/*
    This file is part of KDE-PIM.

    Copyright (c) 2007 Tobias Koenig <tokoe@kde.org>

    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 of the License, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include "vcfendanalyzer.h"

#include <kabc/vcardconverter.h>

#include <strigi/fieldtypes.h>
#include <strigi/analysisresult.h>
#include <strigi/streamendanalyzer.h>

VcfEndAnalyzer::VcfEndAnalyzer( const VcfEndAnalyzerFactory *factory )
  : m_factory( factory )
{
}

bool VcfEndAnalyzer::checkHeader( const char* header, int32_t headersize ) const
{
  const char* magic = "BEGIN:VCARD";
  int32_t magicLength = strlen( magic );

  return headersize >= magicLength && !strncmp( magic, header, magicLength );
}

/**
 * It's easier to use KABC::VCardConverter to extract the single fields from the vCard
 * than doing it manually.
 */
char VcfEndAnalyzer::analyze( Strigi::AnalysisResult& idx, Strigi::InputStream* in )
{
  const char* data;
  if ( in->read( data, 1, in->size() ) < 0 )
    return Strigi::Error;

  const QByteArray text( data, in->size() );

  KABC::VCardConverter converter;
  KABC::Addressee addr = converter.parseVCard( text );

  if ( addr.isEmpty() )
    return Strigi::Error;

  idx.addValue( m_factory->field( Name ), addr.assembledName().toUtf8().data() );
  idx.addValue( m_factory->field( Email ), addr.preferredEmail().toUtf8().data() );
  if (addr.phoneNumbers().size()) {
    idx.addValue( m_factory->field( Telephone ),
      addr.phoneNumbers().first().number().toUtf8().data() );
  }

  return Strigi::Ok;
}

const Strigi::RegisteredField* VcfEndAnalyzerFactory::field( VcfEndAnalyzer::Field field ) const
{
  switch ( field ) {
    default:
    case VcfEndAnalyzer::Name:
      return nameField;
      break;
    case VcfEndAnalyzer::Email:
      return emailField;
      break;
    case VcfEndAnalyzer::Telephone:
      return telephoneField;
      break;
  }
}

void VcfEndAnalyzerFactory::registerFields( Strigi::FieldRegister& reg )
{
  nameField = reg.registerField( "vcf.name", Strigi::FieldRegister::stringType, 1, 0 );
  emailField = reg.registerField( "vcf.email", Strigi::FieldRegister::stringType, 1, 0 );
  telephoneField = reg.registerField( "vcf.telephone", Strigi::FieldRegister::stringType, 1, 0 );
}

<|endoftext|>


<commit_before>#include "ver_competencia.h"
#include "ui_ver_competencia.h"
#include "qpixmap.h"

ver_competencia::ver_competencia(GUI *guiP, Competencia *compP, QWidget *parent) :
    QDialog(parent), gui(guiP),  ui(new Ui::ver_competencia), comp(compP)
{
    ui->setupUi(this);
    QPixmap pix(":/images/Heros64.png");
    ui->label_logo->setPixmap(pix);

    this->setWindowTitle("Ver competencias deportivas");

    ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);

    QString nombre = "Competencia " + compP->getNombre();
    ui->label->setText(nombre);
    ui->label_7->setText(compP->getModalidad()->getTipoMod()->getNombre());
    ui->label_8->setText(compP->getDeporte()->getNombre());

    ui->label_9->setText(compP->getEstado()->getNombre());
    ui->tableWidget->resizeColumnsToContents();

    //Si la competencia no está en estado creada, se permite ver el fixture y se tilda el checkbox
    if (compP->getEstado()->getNombre().toLower() != "creada"){
        ui->checkBox->setCheckable(true);
        ui->checkBox->setChecked(true);
        ui->checkBox->setDisabled(true);
        ui->pushButton_4->setEnabled(true);
    }
    else {
        ui->pushButton_4->setDisabled(true);
        ui->checkBox->setCheckable(false);
    }

    if(compP->getEstado()->getNombre().toLower() == "en disputa" || compP->getEstado()->getNombre().toLower() == "finalizada" ){
        ui->pushButton_5->setDisabled(true);
    }
    // si la competencia no esta planificada o en disputa no se muestra la tabla
    if (!(compP->getEstado()->getNombre().toLower() == "planificada" || compP->getEstado()->getNombre().toLower() == "en disputa")){
        ui->tableWidget->hide();
        ui->label_6->hide();
    }
    else{
        QVector<Partido*> proxEnc = comp->getProximosEncuentros() ;
        if(proxEnc.size() == 0){

        }
        else{

            for (int i = 0; i < proxEnc.size(); ++i) {
                ui->tableWidget->insertRow(i);
                ui->tableWidget->setItem(i,0,new QTableWidgetItem(proxEnc[i]->getEquipoA()->getNombre()));
                ui->tableWidget->setItem(i,1,new QTableWidgetItem(proxEnc[i]->getEquipoB()->getNombre()));
                ui->tableWidget->setItem(i,2,new QTableWidgetItem(QString::number(proxEnc[i]->getFecha())));

            }
        }
        ui->tableWidget->resizeColumnsToContents();
    }
}

void ver_competencia::actualizar()
{
    Competencia* compP = comp;
    QString nombre = "Competencia " + compP->getNombre();
    ui->label->setText(nombre);
    ui->label_7->setText(compP->getModalidad()->getTipoMod()->getNombre());
    ui->label_8->setText(compP->getDeporte()->getNombre());

    ui->label_9->setText(compP->getEstado()->getNombre());
    ui->tableWidget->resizeColumnsToContents();

    //Si la competencia no está en estado creada, se permite ver el fixture y se tilda el checkbox
    if (compP->getEstado()->getNombre().toLower() != "creada"){
        ui->checkBox->setCheckable(true);
        ui->checkBox->setChecked(true);
        ui->checkBox->setDisabled(true);
        ui->pushButton_4->setEnabled(true);
    }
    else {
        ui->pushButton_4->setDisabled(true);
        ui->checkBox->setCheckable(false);
    }

    if(compP->getEstado()->getNombre().toLower() == "en disputa" || compP->getEstado()->getNombre().toLower() == "finalizada" ){
        ui->pushButton_5->setDisabled(true);
    }
    // si la competencia no esta planificada o en disputa no se muestra la tabla
    if (!(compP->getEstado()->getNombre().toLower() == "planificada" || compP->getEstado()->getNombre().toLower() == "en disputa")){
        ui->tableWidget->hide();
        ui->label_6->hide();
    }
    else{
        QVector<Partido*> proxEnc = comp->getProximosEncuentros() ;
        if(proxEnc.size() == 0){

        }
        else{

            for (int i = 0; i < proxEnc.size(); ++i) {
                ui->tableWidget->insertRow(i);
                ui->tableWidget->setItem(i,0,new QTableWidgetItem(proxEnc[i]->getEquipoA()->getNombre()));
                ui->tableWidget->setItem(i,1,new QTableWidgetItem(proxEnc[i]->getEquipoB()->getNombre()));
                ui->tableWidget->setItem(i,2,new QTableWidgetItem(QString::number(proxEnc[i]->getFecha())));

            }
        }
        ui->tableWidget->resizeColumnsToContents();
    }
}

ver_competencia::~ver_competencia()
{
    delete ui;
}

void ver_competencia::on_pushButton_7_clicked() //Salir
{
    this->close();
}

void ver_competencia::on_pushButton_5_clicked() //Generar fixture
{
    QString error;
    if (gui->handleVerCompetencia(this,QString("generarFixture"), error,comp)){
        //Se coloca el tilde en el checkbox
        ui->checkBox->setCheckable(true);
        ui->checkBox->setChecked(true);
        ui->checkBox->setDisabled(true);

        //También se muestran los próximos encuentros
        ui->tableWidget->show();
        ui->label_6->show();
        QVector<Partido*> proxEnc = comp->getProximosEncuentros();
        ui->tableWidget->setRowCount(0);
        qDebug()<<"proxEnc size = "<<proxEnc.size();
        for (int i = 0; i < proxEnc.size(); ++i) {
            ui->tableWidget->insertRow(i);
            ui->tableWidget->setItem(i,0,new QTableWidgetItem(proxEnc[i]->getEquipoA()->getNombre()));
            ui->tableWidget->setItem(i,1,new QTableWidgetItem(proxEnc[i]->getEquipoB()->getNombre()));
            ui->tableWidget->setItem(i,2,new QTableWidgetItem(QString::number(proxEnc[i]->getFecha())));

        }
        ui->tableWidget->resizeColumnsToContents();

        //Se cambia el estado de la competencia
        ui->label_9->setText(comp->getEstado()->getNombre());
        if(comp->getEstado()->getNombre().toLower() == "en disputa"){

            ui->pushButton_5->setDisabled(true);
        }
    }
    else{
        QMessageBox* msg = new QMessageBox(this);
        msg->setText(error);
        QPixmap icono(":/images/Heros-amarillo-64.png");
        msg->setIconPixmap(icono);
        msg->setModal(true);
        msg->exec();
    }

}

void ver_competencia::on_pushButton_6_clicked() //Mostrar tabla posiciones
{
    // si la competencia está en disputa o finalizada y es de liga se muestra la tabla, si no, no
    if((comp->getEstado()->getNombre().toLower() == "en disputa" ||
        comp->getEstado()->getNombre().toLower() == "finalizada" ) &&
        comp->getModalidad()->getTipoMod()->getNombre().toLower() == "liga")
    {
        QString error;
        gui->handleVerCompetencia(this,QString("mostrarTablasPosiciones"),error,comp);

    }
    else if(comp->getModalidad()->getTipoMod()->getNombre().toLower() != "liga"){
        QMessageBox* msg = new QMessageBox(this);
        QString error = "No es posible mostrar la tabla de posiciones, la competencia no es de la modalidad de liga";
        msg->setText(error);
        QPixmap icono(":/images/Heros-rojo-64.png");
        msg->setIconPixmap(icono);
        msg->setModal(true);
        msg->exec();
    }
    else{
        QMessageBox* msg = new QMessageBox(this);
        QString error = "No es posible mostrar la tabla de posiciones, la competencia no está en disputa o finalizada";
        msg->setText(error);
        QPixmap icono(":/images/Heros-rojo-64.png");
        msg->setIconPixmap(icono);
        msg->setModal(true);
        msg->exec();
    }
}

void ver_competencia::on_pushButton_4_clicked() //Mostrar fixture
{
    QString error;
    gui->handleVerCompetencia(this,QString("mostrarFixture"),error,comp);
}

void ver_competencia::on_pushButton_clicked() //Listar participantes
{
    QString error;
    gui->handleVerCompetencia(this,QString("listarParticipantes"),error,comp);
}

void ver_competencia::on_checkBox_stateChanged(int arg1)
{
    if(arg1 == 0){
        ui->pushButton_4->setDisabled(true);
    }
    else if(arg1 == 2){
        ui->pushButton_4->setEnabled(true);
    }
}
<commit_msg>se borra la competencia al salir de Ver Competencia<commit_after>#include "ver_competencia.h"
#include "ui_ver_competencia.h"
#include "qpixmap.h"

ver_competencia::ver_competencia(GUI *guiP, Competencia *compP, QWidget *parent) :
    QDialog(parent), gui(guiP),  ui(new Ui::ver_competencia), comp(compP)
{
    ui->setupUi(this);
    QPixmap pix(":/images/Heros64.png");
    ui->label_logo->setPixmap(pix);

    this->setWindowTitle("Ver competencias deportivas");

    ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);

    QString nombre = "Competencia " + compP->getNombre();
    ui->label->setText(nombre);
    ui->label_7->setText(compP->getModalidad()->getTipoMod()->getNombre());
    ui->label_8->setText(compP->getDeporte()->getNombre());

    ui->label_9->setText(compP->getEstado()->getNombre());
    ui->tableWidget->resizeColumnsToContents();

    //Si la competencia no está en estado creada, se permite ver el fixture y se tilda el checkbox
    if (compP->getEstado()->getNombre().toLower() != "creada"){
        ui->checkBox->setCheckable(true);
        ui->checkBox->setChecked(true);
        ui->checkBox->setDisabled(true);
        ui->pushButton_4->setEnabled(true);
    }
    else {
        ui->pushButton_4->setDisabled(true);
        ui->checkBox->setCheckable(false);
    }

    if(compP->getEstado()->getNombre().toLower() == "en disputa" || compP->getEstado()->getNombre().toLower() == "finalizada" ){
        ui->pushButton_5->setDisabled(true);
    }
    // si la competencia no esta planificada o en disputa no se muestra la tabla
    if (!(compP->getEstado()->getNombre().toLower() == "planificada" || compP->getEstado()->getNombre().toLower() == "en disputa")){
        ui->tableWidget->hide();
        ui->label_6->hide();
    }
    else{
        QVector<Partido*> proxEnc = comp->getProximosEncuentros() ;
        if(proxEnc.size() == 0){

        }
        else{

            for (int i = 0; i < proxEnc.size(); ++i) {
                ui->tableWidget->insertRow(i);
                ui->tableWidget->setItem(i,0,new QTableWidgetItem(proxEnc[i]->getEquipoA()->getNombre()));
                ui->tableWidget->setItem(i,1,new QTableWidgetItem(proxEnc[i]->getEquipoB()->getNombre()));
                ui->tableWidget->setItem(i,2,new QTableWidgetItem(QString::number(proxEnc[i]->getFecha())));

            }
        }
        ui->tableWidget->resizeColumnsToContents();
    }
}

void ver_competencia::actualizar()
{
    Competencia* compP = comp;
    QString nombre = "Competencia " + compP->getNombre();
    ui->label->setText(nombre);
    ui->label_7->setText(compP->getModalidad()->getTipoMod()->getNombre());
    ui->label_8->setText(compP->getDeporte()->getNombre());

    ui->label_9->setText(compP->getEstado()->getNombre());
    ui->tableWidget->resizeColumnsToContents();

    //Si la competencia no está en estado creada, se permite ver el fixture y se tilda el checkbox
    if (compP->getEstado()->getNombre().toLower() != "creada"){
        ui->checkBox->setCheckable(true);
        ui->checkBox->setChecked(true);
        ui->checkBox->setDisabled(true);
        ui->pushButton_4->setEnabled(true);
    }
    else {
        ui->pushButton_4->setDisabled(true);
        ui->checkBox->setCheckable(false);
    }

    if(compP->getEstado()->getNombre().toLower() == "en disputa" || compP->getEstado()->getNombre().toLower() == "finalizada" ){
        ui->pushButton_5->setDisabled(true);
    }
    // si la competencia no esta planificada o en disputa no se muestra la tabla
    if (!(compP->getEstado()->getNombre().toLower() == "planificada" || compP->getEstado()->getNombre().toLower() == "en disputa")){
        ui->tableWidget->hide();
        ui->label_6->hide();
    }
    else{
        QVector<Partido*> proxEnc = comp->getProximosEncuentros() ;
        if(proxEnc.size() == 0){

        }
        else{

            for (int i = 0; i < proxEnc.size(); ++i) {
                ui->tableWidget->insertRow(i);
                ui->tableWidget->setItem(i,0,new QTableWidgetItem(proxEnc[i]->getEquipoA()->getNombre()));
                ui->tableWidget->setItem(i,1,new QTableWidgetItem(proxEnc[i]->getEquipoB()->getNombre()));
                ui->tableWidget->setItem(i,2,new QTableWidgetItem(QString::number(proxEnc[i]->getFecha())));

            }
        }
        ui->tableWidget->resizeColumnsToContents();
    }
}

ver_competencia::~ver_competencia()
{
    delete ui;
}

void ver_competencia::on_pushButton_7_clicked() //Salir
{
    delete comp;
    this->close();
}

void ver_competencia::on_pushButton_5_clicked() //Generar fixture
{
    QString error;
    if (gui->handleVerCompetencia(this,QString("generarFixture"), error,comp)){
        //Se coloca el tilde en el checkbox
        ui->checkBox->setCheckable(true);
        ui->checkBox->setChecked(true);
        ui->checkBox->setDisabled(true);

        //También se muestran los próximos encuentros
        ui->tableWidget->show();
        ui->label_6->show();
        QVector<Partido*> proxEnc = comp->getProximosEncuentros();
        ui->tableWidget->setRowCount(0);
        qDebug()<<"proxEnc size = "<<proxEnc.size();
        for (int i = 0; i < proxEnc.size(); ++i) {
            ui->tableWidget->insertRow(i);
            ui->tableWidget->setItem(i,0,new QTableWidgetItem(proxEnc[i]->getEquipoA()->getNombre()));
            ui->tableWidget->setItem(i,1,new QTableWidgetItem(proxEnc[i]->getEquipoB()->getNombre()));
            ui->tableWidget->setItem(i,2,new QTableWidgetItem(QString::number(proxEnc[i]->getFecha())));

        }
        ui->tableWidget->resizeColumnsToContents();

        //Se cambia el estado de la competencia
        ui->label_9->setText(comp->getEstado()->getNombre());
        if(comp->getEstado()->getNombre().toLower() == "en disputa"){

            ui->pushButton_5->setDisabled(true);
        }
    }
    else{
        QMessageBox* msg = new QMessageBox(this);
        msg->setText(error);
        QPixmap icono(":/images/Heros-amarillo-64.png");
        msg->setIconPixmap(icono);
        msg->setModal(true);
        msg->exec();
    }

}

void ver_competencia::on_pushButton_6_clicked() //Mostrar tabla posiciones
{
    // si la competencia está en disputa o finalizada y es de liga se muestra la tabla, si no, no
    if((comp->getEstado()->getNombre().toLower() == "en disputa" ||
        comp->getEstado()->getNombre().toLower() == "finalizada" ) &&
        comp->getModalidad()->getTipoMod()->getNombre().toLower() == "liga")
    {
        QString error;
        gui->handleVerCompetencia(this,QString("mostrarTablasPosiciones"),error,comp);

    }
    else if(comp->getModalidad()->getTipoMod()->getNombre().toLower() != "liga"){
        QMessageBox* msg = new QMessageBox(this);
        QString error = "No es posible mostrar la tabla de posiciones, la competencia no es de la modalidad de liga";
        msg->setText(error);
        QPixmap icono(":/images/Heros-rojo-64.png");
        msg->setIconPixmap(icono);
        msg->setModal(true);
        msg->exec();
    }
    else{
        QMessageBox* msg = new QMessageBox(this);
        QString error = "No es posible mostrar la tabla de posiciones, la competencia no está en disputa o finalizada";
        msg->setText(error);
        QPixmap icono(":/images/Heros-rojo-64.png");
        msg->setIconPixmap(icono);
        msg->setModal(true);
        msg->exec();
    }
}

void ver_competencia::on_pushButton_4_clicked() //Mostrar fixture
{
    QString error;
    gui->handleVerCompetencia(this,QString("mostrarFixture"),error,comp);
}

void ver_competencia::on_pushButton_clicked() //Listar participantes
{
    QString error;
    gui->handleVerCompetencia(this,QString("listarParticipantes"),error,comp);
}

void ver_competencia::on_checkBox_stateChanged(int arg1)
{
    if(arg1 == 0){
        ui->pushButton_4->setDisabled(true);
    }
    else if(arg1 == 2){
        ui->pushButton_4->setEnabled(true);
    }
}
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

#include "tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h"
#include "tensorflow/contrib/lite/toco/model.h"
#include "tensorflow/contrib/lite/toco/tooling_util.h"
#include "tensorflow/core/platform/logging.h"

namespace toco {

bool ResolveTensorFlowMerge::Run(Model* model, std::size_t op_index) {
  const auto merge_it = model->operators.begin() + op_index;
  const auto* merge_op = merge_it->get();
  if (merge_op->type != OperatorType::kTensorFlowMerge) {
    return false;
  }

  // We need to yield until this Merge node has only 1 input, which will mean
  // that that is the selected input. Other graph transformations on other nodes
  // such as ResolveTensorFlowSwitch, will take care of trimming the
  // non-selected inputs, so that at some point there will be only 1 input left.
  if (merge_op->inputs.size() > 1) {
    AddMessageF("Waiting for %s to be resolved", LogName(*merge_op));
    return false;
  }

  // Now that the merge node has 1 input exactly, it is the same as an Identity
  // node and can be resolved trivially.
  CHECK_EQ(merge_op->inputs.size(), 1);

  // Update the edges of the graph ahead of removing the node.
  for (const auto& other_op : model->operators) {
    for (auto& input : other_op->inputs) {
      if (input == merge_op->outputs[0]) {
        input = merge_op->inputs[0];
      }
    }
  }

  // Remove the node and its output array.
  AddMessageF("Removing already-resolved %s", LogName(*merge_op));
  model->EraseArray(merge_op->outputs[0]);
  model->operators.erase(merge_it);
  return true;
}

}  // namespace toco
<commit_msg>fix typo<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>

#include "tensorflow/contrib/lite/toco/graph_transformations/graph_transformations.h"
#include "tensorflow/contrib/lite/toco/model.h"
#include "tensorflow/contrib/lite/toco/tooling_util.h"
#include "tensorflow/core/platform/logging.h"

namespace toco {

bool ResolveTensorFlowMerge::Run(Model* model, std::size_t op_index) {
  const auto merge_it = model->operators.begin() + op_index;
  const auto* merge_op = merge_it->get();
  if (merge_op->type != OperatorType::kTensorFlowMerge) {
    return false;
  }

  // We need to yield until this Merge node has only 1 input, which will mean
  // that is the selected input. Other graph transformations on other nodes
  // such as ResolveTensorFlowSwitch, will take care of trimming the
  // non-selected inputs, so that at some point there will be only 1 input left.
  if (merge_op->inputs.size() > 1) {
    AddMessageF("Waiting for %s to be resolved", LogName(*merge_op));
    return false;
  }

  // Now that the merge node has 1 input exactly, it is the same as an Identity
  // node and can be resolved trivially.
  CHECK_EQ(merge_op->inputs.size(), 1);

  // Update the edges of the graph ahead of removing the node.
  for (const auto& other_op : model->operators) {
    for (auto& input : other_op->inputs) {
      if (input == merge_op->outputs[0]) {
        input = merge_op->inputs[0];
      }
    }
  }

  // Remove the node and its output array.
  AddMessageF("Removing already-resolved %s", LogName(*merge_op));
  model->EraseArray(merge_op->outputs[0]);
  model->operators.erase(merge_it);
  return true;
}

}  // namespace toco
<|endoftext|>


<commit_before>/* This file is part of VoltDB.
 * Copyright (C) 2008-2010 VoltDB Inc.
 *
 * VoltDB 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 3 of the License, or
 * (at your option) any later version.
 *
 * VoltDB 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 VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef FATALEXCEPTION_HPP_
#define FATALEXCEPTION_HPP_

#include <cstdio>
#include <string>
#include <string.h>
#include <execinfo.h>
#include <cxxabi.h>
#include <vector>
#include "boost/scoped_array.hpp"

#define throwFatalException(...) { char reallysuperbig_nonce_message[8192]; snprintf(reallysuperbig_nonce_message, 8192, __VA_ARGS__); throw voltdb::FatalException( reallysuperbig_nonce_message, __FILE__, __LINE__); }
namespace voltdb {
class FatalException {
public:
    /**
     * Stack trace code from http://tombarta.wordpress.com/2008/08/01/c-stack-traces-with-gcc/
     *
     */
    FatalException(std::string message, const char *filename, unsigned long lineno) :
        m_reason(message), m_filename(filename), m_lineno(lineno) {
        void *traces[128];
        for (int i=0; i < 128; i++) traces[i] = NULL; // silence valgrind
        const int numTraces = backtrace( traces, 128);
        char** traceSymbols = backtrace_symbols( traces, numTraces);
        for (int ii = 0; ii < numTraces; ii++) {
            std::size_t sz = 200;
            char *function = static_cast<char*>(malloc(sz));
            char *begin = NULL, *end = NULL;
            //Find parens surrounding mangled name
            for (char *j = traceSymbols[ii]; *j; ++j) {
                if (*j == '(') {
                    begin = j;
                }
                else if (*j == '+') {
                    end = j;
                }
            }

            if (begin && end) {
                *begin++ = '\0';
                *end = '\0';

                int status;
                char *ret = abi::__cxa_demangle(begin, function, &sz, &status);
                if (ret) {
                    //return value may be a realloc of input
                    function = ret;
                } else {
                    // demangle failed, treat it like a C function with no args
                    strncpy(function, begin, sz);
                    strncat(function, "()", sz);
                    function[sz-1] = '\0';
                }
                m_traces.push_back(std::string(function));
            } else {
                //didn't find the mangled name in the trace
                m_traces.push_back(std::string(traceSymbols[ii]));
            }
            free(function);
        }
        free(traceSymbols);
    }
    const std::string m_reason;
    const char *m_filename;
    const unsigned long m_lineno;
    std::vector<std::string> m_traces;
};
}
#endif /* FATALEXCEPTION_HPP_ */
<commit_msg>Print FatalException bactraces to file.<commit_after>/* This file is part of VoltDB.
 * Copyright (C) 2008-2010 VoltDB Inc.
 *
 * VoltDB 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 3 of the License, or
 * (at your option) any later version.
 *
 * VoltDB 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 VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef FATALEXCEPTION_HPP_
#define FATALEXCEPTION_HPP_

#include <cstdio>
#include <string>
#include <string.h>
#include <execinfo.h>
#include <cxxabi.h>
#include <vector>
#include "boost/scoped_array.hpp"

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

#define throwFatalException(...) { char reallysuperbig_nonce_message[8192]; snprintf(reallysuperbig_nonce_message, 8192, __VA_ARGS__); throw voltdb::FatalException( reallysuperbig_nonce_message, __FILE__, __LINE__); }
namespace voltdb {
class FatalException {
public:
    /**
     * Stack trace code from http://tombarta.wordpress.com/2008/08/01/c-stack-traces-with-gcc/
     *
     */
    FatalException(std::string message, const char *filename, unsigned long lineno) :
        m_reason(message), m_filename(filename), m_lineno(lineno) {

      FILE *bt = fopen("/tmp/voltdb_backtrace.txt", "a+");

      void *traces[128];
      for (int i=0; i < 128; i++) traces[i] = NULL; // silence valgrind
      const int numTraces = backtrace( traces, 128);
      char** traceSymbols = backtrace_symbols( traces, numTraces);

      // write header for backtrace file
      fprintf(bt, "VoltDB Backtrace (%d)\n", numTraces);

      for (int ii = 0; ii < numTraces; ii++) {
    std::size_t sz = 200;
    char *function = static_cast<char*>(malloc(sz));
    char *begin = NULL, *end = NULL;

    // write original symbol to file.
    fprintf(bt, "raw[%d]: %s\n", ii, traceSymbols[ii]);

    //Find parens surrounding mangled name
    for (char *j = traceSymbols[ii]; *j; ++j) {
      if (*j == '(') {
        begin = j;
      }
      else if (*j == '+') {
        end = j;
      }
    }

    if (begin && end) {
      *begin++ = '\0';
      *end = '\0';

      int status;
      char *ret = abi::__cxa_demangle(begin, function, &sz, &status);
      if (ret) {
        //return value may be a realloc of input
        function = ret;
      } else {
        // demangle failed, treat it like a C function with no args
        strncpy(function, begin, sz);
        strncat(function, "()", sz);
        function[sz-1] = '\0';
      }
      m_traces.push_back(std::string(function));
    } else {
      //didn't find the mangled name in the trace
      m_traces.push_back(std::string(traceSymbols[ii]));
    }
    free(function);
      }

      for (int ii=0; ii < m_traces.size(); ii++) {
    const char* str = m_traces[ii].c_str();
    fprintf(bt, "demangled[%d]: %s\n", ii, str);
      }

      fclose(bt);
      free(traceSymbols);
    }
  const std::string m_reason;
  const char *m_filename;
  const unsigned long m_lineno;
  std::vector<std::string> m_traces;
};
}
#endif /* FATALEXCEPTION_HPP_ */
<|endoftext|>


<commit_before>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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) 2015 Cloudius Systems, Ltd.
 */

#include "fstream.hh"
#include "align.hh"
#include "circular_buffer.hh"
#include "semaphore.hh"
#include "reactor.hh"
#include <malloc.h>
#include <string.h>

class file_data_source_impl : public data_source_impl {
    file _file;
    file_input_stream_options _options;
    uint64_t _pos;
    uint64_t _remain;
    circular_buffer<future<temporary_buffer<char>>> _read_buffers;
    unsigned _reads_in_progress = 0;
    std::experimental::optional<promise<>> _done;
public:
    file_data_source_impl(file f, uint64_t offset, uint64_t len, file_input_stream_options options)
            : _file(std::move(f)), _options(options), _pos(offset), _remain(len) {
        // prevent wraparounds
        _remain = std::min(std::numeric_limits<uint64_t>::max() - _pos, _remain);
    }
    virtual future<temporary_buffer<char>> get() override {
        if (_read_buffers.empty()) {
            issue_read_aheads(1);
        }
        auto ret = std::move(_read_buffers.front());
        _read_buffers.pop_front();
        return ret;
    }
    virtual future<> close() {
        _done.emplace();
        if (!_reads_in_progress) {
            _done->set_value();
        }
        return _done->get_future().then([this] {
            for (auto&& c : _read_buffers) {
                c.ignore_ready_future();
            }
        });
    }
private:
    void issue_read_aheads(unsigned min_ra = 0) {
        if (_done) {
            return;
        }
        auto ra = std::max(min_ra, _options.read_ahead);
        _read_buffers.reserve(ra); // prevent push_back() failure
        while (_read_buffers.size() < ra) {
            if (!_remain) {
                if (_read_buffers.size() >= min_ra) {
                    return;
                }
                _read_buffers.push_back(make_ready_future<temporary_buffer<char>>());
                continue;
            }
            ++_reads_in_progress;
            // if _pos is not dma-aligned, we'll get a short read.  Account for that.
            // Also avoid reading beyond _remain.
            uint64_t align = _file.disk_read_dma_alignment();
            auto start = align_down(_pos, align);
            auto end = align_up(std::min(start + _options.buffer_size, _pos + _remain), align);
            auto len = end - start;
            _read_buffers.push_back(futurize<future<temporary_buffer<char>>>::apply([&] {
                    return _file.dma_read_bulk<char>(start, len, _options.io_priority_class);
            }).then_wrapped(
                    [this, start, end, pos = _pos, remain = _remain] (future<temporary_buffer<char>> ret) {
                issue_read_aheads();
                --_reads_in_progress;
                if (_done && !_reads_in_progress) {
                    _done->set_value();
                }
                if ((pos == start && end <= pos + remain) || ret.failed()) {
                    // no games needed
                    return ret;
                } else {
                    // first or last buffer, need trimming
                    auto tmp = ret.get0();
                    auto real_end = start + tmp.size();
                    if (real_end <= pos) {
                        return make_ready_future<temporary_buffer<char>>();
                    }
                    if (real_end > pos + remain) {
                        tmp.trim(pos + remain - start);
                    }
                    if (start < pos) {
                        tmp.trim_front(pos - start);
                    }
                    return make_ready_future<temporary_buffer<char>>(std::move(tmp));
                }
            }));
            auto old_pos = _pos;
            _pos = end;
            _remain = std::max(_pos, old_pos + _remain) - _pos;
        };
    }
};

class file_data_source : public data_source {
public:
    file_data_source(file f, uint64_t offset, uint64_t len, file_input_stream_options options)
        : data_source(std::make_unique<file_data_source_impl>(
                std::move(f), offset, len, options)) {}
};

input_stream<char> make_file_input_stream(
        file f, uint64_t offset, uint64_t len, file_input_stream_options options) {
    return input_stream<char>(file_data_source(std::move(f), offset, len, std::move(options)));
}

input_stream<char> make_file_input_stream(
        file f, uint64_t offset, file_input_stream_options options) {
    return make_file_input_stream(std::move(f), offset, std::numeric_limits<uint64_t>::max(), std::move(options));
}

input_stream<char> make_file_input_stream(
        file f, file_input_stream_options options) {
    return make_file_input_stream(std::move(f), 0, std::move(options));
}

class file_data_sink_impl : public data_sink_impl {
    file _file;
    file_output_stream_options _options;
    uint64_t _pos = 0;
    semaphore _write_behind_sem = { _options.write_behind };
    future<> _background_writes_done = make_ready_future<>();
    bool _failed = false;
public:
    file_data_sink_impl(file f, file_output_stream_options options)
            : _file(std::move(f)), _options(options) {
        _write_behind_sem.ensure_space_for_waiters(1); // So that wait() doesn't throw
    }
    future<> put(net::packet data) { abort(); }
    virtual temporary_buffer<char> allocate_buffer(size_t size) override {
        return temporary_buffer<char>::aligned(_file.memory_dma_alignment(), size);
    }
    virtual future<> put(temporary_buffer<char> buf) override {
        uint64_t pos = _pos;
        _pos += buf.size();
        if (!_options.write_behind) {
            return do_put(pos, std::move(buf));
        }
        // Write behind strategy:
        //
        // 1. Issue N writes in parallel, using a semaphore to limit to N
        // 2. Collect results in _background_writes_done, merging exception futures
        // 3. If we've already seen a failure, don't issue more writes.
        return _write_behind_sem.wait().then([this, pos, buf = std::move(buf)] () mutable {
            if (_failed) {
                _write_behind_sem.signal();
                auto ret = std::move(_background_writes_done);
                _background_writes_done = make_ready_future<>();
                return ret;
            }
            auto this_write_done = do_put(pos, std::move(buf)).finally([this] {
                _write_behind_sem.signal();
            });
            _background_writes_done = when_all(std::move(_background_writes_done), std::move(this_write_done))
                    .then([this] (std::tuple<future<>, future<>> possible_errors) {
                // merge the two errors, preferring the first
                auto& e1 = std::get<0>(possible_errors);
                auto& e2 = std::get<1>(possible_errors);
                if (e1.failed()) {
                    e2.ignore_ready_future();
                    return std::move(e1);
                } else {
                    if (e2.failed()) {
                        _failed = true;
                    }
                    return std::move(e2);
                }
            });
            return make_ready_future<>();
        });
    }
public:
    future<> do_put(uint64_t pos, temporary_buffer<char> buf) noexcept {
      try {
        // put() must usually be of chunks multiple of file::dma_alignment.
        // Only the last part can have an unaligned length. If put() was
        // called again with an unaligned pos, we have a bug in the caller.
        assert(!(pos & (_file.disk_write_dma_alignment() - 1)));
        bool truncate = false;
        auto p = static_cast<const char*>(buf.get());
        size_t buf_size = buf.size();

        if ((buf.size() & (_file.disk_write_dma_alignment() - 1)) != 0) {
            // If buf size isn't aligned, copy its content into a new aligned buf.
            // This should only happen when the user calls output_stream::flush().
            auto tmp = allocate_buffer(align_up(buf.size(), _file.disk_write_dma_alignment()));
            ::memcpy(tmp.get_write(), buf.get(), buf.size());
            buf = std::move(tmp);
            p = buf.get();
            buf_size = buf.size();
            truncate = true;
        }

        return _file.dma_write(pos, p, buf_size, _options.io_priority_class).then(
                [this, buf = std::move(buf), truncate] (size_t size) {
            if (truncate) {
                return _file.truncate(_pos);
            }
            return make_ready_future<>();
        });
      } catch (...) {
          return make_exception_future<>(std::current_exception());
      }
    }
    future<> wait() noexcept {
        // restore to pristine state; for flush() + close() sequence
        // (we allow either flush, or close, or both)
        return _write_behind_sem.wait(_options.write_behind).then([this] {
            return std::exchange(_background_writes_done, make_ready_future<>());
        }).finally([this] {
            _write_behind_sem.signal(_options.write_behind);
        });
    }
public:
    virtual future<> flush() override {
        return wait().then([this] {
            return _file.flush();
        });
    }
    virtual future<> close() noexcept {
        return wait().finally([this] {
            return _file.close();
        });
    }
};

class file_data_sink : public data_sink {
public:
    file_data_sink(file f, file_output_stream_options options)
        : data_sink(std::make_unique<file_data_sink_impl>(
                std::move(f), options)) {}
};

output_stream<char> make_file_output_stream(file f, size_t buffer_size) {
    file_output_stream_options options;
    options.buffer_size = buffer_size;
    return make_file_output_stream(std::move(f), options);
}

output_stream<char> make_file_output_stream(file f, file_output_stream_options options) {
    return output_stream<char>(file_data_sink(std::move(f), options), options.buffer_size, true);
}

<commit_msg>make fstream skippable<commit_after>/*
 * This file is open source software, licensed to you under the terms
 * of the Apache License, Version 2.0 (the "License").  See the NOTICE file
 * distributed with this work for additional information regarding copyright
 * ownership.  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) 2015 Cloudius Systems, Ltd.
 */

#include "fstream.hh"
#include "align.hh"
#include "circular_buffer.hh"
#include "semaphore.hh"
#include "reactor.hh"
#include <malloc.h>
#include <string.h>

class file_data_source_impl : public data_source_impl {
    struct issued_read {
        uint64_t _pos;
        uint64_t _size;
        future<temporary_buffer<char>> _ready;

        issued_read(uint64_t pos, uint64_t size, future<temporary_buffer<char>> f)
            : _pos(pos), _size(size), _ready(std::move(f)) { }
    };

    file _file;
    file_input_stream_options _options;
    uint64_t _pos;
    uint64_t _remain;
    circular_buffer<issued_read> _read_buffers;
    unsigned _reads_in_progress = 0;
    future<> _dropped_reads = make_ready_future<>();
    std::experimental::optional<promise<>> _done;
public:
    file_data_source_impl(file f, uint64_t offset, uint64_t len, file_input_stream_options options)
            : _file(std::move(f)), _options(options), _pos(offset), _remain(len) {
        // prevent wraparounds
        _remain = std::min(std::numeric_limits<uint64_t>::max() - _pos, _remain);
    }
    virtual future<temporary_buffer<char>> get() override {
        if (_read_buffers.empty()) {
            issue_read_aheads(1);
        }
        auto ret = std::move(_read_buffers.front());
        _read_buffers.pop_front();
        return std::move(ret._ready);
    }
    virtual future<temporary_buffer<char>> skip(uint64_t n) override {
        while (n) {
            if (_read_buffers.empty()) {
                assert(n <= _remain);
                _pos += n;
                _remain -= n;
                break;
            }
            auto& front = _read_buffers.front();
            if (n < front._size) {
                front._size -= n;
                front._pos += n;
                front._ready = front._ready.then([n] (temporary_buffer<char> buf) {
                    buf.trim_front(n);
                    return buf;
                });
                break;
            } else {
                auto f = front._ready.then_wrapped([] (auto f) { f.ignore_ready_future(); });
                _dropped_reads = _dropped_reads.then([f = std::move(f)] () mutable { return std::move(f); });
                n -= front._size;
                _read_buffers.pop_front();
            }
        }
        return make_ready_future<temporary_buffer<char>>();
    }
    virtual future<> close() {
        _done.emplace();
        if (!_reads_in_progress) {
            _done->set_value();
        }
        return _done->get_future().then([this] {
            for (auto&& c : _read_buffers) {
                c._ready.ignore_ready_future();
            }
            return std::move(_dropped_reads);
        });
    }
private:
    void issue_read_aheads(unsigned min_ra = 0) {
        if (_done) {
            return;
        }
        auto ra = std::max(min_ra, _options.read_ahead);
        _read_buffers.reserve(ra); // prevent push_back() failure
        while (_read_buffers.size() < ra) {
            if (!_remain) {
                if (_read_buffers.size() >= min_ra) {
                    return;
                }
                _read_buffers.emplace_back(_pos, 0, make_ready_future<temporary_buffer<char>>());
                continue;
            }
            ++_reads_in_progress;
            // if _pos is not dma-aligned, we'll get a short read.  Account for that.
            // Also avoid reading beyond _remain.
            uint64_t align = _file.disk_read_dma_alignment();
            auto start = align_down(_pos, align);
            auto end = align_up(std::min(start + _options.buffer_size, _pos + _remain), align);
            auto len = end - start;
            auto actual_size = std::min(end - _pos, _remain);
            _read_buffers.emplace_back(_pos, actual_size, futurize<future<temporary_buffer<char>>>::apply([&] {
                    return _file.dma_read_bulk<char>(start, len, _options.io_priority_class);
            }).then_wrapped(
                    [this, start, end, pos = _pos, remain = _remain] (future<temporary_buffer<char>> ret) {
                issue_read_aheads();
                --_reads_in_progress;
                if (_done && !_reads_in_progress) {
                    _done->set_value();
                }
                if ((pos == start && end <= pos + remain) || ret.failed()) {
                    // no games needed
                    return ret;
                } else {
                    // first or last buffer, need trimming
                    auto tmp = ret.get0();
                    auto real_end = start + tmp.size();
                    if (real_end <= pos) {
                        return make_ready_future<temporary_buffer<char>>();
                    }
                    if (real_end > pos + remain) {
                        tmp.trim(pos + remain - start);
                    }
                    if (start < pos) {
                        tmp.trim_front(pos - start);
                    }
                    return make_ready_future<temporary_buffer<char>>(std::move(tmp));
                }
            }));
            auto old_pos = _pos;
            _pos = end;
            _remain = std::max(_pos, old_pos + _remain) - _pos;
        };
    }
};

class file_data_source : public data_source {
public:
    file_data_source(file f, uint64_t offset, uint64_t len, file_input_stream_options options)
        : data_source(std::make_unique<file_data_source_impl>(
                std::move(f), offset, len, options)) {}
};

input_stream<char> make_file_input_stream(
        file f, uint64_t offset, uint64_t len, file_input_stream_options options) {
    return input_stream<char>(file_data_source(std::move(f), offset, len, std::move(options)));
}

input_stream<char> make_file_input_stream(
        file f, uint64_t offset, file_input_stream_options options) {
    return make_file_input_stream(std::move(f), offset, std::numeric_limits<uint64_t>::max(), std::move(options));
}

input_stream<char> make_file_input_stream(
        file f, file_input_stream_options options) {
    return make_file_input_stream(std::move(f), 0, std::move(options));
}

class file_data_sink_impl : public data_sink_impl {
    file _file;
    file_output_stream_options _options;
    uint64_t _pos = 0;
    semaphore _write_behind_sem = { _options.write_behind };
    future<> _background_writes_done = make_ready_future<>();
    bool _failed = false;
public:
    file_data_sink_impl(file f, file_output_stream_options options)
            : _file(std::move(f)), _options(options) {
        _write_behind_sem.ensure_space_for_waiters(1); // So that wait() doesn't throw
    }
    future<> put(net::packet data) { abort(); }
    virtual temporary_buffer<char> allocate_buffer(size_t size) override {
        return temporary_buffer<char>::aligned(_file.memory_dma_alignment(), size);
    }
    virtual future<> put(temporary_buffer<char> buf) override {
        uint64_t pos = _pos;
        _pos += buf.size();
        if (!_options.write_behind) {
            return do_put(pos, std::move(buf));
        }
        // Write behind strategy:
        //
        // 1. Issue N writes in parallel, using a semaphore to limit to N
        // 2. Collect results in _background_writes_done, merging exception futures
        // 3. If we've already seen a failure, don't issue more writes.
        return _write_behind_sem.wait().then([this, pos, buf = std::move(buf)] () mutable {
            if (_failed) {
                _write_behind_sem.signal();
                auto ret = std::move(_background_writes_done);
                _background_writes_done = make_ready_future<>();
                return ret;
            }
            auto this_write_done = do_put(pos, std::move(buf)).finally([this] {
                _write_behind_sem.signal();
            });
            _background_writes_done = when_all(std::move(_background_writes_done), std::move(this_write_done))
                    .then([this] (std::tuple<future<>, future<>> possible_errors) {
                // merge the two errors, preferring the first
                auto& e1 = std::get<0>(possible_errors);
                auto& e2 = std::get<1>(possible_errors);
                if (e1.failed()) {
                    e2.ignore_ready_future();
                    return std::move(e1);
                } else {
                    if (e2.failed()) {
                        _failed = true;
                    }
                    return std::move(e2);
                }
            });
            return make_ready_future<>();
        });
    }
public:
    future<> do_put(uint64_t pos, temporary_buffer<char> buf) noexcept {
      try {
        // put() must usually be of chunks multiple of file::dma_alignment.
        // Only the last part can have an unaligned length. If put() was
        // called again with an unaligned pos, we have a bug in the caller.
        assert(!(pos & (_file.disk_write_dma_alignment() - 1)));
        bool truncate = false;
        auto p = static_cast<const char*>(buf.get());
        size_t buf_size = buf.size();

        if ((buf.size() & (_file.disk_write_dma_alignment() - 1)) != 0) {
            // If buf size isn't aligned, copy its content into a new aligned buf.
            // This should only happen when the user calls output_stream::flush().
            auto tmp = allocate_buffer(align_up(buf.size(), _file.disk_write_dma_alignment()));
            ::memcpy(tmp.get_write(), buf.get(), buf.size());
            buf = std::move(tmp);
            p = buf.get();
            buf_size = buf.size();
            truncate = true;
        }

        return _file.dma_write(pos, p, buf_size, _options.io_priority_class).then(
                [this, buf = std::move(buf), truncate] (size_t size) {
            if (truncate) {
                return _file.truncate(_pos);
            }
            return make_ready_future<>();
        });
      } catch (...) {
          return make_exception_future<>(std::current_exception());
      }
    }
    future<> wait() noexcept {
        // restore to pristine state; for flush() + close() sequence
        // (we allow either flush, or close, or both)
        return _write_behind_sem.wait(_options.write_behind).then([this] {
            return std::exchange(_background_writes_done, make_ready_future<>());
        }).finally([this] {
            _write_behind_sem.signal(_options.write_behind);
        });
    }
public:
    virtual future<> flush() override {
        return wait().then([this] {
            return _file.flush();
        });
    }
    virtual future<> close() noexcept {
        return wait().finally([this] {
            return _file.close();
        });
    }
};

class file_data_sink : public data_sink {
public:
    file_data_sink(file f, file_output_stream_options options)
        : data_sink(std::make_unique<file_data_sink_impl>(
                std::move(f), options)) {}
};

output_stream<char> make_file_output_stream(file f, size_t buffer_size) {
    file_output_stream_options options;
    options.buffer_size = buffer_size;
    return make_file_output_stream(std::move(f), options);
}

output_stream<char> make_file_output_stream(file f, file_output_stream_options options) {
    return output_stream<char>(file_data_sink(std::move(f), options), options.buffer_size, true);
}

<|endoftext|>