<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "fnetlistener.h"
#include "communicationmanager.h"
#include "rpcrequestwrapper.h"
#include <vespa/storageapi/message/state.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/fnet/frt/supervisor.h>
#include <sstream>

#include <vespa/log/log.h>

LOG_SETUP(".rpc.listener");

namespace storage {

FNetListener::FNetListener(CommunicationManager& comManager, const config::ConfigUri & configUri, uint32_t port)
    : _comManager(comManager),
      _orb(std::make_unique<FRT_Supervisor>()),
      _closed(false),
      _slobrokRegister(*_orb, configUri)
{
    initRPC();
    if (!_orb->Listen(port)) {
        std::ostringstream ost;
        ost << "Failed to listen to RPC port " << port << ".";
        throw vespalib::IllegalStateException(ost.str(), VESPA_STRLOC);
    }
    _orb->Start();
}

FNetListener::~FNetListener()
{
    if (!_closed) {
        close();
    }
}

int
FNetListener::getListenPort() const
{
    return _orb->GetListenPort();
}

void
FNetListener::registerHandle(const vespalib::stringref & handle) {
    _slobrokRegister.registerName(handle);
    while (_slobrokRegister.busy()) {
        LOG(debug, "Waiting to register in slobrok");
        FastOS_Thread::Sleep(50);
    }
    _handle = handle;
}

void
FNetListener::close()
{
    _closed = true;
    _slobrokRegister.unregisterName(_handle);
    _orb->ShutDown(true);
}

void
FNetListener::initRPC()
{
    FRT_ReflectionBuilder rb(_orb.get());

    rb.DefineMethod(
            "getnodestate3", "sii", "ss", true,
            FRT_METHOD(FNetListener::RPC_getNodeState2),
            this);
    rb.MethodDesc("Get state of this node");
    rb.ParamDesc("nodestate", "Expected state of given node. If correct, the "
            "request will be queued on target until it changes. To not give "
            "any state use the string 'unknown', enforcing a direct reply.");
    rb.ParamDesc("timeout", "Timeout of message in milliseconds, set by the "
            "state requester");
    rb.ReturnDesc("nodestate", "State string for this node");
    rb.ReturnDesc("hostinfo", "Information about host this node is running on");
    //-------------------------------------------------------------------------
    rb.DefineMethod(
            "getnodestate2", "si", "s", true,
            FRT_METHOD(FNetListener::RPC_getNodeState2),
            this);
    rb.MethodDesc("Get state of this node");
    rb.ParamDesc("nodestate", "Expected state of given node. If correct, the "
            "request will be queued on target until it changes. To not give "
            "any state use the string 'unknown', enforcing a direct reply.");
    rb.ParamDesc("timeout", "Timeout of message in milliseconds, set by the "
            "state requester");
    rb.ReturnDesc("nodestate", "State string for this node");
    //-------------------------------------------------------------------------
    rb.DefineMethod(
            "setsystemstate2", "s", "", true,
            FRT_METHOD(FNetListener::RPC_setSystemState2),
            this);
    rb.MethodDesc("Set systemstate on this node");
    rb.ParamDesc("systemstate", "New systemstate to set");
    //-------------------------------------------------------------------------
    rb.DefineMethod(
            "getcurrenttime", "", "lis", true,
            FRT_METHOD(FNetListener::RPC_getCurrentTime),
            this);
    rb.MethodDesc("Get current time on this node");
    rb.ReturnDesc("seconds", "Current time in seconds since epoch");
    rb.ReturnDesc("nanoseconds", "additional nanoseconds since epoch");
    rb.ReturnDesc("hostname", "Host name");
    //-------------------------------------------------------------------------
}

void
FNetListener::RPC_getCurrentTime(FRT_RPCRequest *req)
{
    if (_closed) {
        LOG(debug, "Not handling RPC call getCurrentTime() as we have closed");
        req->SetError(RPCRequestWrapper::ERR_NODE_SHUTTING_DOWN, "Node shutting down");
        return;
    }
    struct timespec t;
    clock_gettime(CLOCK_REALTIME, &t);
    req->GetReturn()->AddInt64(t.tv_sec);
    req->GetReturn()->AddInt32(t.tv_nsec);
    vespalib::string hostname = vespalib::HostName::get();
    req->GetReturn()->AddString(hostname.c_str());
    // all handled, will return immediately
    return;
}

void
FNetListener::RPC_getNodeState2(FRT_RPCRequest *req)
{
    if (_closed) {
        LOG(debug, "Not handling RPC call getNodeState2() as we have closed");
        req->SetError(RPCRequestWrapper::ERR_NODE_SHUTTING_DOWN, "Node shutting down");
        return;
    }

    vespalib::string expected(req->GetParams()->GetValue(0)._string._str,
                         req->GetParams()->GetValue(0)._string._len);

    std::shared_ptr<api::GetNodeStateCommand> cmd(
            new api::GetNodeStateCommand(
                  expected != "unknown" ?
                    std::unique_ptr<lib::NodeState>(new lib::NodeState(expected)) :
                    std::unique_ptr<lib::NodeState>()));

    cmd->setPriority(api::StorageMessage::VERYHIGH);
    cmd->setTimeout(req->GetParams()->GetValue(1)._intval32);
    if (req->GetParams()->GetNumValues() > 2) {
        cmd->setSourceIndex(req->GetParams()->GetValue(2)._intval32);
    }
        // Create a request object to avoid needing a separate transport type
    std::unique_ptr<RPCRequestWrapper> request(new RPCRequestWrapper(req));
    cmd->setTransportContext(std::unique_ptr<api::TransportContext>(
            new StorageTransportContext(std::move(request))));
    req->Detach();
    _comManager.enqueue(cmd);
}

void
FNetListener::RPC_setSystemState2(FRT_RPCRequest *req)
{
    if (_closed) {
        LOG(debug, "Not handling RPC call setSystemState2() as we have closed");
        req->SetError(RPCRequestWrapper::ERR_NODE_SHUTTING_DOWN, "Node shutting down");
        return;
    }
    vespalib::string systemStateStr(req->GetParams()->GetValue(0)._string._str,
                               req->GetParams()->GetValue(0)._string._len);
    lib::ClusterState systemState(systemStateStr);

    std::shared_ptr<api::SetSystemStateCommand> cmd(
            new api::SetSystemStateCommand(systemState));
    cmd->setPriority(api::StorageMessage::VERYHIGH);

        // Create a request object to avoid needing a separate transport type
    std::unique_ptr<RPCRequestWrapper> request(new RPCRequestWrapper(req));
    cmd->setTransportContext(std::unique_ptr<api::TransportContext>(
            new StorageTransportContext(std::move(request))));
    req->Detach();
    _comManager.enqueue(cmd);
}

}
<commit_msg>Use std::make_unique.<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "fnetlistener.h"
#include "communicationmanager.h"
#include "rpcrequestwrapper.h"
#include <vespa/storageapi/message/state.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/util/host_name.h>
#include <vespa/fnet/frt/supervisor.h>
#include <sstream>

#include <vespa/log/log.h>

LOG_SETUP(".rpc.listener");

namespace storage {

FNetListener::FNetListener(CommunicationManager& comManager, const config::ConfigUri & configUri, uint32_t port)
    : _comManager(comManager),
      _orb(std::make_unique<FRT_Supervisor>()),
      _closed(false),
      _slobrokRegister(*_orb, configUri)
{
    initRPC();
    if (!_orb->Listen(port)) {
        std::ostringstream ost;
        ost << "Failed to listen to RPC port " << port << ".";
        throw vespalib::IllegalStateException(ost.str(), VESPA_STRLOC);
    }
    _orb->Start();
}

FNetListener::~FNetListener()
{
    if (!_closed) {
        close();
    }
}

int
FNetListener::getListenPort() const
{
    return _orb->GetListenPort();
}

void
FNetListener::registerHandle(const vespalib::stringref & handle) {
    _slobrokRegister.registerName(handle);
    while (_slobrokRegister.busy()) {
        LOG(debug, "Waiting to register in slobrok");
        FastOS_Thread::Sleep(50);
    }
    _handle = handle;
}

void
FNetListener::close()
{
    _closed = true;
    _slobrokRegister.unregisterName(_handle);
    _orb->ShutDown(true);
}

void
FNetListener::initRPC()
{
    FRT_ReflectionBuilder rb(_orb.get());

    rb.DefineMethod("getnodestate3", "sii", "ss", true, FRT_METHOD(FNetListener::RPC_getNodeState2), this);
    rb.MethodDesc("Get state of this node");
    rb.ParamDesc("nodestate", "Expected state of given node. If correct, the "
            "request will be queued on target until it changes. To not give "
            "any state use the string 'unknown', enforcing a direct reply.");
    rb.ParamDesc("timeout", "Timeout of message in milliseconds, set by the state requester");
    rb.ReturnDesc("nodestate", "State string for this node");
    rb.ReturnDesc("hostinfo", "Information about host this node is running on");
    //-------------------------------------------------------------------------
    rb.DefineMethod("getnodestate2", "si", "s", true, FRT_METHOD(FNetListener::RPC_getNodeState2), this);
    rb.MethodDesc("Get state of this node");
    rb.ParamDesc("nodestate", "Expected state of given node. If correct, the "
            "request will be queued on target until it changes. To not give "
            "any state use the string 'unknown', enforcing a direct reply.");
    rb.ParamDesc("timeout", "Timeout of message in milliseconds, set by the state requester");
    rb.ReturnDesc("nodestate", "State string for this node");
    //-------------------------------------------------------------------------
    rb.DefineMethod("setsystemstate2", "s", "", true, FRT_METHOD(FNetListener::RPC_setSystemState2), this);
    rb.MethodDesc("Set systemstate on this node");
    rb.ParamDesc("systemstate", "New systemstate to set");
    //-------------------------------------------------------------------------
    rb.DefineMethod("getcurrenttime", "", "lis", true, FRT_METHOD(FNetListener::RPC_getCurrentTime), this);
    rb.MethodDesc("Get current time on this node");
    rb.ReturnDesc("seconds", "Current time in seconds since epoch");
    rb.ReturnDesc("nanoseconds", "additional nanoseconds since epoch");
    rb.ReturnDesc("hostname", "Host name");
    //-------------------------------------------------------------------------
}

void
FNetListener::RPC_getCurrentTime(FRT_RPCRequest *req)
{
    if (_closed) {
        LOG(debug, "Not handling RPC call getCurrentTime() as we have closed");
        req->SetError(RPCRequestWrapper::ERR_NODE_SHUTTING_DOWN, "Node shutting down");
        return;
    }
    struct timespec t;
    clock_gettime(CLOCK_REALTIME, &t);
    req->GetReturn()->AddInt64(t.tv_sec);
    req->GetReturn()->AddInt32(t.tv_nsec);
    vespalib::string hostname = vespalib::HostName::get();
    req->GetReturn()->AddString(hostname.c_str());
    // all handled, will return immediately
    return;
}

void
FNetListener::RPC_getNodeState2(FRT_RPCRequest *req)
{
    if (_closed) {
        LOG(debug, "Not handling RPC call getNodeState2() as we have closed");
        req->SetError(RPCRequestWrapper::ERR_NODE_SHUTTING_DOWN, "Node shutting down");
        return;
    }

    vespalib::string expected(req->GetParams()->GetValue(0)._string._str,
                         req->GetParams()->GetValue(0)._string._len);

    std::shared_ptr<api::GetNodeStateCommand> cmd(
            new api::GetNodeStateCommand(expected != "unknown"
                                         ? std::make_unique<lib::NodeState>(expected)
                                         : std::unique_ptr<lib::NodeState>()));

    cmd->setPriority(api::StorageMessage::VERYHIGH);
    cmd->setTimeout(req->GetParams()->GetValue(1)._intval32);
    if (req->GetParams()->GetNumValues() > 2) {
        cmd->setSourceIndex(req->GetParams()->GetValue(2)._intval32);
    }
        // Create a request object to avoid needing a separate transport type
    cmd->setTransportContext(std::make_unique<StorageTransportContext>(std::make_unique<RPCRequestWrapper>(req)));
    req->Detach();
    _comManager.enqueue(cmd);
}

void
FNetListener::RPC_setSystemState2(FRT_RPCRequest *req)
{
    if (_closed) {
        LOG(debug, "Not handling RPC call setSystemState2() as we have closed");
        req->SetError(RPCRequestWrapper::ERR_NODE_SHUTTING_DOWN, "Node shutting down");
        return;
    }
    vespalib::string systemStateStr(req->GetParams()->GetValue(0)._string._str,
                                    req->GetParams()->GetValue(0)._string._len);
    lib::ClusterState systemState(systemStateStr);

    std::shared_ptr<api::SetSystemStateCommand> cmd(std::make_shared<api::SetSystemStateCommand>(systemState));
    cmd->setPriority(api::StorageMessage::VERYHIGH);

    // Create a request object to avoid needing a separate transport type
    cmd->setTransportContext(std::make_unique<StorageTransportContext>(std::make_unique<RPCRequestWrapper>(req)));
    req->Detach();
    _comManager.enqueue(cmd);
}

}
<|endoftext|>


<commit_before>#include <QtDebug>
#include <duipannableviewport.h>
#include <QGraphicsLayout>
#include <QGridLayout>
#include "duiwidgetview.h"
#include "duilabel.h"
#include "duilinearlayout.h"

#include "dcppage.h"
#include "dcpbackgroundview.h"

DcpPage::DcpPage() : DuiApplicationPage()
{
}

DcpPage::~DcpPage()
{
    if (m_DesktopViewport)
        delete m_DesktopViewport;
    if (m_PanWidget)
        delete m_PanWidget;
    if (m_PanLayout)
        delete m_PanLayout;
    if (m_MainLayout)
        delete m_MainLayout;
    if (m_Title)
        delete m_Title;
    if (m_BackgroundView)
        delete m_BackgroundView;
}

void DcpPage::createContent()
{
    m_MainLayout = new DuiLinearLayout(Qt::Vertical);
    m_DesktopViewport = new DuiPannableViewport(Qt::Vertical, this);
    m_BackgroundView = new DcpBackgroundView(m_DesktopViewport);
    m_DesktopViewport->setView(m_BackgroundView);
    m_PanWidget = new DuiWidget();
    m_PanLayout = new DuiLinearLayout(Qt::Vertical);
    m_PanWidget->setLayout(m_PanLayout);
    m_DesktopViewport->setWidget(m_PanWidget);

    m_Title = new DuiLabel("-");
    m_Title->setAlignment(Qt::AlignCenter);
    m_Title->setMaximumHeight(30);
    m_MainLayout->addItem(m_Title);
    m_MainLayout->addItem(m_DesktopViewport);
    setLayout(m_MainLayout);
}

const QString
DcpPage::title() const
{
    return m_Title->text();
}

void
DcpPage::setTitle(const QString& title)
{
    m_Title->setText(title);
}

void DcpPage::organizeContent(Dui::Orientation ori)
{
    Q_UNUSED(ori);

    // make the layout reorganize its elements:
    QGraphicsLayout* layout = this->layout();
    if (!layout) return;
    layout->invalidate();
    layout->activate();
}

<commit_msg>The destructor of dcppage was modified.<commit_after>#include <QtDebug>
#include <duipannableviewport.h>
#include <QGraphicsLayout>
#include <QGridLayout>
#include "duiwidgetview.h"
#include "duilabel.h"
#include "duilinearlayout.h"

#include "dcppage.h"
#include "dcpbackgroundview.h"

DcpPage::DcpPage() : DuiApplicationPage()
{
}

DcpPage::~DcpPage()
{
    if (m_DesktopViewport)
        delete m_DesktopViewport;
    if (m_Title)
        delete m_Title;
    if (m_BackgroundView)
        delete m_BackgroundView;
}

void DcpPage::createContent()
{
    m_MainLayout = new DuiLinearLayout(Qt::Vertical);
    m_DesktopViewport = new DuiPannableViewport(Qt::Vertical, this);
    m_BackgroundView = new DcpBackgroundView(m_DesktopViewport);
    m_DesktopViewport->setView(m_BackgroundView);
    m_PanWidget = new DuiWidget();
    m_PanLayout = new DuiLinearLayout(Qt::Vertical);
    m_PanWidget->setLayout(m_PanLayout);
    m_DesktopViewport->setWidget(m_PanWidget);

    m_Title = new DuiLabel("-");
    m_Title->setAlignment(Qt::AlignCenter);
    m_Title->setMaximumHeight(30);
    m_MainLayout->addItem(m_Title);
    m_MainLayout->addItem(m_DesktopViewport);
    setLayout(m_MainLayout);
}

const QString
DcpPage::title() const
{
    return m_Title->text();
}

void
DcpPage::setTitle(const QString& title)
{
    m_Title->setText(title);
}

void DcpPage::organizeContent(Dui::Orientation ori)
{
    Q_UNUSED(ori);

    // make the layout reorganize its elements:
    QGraphicsLayout* layout = this->layout();
    if (!layout) return;
    layout->invalidate();
    layout->activate();
}

<|endoftext|>


<commit_before>/*
 * Copyright 2017-present Facebook, Inc.
 *
 * 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 "Mocks.h"

using namespace folly;
using namespace testing;
using namespace wangle;

using TestServer = ServerBootstrap<DefaultPipeline>;
using TestClient = ClientBootstrap<DefaultPipeline>;

class TestClientPipelineFactory : public PipelineFactory<DefaultPipeline> {
 public:
  DefaultPipeline::Ptr newPipeline(
      std::shared_ptr<AsyncTransportWrapper> socket) override {
    // Socket should be connected already
    EXPECT_TRUE(socket->good());

    auto pipeline = DefaultPipeline::create();
    pipeline->addBack(wangle::AsyncSocketHandler(socket));
    pipeline->finalize();
    return pipeline;
  }
};

class AcceptRoutingHandlerTest : public Test {
 public:
  void SetUp() override {
    routingData_.routingData = 'A';

    downstreamHandler_ = new MockBytesToBytesHandler();
    downstreamPipelineFactory_ =
        std::make_shared<MockDownstreamPipelineFactory>(downstreamHandler_);

    server_ = std::make_unique<TestServer>();

    // A routing pipeline with a mock routing handler that we can set
    // expectations on.
    routingPipeline_ = DefaultPipeline::create();

    routingDataHandlerFactory_ =
        std::make_shared<MockRoutingDataHandlerFactory>();
    acceptRoutingHandler_ = new MockAcceptRoutingHandler(
        server_.get(),
        routingDataHandlerFactory_,
        downstreamPipelineFactory_,
        routingPipeline_);
    routingDataHandler_ =
        new MockRoutingDataHandler(kConnId0, acceptRoutingHandler_);
    routingDataHandlerFactory_->setRoutingDataHandler(routingDataHandler_);

    acceptPipeline_ = AcceptPipeline::create();
    acceptPipeline_->addBack(
        std::shared_ptr<MockAcceptRoutingHandler>(acceptRoutingHandler_));
    acceptPipeline_->finalize();

    // A single threaded IOGroup shared between client and server for a
    // deterministic event list.
    auto ioGroup = std::make_shared<IOThreadPoolExecutor>(kNumIOThreads);

    acceptPipelineFactory_ =
        std::make_shared<MockAcceptPipelineFactory>(acceptPipeline_);
    server_->pipeline(acceptPipelineFactory_)->group(ioGroup, ioGroup)->bind(0);
    server_->getSockets()[0]->getAddress(&address_);
    VLOG(4) << "Start server at " << address_;
  }

  EventBase* getEventBase() {
    return server_->getIOGroup()->getEventBase();
  }

  Future<DefaultPipeline*> clientConnect() {
    client_ = std::make_shared<TestClient>();
    client_->pipelineFactory(std::make_shared<TestClientPipelineFactory>());
    client_->group(server_->getIOGroup());
    return client_->connect(address_);
  }

  Future<DefaultPipeline*> clientConnectAndWrite() {
    auto clientPipelinePromise =
        std::make_shared<folly::Promise<DefaultPipeline*>>();

    getEventBase()->runInEventBaseThread([=]() {
      clientConnect().then([=](DefaultPipeline* clientPipeline) {
        VLOG(4) << "Client connected. Send data.";
        auto data = IOBuf::create(1);
        data->append(1);
        *(data->writableData()) = 'a';
        clientPipeline->write(std::move(data)).then([=]() {
          clientPipelinePromise->setValue(clientPipeline);
        });
      });
    });

    return clientPipelinePromise->getFuture();
  }

  Future<DefaultPipeline*> clientConnectAndCleanClose() {
    auto clientPipelinePromise =
        std::make_shared<folly::Promise<DefaultPipeline*>>();

    getEventBase()->runInEventBaseThread([=]() {
      clientConnectAndWrite().then([=](DefaultPipeline* clientPipeline) {
        VLOG(4) << "Client close";
        clientPipeline->close().then(
            [=]() { clientPipelinePromise->setValue(clientPipeline); });
      });
    });

    return clientPipelinePromise->getFuture();
  }

  Future<DefaultPipeline*> justClientConnect() {
    auto clientPipelinePromise =
        std::make_shared<folly::Promise<DefaultPipeline*>>();
    getEventBase()->runInEventBaseThread([=]() {
      clientConnect().then([=](DefaultPipeline* clientPipeline) {
        clientPipelinePromise->setValue(clientPipeline);
      });
    });

    return clientPipelinePromise->getFuture();
  }

  void sendClientException(DefaultPipeline* clientPipeline) {
    getEventBase()->runInEventBaseThread([=]() {
      clientPipeline->writeException(
          std::runtime_error("Client socket exception, right after connect."));
    });
  }

  void TearDown() override {
    acceptPipeline_.reset();
    acceptPipelineFactory_->cleanup();
  }

 protected:
  std::unique_ptr<TestServer> server_;
  std::shared_ptr<MockAcceptPipelineFactory> acceptPipelineFactory_;
  AcceptPipeline::Ptr acceptPipeline_;
  DefaultPipeline::Ptr routingPipeline_;
  std::shared_ptr<MockRoutingDataHandlerFactory> routingDataHandlerFactory_;
  MockRoutingDataHandler* routingDataHandler_;

  MockAcceptRoutingHandler* acceptRoutingHandler_;
  MockBytesToBytesHandler* downstreamHandler_;
  std::shared_ptr<MockDownstreamPipelineFactory> downstreamPipelineFactory_;
  SocketAddress address_;
  RoutingDataHandler<char>::RoutingData routingData_;

  std::shared_ptr<TestClient> client_;

  int kConnId0{0};
  int kNumIOThreads{1};
};

TEST_F(AcceptRoutingHandlerTest, ParseRoutingDataSuccess) {
  // Server receives data, and parses routing data
  EXPECT_CALL(*routingDataHandler_, transportActive(_));
  EXPECT_CALL(*routingDataHandler_, parseRoutingData(_, _))
      .WillOnce(
          Invoke([&](folly::IOBufQueue& /*bufQueue*/,
                     MockRoutingDataHandler::RoutingData& /*routingData*/) {
            VLOG(4) << "Parsed routing data";
            return true;
          }));

  // Downstream pipeline is created, and its handler receives events
  boost::barrier barrier(2);
  EXPECT_CALL(*downstreamHandler_, transportActive(_));
  EXPECT_CALL(*downstreamHandler_, read(_, _))
      .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* /*ctx*/,
                           IOBufQueue& /*bufQueue*/) {
        VLOG(4) << "Downstream received a read";
      }));
  EXPECT_CALL(*downstreamHandler_, readEOF(_))
      .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* ctx) {
        VLOG(4) << "Downstream EOF";
        ctx->fireClose();
        barrier.wait();
      }));
  EXPECT_CALL(*downstreamHandler_, transportInactive(_));

  // Send client request that triggers server processing
  clientConnectAndCleanClose();

  barrier.wait();

  // Routing pipeline has been erased
  EXPECT_EQ(0, acceptRoutingHandler_->getRoutingPipelineCount());
}

TEST_F(AcceptRoutingHandlerTest, SocketErrorInRoutingPipeline) {
  // Server receives data, and parses routing data
  boost::barrier barrierConnect(2);
  EXPECT_CALL(*routingDataHandler_, transportActive(_));
  EXPECT_CALL(*routingDataHandler_, parseRoutingData(_, _))
      .WillOnce(
          Invoke([&](folly::IOBufQueue& /*bufQueue*/,
                     MockRoutingDataHandler::RoutingData& /*routingData*/) {
            VLOG(4) << "Need more data to be parse.";
            barrierConnect.wait();
            return false;
          }));

  // Send client request that triggers server processing
  auto futureClientPipeline = clientConnectAndWrite();

  // Socket exception after routing pipeline had been created
  barrierConnect.wait();
  boost::barrier barrierException(2);
  std::move(futureClientPipeline).then([](DefaultPipeline* clientPipeline) {
    clientPipeline->getTransport()->getEventBase()->runInEventBaseThread(
        [clientPipeline]() {
          clientPipeline->writeException(
              std::runtime_error("Socket error while expecting routing data."));
        });
  });
  EXPECT_CALL(*routingDataHandler_, readException(_, _))
      .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* /*ctx*/,
                           folly::exception_wrapper ex) {
        VLOG(4) << "Routing data handler Exception";
        acceptRoutingHandler_->onError(kConnId0, ex);
        barrierException.wait();
      }));
  barrierException.wait();

  // Downstream pipeline is not created
  EXPECT_CALL(*downstreamHandler_, transportActive(_)).Times(0);
  delete downstreamHandler_;

  // Routing pipeline has been erased
  EXPECT_EQ(0, acceptRoutingHandler_->getRoutingPipelineCount());
}

TEST_F(AcceptRoutingHandlerTest, OnNewConnectionWithBadSocket) {
  // Routing data handler doesn't receive any data
  EXPECT_CALL(*routingDataHandler_, parseRoutingData(_, _)).Times(0);

  // Downstream pipeline is not created
  EXPECT_CALL(*downstreamHandler_, transportActive(_)).Times(0);
  delete downstreamHandler_;

  // Send client request that triggers server processing
  boost::barrier barrierConnect(2);
  EXPECT_CALL(*routingDataHandler_, transportActive(_))
      .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* /*ctx*/) {
        barrierConnect.wait();
      }));
  auto futureClientPipeline = justClientConnect();
  barrierConnect.wait();
  futureClientPipeline.wait();

  // Expect an exception on the routing data handler
  boost::barrier barrierException(2);
  EXPECT_CALL(*routingDataHandler_, readException(_, _))
      .WillOnce(Invoke(
          [&](MockBytesToBytesHandler::Context* /*ctx*/,
              folly::exception_wrapper /*ex*/) { barrierException.wait(); }));
  sendClientException(futureClientPipeline.value());
  barrierException.wait();

  // Routing pipeline has been added
  EXPECT_EQ(1, acceptRoutingHandler_->getRoutingPipelineCount());
}

TEST_F(AcceptRoutingHandlerTest, RoutingPipelineErasedOnlyOnce) {
  // Simulate client socket throwing an exception, while routing data handler
  // parsed data successfully.
  acceptPipeline_->readException(
      std::runtime_error("An exception from the socket."));
  acceptRoutingHandler_->onRoutingData(kConnId0, routingData_);
}
<commit_msg>then to thenValue<commit_after>/*
 * Copyright 2017-present Facebook, Inc.
 *
 * 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 "Mocks.h"

using namespace folly;
using namespace testing;
using namespace wangle;

using TestServer = ServerBootstrap<DefaultPipeline>;
using TestClient = ClientBootstrap<DefaultPipeline>;

class TestClientPipelineFactory : public PipelineFactory<DefaultPipeline> {
 public:
  DefaultPipeline::Ptr newPipeline(
      std::shared_ptr<AsyncTransportWrapper> socket) override {
    // Socket should be connected already
    EXPECT_TRUE(socket->good());

    auto pipeline = DefaultPipeline::create();
    pipeline->addBack(wangle::AsyncSocketHandler(socket));
    pipeline->finalize();
    return pipeline;
  }
};

class AcceptRoutingHandlerTest : public Test {
 public:
  void SetUp() override {
    routingData_.routingData = 'A';

    downstreamHandler_ = new MockBytesToBytesHandler();
    downstreamPipelineFactory_ =
        std::make_shared<MockDownstreamPipelineFactory>(downstreamHandler_);

    server_ = std::make_unique<TestServer>();

    // A routing pipeline with a mock routing handler that we can set
    // expectations on.
    routingPipeline_ = DefaultPipeline::create();

    routingDataHandlerFactory_ =
        std::make_shared<MockRoutingDataHandlerFactory>();
    acceptRoutingHandler_ = new MockAcceptRoutingHandler(
        server_.get(),
        routingDataHandlerFactory_,
        downstreamPipelineFactory_,
        routingPipeline_);
    routingDataHandler_ =
        new MockRoutingDataHandler(kConnId0, acceptRoutingHandler_);
    routingDataHandlerFactory_->setRoutingDataHandler(routingDataHandler_);

    acceptPipeline_ = AcceptPipeline::create();
    acceptPipeline_->addBack(
        std::shared_ptr<MockAcceptRoutingHandler>(acceptRoutingHandler_));
    acceptPipeline_->finalize();

    // A single threaded IOGroup shared between client and server for a
    // deterministic event list.
    auto ioGroup = std::make_shared<IOThreadPoolExecutor>(kNumIOThreads);

    acceptPipelineFactory_ =
        std::make_shared<MockAcceptPipelineFactory>(acceptPipeline_);
    server_->pipeline(acceptPipelineFactory_)->group(ioGroup, ioGroup)->bind(0);
    server_->getSockets()[0]->getAddress(&address_);
    VLOG(4) << "Start server at " << address_;
  }

  EventBase* getEventBase() {
    return server_->getIOGroup()->getEventBase();
  }

  Future<DefaultPipeline*> clientConnect() {
    client_ = std::make_shared<TestClient>();
    client_->pipelineFactory(std::make_shared<TestClientPipelineFactory>());
    client_->group(server_->getIOGroup());
    return client_->connect(address_);
  }

  Future<DefaultPipeline*> clientConnectAndWrite() {
    auto clientPipelinePromise =
        std::make_shared<folly::Promise<DefaultPipeline*>>();

    getEventBase()->runInEventBaseThread([=]() {
      clientConnect().thenValue([=](DefaultPipeline* clientPipeline) {
        VLOG(4) << "Client connected. Send data.";
        auto data = IOBuf::create(1);
        data->append(1);
        *(data->writableData()) = 'a';
        clientPipeline->write(std::move(data)).thenValue([=](auto&&) {
          clientPipelinePromise->setValue(clientPipeline);
        });
      });
    });

    return clientPipelinePromise->getFuture();
  }

  Future<DefaultPipeline*> clientConnectAndCleanClose() {
    auto clientPipelinePromise =
        std::make_shared<folly::Promise<DefaultPipeline*>>();

    getEventBase()->runInEventBaseThread([=]() {
      clientConnectAndWrite().thenValue([=](DefaultPipeline* clientPipeline) {
        VLOG(4) << "Client close";
        clientPipeline->close().thenValue(
            [=](auto&&) { clientPipelinePromise->setValue(clientPipeline); });
      });
    });

    return clientPipelinePromise->getFuture();
  }

  Future<DefaultPipeline*> justClientConnect() {
    auto clientPipelinePromise =
        std::make_shared<folly::Promise<DefaultPipeline*>>();
    getEventBase()->runInEventBaseThread([=]() {
      clientConnect().thenValue([=](DefaultPipeline* clientPipeline) {
        clientPipelinePromise->setValue(clientPipeline);
      });
    });

    return clientPipelinePromise->getFuture();
  }

  void sendClientException(DefaultPipeline* clientPipeline) {
    getEventBase()->runInEventBaseThread([=]() {
      clientPipeline->writeException(
          std::runtime_error("Client socket exception, right after connect."));
    });
  }

  void TearDown() override {
    acceptPipeline_.reset();
    acceptPipelineFactory_->cleanup();
  }

 protected:
  std::unique_ptr<TestServer> server_;
  std::shared_ptr<MockAcceptPipelineFactory> acceptPipelineFactory_;
  AcceptPipeline::Ptr acceptPipeline_;
  DefaultPipeline::Ptr routingPipeline_;
  std::shared_ptr<MockRoutingDataHandlerFactory> routingDataHandlerFactory_;
  MockRoutingDataHandler* routingDataHandler_;

  MockAcceptRoutingHandler* acceptRoutingHandler_;
  MockBytesToBytesHandler* downstreamHandler_;
  std::shared_ptr<MockDownstreamPipelineFactory> downstreamPipelineFactory_;
  SocketAddress address_;
  RoutingDataHandler<char>::RoutingData routingData_;

  std::shared_ptr<TestClient> client_;

  int kConnId0{0};
  int kNumIOThreads{1};
};

TEST_F(AcceptRoutingHandlerTest, ParseRoutingDataSuccess) {
  // Server receives data, and parses routing data
  EXPECT_CALL(*routingDataHandler_, transportActive(_));
  EXPECT_CALL(*routingDataHandler_, parseRoutingData(_, _))
      .WillOnce(
          Invoke([&](folly::IOBufQueue& /*bufQueue*/,
                     MockRoutingDataHandler::RoutingData& /*routingData*/) {
            VLOG(4) << "Parsed routing data";
            return true;
          }));

  // Downstream pipeline is created, and its handler receives events
  boost::barrier barrier(2);
  EXPECT_CALL(*downstreamHandler_, transportActive(_));
  EXPECT_CALL(*downstreamHandler_, read(_, _))
      .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* /*ctx*/,
                           IOBufQueue& /*bufQueue*/) {
        VLOG(4) << "Downstream received a read";
      }));
  EXPECT_CALL(*downstreamHandler_, readEOF(_))
      .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* ctx) {
        VLOG(4) << "Downstream EOF";
        ctx->fireClose();
        barrier.wait();
      }));
  EXPECT_CALL(*downstreamHandler_, transportInactive(_));

  // Send client request that triggers server processing
  clientConnectAndCleanClose();

  barrier.wait();

  // Routing pipeline has been erased
  EXPECT_EQ(0, acceptRoutingHandler_->getRoutingPipelineCount());
}

TEST_F(AcceptRoutingHandlerTest, SocketErrorInRoutingPipeline) {
  // Server receives data, and parses routing data
  boost::barrier barrierConnect(2);
  EXPECT_CALL(*routingDataHandler_, transportActive(_));
  EXPECT_CALL(*routingDataHandler_, parseRoutingData(_, _))
      .WillOnce(
          Invoke([&](folly::IOBufQueue& /*bufQueue*/,
                     MockRoutingDataHandler::RoutingData& /*routingData*/) {
            VLOG(4) << "Need more data to be parse.";
            barrierConnect.wait();
            return false;
          }));

  // Send client request that triggers server processing
  auto futureClientPipeline = clientConnectAndWrite();

  // Socket exception after routing pipeline had been created
  barrierConnect.wait();
  boost::barrier barrierException(2);
  std::move(futureClientPipeline).thenValue([](DefaultPipeline* clientPipeline) {
    clientPipeline->getTransport()->getEventBase()->runInEventBaseThread(
        [clientPipeline]() {
          clientPipeline->writeException(
              std::runtime_error("Socket error while expecting routing data."));
        });
  });
  EXPECT_CALL(*routingDataHandler_, readException(_, _))
      .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* /*ctx*/,
                           folly::exception_wrapper ex) {
        VLOG(4) << "Routing data handler Exception";
        acceptRoutingHandler_->onError(kConnId0, ex);
        barrierException.wait();
      }));
  barrierException.wait();

  // Downstream pipeline is not created
  EXPECT_CALL(*downstreamHandler_, transportActive(_)).Times(0);
  delete downstreamHandler_;

  // Routing pipeline has been erased
  EXPECT_EQ(0, acceptRoutingHandler_->getRoutingPipelineCount());
}

TEST_F(AcceptRoutingHandlerTest, OnNewConnectionWithBadSocket) {
  // Routing data handler doesn't receive any data
  EXPECT_CALL(*routingDataHandler_, parseRoutingData(_, _)).Times(0);

  // Downstream pipeline is not created
  EXPECT_CALL(*downstreamHandler_, transportActive(_)).Times(0);
  delete downstreamHandler_;

  // Send client request that triggers server processing
  boost::barrier barrierConnect(2);
  EXPECT_CALL(*routingDataHandler_, transportActive(_))
      .WillOnce(Invoke([&](MockBytesToBytesHandler::Context* /*ctx*/) {
        barrierConnect.wait();
      }));
  auto futureClientPipeline = justClientConnect();
  barrierConnect.wait();
  futureClientPipeline.wait();

  // Expect an exception on the routing data handler
  boost::barrier barrierException(2);
  EXPECT_CALL(*routingDataHandler_, readException(_, _))
      .WillOnce(Invoke(
          [&](MockBytesToBytesHandler::Context* /*ctx*/,
              folly::exception_wrapper /*ex*/) { barrierException.wait(); }));
  sendClientException(futureClientPipeline.value());
  barrierException.wait();

  // Routing pipeline has been added
  EXPECT_EQ(1, acceptRoutingHandler_->getRoutingPipelineCount());
}

TEST_F(AcceptRoutingHandlerTest, RoutingPipelineErasedOnlyOnce) {
  // Simulate client socket throwing an exception, while routing data handler
  // parsed data successfully.
  acceptPipeline_->readException(
      std::runtime_error("An exception from the socket."));
  acceptRoutingHandler_->onRoutingData(kConnId0, routingData_);
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2012-2014 The SSDB Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.
*/
#include "ssdb_impl.h"
#include "rocksdb/env.h"
#include "rocksdb/iterator.h"
#include "rocksdb/cache.h"
#include "rocksdb/filter_policy.h"

#include "chess_merger.h"
#include "iterator.h"
#include "t_kv.h"
#include "t_hash.h"
#include "t_zset.h"
#include "t_queue.h"

SSDBImpl::SSDBImpl(){
    ldb = NULL;
    _binlogs = NULL;
	_encoder = new ChessHashEncoder;
}

SSDBImpl::~SSDBImpl(){
    if(_binlogs){
		delete _binlogs;
    }
    if(ldb){
		delete ldb;
    }
    /*if(options.block_cache){
      delete options.block_cache;
      }
      if(options.filter_policy){
      delete options.filter_policy;
      }*/
}

SSDB* SSDB::open(const Options &opt, const std::string &dir){
    SSDBImpl *ssdb = new SSDBImpl();
    ssdb->options.create_if_missing = true;
    ssdb->options.merge_operator = std::make_shared<ChessMergeOperator>();
    ssdb->options.IncreaseParallelism();
    ssdb->options.OptimizeLevelStyleCompaction();
    ssdb->options.max_background_compactions = 8;
    ssdb->options.max_background_flushes = 8;
    ssdb->options.env->SetBackgroundThreads(8, rocksdb::Env::LOW);
    ssdb->options.env->SetBackgroundThreads(8, rocksdb::Env::HIGH);
    /*
      ssdb->options.max_open_files = opt.max_open_files;
      ssdb->options.filter_policy = rocksdb::NewBloomFilterPolicy(10);
      ssdb->options.block_cache = rocksdb::NewLRUCache(opt.cache_size * 1048576);
      ssdb->options.block_size = opt.block_size * 1024;
      ssdb->options.write_buffer_size = opt.write_buffer_size * 1024 * 1024;
      ssdb->options.compaction_speed = opt.compaction_speed;
      if(opt.compression == "yes"){
      ssdb->options.compression = rocksdb::kSnappyCompression;
      }else{
      ssdb->options.compression = rocksdb::kNoCompression;
      }
    */
    // TBD(kg): options
    static const std::string kOplogCF = "oplogCF";
    rocksdb::ColumnFamilyOptions oplogOption;
    oplogOption.write_buffer_size = opt.write_buffer_size * 1024 * 1024;
    oplogOption.target_file_size_base = oplogOption.write_buffer_size;
    std::vector<rocksdb::ColumnFamilyDescriptor> cfDescriptors = {
		rocksdb::ColumnFamilyDescriptor(rocksdb::kDefaultColumnFamilyName, ssdb->options),
		rocksdb::ColumnFamilyDescriptor(kOplogCF, oplogOption)
    };
    rocksdb::DB* db = nullptr;
    rocksdb::Status status;
    int cnt = 0;
    while (cnt < 2) {
		status = rocksdb::DB::Open(ssdb->options, dir, cfDescriptors, &ssdb->_cfHandles, &db);
		if (!status.ok()) {
			status = rocksdb::DB::OpenForReadOnly(ssdb->options, dir, &db);
			assert(status.ok());
			rocksdb::ColumnFamilyHandle* cf = nullptr;
			status = db->CreateColumnFamily(oplogOption, kOplogCF, &cf);
			assert(status.ok());
			delete cf;
			delete db;
			cnt ++;
		} else {
			break;
		}
    }
    if (!status.ok()) {
		log_error("open db failed: %s", status.ToString().c_str());
		goto err;
    }
    ssdb->ldb = db;
    ssdb->_binlogs = new BinlogQueue(ssdb->ldb, ssdb->_cfHandles, opt.binlog, opt.binlog_capacity);

    return ssdb;
 err:
    if(ssdb){
		delete ssdb;
    }
    return NULL;
}

int SSDBImpl::flushdb(){
    Transaction trans(_binlogs);
    int ret = 0;
    bool stop = false;
    while(!stop){
		rocksdb::Iterator *it;
		rocksdb::ReadOptions iterate_options;
		iterate_options.fill_cache = false;
		rocksdb::WriteOptions write_opts;

		it = ldb->NewIterator(iterate_options);
		it->SeekToFirst();
		for(int i=0; i<10000; i++){
			if(!it->Valid()){
				stop = true;
				break;
			}
			//log_debug("%s", hexmem(it->key().data(), it->key().size()).c_str());
			rocksdb::Status s = ldb->Delete(write_opts, it->key());
			if(!s.ok()){
				log_error("del error: %s", s.ToString().c_str());
				stop = true;
				ret = -1;
				break;
			}
			it->Next();
		}
		delete it;
    }
    _binlogs->flush();
    return ret;
}

Iterator* SSDBImpl::iterator(const std::string &start, const std::string &end, uint64_t limit){
    rocksdb::Iterator *it;
    rocksdb::ReadOptions iterate_options;
    iterate_options.fill_cache = false;
    it = ldb->NewIterator(iterate_options);
    it->Seek(start);
    // TBD(kg): why Next() is called here ?
    /*if(it->Valid() && it->key() == start){
	  it->Next();
	  }*/
    return new Iterator(it, end, limit);
}

Iterator* SSDBImpl::rev_iterator(const std::string &start, const std::string &end, uint64_t limit){
    rocksdb::Iterator *it;
    rocksdb::ReadOptions iterate_options;
    iterate_options.fill_cache = false;
    it = ldb->NewIterator(iterate_options);
    it->Seek(start);
    if(!it->Valid()){
		it->SeekToLast();
    }else{
		it->Prev();
    }
    return new Iterator(it, end, limit, Iterator::BACKWARD);
}

/* raw operates */

int SSDBImpl::raw_set(const Bytes &key, const Bytes &val){
    rocksdb::WriteOptions write_opts;
    rocksdb::Status s = ldb->Put(write_opts, slice(key), slice(val));
    if(!s.ok()){
		log_error("set error: %s", s.ToString().c_str());
		return -1;
    }
    return 1;
}

int SSDBImpl::raw_del(const Bytes &key){
    rocksdb::WriteOptions write_opts;
    rocksdb::Status s = ldb->Delete(write_opts, slice(key));
    if(!s.ok()){
		log_error("del error: %s", s.ToString().c_str());
		return -1;
    }
    return 1;
}

int SSDBImpl::raw_get(const Bytes &key, std::string *val){
    rocksdb::ReadOptions opts;
    opts.fill_cache = false;
    rocksdb::Status s = ldb->Get(opts, slice(key), val);
    if(s.IsNotFound()){
		return 0;
    }
    if(!s.ok()){
		log_error("get error: %s", s.ToString().c_str());
		return -1;
    }
    return 1;
}

uint64_t SSDBImpl::size(){
    std::string s = "A";
    std::string e(1, 'z' + 1);
    rocksdb::Range ranges[1];
    ranges[0] = rocksdb::Range(s, e);
    uint64_t sizes[1];
    ldb->GetApproximateSizes(ranges, 1, sizes);
    return sizes[0];
}

std::vector<std::string> SSDBImpl::info(){
    //  "rocksdb.num-files-at-level<N>" - return the number of files at level <N>,
    //     where <N> is an ASCII representation of a level number (e.g. "0").
    //  "rocksdb.stats" - returns a multi-line string that describes statistics
    //     about the internal operation of the DB.
    //  "rocksdb.sstables" - returns a multi-line string that describes all
    //     of the sstables that make up the db contents.
    std::vector<std::string> info;
    std::vector<std::string> keys;
    /*
      for(int i=0; i<7; i++){
      char buf[128];
      snprintf(buf, sizeof(buf), "rocksdb.num-files-at-level%d", i);
      keys.push_back(buf);
      }
    */
    keys.push_back("rocksdb.stats");
    //keys.push_back("rocksdb.sstables");

    for(size_t i=0; i<keys.size(); i++){
		std::string key = keys[i];
		std::string val;
		if(ldb->GetProperty(key, &val)){
			info.push_back(key);
			info.push_back(val);
		}
    }

    return info;
}

void SSDBImpl::compact(){
    //ldb->CompactRange(NULL, NULL);
    for (int i = 0; i < _cfHandles.size(); i++) {
		ldb->Flush(rocksdb::FlushOptions(), _cfHandles[i]);
    }
}

int SSDBImpl::key_range(std::vector<std::string> *keys){
    int ret = 0;
    std::string kstart, kend;
    std::string hstart, hend;
    std::string zstart, zend;
    std::string qstart, qend;

    Iterator *it;

    it = this->iterator(encode_kv_key(""), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::KV){
			std::string n;
			if(decode_kv_key(ks, &n) == -1){
				ret = -1;
			}else{
				kstart = n;
			}
		}
    }
    delete it;

    it = this->rev_iterator(encode_kv_key("\xff"), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::KV){
			std::string n;
			if(decode_kv_key(ks, &n) == -1){
				ret = -1;
			}else{
				kend = n;
			}
		}
    }
    delete it;

    // TBD(kg): use hkey instead of hsize_key
    /*it = this->iterator(encode_hsize_key(""), "", 1);
	  if(it->next()){
	  Bytes ks = it->key();
	  if(ks.data()[0] == DataType::HSIZE){
	  std::string n;
	  if(decode_hsize_key(ks, &n) == -1){
	  ret = -1;
	  }else{
	  hstart = n;
	  }
	  }
	  }
	  delete it;

	  it = this->rev_iterator(encode_hsize_key("\xff"), "", 1);
	  if(it->next()){
	  Bytes ks = it->key();
	  if(ks.data()[0] == DataType::HSIZE){
	  std::string n;
	  if(decode_hsize_key(ks, &n) == -1){
	  ret = -1;
	  }else{
	  hend = n;
	  }
	  }
	  }
	  delete it;*/

    it = this->iterator(encode_zsize_key(""), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::ZSIZE){
			std::string n;
			if(decode_zsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				zstart = n;
			}
		}
    }
    delete it;

    it = this->rev_iterator(encode_zsize_key("\xff"), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::ZSIZE){
			std::string n;
			if(decode_zsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				zend = n;
			}
		}
    }
    delete it;

    it = this->iterator(encode_qsize_key(""), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::QSIZE){
			std::string n;
			if(decode_qsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				qstart = n;
			}
		}
    }
    delete it;

    it = this->rev_iterator(encode_qsize_key("\xff"), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::QSIZE){
			std::string n;
			if(decode_qsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				qend = n;
			}
		}
    }
    delete it;

    keys->push_back(kstart);
    keys->push_back(kend);
    keys->push_back(hstart);
    keys->push_back(hend);
    keys->push_back(zstart);
    keys->push_back(zend);
    keys->push_back(qstart);
    keys->push_back(qend);

    return ret;
}
<commit_msg>Destroy ColumnFamilies as well during terminating phase<commit_after>/*
  Copyright (c) 2012-2014 The SSDB Authors. All rights reserved.
  Use of this source code is governed by a BSD-style license that can be
  found in the LICENSE file.
*/
#include "ssdb_impl.h"
#include "rocksdb/env.h"
#include "rocksdb/iterator.h"
#include "rocksdb/cache.h"
#include "rocksdb/filter_policy.h"

#include "chess_merger.h"
#include "iterator.h"
#include "t_kv.h"
#include "t_hash.h"
#include "t_zset.h"
#include "t_queue.h"

SSDBImpl::SSDBImpl(){
    ldb = NULL;
    _binlogs = NULL;
	_encoder = new ChessHashEncoder;
}

SSDBImpl::~SSDBImpl() {
    if (_binlogs) {
		delete _binlogs;
    }
    if (ldb) {
		for (int i = 0; i < _cfHandles.size(); i++) {
			ldb->DestroyColumnFamilyHandle(_cfHandles[i]);
		}
		delete ldb;
    }

    /*if(options.block_cache){
      delete options.block_cache;
      }
      if(options.filter_policy){
      delete options.filter_policy;
      }*/
}

SSDB* SSDB::open(const Options &opt, const std::string &dir){
    SSDBImpl *ssdb = new SSDBImpl();
    ssdb->options.create_if_missing = true;
    ssdb->options.merge_operator = std::make_shared<ChessMergeOperator>();
    ssdb->options.IncreaseParallelism();
    ssdb->options.OptimizeLevelStyleCompaction();
    ssdb->options.max_background_compactions = 8;
    ssdb->options.max_background_flushes = 8;
    ssdb->options.env->SetBackgroundThreads(8, rocksdb::Env::LOW);
    ssdb->options.env->SetBackgroundThreads(8, rocksdb::Env::HIGH);
    /*
      ssdb->options.max_open_files = opt.max_open_files;
      ssdb->options.filter_policy = rocksdb::NewBloomFilterPolicy(10);
      ssdb->options.block_cache = rocksdb::NewLRUCache(opt.cache_size * 1048576);
      ssdb->options.block_size = opt.block_size * 1024;
      ssdb->options.write_buffer_size = opt.write_buffer_size * 1024 * 1024;
      ssdb->options.compaction_speed = opt.compaction_speed;
      if(opt.compression == "yes"){
      ssdb->options.compression = rocksdb::kSnappyCompression;
      }else{
      ssdb->options.compression = rocksdb::kNoCompression;
      }
    */
    // TBD(kg): options
    static const std::string kOplogCF = "oplogCF";
    rocksdb::ColumnFamilyOptions oplogOption;
    oplogOption.write_buffer_size = opt.write_buffer_size * 1024 * 1024;
    oplogOption.target_file_size_base = oplogOption.write_buffer_size;
    std::vector<rocksdb::ColumnFamilyDescriptor> cfDescriptors = {
		rocksdb::ColumnFamilyDescriptor(rocksdb::kDefaultColumnFamilyName, ssdb->options),
		rocksdb::ColumnFamilyDescriptor(kOplogCF, oplogOption)
    };
    rocksdb::DB* db = nullptr;
    rocksdb::Status status;
    int cnt = 0;
    while (cnt < 2) {
		status = rocksdb::DB::Open(ssdb->options, dir, cfDescriptors, &ssdb->_cfHandles, &db);
		if (!status.ok()) {
			status = rocksdb::DB::OpenForReadOnly(ssdb->options, dir, &db);
			assert(status.ok());
			rocksdb::ColumnFamilyHandle* cf = nullptr;
			status = db->CreateColumnFamily(oplogOption, kOplogCF, &cf);
			assert(status.ok());
			delete cf;
			delete db;
			cnt ++;
		} else {
			break;
		}
    }
    if (!status.ok()) {
		log_error("open db failed: %s", status.ToString().c_str());
		goto err;
    }
    ssdb->ldb = db;
    ssdb->_binlogs = new BinlogQueue(ssdb->ldb, ssdb->_cfHandles, opt.binlog, opt.binlog_capacity);

    return ssdb;
 err:
    if(ssdb){
		delete ssdb;
    }
    return NULL;
}

int SSDBImpl::flushdb(){
    Transaction trans(_binlogs);
    int ret = 0;
    bool stop = false;
    while(!stop){
		rocksdb::Iterator *it;
		rocksdb::ReadOptions iterate_options;
		iterate_options.fill_cache = false;
		rocksdb::WriteOptions write_opts;

		it = ldb->NewIterator(iterate_options);
		it->SeekToFirst();
		for(int i=0; i<10000; i++){
			if(!it->Valid()){
				stop = true;
				break;
			}
			//log_debug("%s", hexmem(it->key().data(), it->key().size()).c_str());
			rocksdb::Status s = ldb->Delete(write_opts, it->key());
			if(!s.ok()){
				log_error("del error: %s", s.ToString().c_str());
				stop = true;
				ret = -1;
				break;
			}
			it->Next();
		}
		delete it;
    }
    _binlogs->flush();
    return ret;
}

Iterator* SSDBImpl::iterator(const std::string &start, const std::string &end, uint64_t limit){
    rocksdb::Iterator *it;
    rocksdb::ReadOptions iterate_options;
    iterate_options.fill_cache = false;
    it = ldb->NewIterator(iterate_options);
    it->Seek(start);
    // TBD(kg): why Next() is called here ?
    /*if(it->Valid() && it->key() == start){
	  it->Next();
	  }*/
    return new Iterator(it, end, limit);
}

Iterator* SSDBImpl::rev_iterator(const std::string &start, const std::string &end, uint64_t limit){
    rocksdb::Iterator *it;
    rocksdb::ReadOptions iterate_options;
    iterate_options.fill_cache = false;
    it = ldb->NewIterator(iterate_options);
    it->Seek(start);
    if(!it->Valid()){
		it->SeekToLast();
    }else{
		it->Prev();
    }
    return new Iterator(it, end, limit, Iterator::BACKWARD);
}

/* raw operates */

int SSDBImpl::raw_set(const Bytes &key, const Bytes &val){
    rocksdb::WriteOptions write_opts;
    rocksdb::Status s = ldb->Put(write_opts, slice(key), slice(val));
    if(!s.ok()){
		log_error("set error: %s", s.ToString().c_str());
		return -1;
    }
    return 1;
}

int SSDBImpl::raw_del(const Bytes &key){
    rocksdb::WriteOptions write_opts;
    rocksdb::Status s = ldb->Delete(write_opts, slice(key));
    if(!s.ok()){
		log_error("del error: %s", s.ToString().c_str());
		return -1;
    }
    return 1;
}

int SSDBImpl::raw_get(const Bytes &key, std::string *val){
    rocksdb::ReadOptions opts;
    opts.fill_cache = false;
    rocksdb::Status s = ldb->Get(opts, slice(key), val);
    if(s.IsNotFound()){
		return 0;
    }
    if(!s.ok()){
		log_error("get error: %s", s.ToString().c_str());
		return -1;
    }
    return 1;
}

uint64_t SSDBImpl::size(){
    std::string s = "A";
    std::string e(1, 'z' + 1);
    rocksdb::Range ranges[1];
    ranges[0] = rocksdb::Range(s, e);
    uint64_t sizes[1];
    ldb->GetApproximateSizes(ranges, 1, sizes);
    return sizes[0];
}

std::vector<std::string> SSDBImpl::info(){
    //  "rocksdb.num-files-at-level<N>" - return the number of files at level <N>,
    //     where <N> is an ASCII representation of a level number (e.g. "0").
    //  "rocksdb.stats" - returns a multi-line string that describes statistics
    //     about the internal operation of the DB.
    //  "rocksdb.sstables" - returns a multi-line string that describes all
    //     of the sstables that make up the db contents.
    std::vector<std::string> info;
    std::vector<std::string> keys;
    /*
      for(int i=0; i<7; i++){
      char buf[128];
      snprintf(buf, sizeof(buf), "rocksdb.num-files-at-level%d", i);
      keys.push_back(buf);
      }
    */
    keys.push_back("rocksdb.stats");
    //keys.push_back("rocksdb.sstables");

    for(size_t i=0; i<keys.size(); i++){
		std::string key = keys[i];
		std::string val;
		if(ldb->GetProperty(key, &val)){
			info.push_back(key);
			info.push_back(val);
		}
    }

    return info;
}

void SSDBImpl::compact(){
    //ldb->CompactRange(NULL, NULL);
    for (int i = 0; i < _cfHandles.size(); i++) {
		ldb->Flush(rocksdb::FlushOptions(), _cfHandles[i]);
    }
}

int SSDBImpl::key_range(std::vector<std::string> *keys){
    int ret = 0;
    std::string kstart, kend;
    std::string hstart, hend;
    std::string zstart, zend;
    std::string qstart, qend;

    Iterator *it;

    it = this->iterator(encode_kv_key(""), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::KV){
			std::string n;
			if(decode_kv_key(ks, &n) == -1){
				ret = -1;
			}else{
				kstart = n;
			}
		}
    }
    delete it;

    it = this->rev_iterator(encode_kv_key("\xff"), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::KV){
			std::string n;
			if(decode_kv_key(ks, &n) == -1){
				ret = -1;
			}else{
				kend = n;
			}
		}
    }
    delete it;

    // TBD(kg): use hkey instead of hsize_key
    /*it = this->iterator(encode_hsize_key(""), "", 1);
	  if(it->next()){
	  Bytes ks = it->key();
	  if(ks.data()[0] == DataType::HSIZE){
	  std::string n;
	  if(decode_hsize_key(ks, &n) == -1){
	  ret = -1;
	  }else{
	  hstart = n;
	  }
	  }
	  }
	  delete it;

	  it = this->rev_iterator(encode_hsize_key("\xff"), "", 1);
	  if(it->next()){
	  Bytes ks = it->key();
	  if(ks.data()[0] == DataType::HSIZE){
	  std::string n;
	  if(decode_hsize_key(ks, &n) == -1){
	  ret = -1;
	  }else{
	  hend = n;
	  }
	  }
	  }
	  delete it;*/

    it = this->iterator(encode_zsize_key(""), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::ZSIZE){
			std::string n;
			if(decode_zsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				zstart = n;
			}
		}
    }
    delete it;

    it = this->rev_iterator(encode_zsize_key("\xff"), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::ZSIZE){
			std::string n;
			if(decode_zsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				zend = n;
			}
		}
    }
    delete it;

    it = this->iterator(encode_qsize_key(""), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::QSIZE){
			std::string n;
			if(decode_qsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				qstart = n;
			}
		}
    }
    delete it;

    it = this->rev_iterator(encode_qsize_key("\xff"), "", 1);
    if(it->next()){
		Bytes ks = it->key();
		if(ks.data()[0] == DataType::QSIZE){
			std::string n;
			if(decode_qsize_key(ks, &n) == -1){
				ret = -1;
			}else{
				qend = n;
			}
		}
    }
    delete it;

    keys->push_back(kstart);
    keys->push_back(kend);
    keys->push_back(hstart);
    keys->push_back(hend);
    keys->push_back(zstart);
    keys->push_back(zend);
    keys->push_back(qstart);
    keys->push_back(qend);

    return ret;
}
<|endoftext|>


<commit_before>#include <yuni/yuni.h>
#include <yuni/core/process/program.h>
#include <yuni/datetime/timestamp.h>
#include <yuni/core/getopt.h>
#include <iostream>

using namespace Yuni;

int main(int argc, char* argv[])
{
	if (argc < 2)
	{
		std::cout << "Usage: " << argv[0] << " <program> [<args>]\n";
		return EXIT_FAILURE;
	}

	Process::Program process;

	// providing arguments
	process.program(argv[1]);
	for (int i = 2; i < argc; ++i)
		process.argumentAdd(argv[i]);

	// use milliseconds instead of seconds
	process.durationPrecision(Process::Program::dpMilliseconds);

	// execute the command
	sint64 duration;
	int exitStatus = process.execute() ? process.wait(&duration) : EXIT_FAILURE;

	// display the result nearly like `time`
	std::cout << argv[1];
	for (int i = 2; i < argc; ++i)
		std::cout << ' ' << argv[i];

	std::cout << "  " << duration << "ms\n";
	return exitStatus;
}

<commit_msg>sample Yuni::Process::Program: fixed variable uninitialized<commit_after>#include <yuni/yuni.h>
#include <yuni/core/process/program.h>
#include <yuni/datetime/timestamp.h>
#include <yuni/core/getopt.h>
#include <iostream>

using namespace Yuni;

int main(int argc, char* argv[])
{
	if (argc < 2)
	{
		std::cout << "Usage: " << argv[0] << " <program> [<args>]\n";
		return EXIT_FAILURE;
	}

	Process::Program process;

	// providing arguments
	process.program(argv[1]);
	for (int i = 2; i < argc; ++i)
		process.argumentAdd(argv[i]);

	// use milliseconds instead of seconds
	process.durationPrecision(Process::Program::dpMilliseconds);

	// execute the command
	sint64 duration = 0;
	int exitStatus = process.execute() ? process.wait(&duration) : EXIT_FAILURE;

	// display the result nearly like `time`
	std::cout << argv[1];
	for (int i = 2; i < argc; ++i)
		std::cout << ' ' << argv[i];

	std::cout << "  " << duration << "ms\n";
	return exitStatus;
}

<|endoftext|>


<commit_before>// (C) Robert Osfield, Feb 2004.
// GPL'd.

#include <osg/ImageStream>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>
#include <osg/Timer>

#include <osgDB/Registry>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>

#include <xine.h>
#include <xine/xineutils.h>
#include <xine/video_out.h>

#include "video_out_rgb.h"

namespace osgXine
{

class XineImageStream : public osg::ImageStream
{
    public:
        XineImageStream():
            _xine(0),
            _vo(0),
            _ao(0),
            _visual(0),
            _stream(0),
            _event_queue(0),
            _ready(false)
        {
            setOrigin(osg::Image::TOP_LEFT);
        }

        /** Copy constructor using CopyOp to manage deep vs shallow copy. */
        XineImageStream(const XineImageStream& image,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
            ImageStream(image,copyop) {}

        META_Object(osgXine,XineImageStream);

        bool open(xine_t* xine, const std::string& filename)
        {
            if (filename==getFileName()) return true;

            _xine = xine;

            // create visual
            rgbout_visual_info_t* visual = new rgbout_visual_info_t;
            visual->levels = PXLEVEL_ALL;
            visual->format = PX_RGB32;
            visual->user_data = this;
            visual->callback = my_render_frame;

            // set up video driver
            _vo = xine_open_video_driver(_xine, "rgb", XINE_VISUAL_TYPE_RGBOUT, (void*)visual);

            // set up audio driver
            char* audio_driver = getenv("OSG_XINE_AUDIO_DRIVER");
            _ao = audio_driver ? xine_open_audio_driver(_xine, audio_driver, NULL) : xine_open_audio_driver(_xine, "auto", NULL);

            if (!_vo)
            {
                osg::notify(osg::NOTICE)<<"XineImageStream::open() : Failed to create video driver"<<std::endl;
                return false;
            }

            // set up stream
            _stream = xine_stream_new(_xine, _ao, _vo);

            _event_queue = xine_event_new_queue(_stream);
            xine_event_create_listener_thread(_event_queue, event_listener, this);

            int result = xine_open(_stream, filename.c_str());

            if (result==0)
            {
                osg::notify(osg::INFO)<<"XineImageStream::open() : Could not ready movie file."<<std::endl;
                close();
                return false;
            }

            _ready = false;

            int width = xine_get_stream_info(_stream,XINE_STREAM_INFO_VIDEO_WIDTH);
            int height = xine_get_stream_info(_stream,XINE_STREAM_INFO_VIDEO_HEIGHT);
            allocateImage(width,height,1,GL_RGB,GL_UNSIGNED_BYTE,1);

            osg::notify(osg::INFO)<<"XineImageStream::open() size "<<width<<" "<<height<<std::endl;

            // play();

            return true;

        }

        virtual void play()
        {
            if (_status!=PLAYING && _stream)
            {
                if (_status==PAUSED)
                {
                    xine_set_param (_stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
                    _status=PLAYING;
                }
                else
                {
                    osg::notify(osg::INFO)<<"XineImageStream::play()"<<std::endl;
                    if (xine_play(_stream, 0, 0))
                    {
                        while (!_ready)
                        {
                            osg::notify(osg::INFO)<<"   waiting..."<<std::endl;
                            OpenThreads::Thread::microSleep(10000);
                        }

                        _status=PLAYING;

                    }
                    else
                    {
                        osg::notify(osg::NOTICE)<<"Error!!!"<<std::endl;
                    }
                }
            }
        }

        virtual void pause()
        {
            if (_status==PAUSED || _status==INVALID) return;

            _status=PAUSED;

            if (_stream)
            {
                xine_set_param (_stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
            }
        }

        virtual void rewind()
        {
            if (_status==INVALID) return;

            _status=REWINDING;
            if (_stream)
            {
                osg::notify(osg::INFO)<<"Warning::XineImageStream::rewind() - rewind disabled at present."<<std::endl;
                //xine_trick_mode(_stream,XINE_TRICK_MODE_FAST_REWIND,0);
            }
        }

        virtual void quit(bool /*waitForThreadToExit*/ = true)
        {
            close();
        }

        static void my_render_frame(uint32_t width, uint32_t height, void* data, void* userData)
        {
            XineImageStream* imageStream = (XineImageStream*) userData;

            GLenum pixelFormat = GL_BGRA;

        #if 0
            if (!imageStream->_ready)
            {
                imageStream->allocateImage(width,height,1,pixelFormat,GL_UNSIGNED_BYTE,1);
                imageStream->setInternalTextureFormat(GL_RGBA);
            }

            osg::Timer_t start_tick = osg::Timer::instance()->tick();

            memcpy(imageStream->data(),data,imageStream->getTotalSizeInBytes());

            osg::notify(osg::INFO)<<"image memcpy size="<<imageStream->getTotalSizeInBytes()<<" time="<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;

            imageStream->dirty();
        #else
             imageStream->setImage(width,height,1,
                              GL_RGB,
                              pixelFormat,GL_UNSIGNED_BYTE,
                              (unsigned char *)data,
                              osg::Image::NO_DELETE,
                              1);
        #endif
            imageStream->_ready = true;
        }

        xine_t*                 _xine;

        xine_video_port_t*      _vo;
        xine_audio_port_t*      _ao;

        rgbout_visual_info_t*   _visual;
        xine_stream_t*          _stream;
        xine_event_queue_t*     _event_queue;
        bool                    _ready;

    protected:

        virtual ~XineImageStream()
        {
            osg::notify(osg::INFO)<<"Killing XineImageStream"<<std::endl;
            close();
            osg::notify(osg::INFO)<<"Closed XineImageStream"<<std::endl;
        }

        void close()
        {

            osg::notify(osg::INFO)<<"XineImageStream::close()"<<std::endl;

            if (_stream)
            {
                  osg::notify(osg::INFO)<<"  Closing stream"<<std::endl;

                  xine_close(_stream);

                  osg::notify(osg::INFO)<<"  Disposing stream"<<std::endl;

                  xine_dispose(_stream);
                  _stream = 0;
            }

            if (_event_queue)
            {
                _event_queue = 0;
            }

            if (_ao)
            {
               osg::notify(osg::INFO)<<"  Closing audio driver"<<std::endl;

                xine_close_audio_driver(_xine, _ao);

                _ao = 0;
            }

            if (_vo)
            {
               osg::notify(osg::INFO)<<"  Closing video driver"<<std::endl;

                xine_close_video_driver(_xine, _vo);

                _vo = 0;
            }

           osg::notify(osg::INFO)<<"closed XineImageStream "<<std::endl;

        }

        static void event_listener(void *user_data, const xine_event_t *event)
        {
            XineImageStream* xis = reinterpret_cast<XineImageStream*>(user_data);
            switch(event->type)
            {
            case XINE_EVENT_UI_PLAYBACK_FINISHED:
                if (xis->getLoopingMode()==LOOPING)
                {
                    //rewind();
                    xine_play(xis->_stream, 0, 0);
                }
                break;
            }
        }

};

}

class ReaderWriterXine : public osgDB::ReaderWriter
{
    public:

        ReaderWriterXine()
        {
            _xine = xine_new();

            const char* user_home = xine_get_homedir();
            if(user_home)
            {
                char* cfgfile = NULL;
                asprintf(&(cfgfile), "%s/.xine/config", user_home);
                xine_config_load(_xine, cfgfile);
            }

            xine_init(_xine);

            register_rgbout_plugin(_xine);
        }

        virtual ~ReaderWriterXine()
        {
            osg::notify(osg::INFO)<<"~ReaderWriterXine()"<<std::endl;

            if (_xine) xine_exit(_xine);
            _xine = NULL;
        }

        virtual const char* className() const { return "Xine ImageStream Reader"; }

        virtual bool acceptsExtension(const std::string& extension) const
        {
            return osgDB::equalCaseInsensitive(extension,"mpg") ||
                   osgDB::equalCaseInsensitive(extension,"mpv") ||
                   osgDB::equalCaseInsensitive(extension,"db") ||
                   osgDB::equalCaseInsensitive(extension,"mov") ||
                   osgDB::equalCaseInsensitive(extension,"avi") ||
                   osgDB::equalCaseInsensitive(extension,"wmv") ||
                   osgDB::equalCaseInsensitive(extension,"xine");
        }

        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
        {
            std::string ext = osgDB::getLowerCaseFileExtension(file);
            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

            std::string fileName;
            if (ext=="xine")
            {
                fileName = osgDB::getNameLessExtension(file);
                osg::notify(osg::NOTICE)<<"Xine stipped filename = "<<fileName;
            }
            else
            {
                fileName = osgDB::findDataFile( file, options );
                if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
            }

            osg::notify(osg::INFO)<<"ReaderWriterXine::readImage "<< file<< std::endl;

            osg::ref_ptr<osgXine::XineImageStream> imageStream = new osgXine::XineImageStream();

            if (!imageStream->open(_xine, fileName)) return ReadResult::FILE_NOT_HANDLED;

            return imageStream.release();
        }

    protected:
        xine_t*             _xine;

};

// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(xine, ReaderWriterXine)
<commit_msg>Added flv to the list of accepted movie types<commit_after>// (C) Robert Osfield, Feb 2004.
// GPL'd.

#include <osg/ImageStream>
#include <osg/Notify>
#include <osg/Geode>
#include <osg/GL>
#include <osg/Timer>

#include <osgDB/Registry>
#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>

#include <xine.h>
#include <xine/xineutils.h>
#include <xine/video_out.h>

#include "video_out_rgb.h"

namespace osgXine
{

class XineImageStream : public osg::ImageStream
{
    public:
        XineImageStream():
            _xine(0),
            _vo(0),
            _ao(0),
            _visual(0),
            _stream(0),
            _event_queue(0),
            _ready(false)
        {
            setOrigin(osg::Image::TOP_LEFT);
        }

        /** Copy constructor using CopyOp to manage deep vs shallow copy. */
        XineImageStream(const XineImageStream& image,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY):
            ImageStream(image,copyop) {}

        META_Object(osgXine,XineImageStream);

        bool open(xine_t* xine, const std::string& filename)
        {
            if (filename==getFileName()) return true;

            _xine = xine;

            // create visual
            rgbout_visual_info_t* visual = new rgbout_visual_info_t;
            visual->levels = PXLEVEL_ALL;
            visual->format = PX_RGB32;
            visual->user_data = this;
            visual->callback = my_render_frame;

            // set up video driver
            _vo = xine_open_video_driver(_xine, "rgb", XINE_VISUAL_TYPE_RGBOUT, (void*)visual);

            // set up audio driver
            char* audio_driver = getenv("OSG_XINE_AUDIO_DRIVER");
            _ao = audio_driver ? xine_open_audio_driver(_xine, audio_driver, NULL) : xine_open_audio_driver(_xine, "auto", NULL);

            if (!_vo)
            {
                osg::notify(osg::NOTICE)<<"XineImageStream::open() : Failed to create video driver"<<std::endl;
                return false;
            }

            // set up stream
            _stream = xine_stream_new(_xine, _ao, _vo);

            _event_queue = xine_event_new_queue(_stream);
            xine_event_create_listener_thread(_event_queue, event_listener, this);

            int result = xine_open(_stream, filename.c_str());

            if (result==0)
            {
                osg::notify(osg::INFO)<<"XineImageStream::open() : Could not ready movie file."<<std::endl;
                close();
                return false;
            }

            _ready = false;

            int width = xine_get_stream_info(_stream,XINE_STREAM_INFO_VIDEO_WIDTH);
            int height = xine_get_stream_info(_stream,XINE_STREAM_INFO_VIDEO_HEIGHT);
            allocateImage(width,height,1,GL_RGB,GL_UNSIGNED_BYTE,1);

            osg::notify(osg::INFO)<<"XineImageStream::open() size "<<width<<" "<<height<<std::endl;

            // play();

            return true;

        }

        virtual void play()
        {
            if (_status!=PLAYING && _stream)
            {
                if (_status==PAUSED)
                {
                    xine_set_param (_stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL);
                    _status=PLAYING;
                }
                else
                {
                    osg::notify(osg::INFO)<<"XineImageStream::play()"<<std::endl;
                    if (xine_play(_stream, 0, 0))
                    {
                        while (!_ready)
                        {
                            osg::notify(osg::INFO)<<"   waiting..."<<std::endl;
                            OpenThreads::Thread::microSleep(10000);
                        }

                        _status=PLAYING;

                    }
                    else
                    {
                        osg::notify(osg::NOTICE)<<"Error!!!"<<std::endl;
                    }
                }
            }
        }

        virtual void pause()
        {
            if (_status==PAUSED || _status==INVALID) return;

            _status=PAUSED;

            if (_stream)
            {
                xine_set_param (_stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE);
            }
        }

        virtual void rewind()
        {
            if (_status==INVALID) return;

            _status=REWINDING;
            if (_stream)
            {
                osg::notify(osg::INFO)<<"Warning::XineImageStream::rewind() - rewind disabled at present."<<std::endl;
                //xine_trick_mode(_stream,XINE_TRICK_MODE_FAST_REWIND,0);
            }
        }

        virtual void quit(bool /*waitForThreadToExit*/ = true)
        {
            close();
        }

        static void my_render_frame(uint32_t width, uint32_t height, void* data, void* userData)
        {
            XineImageStream* imageStream = (XineImageStream*) userData;

            GLenum pixelFormat = GL_BGRA;

        #if 0
            if (!imageStream->_ready)
            {
                imageStream->allocateImage(width,height,1,pixelFormat,GL_UNSIGNED_BYTE,1);
                imageStream->setInternalTextureFormat(GL_RGBA);
            }

            osg::Timer_t start_tick = osg::Timer::instance()->tick();

            memcpy(imageStream->data(),data,imageStream->getTotalSizeInBytes());

            osg::notify(osg::INFO)<<"image memcpy size="<<imageStream->getTotalSizeInBytes()<<" time="<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;

            imageStream->dirty();
        #else
             imageStream->setImage(width,height,1,
                              GL_RGB,
                              pixelFormat,GL_UNSIGNED_BYTE,
                              (unsigned char *)data,
                              osg::Image::NO_DELETE,
                              1);
        #endif
            imageStream->_ready = true;
        }

        xine_t*                 _xine;

        xine_video_port_t*      _vo;
        xine_audio_port_t*      _ao;

        rgbout_visual_info_t*   _visual;
        xine_stream_t*          _stream;
        xine_event_queue_t*     _event_queue;
        bool                    _ready;

    protected:

        virtual ~XineImageStream()
        {
            osg::notify(osg::INFO)<<"Killing XineImageStream"<<std::endl;
            close();
            osg::notify(osg::INFO)<<"Closed XineImageStream"<<std::endl;
        }

        void close()
        {

            osg::notify(osg::INFO)<<"XineImageStream::close()"<<std::endl;

            if (_stream)
            {
                  osg::notify(osg::INFO)<<"  Closing stream"<<std::endl;

                  xine_close(_stream);

                  osg::notify(osg::INFO)<<"  Disposing stream"<<std::endl;

                  xine_dispose(_stream);
                  _stream = 0;
            }

            if (_event_queue)
            {
                _event_queue = 0;
            }

            if (_ao)
            {
               osg::notify(osg::INFO)<<"  Closing audio driver"<<std::endl;

                xine_close_audio_driver(_xine, _ao);

                _ao = 0;
            }

            if (_vo)
            {
               osg::notify(osg::INFO)<<"  Closing video driver"<<std::endl;

                xine_close_video_driver(_xine, _vo);

                _vo = 0;
            }

           osg::notify(osg::INFO)<<"closed XineImageStream "<<std::endl;

        }

        static void event_listener(void *user_data, const xine_event_t *event)
        {
            XineImageStream* xis = reinterpret_cast<XineImageStream*>(user_data);
            switch(event->type)
            {
            case XINE_EVENT_UI_PLAYBACK_FINISHED:
                if (xis->getLoopingMode()==LOOPING)
                {
                    //rewind();
                    xine_play(xis->_stream, 0, 0);
                }
                break;
            }
        }

};

}

class ReaderWriterXine : public osgDB::ReaderWriter
{
    public:

        ReaderWriterXine()
        {
            _xine = xine_new();

            const char* user_home = xine_get_homedir();
            if(user_home)
            {
                char* cfgfile = NULL;
                asprintf(&(cfgfile), "%s/.xine/config", user_home);
                xine_config_load(_xine, cfgfile);
            }

            xine_init(_xine);

            register_rgbout_plugin(_xine);
        }

        virtual ~ReaderWriterXine()
        {
            osg::notify(osg::INFO)<<"~ReaderWriterXine()"<<std::endl;

            if (_xine) xine_exit(_xine);
            _xine = NULL;
        }

        virtual const char* className() const { return "Xine ImageStream Reader"; }

        virtual bool acceptsExtension(const std::string& extension) const
        {
            return osgDB::equalCaseInsensitive(extension,"mpg") ||
                   osgDB::equalCaseInsensitive(extension,"mpv") ||
                   osgDB::equalCaseInsensitive(extension,"db") ||
                   osgDB::equalCaseInsensitive(extension,"flv") ||
                   osgDB::equalCaseInsensitive(extension,"mov") ||
                   osgDB::equalCaseInsensitive(extension,"avi") ||
                   osgDB::equalCaseInsensitive(extension,"wmv") ||
                   osgDB::equalCaseInsensitive(extension,"xine");
        }

        virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const
        {
            std::string ext = osgDB::getLowerCaseFileExtension(file);
            if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;

            std::string fileName;
            if (ext=="xine")
            {
                fileName = osgDB::getNameLessExtension(file);
                osg::notify(osg::NOTICE)<<"Xine stipped filename = "<<fileName;
            }
            else
            {
                fileName = osgDB::findDataFile( file, options );
                if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
            }

            osg::notify(osg::INFO)<<"ReaderWriterXine::readImage "<< file<< std::endl;

            osg::ref_ptr<osgXine::XineImageStream> imageStream = new osgXine::XineImageStream();

            if (!imageStream->open(_xine, fileName)) return ReadResult::FILE_NOT_HANDLED;

            return imageStream.release();
        }

    protected:
        xine_t*             _xine;

};

// now register with Registry to instantiate the above
// reader/writer.
REGISTER_OSGPLUGIN(xine, ReaderWriterXine)
<|endoftext|>


<commit_before>//
//
//    The Laxkit, a windowing toolkit
//    Please consult http://laxkit.sourceforge.net about where to send any
//    correspondence about this software.
//
//    This library is free software; you can redistribute it and/or
//    modify it under the terms of the GNU Library General Public
//    License as published by the Free Software Foundation; either
//    version 2 of the License, or (at your option) any later version.
//
//    This library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//    Library General Public License for more details.
//
//    You should have received a copy of the GNU Library General Public
//    License along with this library; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//    Copyright (C) 2004-2007,2012,2015 by Tom Lechner
//

#include <lax/anobject.h>
#include <lax/misc.h>
#include <lax/strmanip.h>

#include <iostream>
using namespace std;
#define DBG

namespace Laxkit {

//-------------------------- anObject ----------------------------
/*! \class anObject
 * \brief Base class for all Laxkit objects
 *
 * In the constructor, object_id gets assinged a number returned from getUniqueNumber().
 *
 * Also provides inc_count() and dec_count() for reference counting.
 * Objects are created with a count of 1.
 */

DBG static int numofanObject=0;

//! Set object_id=getUniqueNumber().
anObject::anObject()
{
	suppress_debug=0;
	DBG numofanObject++;

	object_id=getUniqueNumber();
	object_idstr=NULL;
	DBG cerr <<"anObject tracker "<<object_id<<"   created    num of anObjects: "<<numofanObject<<endl;

	_count=1;
}

/*! \fn const char *anObject::whattype()
 * \brief Returns the type of anObject.
 *
 * Usually, this corresponds to the C++ class name. However, it is also intended
 * to be used to say what the object should be considered to be. For instance, if you
 * subclass ImagePatchInterface to behave better, the program should still think of it
 * as an ImagePatchInterface, which is something the C++ typeinfo features are not
 * really designed for.
 */

//! Empty virtual destructor.
anObject::~anObject()
{
	DBG numofanObject--;
	DBG cerr <<"anObject tracker "<<object_id<<"   destroyed  num of anObjects: "<<numofanObject<<endl;

	if (object_idstr) delete[] object_idstr;
}

/*! \fn anObject *anObject::ObjectOwner()
 *
 * By default, NULL is returned. This can be used, for instance, by ResourceManager or by
 * some interface data to determine if this object is a shared resource, or is directly owned
 * by someone.
 */

//---------------- reference counting stuff

/*! \var int anObject::_count
 * \brief The reference count of the object.
 *
 * Controlled with inc_count() and dec_count(). When the count
 * is less or equal to 0, the object is deleted. See dec_count() for more.
 */

/*! \fn int anObject::inc_count()
 * \brief Increment the data's count by 1. Returns count.
 */
int anObject::inc_count()
{
	_count++;
	DBG if (!suppress_debug) {
	DBG   cerr <<"refcounted inc count, now: "<<_count<<endl;
	DBG   cerr<<whattype()<<" "<<object_id<<" inc counted: "<<_count<<endl;
	DBG }
	return _count;
}

//! Decrement the count of the data, deleting if count is less than or equal to 0.
/*! If count gets decremented to 0, then call "delete this".
 *
 * Returns the count. If 0 is returned, the item is gone, and should
 * not be accessed any more.
 */
int anObject::dec_count()
{
	_count--;
	DBG if (!suppress_debug) {
	DBG   cerr <<"refcounted dec count, now: "<<_count<<(_count==0?", deleting":"")<<endl;
	DBG   cerr<<whattype()<<" "<<object_id<<" dec counted: "<<_count<<endl;
	DBG }

	if (_count<=0) {
		int yesdelete=1;
		int c=_count;
		if (yesdelete) delete this;
		return c;
	}
	return _count;
}

const char *anObject::Id()
{
	if (object_idstr) return object_idstr;
	else object_idstr=make_id(whattype());
	return object_idstr;
}

/*! Warning! Passing in NULL will make object_idstr==NULL!
 */
const char *anObject::Id(const char *newid)
{
	makestr(object_idstr,newid);
	return object_idstr;
}

} // namespace Laxkit

<commit_msg>minor doc change<commit_after>//
//
//    The Laxkit, a windowing toolkit
//    Please consult http://laxkit.sourceforge.net about where to send any
//    correspondence about this software.
//
//    This library is free software; you can redistribute it and/or
//    modify it under the terms of the GNU Library General Public
//    License as published by the Free Software Foundation; either
//    version 2 of the License, or (at your option) any later version.
//
//    This library is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//    Library General Public License for more details.
//
//    You should have received a copy of the GNU Library General Public
//    License along with this library; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//    Copyright (C) 2004-2007,2012,2015 by Tom Lechner
//

#include <lax/anobject.h>
#include <lax/misc.h>
#include <lax/strmanip.h>

#include <iostream>
using namespace std;
#define DBG

namespace Laxkit {

//-------------------------- anObject ----------------------------
/*! \class anObject
 * \brief Base class for all Laxkit objects
 *
 * In the constructor, object_id gets assinged a number returned from getUniqueNumber().
 *
 * Also provides inc_count() and dec_count() for reference counting.
 * Objects are created with a count of 1.
 */

DBG static int numofanObject=0;

//! Set object_id=getUniqueNumber().
anObject::anObject()
{
	suppress_debug=0;
	DBG numofanObject++;

	object_id=getUniqueNumber();
	object_idstr=NULL;
	DBG cerr <<"anObject tracker "<<object_id<<"   created    num of anObjects: "<<numofanObject<<endl;

	_count=1;
}

/*! \fn const char *anObject::whattype()
 * \brief Returns the type of anObject.
 *
 * Usually, this corresponds to the C++ class name. However, it is also intended
 * to be used to say what the object should be considered to be. For instance, if you
 * subclass ImagePatchInterface to behave better, the program should still think of it
 * as an ImagePatchInterface, which is something the C++ typeinfo features are not
 * really designed for.
 */

//! Empty virtual destructor.
anObject::~anObject()
{
	DBG numofanObject--;
	DBG cerr <<"anObject tracker "<<object_id<<"   destroyed  num of anObjects: "<<numofanObject<<endl;

	if (object_idstr) delete[] object_idstr;
}

/*! \fn anObject *anObject::ObjectOwner()
 *
 * By default, NULL is returned. This can be used, for instance, by ResourceManager or by
 * some interface data to determine if this object is a shared resource, or is directly owned
 * by someone.
 */

//---------------- reference counting stuff

/*! \var int anObject::_count
 * \brief The reference count of the object.
 *
 * Controlled with inc_count() and dec_count(). When the count
 * is less or equal to 0, the object is deleted. See dec_count() for more.
 */

/*! \fn int anObject::inc_count()
 * \brief Increment the data's count by 1. Returns count.
 */
int anObject::inc_count()
{
	_count++;
	DBG if (!suppress_debug) {
	DBG   cerr <<"refcounted inc count, now: "<<_count<<endl;
	DBG   cerr<<whattype()<<" "<<object_id<<" inc counted: "<<_count<<endl;
	DBG }
	return _count;
}

//! Decrement the count of the data, deleting if count is less than or equal to 0.
/*! If count gets decremented to 0, then call "delete this".
 *
 * Returns the count. If 0 is returned, the item is gone, and should
 * not be accessed any more.
 */
int anObject::dec_count()
{
	_count--;
	DBG if (!suppress_debug) {
	DBG   cerr <<"refcounted dec count, now: "<<_count<<(_count==0?", deleting":"")<<endl;
	DBG   cerr<<whattype()<<" "<<object_id<<" dec counted: "<<_count<<endl;
	DBG }

	if (_count<=0) {
		int yesdelete=1;
		int c=_count;
		if (yesdelete) delete this;
		return c;
	}
	return _count;
}

/*! Return the id of the object. If NULL, then create a default one and return that.
 */
const char *anObject::Id()
{
	if (object_idstr) return object_idstr;
	else object_idstr=make_id(whattype());
	return object_idstr;
}

/*! Warning! Passing in NULL will make object_idstr==NULL!
 */
const char *anObject::Id(const char *newid)
{
	makestr(object_idstr,newid);
	return object_idstr;
}

} // namespace Laxkit

<|endoftext|>