<commit_before>#include "DistributeFileSys.h"
#include <common/Utilities.h>

#include <glog/logging.h>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>

namespace bfs = boost::filesystem;

static const std::string dfs_copy_prefix = "/sf1r_global_data";

namespace sf1r
{

DistributeFileSys::DistributeFileSys()
    :dfs_enabled_(false)
{
}

bool DistributeFileSys::isEnabled()
{
    return dfs_enabled_ && !dfs_mount_dir_.empty();
}

void DistributeFileSys::enableDFS(const std::string& mount_dir, const std::string& dfs_local_root)
{
    dfs_enabled_ = true;
    dfs_mount_dir_ = mount_dir;
    dfs_local_root_ = dfs_local_root;
}

std::string DistributeFileSys::getDFSPath(const std::string& dfs_location)
{
    const static std::string empty_path;
    if (!dfs_enabled_ || dfs_mount_dir_.empty())
    {
        LOG(INFO) << "dfs is not enabled.";
        return empty_path;
    }
    return dfs_mount_dir_ + "/" + dfs_location;
}

std::string DistributeFileSys::getDFSLocalFullPath(const std::string& dfs_location)
{
    const static std::string empty_path;
    if (!dfs_enabled_ || dfs_local_root_.empty())
    {
        LOG(INFO) << "dfs is not enabled.";
        return empty_path;
    }
    return dfs_local_root_ + "/" + dfs_location;
}

bool DistributeFileSys::copyToDFS(std::string& in_out_path, const std::string& custom_prefix)
{
    static const bfs::directory_iterator end_it = bfs::directory_iterator();
    bfs::path dfs_out_path = bfs::path(dfs_copy_prefix)/bfs::path(custom_prefix);
    dfs_out_path /= bfs::path(boost::lexical_cast<std::string>(Utilities::createTimeStamp()));
    bfs::path dest = bfs::path(getDFSPath(dfs_out_path.string()));
    if (!bfs::exists(dest))
    {
        bfs::create_directories(dest);
    }
    try
    {
        for( bfs::directory_iterator file(in_out_path); file != end_it; ++file )
        {
            bfs::path current(file->path());
            if (!bfs::exists(current))
            {
                continue;
            }
            if(bfs::is_regular_file(current))
            {
                LOG(INFO) << "copying : " << current << " to " << dest;
                bfs::copy_file(current, dest / current.filename(), bfs::copy_option::overwrite_if_exists);
            }
        }
    }
    catch(const std::exception& e)
    {
        LOG(ERROR) << "coping file to dfs failed: " << e.what();
        return false;
    }
    in_out_path = dfs_out_path.string();
    return true;
}

}
<commit_msg>disable DFS currently<commit_after>#include "DistributeFileSys.h"
#include <common/Utilities.h>

#include <glog/logging.h>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>

namespace bfs = boost::filesystem;

static const std::string dfs_copy_prefix = "/sf1r_global_data";

namespace sf1r
{

DistributeFileSys::DistributeFileSys()
    :dfs_enabled_(false)
{
}

bool DistributeFileSys::isEnabled()
{
    return false;
    return dfs_enabled_ && !dfs_mount_dir_.empty();
}

void DistributeFileSys::enableDFS(const std::string& mount_dir, const std::string& dfs_local_root)
{
    dfs_enabled_ = true;
    dfs_mount_dir_ = mount_dir;
    dfs_local_root_ = dfs_local_root;
}

std::string DistributeFileSys::getDFSPath(const std::string& dfs_location)
{
    const static std::string empty_path;
    if (!dfs_enabled_ || dfs_mount_dir_.empty())
    {
        LOG(INFO) << "dfs is not enabled.";
        return empty_path;
    }
    return dfs_mount_dir_ + "/" + dfs_location;
}

std::string DistributeFileSys::getDFSLocalFullPath(const std::string& dfs_location)
{
    const static std::string empty_path;
    if (!dfs_enabled_ || dfs_local_root_.empty())
    {
        LOG(INFO) << "dfs is not enabled.";
        return empty_path;
    }
    return dfs_local_root_ + "/" + dfs_location;
}

bool DistributeFileSys::copyToDFS(std::string& in_out_path, const std::string& custom_prefix)
{
    static const bfs::directory_iterator end_it = bfs::directory_iterator();
    bfs::path dfs_out_path = bfs::path(dfs_copy_prefix)/bfs::path(custom_prefix);
    dfs_out_path /= bfs::path(boost::lexical_cast<std::string>(Utilities::createTimeStamp()));
    bfs::path dest = bfs::path(getDFSPath(dfs_out_path.string()));
    if (!bfs::exists(dest))
    {
        bfs::create_directories(dest);
    }
    try
    {
        for( bfs::directory_iterator file(in_out_path); file != end_it; ++file )
        {
            bfs::path current(file->path());
            if (!bfs::exists(current))
            {
                continue;
            }
            if(bfs::is_regular_file(current))
            {
                LOG(INFO) << "copying : " << current << " to " << dest;
                bfs::copy_file(current, dest / current.filename(), bfs::copy_option::overwrite_if_exists);
            }
        }
    }
    catch(const std::exception& e)
    {
        LOG(ERROR) << "coping file to dfs failed: " << e.what();
        return false;
    }
    in_out_path = dfs_out_path.string();
    return true;
}

}
<|endoftext|>


<commit_before>#include "Controller.h"
#include "ConfigMessage.h"
#include "System/Config.h"
#include "Framework/Replication/ReplicationConfig.h"
#include "Framework/Replication/PaxosLease/PaxosLease.h"
#include "Application/Common/ContextTransport.h"
#include "Application/Common/ClientSession.h"
#include "Application/Common/ClusterMessage.h"

void Controller::Init()
{
    unsigned        numControllers;
    int64_t         nodeID;
    uint64_t        runID;
    const char*     str;
    Endpoint        endpoint;

    primaryLeaseTimeout.SetCallable(MFUNC(Controller, OnPrimaryLeaseTimeout));

    systemDatabase.Open(configFile.GetValue("database.dir", "db"), "system");
    REPLICATION_CONFIG->Init(systemDatabase.GetTable("system"));

    runID = REPLICATION_CONFIG->GetRunID();
    runID += 1;
    REPLICATION_CONFIG->SetRunID(runID);
    REPLICATION_CONFIG->Commit();

    nodeID = configFile.GetIntValue("nodeID", -1);
    if (nodeID < 0)
        ASSERT_FAIL();

    CONTEXT_TRANSPORT->SetSelfNodeID(nodeID);
    REPLICATION_CONFIG->SetNodeID(nodeID);

    CONTEXT_TRANSPORT->SetClusterContext(this);

    // connect to the controller nodes
    numControllers = (unsigned) configFile.GetListNum("controllers");
    for (nodeID = 0; nodeID < numControllers; nodeID++)
    {
        str = configFile.GetListValue("controllers", nodeID, "");
        endpoint.Set(str);
        CONTEXT_TRANSPORT->AddNode(nodeID, endpoint);
    }

    configState.Init();
    configContext.Init(this, numControllers, systemDatabase.GetTable("paxos"));
    CONTEXT_TRANSPORT->AddQuorumContext(&configContext);

    ReadConfigState();
}

void Controller::Shutdown()
{
    CONTEXT_TRANSPORT->Shutdown();
    REPLICATION_CONFIG->Shutdown();
    systemDatabase.Close();
}

int64_t Controller::GetMaster()
{
    return (int64_t) configContext.GetLeader();
}

uint64_t Controller::GetNodeID()
{
    return REPLICATION_CONFIG->GetNodeID();
}

ConfigState* Controller::GetConfigState()
{
    return &configState;
}

void Controller::OnLearnLease()
{
    configState.hasMaster = true;
    configState.masterID = GetMaster();
}

void Controller::OnLeaseTimeout()
{
    ConfigMessage*  itMessage;
    ClientRequest*  itRequest;

    configState.hasMaster = false;
    configState.masterID = 0;

    for (itRequest = requests.First(); itRequest != NULL; itRequest = requests.First())
    {
        requests.Remove(itRequest);
        itRequest->response.NoService();
        itRequest->OnComplete();
    }
    assert(requests.GetLength() == 0);

    for (itRequest = listenRequests.First(); itRequest != NULL; itRequest = listenRequests.First())
    {
        listenRequests.Remove(itRequest);
        itRequest->response.NoService();
        itRequest->OnComplete();
    }
    assert(listenRequests.GetLength() == 0);

    for (itMessage = configMessages.First(); itMessage != NULL; itMessage = configMessages.Delete(itMessage));
    assert(configMessages.GetLength() == 0);
}

void Controller::OnAppend(ConfigMessage& message, bool ownAppend)
{
    ClusterMessage  clusterMessage;

    if (message.type == CONFIGMESSAGE_REGISTER_SHARDSERVER)
    {
        // tell ContextTransport that this connection has a new nodeID
        CONTEXT_TRANSPORT->SetConnectionNodeID(message.endpoint, message.nodeID);
        // tell the shard server
        clusterMessage.SetNodeID(message.nodeID);
        CONTEXT_TRANSPORT->SendClusterMessage(message.nodeID, clusterMessage);
    }

    configState.OnMessage(message);
    WriteConfigState();

    if (ownAppend)
    {
        assert(configMessages.GetLength() > 0);
        assert(configMessages.First()->type == message.type);
        if (configMessages.First()->fromClient)
            SendClientResponse(message);
        configMessages.Delete(configMessages.First());
    }

    if (configContext.IsLeader())
        UpdateListeners();
}

bool Controller::IsValidClientRequest(ClientRequest* request)
{
     return request->IsControllerRequest();
}

void Controller::OnClientRequest(ClientRequest* request)
{
    ConfigMessage*  message;

    if (request->type == CLIENTREQUEST_GET_MASTER)
    {
        if (configContext.IsLeaderKnown())
            request->response.Number(configContext.GetLeader());
        else
            request->response.NoService();

        request->OnComplete();
        return;
    }
    else if (request->type == CLIENTREQUEST_GET_CONFIG_STATE)
    {
        listenRequests.Append(request);
        request->response.GetConfigStateResponse(&configState);
        request->OnComplete(false);
        return;
    }

    message = new ConfigMessage;
    FromClientRequest(request, message);

    if (!configState.CompleteMessage(*message))
    {
        delete message;
        request->response.Failed();
        request->OnComplete();
        return;
    }

    requests.Append(request);
    configMessages.Append(message);
    TryAppend();
}

void Controller::OnClientClose(ClientSession* session)
{
    ClientRequest*  it;
    ClientRequest*  next;

    for (it = listenRequests.First(); it != NULL; it = next)
    {
        next = listenRequests.Next(it);
        if (it->session == session)
        {
            listenRequests.Remove(it);
            it->OnComplete();
        }
    }
}

void Controller::OnClusterMessage(uint64_t /*nodeID*/, ClusterMessage& message)
{
    if (!configContext.IsLeader())
        return;

    switch (message.type)
    {
        case CLUSTERMESSAGE_SET_NODEID:
            ASSERT_FAIL();
        case CLUSTERMESSAGE_SET_CONFIG_STATE:
            ASSERT_FAIL();
        case CLUSTERMESSAGE_REQUEST_LEASE:
            OnRequestLease(message);
            break;
        case CLUSTERMESSAGE_RECEIVE_LEASE:
            ASSERT_FAIL();
    }
}

void Controller::OnIncomingConnectionReady(uint64_t nodeID, Endpoint endpoint)
{
    ClusterMessage      clusterMessage;
    ConfigShardServer*  shardServer;

    // if it's a shard server, send the configState
    if (nodeID >= CONFIG_MIN_SHARD_NODE_ID)
    {
        // TODO: send shutdown message in case of bad configuration
        shardServer = configState.GetShardServer(nodeID);
        if (shardServer == NULL)
            return;

        if (shardServer->endpoint != endpoint)
        {
            Log_Message("Badly configured shard server trying to connect"
             ", nodeID: %" PRIu64
             ", endpoint: %s",
             nodeID, endpoint.ToString());

            return;
        }

        clusterMessage.SetConfigState(&configState);
        CONTEXT_TRANSPORT->SendClusterMessage(nodeID, clusterMessage);
    }
}

bool Controller::OnAwaitingNodeID(Endpoint endpoint)
{
    ConfigShardServer*              shardServer;
    ConfigState::ShardServerList*   shardServers;
    ClusterMessage                  clusterMessage;

    if (!configContext.IsLeader())
        return true; // drop connection

    // look for existing endpoint
    shardServers = &configState.shardServers;
    for (shardServer = shardServers->First(); shardServer != NULL; shardServer = shardServers->Next(shardServer))
    {
        if (shardServer->endpoint == endpoint)
        {
            // tell ContextTransport that this connection has a new nodeID
            CONTEXT_TRANSPORT->SetConnectionNodeID(endpoint, shardServer->nodeID);

            // tell the shard server
            clusterMessage.SetNodeID(shardServer->nodeID);
            CONTEXT_TRANSPORT->SendClusterMessage(shardServer->nodeID, clusterMessage);

            // send config state
            clusterMessage.SetConfigState(&configState);
            CONTEXT_TRANSPORT->SendClusterMessage(shardServer->nodeID, clusterMessage);
            return false;
        }
    }

    TryRegisterShardServer(endpoint);
    return false;
}

void Controller::TryAppend()
{
    if (!configContext.IsAppending())
        configContext.Append(configMessages.First());
}

void Controller::FromClientRequest(ClientRequest* request, ConfigMessage* message)
{
    message->fromClient = true;

    switch (request->type)
    {
        case CLIENTREQUEST_CREATE_QUORUM:
            message->type = CONFIGMESSAGE_CREATE_QUORUM;
            message->productionType = request->productionType;
            message->nodes = request->nodes;
            return;
        case CLIENTREQUEST_CREATE_DATABASE:
            message->type = CONFIGMESSAGE_CREATE_DATABASE;
            message->name.Wrap(request->name);
            message->productionType = request->productionType;
            return;
        case CLIENTREQUEST_RENAME_DATABASE:
            message->type = CONFIGMESSAGE_RENAME_DATABASE;
            message->databaseID = request->databaseID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_DELETE_DATABASE:
            message->type = CONFIGMESSAGE_DELETE_DATABASE;
            message->databaseID = request->databaseID;
            return;
        case CLIENTREQUEST_CREATE_TABLE:
            message->type = CONFIGMESSAGE_CREATE_TABLE;
            message->databaseID = request->databaseID;
            message->quorumID = request->quorumID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_RENAME_TABLE:
            message->type = CONFIGMESSAGE_RENAME_TABLE;
            message->databaseID = request->databaseID;
            message->tableID = request->tableID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_DELETE_TABLE:
            message->type = CONFIGMESSAGE_DELETE_TABLE;
            message->databaseID = request->databaseID;
            message->tableID = request->tableID;
            return;
        default:
            ASSERT_FAIL();
    }
}

void Controller::ToClientResponse(ConfigMessage* message, ClientResponse* response)
{
    switch (response->request->type)
    {
        case CLIENTREQUEST_CREATE_QUORUM:
            response->Number(message->quorumID);
            return;
        case CLIENTREQUEST_CREATE_DATABASE:
            response->Number(message->databaseID);
            return;
        case CLIENTREQUEST_RENAME_DATABASE:
            response->OK();
            return;
        case CLIENTREQUEST_DELETE_DATABASE:
            response->OK();
            return;
        case CLIENTREQUEST_CREATE_TABLE:
            response->Number(message->tableID);
            return;
        case CLIENTREQUEST_RENAME_TABLE:
            response->OK();
            return;
        case CLIENTREQUEST_DELETE_TABLE:
            response->OK();
            return;
        default:
            ASSERT_FAIL();
    }
}

void Controller::OnPrimaryLeaseTimeout()
{
    uint64_t        now;
    ConfigQuorum*   quorum;
    PrimaryLease*   itLease;

    now = EventLoop::Now();

    for (itLease = primaryLeases.First(); itLease != NULL; /* advanced in body */)
    {
        if (itLease->expireTime < now)
        {
            quorum = configState.GetQuorum(itLease->quorumID);
            quorum->hasPrimary = false;
            quorum->primaryID = 0;
            itLease = primaryLeases.Delete(itLease);
        }
        else
            break;
    }

    UpdatePrimaryLeaseTimer();
    UpdateListeners();
}

void Controller::TryRegisterShardServer(Endpoint& endpoint)
{
    ConfigMessage*      message;

    message = new ConfigMessage;
    message->fromClient = false;
    message->RegisterShardServer(0, endpoint);
    if (!configState.CompleteMessage(*message))
        ASSERT_FAIL();

    configMessages.Append(message);
    TryAppend();
}

void Controller::ReadConfigState()
{
    bool        ret;
    ReadBuffer  value;

    ret =  true;
    ret &= systemDatabase.GetTable("config")->Get(ReadBuffer("state"), value);
    ret &= configState.Read(value);
    if (!ret)
        Log_Message("Starting with empty database...");

    Log_Trace("%.*s", P(&value));
}

void Controller::WriteConfigState()
{
    configState.Write(configStateBuffer);
    systemDatabase.GetTable("config")->Set(ReadBuffer("state"), ReadBuffer(configStateBuffer));
    systemDatabase.Commit();
}

void Controller::SendClientResponse(ConfigMessage& message)
{
    ClientRequest* request;

    assert(requests.GetLength() > 0);

    request = requests.First();
    requests.Remove(request);

    ToClientResponse(&message, &request->response);
    request->OnComplete();

}

void Controller::OnRequestLease(ClusterMessage& message)
{
    uint64_t*       it;
    ConfigQuorum*   quorum;

    quorum = configState.GetQuorum(message.quorumID);

    if (quorum == NULL)
    {
        Log_Trace("nodeID " PRIu64 " requesting lease for non-existing quorum %" PRIu64 "",
         message.nodeID, message.quorumID);
        return;
    }

    if (quorum->hasPrimary)
    {
        if (quorum->primaryID != message.nodeID)
            return;
        else
            ExtendPrimaryLease(*quorum, message);
    }

    for (it = quorum->activeNodes.First(); it != NULL; it = quorum->activeNodes.Next(it))
    {
        if (*it == message.nodeID)
            break;
    }

    if (it == NULL)
    {
        Log_Trace("nodeID " PRIu64 " requesting lease but not active member or quorum %" PRIu64 "",
         message.nodeID, message.quorumID);
        return;
    }

    AssignPrimaryLease(*quorum, message);
}

void Controller::AssignPrimaryLease(ConfigQuorum& quorum, ClusterMessage& message)
{
    unsigned        duration;
    PrimaryLease*   primaryLease;
    ClusterMessage  response;

    quorum.hasPrimary = true;
    quorum.primaryID = message.nodeID;

    primaryLease = new PrimaryLease;
    primaryLease->quorumID = quorum.quorumID;
    primaryLease->nodeID = quorum.primaryID;
    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);
    primaryLease->expireTime = EventLoop::Now() + duration;
    primaryLeases.Add(primaryLease);

    UpdatePrimaryLeaseTimer();

    response.ReceiveLease(message.nodeID, message.quorumID, message.proposalID, duration);
    CONTEXT_TRANSPORT->SendClusterMessage(response.nodeID, response);
}

void Controller::ExtendPrimaryLease(ConfigQuorum& quorum, ClusterMessage& message)
{
    unsigned        duration;
    PrimaryLease*   it;
    ClusterMessage  response;

    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);

    for (it = primaryLeases.First(); it != NULL; it = primaryLeases.Next(it))
    {
        if (it->quorumID == quorum.quorumID)
            break;
    }

    assert(it != NULL);

    primaryLeases.Remove(it);
    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);
    it->expireTime = EventLoop::Now() + duration;
    primaryLeases.Add(it);
    UpdatePrimaryLeaseTimer();

    response.ReceiveLease(message.nodeID, message.quorumID, message.proposalID, duration);
    CONTEXT_TRANSPORT->SendClusterMessage(response.nodeID, response);
}

void Controller::UpdatePrimaryLeaseTimer()
{
    PrimaryLease* primaryLease;

    primaryLease = primaryLeases.First();
    if (!primaryLease)
        return;

    if (!primaryLeaseTimeout.IsActive() ||
     primaryLease->expireTime < primaryLeaseTimeout.GetExpireTime())
    {
        EventLoop::Remove(&primaryLeaseTimeout);
        primaryLeaseTimeout.SetExpireTime(primaryLease->expireTime);
        EventLoop::Add(&primaryLeaseTimeout);
    }
}

void Controller::UpdateListeners()
{
    ClientRequest*                  itRequest;
    ConfigShardServer*              itShardServer;
    ConfigState::ShardServerList*   shardServers;
    ClusterMessage                  message;

    // update clients
    for (itRequest = listenRequests.First(); itRequest != NULL; itRequest = listenRequests.Next(itRequest))
    {
        itRequest->response.GetConfigStateResponse(&configState);
        itRequest->OnComplete(false);
    }

    // update shard servers
    message.SetConfigState(&configState);
    shardServers = &configState.shardServers;
    for (itShardServer = shardServers->First();
     itShardServer != NULL;
     itShardServer = shardServers->Next(itShardServer))
    {
        CONTEXT_TRANSPORT->SendClusterMessage(itShardServer->nodeID, message);
    }
}
<commit_msg>Fixed bugs.<commit_after>#include "Controller.h"
#include "ConfigMessage.h"
#include "System/Config.h"
#include "Framework/Replication/ReplicationConfig.h"
#include "Framework/Replication/PaxosLease/PaxosLease.h"
#include "Application/Common/ContextTransport.h"
#include "Application/Common/ClientSession.h"
#include "Application/Common/ClusterMessage.h"

void Controller::Init()
{
    unsigned        numControllers;
    int64_t         nodeID;
    uint64_t        runID;
    const char*     str;
    Endpoint        endpoint;

    primaryLeaseTimeout.SetCallable(MFUNC(Controller, OnPrimaryLeaseTimeout));

    systemDatabase.Open(configFile.GetValue("database.dir", "db"), "system");
    REPLICATION_CONFIG->Init(systemDatabase.GetTable("system"));

    runID = REPLICATION_CONFIG->GetRunID();
    runID += 1;
    REPLICATION_CONFIG->SetRunID(runID);
    REPLICATION_CONFIG->Commit();

    nodeID = configFile.GetIntValue("nodeID", -1);
    if (nodeID < 0)
        ASSERT_FAIL();

    CONTEXT_TRANSPORT->SetSelfNodeID(nodeID);
    REPLICATION_CONFIG->SetNodeID(nodeID);

    CONTEXT_TRANSPORT->SetClusterContext(this);

    // connect to the controller nodes
    numControllers = (unsigned) configFile.GetListNum("controllers");
    for (nodeID = 0; nodeID < numControllers; nodeID++)
    {
        str = configFile.GetListValue("controllers", nodeID, "");
        endpoint.Set(str);
        CONTEXT_TRANSPORT->AddNode(nodeID, endpoint);
    }

    configState.Init();
    configContext.Init(this, numControllers, systemDatabase.GetTable("paxos"));
    CONTEXT_TRANSPORT->AddQuorumContext(&configContext);

    ReadConfigState();
}

void Controller::Shutdown()
{
    CONTEXT_TRANSPORT->Shutdown();
    REPLICATION_CONFIG->Shutdown();
    systemDatabase.Close();
}

int64_t Controller::GetMaster()
{
    return (int64_t) configContext.GetLeader();
}

uint64_t Controller::GetNodeID()
{
    return REPLICATION_CONFIG->GetNodeID();
}

ConfigState* Controller::GetConfigState()
{
    return &configState;
}

void Controller::OnLearnLease()
{
    configState.hasMaster = true;
    configState.masterID = GetMaster();
    if ((uint64_t) GetMaster() == GetNodeID())
        UpdateListeners();
}

void Controller::OnLeaseTimeout()
{
    ConfigMessage*  itMessage;
    ClientRequest*  itRequest;

    configState.hasMaster = false;
    configState.masterID = 0;

    for (itRequest = requests.First(); itRequest != NULL; itRequest = requests.First())
    {
        requests.Remove(itRequest);
        itRequest->response.NoService();
        itRequest->OnComplete();
    }
    assert(requests.GetLength() == 0);

    for (itRequest = listenRequests.First(); itRequest != NULL; itRequest = listenRequests.First())
    {
        listenRequests.Remove(itRequest);
        itRequest->response.NoService();
        itRequest->OnComplete();
    }
    assert(listenRequests.GetLength() == 0);

    for (itMessage = configMessages.First(); itMessage != NULL; itMessage = configMessages.Delete(itMessage));
    assert(configMessages.GetLength() == 0);
}

void Controller::OnAppend(ConfigMessage& message, bool ownAppend)
{
    ClusterMessage  clusterMessage;

    if (message.type == CONFIGMESSAGE_REGISTER_SHARDSERVER)
    {
        // tell ContextTransport that this connection has a new nodeID
        CONTEXT_TRANSPORT->SetConnectionNodeID(message.endpoint, message.nodeID);
        // tell the shard server
        clusterMessage.SetNodeID(message.nodeID);
        CONTEXT_TRANSPORT->SendClusterMessage(message.nodeID, clusterMessage);
    }

    configState.OnMessage(message);
    WriteConfigState();

    if (ownAppend)
    {
        assert(configMessages.GetLength() > 0);
        assert(configMessages.First()->type == message.type);
        if (configMessages.First()->fromClient)
            SendClientResponse(message);
        configMessages.Delete(configMessages.First());
    }

    if (configContext.IsLeader())
        UpdateListeners();
}

bool Controller::IsValidClientRequest(ClientRequest* request)
{
     return request->IsControllerRequest();
}

void Controller::OnClientRequest(ClientRequest* request)
{
    ConfigMessage*  message;

    if (request->type == CLIENTREQUEST_GET_MASTER)
    {
        if (configContext.IsLeaderKnown())
            request->response.Number(configContext.GetLeader());
        else
            request->response.NoService();

        request->OnComplete();
        return;
    }
    else if (request->type == CLIENTREQUEST_GET_CONFIG_STATE)
    {
        listenRequests.Append(request);
        request->response.GetConfigStateResponse(&configState);
        request->OnComplete(false);
        return;
    }

    message = new ConfigMessage;
    FromClientRequest(request, message);

    if (!configState.CompleteMessage(*message))
    {
        delete message;
        request->response.Failed();
        request->OnComplete();
        return;
    }

    requests.Append(request);
    configMessages.Append(message);
    TryAppend();
}

void Controller::OnClientClose(ClientSession* session)
{
    ClientRequest*  it;
    ClientRequest*  next;

    for (it = listenRequests.First(); it != NULL; it = next)
    {
        next = listenRequests.Next(it);
        if (it->session == session)
        {
            listenRequests.Remove(it);
            it->OnComplete();
        }
    }
}

void Controller::OnClusterMessage(uint64_t /*nodeID*/, ClusterMessage& message)
{
    if (!configContext.IsLeader())
        return;

    switch (message.type)
    {
        case CLUSTERMESSAGE_SET_NODEID:
            ASSERT_FAIL();
        case CLUSTERMESSAGE_SET_CONFIG_STATE:
            ASSERT_FAIL();
        case CLUSTERMESSAGE_REQUEST_LEASE:
            OnRequestLease(message);
            break;
        case CLUSTERMESSAGE_RECEIVE_LEASE:
            ASSERT_FAIL();
    }
}

void Controller::OnIncomingConnectionReady(uint64_t nodeID, Endpoint endpoint)
{
    ClusterMessage      clusterMessage;
    ConfigShardServer*  shardServer;

    // if it's a shard server, send the configState
    if (nodeID >= CONFIG_MIN_SHARD_NODE_ID)
    {
        // TODO: send shutdown message in case of bad configuration
        shardServer = configState.GetShardServer(nodeID);
        if (shardServer == NULL)
            return;

        if (shardServer->endpoint != endpoint)
        {
            Log_Message("Badly configured shard server trying to connect"
             ", nodeID: %" PRIu64
             ", endpoint: %s",
             nodeID, endpoint.ToString());

            return;
        }

        clusterMessage.SetConfigState(&configState);
        CONTEXT_TRANSPORT->SendClusterMessage(nodeID, clusterMessage);
    }
}

bool Controller::OnAwaitingNodeID(Endpoint endpoint)
{
    ConfigShardServer*              shardServer;
    ConfigState::ShardServerList*   shardServers;
    ClusterMessage                  clusterMessage;

    if (!configContext.IsLeader())
        return true; // drop connection

    // look for existing endpoint
    shardServers = &configState.shardServers;
    for (shardServer = shardServers->First(); shardServer != NULL; shardServer = shardServers->Next(shardServer))
    {
        if (shardServer->endpoint == endpoint)
        {
            // tell ContextTransport that this connection has a new nodeID
            CONTEXT_TRANSPORT->SetConnectionNodeID(endpoint, shardServer->nodeID);

            // tell the shard server
            clusterMessage.SetNodeID(shardServer->nodeID);
            CONTEXT_TRANSPORT->SendClusterMessage(shardServer->nodeID, clusterMessage);

            // send config state
            clusterMessage.SetConfigState(&configState);
            CONTEXT_TRANSPORT->SendClusterMessage(shardServer->nodeID, clusterMessage);
            return false;
        }
    }

    TryRegisterShardServer(endpoint);
    return false;
}

void Controller::TryAppend()
{
    if (!configContext.IsAppending())
        configContext.Append(configMessages.First());
}

void Controller::FromClientRequest(ClientRequest* request, ConfigMessage* message)
{
    message->fromClient = true;

    switch (request->type)
    {
        case CLIENTREQUEST_CREATE_QUORUM:
            message->type = CONFIGMESSAGE_CREATE_QUORUM;
            message->productionType = request->productionType;
            message->nodes = request->nodes;
            return;
        case CLIENTREQUEST_CREATE_DATABASE:
            message->type = CONFIGMESSAGE_CREATE_DATABASE;
            message->name.Wrap(request->name);
            message->productionType = request->productionType;
            return;
        case CLIENTREQUEST_RENAME_DATABASE:
            message->type = CONFIGMESSAGE_RENAME_DATABASE;
            message->databaseID = request->databaseID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_DELETE_DATABASE:
            message->type = CONFIGMESSAGE_DELETE_DATABASE;
            message->databaseID = request->databaseID;
            return;
        case CLIENTREQUEST_CREATE_TABLE:
            message->type = CONFIGMESSAGE_CREATE_TABLE;
            message->databaseID = request->databaseID;
            message->quorumID = request->quorumID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_RENAME_TABLE:
            message->type = CONFIGMESSAGE_RENAME_TABLE;
            message->databaseID = request->databaseID;
            message->tableID = request->tableID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_DELETE_TABLE:
            message->type = CONFIGMESSAGE_DELETE_TABLE;
            message->databaseID = request->databaseID;
            message->tableID = request->tableID;
            return;
        default:
            ASSERT_FAIL();
    }
}

void Controller::ToClientResponse(ConfigMessage* message, ClientResponse* response)
{
    switch (response->request->type)
    {
        case CLIENTREQUEST_CREATE_QUORUM:
            response->Number(message->quorumID);
            return;
        case CLIENTREQUEST_CREATE_DATABASE:
            response->Number(message->databaseID);
            return;
        case CLIENTREQUEST_RENAME_DATABASE:
            response->OK();
            return;
        case CLIENTREQUEST_DELETE_DATABASE:
            response->OK();
            return;
        case CLIENTREQUEST_CREATE_TABLE:
            response->Number(message->tableID);
            return;
        case CLIENTREQUEST_RENAME_TABLE:
            response->OK();
            return;
        case CLIENTREQUEST_DELETE_TABLE:
            response->OK();
            return;
        default:
            ASSERT_FAIL();
    }
}

void Controller::OnPrimaryLeaseTimeout()
{
    uint64_t        now;
    ConfigQuorum*   quorum;
    PrimaryLease*   itLease;

    now = EventLoop::Now();

    for (itLease = primaryLeases.First(); itLease != NULL; /* advanced in body */)
    {
        if (itLease->expireTime < now)
        {
            quorum = configState.GetQuorum(itLease->quorumID);
            quorum->hasPrimary = false;
            quorum->primaryID = 0;
            itLease = primaryLeases.Delete(itLease);
        }
        else
            break;
    }

    UpdatePrimaryLeaseTimer();
    UpdateListeners();
}

void Controller::TryRegisterShardServer(Endpoint& endpoint)
{
    ConfigMessage*      message;

    message = new ConfigMessage;
    message->fromClient = false;
    message->RegisterShardServer(0, endpoint);
    if (!configState.CompleteMessage(*message))
        ASSERT_FAIL();

    configMessages.Append(message);
    TryAppend();
}

void Controller::ReadConfigState()
{
    bool        ret;
    ReadBuffer  value;

    ret =  true;
    ret &= systemDatabase.GetTable("config")->Get(ReadBuffer("state"), value);
    ret &= configState.Read(value);
    if (!ret)
        Log_Message("Starting with empty database...");

    Log_Trace("%.*s", P(&value));
}

void Controller::WriteConfigState()
{
    configState.Write(configStateBuffer);
    systemDatabase.GetTable("config")->Set(ReadBuffer("state"), ReadBuffer(configStateBuffer));
    systemDatabase.Commit();
}

void Controller::SendClientResponse(ConfigMessage& message)
{
    ClientRequest* request;

    assert(requests.GetLength() > 0);

    request = requests.First();
    requests.Remove(request);

    ToClientResponse(&message, &request->response);
    request->OnComplete();

}

void Controller::OnRequestLease(ClusterMessage& message)
{
    uint64_t*       it;
    ConfigQuorum*   quorum;

    quorum = configState.GetQuorum(message.quorumID);

    if (quorum == NULL)
    {
        Log_Trace("nodeID " PRIu64 " requesting lease for non-existing quorum %" PRIu64 "",
         message.nodeID, message.quorumID);
        return;
    }

    if (quorum->hasPrimary)
    {
        if (quorum->primaryID != message.nodeID)
            return;
        else
            ExtendPrimaryLease(*quorum, message);
    }

    for (it = quorum->activeNodes.First(); it != NULL; it = quorum->activeNodes.Next(it))
    {
        if (*it == message.nodeID)
            break;
    }

    if (it == NULL)
    {
        Log_Trace("nodeID " PRIu64 " requesting lease but not active member or quorum %" PRIu64 "",
         message.nodeID, message.quorumID);
        return;
    }

    AssignPrimaryLease(*quorum, message);
}

void Controller::AssignPrimaryLease(ConfigQuorum& quorum, ClusterMessage& message)
{
    unsigned        duration;
    PrimaryLease*   primaryLease;
    ClusterMessage  response;

    quorum.hasPrimary = true;
    quorum.primaryID = message.nodeID;

    primaryLease = new PrimaryLease;
    primaryLease->quorumID = quorum.quorumID;
    primaryLease->nodeID = quorum.primaryID;
    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);
    primaryLease->expireTime = EventLoop::Now() + duration;
    primaryLeases.Add(primaryLease);

    UpdatePrimaryLeaseTimer();

    response.ReceiveLease(message.nodeID, message.quorumID, message.proposalID, duration);
    CONTEXT_TRANSPORT->SendClusterMessage(response.nodeID, response);
}

void Controller::ExtendPrimaryLease(ConfigQuorum& quorum, ClusterMessage& message)
{
    unsigned        duration;
    PrimaryLease*   it;
    ClusterMessage  response;

    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);

    for (it = primaryLeases.First(); it != NULL; it = primaryLeases.Next(it))
    {
        if (it->quorumID == quorum.quorumID)
            break;
    }

    assert(it != NULL);

    primaryLeases.Remove(it);
    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);
    it->expireTime = EventLoop::Now() + duration;
    primaryLeases.Add(it);
    UpdatePrimaryLeaseTimer();

    response.ReceiveLease(message.nodeID, message.quorumID, message.proposalID, duration);
    CONTEXT_TRANSPORT->SendClusterMessage(response.nodeID, response);
}

void Controller::UpdatePrimaryLeaseTimer()
{
    PrimaryLease* primaryLease;

    primaryLease = primaryLeases.First();
    if (!primaryLease)
        return;

    if (!primaryLeaseTimeout.IsActive() ||
     primaryLease->expireTime < primaryLeaseTimeout.GetExpireTime())
    {
        EventLoop::Remove(&primaryLeaseTimeout);
        primaryLeaseTimeout.SetExpireTime(primaryLease->expireTime);
        EventLoop::Add(&primaryLeaseTimeout);
    }
}

void Controller::UpdateListeners()
{
    ClientRequest*                  itRequest;
    ConfigShardServer*              itShardServer;
    ConfigState::ShardServerList*   shardServers;
    ClusterMessage                  message;

    // update clients
    for (itRequest = listenRequests.First(); itRequest != NULL; itRequest = listenRequests.Next(itRequest))
    {
        itRequest->response.GetConfigStateResponse(&configState);
        itRequest->OnComplete(false);
    }

    // update shard servers
    message.SetConfigState(&configState);
    shardServers = &configState.shardServers;
    for (itShardServer = shardServers->First();
     itShardServer != NULL;
     itShardServer = shardServers->Next(itShardServer))
    {
        CONTEXT_TRANSPORT->SendClusterMessage(itShardServer->nodeID, message);
    }
}
<|endoftext|>


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

#include "IECoreMaya/FromMayaShapeConverter.h"
#include "IECoreMaya/FromMayaPlugConverter.h"

#include "IECore/CompoundParameter.h"
#include "IECore/Primitive.h"
#include "IECore/MessageHandler.h"
#include "IECore/DespatchTypedData.h"

#include "maya/MFnDependencyNode.h"
#include "maya/MFnAttribute.h"

using namespace IECoreMaya;

FromMayaShapeConverter::FromMayaShapeConverter( const std::string &name, const std::string &description, const MObject &object )
	:	FromMayaObjectConverter( name, description, object )
{
	constructCommon();
}

FromMayaShapeConverter::FromMayaShapeConverter( const std::string &name, const std::string &description, const MDagPath &dagPath )
	:	FromMayaObjectConverter( name, description, dagPath.node() ), m_dagPath( dagPath )
{
	constructCommon();
}

void FromMayaShapeConverter::constructCommon()
{

	IECore::IntParameter::PresetsMap spacePresets;
	spacePresets["Object"] = Object;
	spacePresets["World"] = World;
	m_spaceParameter = new IECore::IntParameter(
		"space",
		"The space in which the object is exported.",
		Object,
		Object,
		World,
		spacePresets,
		true
	);

	IECore::StringParameter::PresetsMap primVarAttrPrefixPresets;
	primVarAttrPrefixPresets["MTOR"] = "rman";
	primVarAttrPrefixPresets["3Delight"] = "delight";
	primVarAttrPrefixPresets["None"] = "";
	m_primVarAttrPrefixParameter = new IECore::StringParameter(
		"primVarAttrPrefix",
		"Any attribute names beginning with this prefix are considered to represent primitive variables and are converted as such."
		"The interpolation type of the variable is guessed, unless the attribute name begins with prefix_?_, in which case the ? is"
		"used to specify type - C for constant, U for uniform, V for Vertex, Y for varying and F for facevarying",
		"delight", // compatibility with 3delight by default
		primVarAttrPrefixPresets
	);

	parameters()->addParameter( m_spaceParameter );
	parameters()->addParameter( m_primVarAttrPrefixParameter );

}

IECore::IntParameterPtr FromMayaShapeConverter::spaceParameter()
{
	return m_spaceParameter;
}

IECore::ConstIntParameterPtr FromMayaShapeConverter::spaceParameter() const
{
	return m_spaceParameter;
}

IECore::StringParameterPtr FromMayaShapeConverter::primVarAttrPrefixParameter()
{
	return m_primVarAttrPrefixParameter;
}

IECore::ConstStringParameterPtr FromMayaShapeConverter::primVarAttrPrefixParameter() const
{
	return m_primVarAttrPrefixParameter;
}

IECore::ObjectPtr FromMayaShapeConverter::doConversion( const MObject &object, IECore::ConstCompoundObjectPtr operands ) const
{
	IECore::PrimitivePtr p = 0;
	const MDagPath *d = dagPath( true );
	if( d )
	{
		p = doPrimitiveConversion( *d, operands );
	}
	else
	{
		p = doPrimitiveConversion( object, operands );
	}
	if( p )
	{
		addPrimVars( object, p );
	}
	return p;
}

void FromMayaShapeConverter::addPrimVars( const MObject &object, IECore::PrimitivePtr primitive ) const
{
	MFnDependencyNode fnNode( object );
	if( !fnNode.hasObj( object ) )
	{
		return;
	}

	MString prefix = m_primVarAttrPrefixParameter->getTypedValue().c_str();
	unsigned int n = fnNode.attributeCount();
	for( unsigned int i=0; i<n; i++ )
	{
		MObject attr = fnNode.attribute( i );
		MFnAttribute fnAttr( attr );
		MString attrName = fnAttr.name();
		if( attrName.substring( 0, prefix.length()-1 )==prefix && attrName.length() > prefix.length() )
		{
			MPlug plug = fnNode.findPlug( attr );
			if( !plug.parent().isNull() )
			{
				continue; // we don't want to pick up the children of compound numeric attributes
			}
			MString plugName = plug.name();

			// find a converter for the plug, asking for conversion to float types by preference
			FromMayaConverterPtr converter = FromMayaPlugConverter::create( plug, IECore::FloatDataTypeId );
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::V3fDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::V3fVectorDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::FloatVectorDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug );
			}

			// run the conversion and check we've got data as a result
			IECore::DataPtr data = 0;
			if( converter )
			{
				 data = IECore::runTimeCast<IECore::Data>( converter->convert() );
			}
			if( !data )
			{
				IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" could not be converted to Data." ) % plugName.asChar() );
				continue;
			}

			// convert V3fData to Color3fData if attribute has usedAsColor() set.
			if( IECore::V3fDataPtr vData = IECore::runTimeCast<IECore::V3fData>( data ) )
			{
				if( fnAttr.isUsedAsColor() )
				{
					Imath::V3f v = vData->readable();
					data = new IECore::Color3fData( Imath::Color3f( v.x, v.y, v.z ) );
				}
			}

			// see if interpolation has been specified, and find primitive variable name
			std::string primVarName = attrName.asChar() + prefix.length();
			IECore::PrimitiveVariable::Interpolation interpolation = IECore::PrimitiveVariable::Invalid;
			if( attrName.length()>prefix.length()+3 )
			{
				const char *c = attrName.asChar();
				if( c[prefix.length()]=='_' && c[prefix.length()+2]=='_' )
				{
					char t = c[prefix.length()+1];
					primVarName = attrName.asChar() + prefix.length() + 3;
					switch( t )
					{
						case 'C' :
							interpolation = IECore::PrimitiveVariable::Constant;
							break;
						case 'U' :
							interpolation = IECore::PrimitiveVariable::Uniform;
							break;
						case 'V' :
							interpolation = IECore::PrimitiveVariable::Vertex;
							break;
						case 'Y' :
							interpolation = IECore::PrimitiveVariable::Varying;
							break;
						case 'F' :
							interpolation = IECore::PrimitiveVariable::FaceVarying;
							break;
						default :
							IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" has unknown interpolation - guessing interpolation." ) % plugName.asChar() );
							break;
					}
				}
			}

			// guess interpolation if not specified
			if( interpolation==IECore::PrimitiveVariable::Invalid )
			{
				interpolation = primitive->inferInterpolation( data );
			}

			if( interpolation==IECore::PrimitiveVariable::Invalid )
			{
				IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" has unsuitable size." ) % plugName.asChar() );
				continue;
			}

			// finally add the primvar
			primitive->variables[primVarName] = IECore::PrimitiveVariable( interpolation, data );

		}
	}

}

MSpace::Space FromMayaShapeConverter::space() const
{
	Space s = (Space)m_spaceParameter->getNumericValue();
	switch( s )
	{
		case Object :
			return MSpace::kObject;
		case World :
			return MSpace::kWorld;
	}
	assert( 0 ); // should never get here
	return MSpace::kObject;
}

const MDagPath *FromMayaShapeConverter::dagPath( bool emitSpaceWarnings ) const
{
	if( m_dagPath.isValid() )
	{
		return &m_dagPath;
	}

	if( emitSpaceWarnings && space()==MSpace::kWorld )
	{
		IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter", "World space requested but no dag path provided." );
	}

	return 0;
}

FromMayaShapeConverterPtr FromMayaShapeConverter::create( const MDagPath &dagPath, IECore::TypeId resultType )
{
	const ShapeTypesToFnsMap *m = shapeTypesToFns();
	ShapeTypesToFnsMap::const_iterator it = m->find( ShapeTypes( dagPath.apiType(), resultType ) );
	if( it!=m->end() )
	{
		return it->second( dagPath );
	}
	return 0;
}

void FromMayaShapeConverter::registerShapeConverter( const MFn::Type fromType, IECore::TypeId resultType, ShapeCreatorFn creator )
{
	ShapeTypesToFnsMap *m = shapeTypesToFns();
	m->insert( ShapeTypesToFnsMap::value_type( ShapeTypes( fromType, resultType ), creator ) );
	m->insert( ShapeTypesToFnsMap::value_type( ShapeTypes( fromType, IECore::InvalidTypeId ), creator ) ); // for the create function which doesn't care about resultType
}

FromMayaShapeConverter::ShapeTypesToFnsMap *FromMayaShapeConverter::shapeTypesToFns()
{
	static ShapeTypesToFnsMap *m = new ShapeTypesToFnsMap;
	return m;
}

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

#include "IECoreMaya/FromMayaShapeConverter.h"
#include "IECoreMaya/FromMayaPlugConverter.h"

#include "IECore/CompoundParameter.h"
#include "IECore/Primitive.h"
#include "IECore/MessageHandler.h"
#include "IECore/DespatchTypedData.h"

#include "maya/MFnDependencyNode.h"
#include "maya/MFnAttribute.h"

using namespace IECoreMaya;

FromMayaShapeConverter::FromMayaShapeConverter( const std::string &name, const std::string &description, const MObject &object )
	:	FromMayaObjectConverter( name, description, object )
{
	constructCommon();
}

FromMayaShapeConverter::FromMayaShapeConverter( const std::string &name, const std::string &description, const MDagPath &dagPath )
	:	FromMayaObjectConverter( name, description, dagPath.node() ), m_dagPath( dagPath )
{
	constructCommon();
}

void FromMayaShapeConverter::constructCommon()
{

	IECore::IntParameter::PresetsMap spacePresets;
	spacePresets["Object"] = Object;
	spacePresets["World"] = World;
	m_spaceParameter = new IECore::IntParameter(
		"space",
		"The space in which the object is exported.",
		Object,
		Object,
		World,
		spacePresets,
		true
	);

	IECore::StringParameter::PresetsMap primVarAttrPrefixPresets;
	primVarAttrPrefixPresets["MTOR"] = "rman";
	primVarAttrPrefixPresets["3Delight"] = "delight";
	primVarAttrPrefixPresets["None"] = "";
	m_primVarAttrPrefixParameter = new IECore::StringParameter(
		"primVarAttrPrefix",
		"Any attribute names beginning with this prefix are considered to represent primitive variables and are converted as such."
		"The interpolation type of the variable is guessed, unless the attribute name begins with prefix_?_, in which case the ? is"
		"used to specify type - C for constant, U for uniform, V for Vertex, Y for varying and F for facevarying",
		"delight", // compatibility with 3delight by default
		primVarAttrPrefixPresets
	);

	parameters()->addParameter( m_spaceParameter );
	parameters()->addParameter( m_primVarAttrPrefixParameter );

}

IECore::IntParameterPtr FromMayaShapeConverter::spaceParameter()
{
	return m_spaceParameter;
}

IECore::ConstIntParameterPtr FromMayaShapeConverter::spaceParameter() const
{
	return m_spaceParameter;
}

IECore::StringParameterPtr FromMayaShapeConverter::primVarAttrPrefixParameter()
{
	return m_primVarAttrPrefixParameter;
}

IECore::ConstStringParameterPtr FromMayaShapeConverter::primVarAttrPrefixParameter() const
{
	return m_primVarAttrPrefixParameter;
}

IECore::ObjectPtr FromMayaShapeConverter::doConversion( const MObject &object, IECore::ConstCompoundObjectPtr operands ) const
{
	IECore::PrimitivePtr p = 0;

	/// \todo Surely here we should only be specifying "true" for argument "emitSpaceWarnings" if we're not converting from some DG data?
	const MDagPath *d = dagPath( true );
	if( d )
	{
		p = doPrimitiveConversion( *d, operands );
	}
	else
	{
		p = doPrimitiveConversion( object, operands );
	}
	if( p )
	{
		addPrimVars( object, p );
	}
	return p;
}

void FromMayaShapeConverter::addPrimVars( const MObject &object, IECore::PrimitivePtr primitive ) const
{
	MFnDependencyNode fnNode( object );
	if( !fnNode.hasObj( object ) )
	{
		return;
	}

	MString prefix = m_primVarAttrPrefixParameter->getTypedValue().c_str();
	unsigned int n = fnNode.attributeCount();
	for( unsigned int i=0; i<n; i++ )
	{
		MObject attr = fnNode.attribute( i );
		MFnAttribute fnAttr( attr );
		MString attrName = fnAttr.name();
		if( attrName.substring( 0, prefix.length()-1 )==prefix && attrName.length() > prefix.length() )
		{
			MPlug plug = fnNode.findPlug( attr );
			if( !plug.parent().isNull() )
			{
				continue; // we don't want to pick up the children of compound numeric attributes
			}
			MString plugName = plug.name();

			// find a converter for the plug, asking for conversion to float types by preference
			FromMayaConverterPtr converter = FromMayaPlugConverter::create( plug, IECore::FloatDataTypeId );
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::V3fDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::V3fVectorDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug, IECore::FloatVectorDataTypeId );
			}
			if( !converter )
			{
				converter = FromMayaPlugConverter::create( plug );
			}

			// run the conversion and check we've got data as a result
			IECore::DataPtr data = 0;
			if( converter )
			{
				 data = IECore::runTimeCast<IECore::Data>( converter->convert() );
			}
			if( !data )
			{
				IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" could not be converted to Data." ) % plugName.asChar() );
				continue;
			}

			// convert V3fData to Color3fData if attribute has usedAsColor() set.
			if( IECore::V3fDataPtr vData = IECore::runTimeCast<IECore::V3fData>( data ) )
			{
				if( fnAttr.isUsedAsColor() )
				{
					Imath::V3f v = vData->readable();
					data = new IECore::Color3fData( Imath::Color3f( v.x, v.y, v.z ) );
				}
			}

			// see if interpolation has been specified, and find primitive variable name
			std::string primVarName = attrName.asChar() + prefix.length();
			IECore::PrimitiveVariable::Interpolation interpolation = IECore::PrimitiveVariable::Invalid;
			if( attrName.length()>prefix.length()+3 )
			{
				const char *c = attrName.asChar();
				if( c[prefix.length()]=='_' && c[prefix.length()+2]=='_' )
				{
					char t = c[prefix.length()+1];
					primVarName = attrName.asChar() + prefix.length() + 3;
					switch( t )
					{
						case 'C' :
							interpolation = IECore::PrimitiveVariable::Constant;
							break;
						case 'U' :
							interpolation = IECore::PrimitiveVariable::Uniform;
							break;
						case 'V' :
							interpolation = IECore::PrimitiveVariable::Vertex;
							break;
						case 'Y' :
							interpolation = IECore::PrimitiveVariable::Varying;
							break;
						case 'F' :
							interpolation = IECore::PrimitiveVariable::FaceVarying;
							break;
						default :
							IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" has unknown interpolation - guessing interpolation." ) % plugName.asChar() );
							break;
					}
				}
			}

			// guess interpolation if not specified
			if( interpolation==IECore::PrimitiveVariable::Invalid )
			{
				interpolation = primitive->inferInterpolation( data );
			}

			if( interpolation==IECore::PrimitiveVariable::Invalid )
			{
				IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter::addPrimVars", boost::format( "Attribute \"%s\" has unsuitable size." ) % plugName.asChar() );
				continue;
			}

			// finally add the primvar
			primitive->variables[primVarName] = IECore::PrimitiveVariable( interpolation, data );

		}
	}

}

MSpace::Space FromMayaShapeConverter::space() const
{
	Space s = (Space)m_spaceParameter->getNumericValue();
	switch( s )
	{
		case Object :
			return MSpace::kObject;
		case World :
			return MSpace::kWorld;
	}
	assert( 0 ); // should never get here
	return MSpace::kObject;
}

const MDagPath *FromMayaShapeConverter::dagPath( bool emitSpaceWarnings ) const
{
	if( m_dagPath.isValid() )
	{
		return &m_dagPath;
	}

	if( emitSpaceWarnings && space()==MSpace::kWorld )
	{
		IECore::msg( IECore::Msg::Warning, "FromMayaShapeConverter", "World space requested but no dag path provided." );
	}

	return 0;
}

FromMayaShapeConverterPtr FromMayaShapeConverter::create( const MDagPath &dagPath, IECore::TypeId resultType )
{
	const ShapeTypesToFnsMap *m = shapeTypesToFns();
	ShapeTypesToFnsMap::const_iterator it = m->find( ShapeTypes( dagPath.apiType(), resultType ) );
	if( it!=m->end() )
	{
		return it->second( dagPath );
	}
	return 0;
}

void FromMayaShapeConverter::registerShapeConverter( const MFn::Type fromType, IECore::TypeId resultType, ShapeCreatorFn creator )
{
	ShapeTypesToFnsMap *m = shapeTypesToFns();
	m->insert( ShapeTypesToFnsMap::value_type( ShapeTypes( fromType, resultType ), creator ) );
	m->insert( ShapeTypesToFnsMap::value_type( ShapeTypes( fromType, IECore::InvalidTypeId ), creator ) ); // for the create function which doesn't care about resultType
}

FromMayaShapeConverter::ShapeTypesToFnsMap *FromMayaShapeConverter::shapeTypesToFns()
{
	static ShapeTypesToFnsMap *m = new ShapeTypesToFnsMap;
	return m;
}

<|endoftext|>


<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __BSE_CXXAUX_HH__
#define __BSE_CXXAUX_HH__

#include <bse/sysconfig.h>
#include <sys/types.h>                  // uint, ssize
#include <cstdint>                      // uint64_t
#include <memory>
#include <vector>
#include <map>

namespace Bse {

typedef uint32_t uint;          ///< Provide 'uint' as convenience type.
static_assert (sizeof (uint) == 4, "");

// == type aliases ==
typedef uint8_t         uint8;          ///< An 8-bit unsigned integer.
typedef uint16_t        uint16;         ///< A 16-bit unsigned integer.
typedef uint32_t        uint32;         ///< A 32-bit unsigned integer.
typedef uint64_t        uint64;         ///< A 64-bit unsigned integer, use PRI*64 in format strings.
typedef int8_t          int8;           ///< An 8-bit signed integer.
typedef int16_t         int16;          ///< A 16-bit signed integer.
typedef int32_t         int32;          ///< A 32-bit signed integer.
typedef int64_t         int64;          ///< A 64-bit unsigned integer, use PRI*64 in format strings.
typedef uint32_t        unichar;        ///< A 32-bit unsigned integer used for Unicode characters.
static_assert (sizeof (uint8) == 1 && sizeof (uint16) == 2 && sizeof (uint32) == 4 && sizeof (uint64) == 8, "");
static_assert (sizeof (int8)  == 1 && sizeof (int16)  == 2 && sizeof (int32)  == 4 && sizeof (int64)  == 8, "");
static_assert (sizeof (int) == 4 && sizeof (uint) == 4 && sizeof (unichar) == 4, "");
using   std::map;
using   std::vector;
typedef std::string String;             ///< Convenience alias for std::string.
typedef vector<String> StringVector;    ///< Convenience alias for a std::vector<std::string>.

// == Utility Macros ==
#define BSE_CPP_STRINGIFY(s)    BSE_CPP_STRINGIFY_ (s)                  ///< Convert macro argument into a C const char*.
#define BSE_CPP_STRINGIFY_(s)   #s                                      // Indirection helper, required to expand macros like __LINE__
#define BSE_CPP_PASTE2_(a,b)    a ## b                                  // Indirection helper, required to expand macros like __LINE__
#define BSE_CPP_PASTE2(a,b)     BSE_CPP_PASTE2_ (a,b)                   ///< Paste two macro arguments into one C symbol name
#define BSE_ISLIKELY(expr)      __builtin_expect (bool (expr), 1)       ///< Compiler hint to optimize for @a expr evaluating to true.
#define BSE_UNLIKELY(expr)      __builtin_expect (bool (expr), 0)       ///< Compiler hint to optimize for @a expr evaluating to false.
#define BSE_ABS(a)              ((a) < 0 ? -(a) : (a))                  ///< Yield the absolute value of @a a.
#define BSE_MIN(a,b)            ((a) <= (b) ? (a) : (b))                ///< Yield the smaller value of @a a and @a b.
#define BSE_MAX(a,b)            ((a) >= (b) ? (a) : (b))                ///< Yield the greater value of @a a and @a b.
#define BSE_CLAMP(v,mi,ma)      ((v) < (mi) ? (mi) : ((v) > (ma) ? (ma) : (v))) ///< Yield @a v clamped to [ @a mi .. @a ma ].
#define BSE_ARRAY_SIZE(array)   (sizeof (array) / sizeof ((array)[0]))          ///< Yield the number of C @a array elements.
#define BSE_ALIGN(size, base)   ((base) * ((size_t (size) + (base) - 1) / (base))) ///< Round up @a size to multiples of @a base.
#define BSE_DEPRECATED          __attribute__ ((__deprecated__))

// Bse macro shorthands for GCC Attributes.
#define BSE_ALWAYS_INLINE       __attribute__ ((always_inline))
#define BSE_COLD                __attribute__ ((__cold__))
#define BSE_CONST               __attribute__ ((__const__))
#define BSE_CONSTRUCTOR	        __attribute__ ((constructor,used))      // gcc-3.3 also needs "used" to emit code
#define BSE_DEPRECATED          __attribute__ ((__deprecated__))
#define BSE_FORMAT(fx)          __attribute__ ((__format_arg__ (fx)))
#define BSE_HOT                 __attribute__ ((__hot__))
#define BSE_MALLOC              __attribute__ ((__malloc__))
#define BSE_MAY_ALIAS           __attribute__ ((may_alias))
#define BSE_NOINLINE	        __attribute__ ((noinline))
#define BSE_NORETURN            __attribute__ ((__noreturn__))
#define BSE_NO_INSTRUMENT       __attribute__ ((__no_instrument_function__))
#define BSE_PRINTF(fx, ax)      __attribute__ ((__format__ (__printf__, fx, ax)))
#define BSE_PURE                __attribute__ ((__pure__))
#define BSE_SCANF(fx, ax)       __attribute__ ((__format__ (__scanf__, fx, ax)))
#define BSE_SENTINEL            __attribute__ ((__sentinel__))
#define BSE_UNUSED              __attribute__ ((__unused__))
#define BSE_USE_RESULT          __attribute__ ((warn_unused_result))
#define BSE_USED                __attribute__ ((__used__))
#define BSE_WEAK                __attribute__ ((__weak__))

/// Return silently if @a cond does not evaluate to true, with return value @a ...
#define BSE_RETURN_UNLESS(cond, ...)      do { if (BSE_UNLIKELY (!bool (cond))) return __VA_ARGS__; } while (0)

/// Delete copy ctor and assignment operator.
#define BSE_CLASS_NON_COPYABLE(ClassName)  \
  /*copy-ctor*/ ClassName  (const ClassName&) = delete; \
  ClassName&    operator=  (const ClassName&) = delete
#ifdef __clang__ // clang++-3.8.0: work around 'variable length array of non-POD element type'
#define BSE_DECLARE_VLA(Type, var, count)          std::vector<Type> var (count)
#else // sane c++
#define BSE_DECLARE_VLA(Type, var, count)          Type var[count] ///< Declare a variable length array (clang++ uses std::vector<>).
#endif

/// Test string equality at compile time.
extern inline constexpr bool
constexpr_equals (const char *a, const char *b, size_t n)
{
  return n == 0 || (a[0] == b[0] && (a[0] == 0 || constexpr_equals (a + 1, b + 1, n - 1)));
}

/// Call inplace new operator by automatically inferring the Type.
template<class Type, class ...Ts> __attribute__ ((always_inline)) inline void
new_inplace (Type &typemem, Ts &&... args)
{
  new (&typemem) Type (std::forward<Ts> (args)...);
}

/// Call inplace delete operator by automatically inferring the Type.
template<class Type> __attribute__ ((always_inline)) inline void
delete_inplace (Type &typemem)
{
  typemem.~Type();
}

/**
 * A std::make_shared<>() wrapper class to access private ctor & dtor.
 * To call std::make_shared<T>() on a class @a T, its constructor and
 * destructor must be public. For classes with private or protected
 * constructor or destructor, this class can be used as follows:
 * @code{.cc}
 * class Type {
 *   Type (ctor_args...);                // Private ctor.
 *   friend class FriendAllocator<Type>; // Allow access to ctor/dtor of Type.
 * };
 * std::shared_ptr<Type> t = FriendAllocator<Type>::make_shared (ctor_args...);
 * @endcode
 */
template<class T>
class FriendAllocator : public std::allocator<T> {
public:
  /// Construct type @a C object, standard allocator requirement.
  template<typename C, typename... Args> static inline void
  construct (C *p, Args &&... args)
  {
    ::new ((void*) p) C (std::forward<Args> (args)...);
  }
  /// Delete type @a C object, standard allocator requirement.
  template<typename C> static inline void
  destroy (C *p)
  {
    p->~C ();
  }
  /**
   * Construct an object of type @a T that is wrapped into a std::shared_ptr<T>.
   * @param args        The list of arguments to pass into a T() constructor.
   * @return            A std::shared_ptr<T> owning the newly created object.
   */
  template<typename ...Args> static inline std::shared_ptr<T>
  make_shared (Args &&... args)
  {
    return std::allocate_shared<T> (FriendAllocator(), std::forward<Args> (args)...);
  }
};

/** Shorthand for std::dynamic_pointer_cast<>(shared_from_this()).
 * A shared_ptr_cast() takes a std::shared_ptr or a pointer to an @a object that
 * supports std::enable_shared_from_this::shared_from_this().
 * Using std::dynamic_pointer_cast(), the shared_ptr passed in (or retrieved via
 * calling shared_from_this()) is cast into a std::shared_ptr<@a Target>, possibly
 * resulting in an empty (NULL) std::shared_ptr if the underlying dynamic_cast()
 * was not successful or if a NULL @a object was passed in.
 * Note that shared_from_this() can throw a std::bad_weak_ptr exception if
 * the object has no associated std::shared_ptr (usually during ctor and dtor), in
 * which case the exception will also be thrown from shared_ptr_cast<Target>().
 * However a shared_ptr_cast<Target*>() call will not throw and yield an empty
 * (NULL) std::shared_ptr<@a Target>. This is analogous to dynamic_cast<T@amp> which
 * throws, versus dynamic_cast<T*> which yields NULL.
 * @return A std::shared_ptr<@a Target> storing a pointer to @a object or NULL.
 * @throws std::bad_weak_ptr if shared_from_this() throws, unless the @a Target* form is used.
 */
template<class Target, class Source> std::shared_ptr<typename std::remove_pointer<Target>::type>
shared_ptr_cast (Source *object)
{
  if (!object)
    return NULL;
  // construct shared_ptr if possible
  typedef decltype (object->shared_from_this()) ObjectP;
  ObjectP sptr;
  if (std::is_pointer<Target>::value)
    try {
      sptr = object->shared_from_this();
    } catch (const std::bad_weak_ptr&) {
      return NULL;
    }
  else // for non-pointers, allow bad_weak_ptr exceptions
    sptr = object->shared_from_this();
  // cast into target shared_ptr<> type
  return std::dynamic_pointer_cast<typename std::remove_pointer<Target>::type> (sptr);
}
/// See shared_ptr_cast(Source*).
template<class Target, class Source> const std::shared_ptr<typename std::remove_pointer<Target>::type>
shared_ptr_cast (const Source *object)
{
  return shared_ptr_cast<Target> (const_cast<Source*> (object));
}
/// See shared_ptr_cast(Source*).
template<class Target, class Source> std::shared_ptr<typename std::remove_pointer<Target>::type>
shared_ptr_cast (std::shared_ptr<Source> &sptr)
{
  return std::dynamic_pointer_cast<typename std::remove_pointer<Target>::type> (sptr);
}
/// See shared_ptr_cast(Source*).
template<class Target, class Source> const std::shared_ptr<typename std::remove_pointer<Target>::type>
shared_ptr_cast (const std::shared_ptr<Source> &sptr)
{
  return shared_ptr_cast<Target> (const_cast<std::shared_ptr<Source>&> (sptr));
}

} // Bse

#endif // __BSE_CXXAUX_HH__
<commit_msg>BSE: cxxaux.hh: add make_jump_table{_indexed} for runtime template selection<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#ifndef __BSE_CXXAUX_HH__
#define __BSE_CXXAUX_HH__

#include <bse/sysconfig.h>
#include <sys/types.h>                  // uint, ssize
#include <cstdint>                      // uint64_t
#include <memory>
#include <vector>
#include <map>

namespace Bse {

typedef uint32_t uint;          ///< Provide 'uint' as convenience type.
static_assert (sizeof (uint) == 4, "");

// == type aliases ==
typedef uint8_t         uint8;          ///< An 8-bit unsigned integer.
typedef uint16_t        uint16;         ///< A 16-bit unsigned integer.
typedef uint32_t        uint32;         ///< A 32-bit unsigned integer.
typedef uint64_t        uint64;         ///< A 64-bit unsigned integer, use PRI*64 in format strings.
typedef int8_t          int8;           ///< An 8-bit signed integer.
typedef int16_t         int16;          ///< A 16-bit signed integer.
typedef int32_t         int32;          ///< A 32-bit signed integer.
typedef int64_t         int64;          ///< A 64-bit unsigned integer, use PRI*64 in format strings.
typedef uint32_t        unichar;        ///< A 32-bit unsigned integer used for Unicode characters.
static_assert (sizeof (uint8) == 1 && sizeof (uint16) == 2 && sizeof (uint32) == 4 && sizeof (uint64) == 8, "");
static_assert (sizeof (int8)  == 1 && sizeof (int16)  == 2 && sizeof (int32)  == 4 && sizeof (int64)  == 8, "");
static_assert (sizeof (int) == 4 && sizeof (uint) == 4 && sizeof (unichar) == 4, "");
using   std::map;
using   std::vector;
typedef std::string String;             ///< Convenience alias for std::string.
typedef vector<String> StringVector;    ///< Convenience alias for a std::vector<std::string>.

// == Utility Macros ==
#define BSE_CPP_STRINGIFY(s)    BSE_CPP_STRINGIFY_ (s)                  ///< Convert macro argument into a C const char*.
#define BSE_CPP_STRINGIFY_(s)   #s                                      // Indirection helper, required to expand macros like __LINE__
#define BSE_CPP_PASTE2_(a,b)    a ## b                                  // Indirection helper, required to expand macros like __LINE__
#define BSE_CPP_PASTE2(a,b)     BSE_CPP_PASTE2_ (a,b)                   ///< Paste two macro arguments into one C symbol name
#define BSE_ISLIKELY(expr)      __builtin_expect (bool (expr), 1)       ///< Compiler hint to optimize for @a expr evaluating to true.
#define BSE_UNLIKELY(expr)      __builtin_expect (bool (expr), 0)       ///< Compiler hint to optimize for @a expr evaluating to false.
#define BSE_ABS(a)              ((a) < 0 ? -(a) : (a))                  ///< Yield the absolute value of @a a.
#define BSE_MIN(a,b)            ((a) <= (b) ? (a) : (b))                ///< Yield the smaller value of @a a and @a b.
#define BSE_MAX(a,b)            ((a) >= (b) ? (a) : (b))                ///< Yield the greater value of @a a and @a b.
#define BSE_CLAMP(v,mi,ma)      ((v) < (mi) ? (mi) : ((v) > (ma) ? (ma) : (v))) ///< Yield @a v clamped to [ @a mi .. @a ma ].
#define BSE_ARRAY_SIZE(array)   (sizeof (array) / sizeof ((array)[0]))          ///< Yield the number of C @a array elements.
#define BSE_ALIGN(size, base)   ((base) * ((size_t (size) + (base) - 1) / (base))) ///< Round up @a size to multiples of @a base.
#define BSE_DEPRECATED          __attribute__ ((__deprecated__))

// Bse macro shorthands for GCC Attributes.
#define BSE_ALWAYS_INLINE       __attribute__ ((always_inline))
#define BSE_COLD                __attribute__ ((__cold__))
#define BSE_CONST               __attribute__ ((__const__))
#define BSE_CONSTRUCTOR	        __attribute__ ((constructor,used))      // gcc-3.3 also needs "used" to emit code
#define BSE_DEPRECATED          __attribute__ ((__deprecated__))
#define BSE_FORMAT(fx)          __attribute__ ((__format_arg__ (fx)))
#define BSE_HOT                 __attribute__ ((__hot__))
#define BSE_MALLOC              __attribute__ ((__malloc__))
#define BSE_MAY_ALIAS           __attribute__ ((may_alias))
#define BSE_NOINLINE	        __attribute__ ((noinline))
#define BSE_NORETURN            __attribute__ ((__noreturn__))
#define BSE_NO_INSTRUMENT       __attribute__ ((__no_instrument_function__))
#define BSE_PRINTF(fx, ax)      __attribute__ ((__format__ (__printf__, fx, ax)))
#define BSE_PURE                __attribute__ ((__pure__))
#define BSE_SCANF(fx, ax)       __attribute__ ((__format__ (__scanf__, fx, ax)))
#define BSE_SENTINEL            __attribute__ ((__sentinel__))
#define BSE_UNUSED              __attribute__ ((__unused__))
#define BSE_USE_RESULT          __attribute__ ((warn_unused_result))
#define BSE_USED                __attribute__ ((__used__))
#define BSE_WEAK                __attribute__ ((__weak__))

/// Return silently if @a cond does not evaluate to true, with return value @a ...
#define BSE_RETURN_UNLESS(cond, ...)      do { if (BSE_UNLIKELY (!bool (cond))) return __VA_ARGS__; } while (0)

/// Delete copy ctor and assignment operator.
#define BSE_CLASS_NON_COPYABLE(ClassName)  \
  /*copy-ctor*/ ClassName  (const ClassName&) = delete; \
  ClassName&    operator=  (const ClassName&) = delete
#ifdef __clang__ // clang++-3.8.0: work around 'variable length array of non-POD element type'
#define BSE_DECLARE_VLA(Type, var, count)          std::vector<Type> var (count)
#else // sane c++
#define BSE_DECLARE_VLA(Type, var, count)          Type var[count] ///< Declare a variable length array (clang++ uses std::vector<>).
#endif

/// Test string equality at compile time.
extern inline constexpr bool
constexpr_equals (const char *a, const char *b, size_t n)
{
  return n == 0 || (a[0] == b[0] && (a[0] == 0 || constexpr_equals (a + 1, b + 1, n - 1)));
}

/// Call inplace new operator by automatically inferring the Type.
template<class Type, class ...Ts> __attribute__ ((always_inline)) inline void
new_inplace (Type &typemem, Ts &&... args)
{
  new (&typemem) Type (std::forward<Ts> (args)...);
}

/// Call inplace delete operator by automatically inferring the Type.
template<class Type> __attribute__ ((always_inline)) inline void
delete_inplace (Type &typemem)
{
  typemem.~Type();
}

/**
 * A std::make_shared<>() wrapper class to access private ctor & dtor.
 * To call std::make_shared<T>() on a class @a T, its constructor and
 * destructor must be public. For classes with private or protected
 * constructor or destructor, this class can be used as follows:
 * @code{.cc}
 * class Type {
 *   Type (ctor_args...);                // Private ctor.
 *   friend class FriendAllocator<Type>; // Allow access to ctor/dtor of Type.
 * };
 * std::shared_ptr<Type> t = FriendAllocator<Type>::make_shared (ctor_args...);
 * @endcode
 */
template<class T>
class FriendAllocator : public std::allocator<T> {
public:
  /// Construct type @a C object, standard allocator requirement.
  template<typename C, typename... Args> static inline void
  construct (C *p, Args &&... args)
  {
    ::new ((void*) p) C (std::forward<Args> (args)...);
  }
  /// Delete type @a C object, standard allocator requirement.
  template<typename C> static inline void
  destroy (C *p)
  {
    p->~C ();
  }
  /**
   * Construct an object of type @a T that is wrapped into a std::shared_ptr<T>.
   * @param args        The list of arguments to pass into a T() constructor.
   * @return            A std::shared_ptr<T> owning the newly created object.
   */
  template<typename ...Args> static inline std::shared_ptr<T>
  make_shared (Args &&... args)
  {
    return std::allocate_shared<T> (FriendAllocator(), std::forward<Args> (args)...);
  }
};

/** Shorthand for std::dynamic_pointer_cast<>(shared_from_this()).
 * A shared_ptr_cast() takes a std::shared_ptr or a pointer to an @a object that
 * supports std::enable_shared_from_this::shared_from_this().
 * Using std::dynamic_pointer_cast(), the shared_ptr passed in (or retrieved via
 * calling shared_from_this()) is cast into a std::shared_ptr<@a Target>, possibly
 * resulting in an empty (NULL) std::shared_ptr if the underlying dynamic_cast()
 * was not successful or if a NULL @a object was passed in.
 * Note that shared_from_this() can throw a std::bad_weak_ptr exception if
 * the object has no associated std::shared_ptr (usually during ctor and dtor), in
 * which case the exception will also be thrown from shared_ptr_cast<Target>().
 * However a shared_ptr_cast<Target*>() call will not throw and yield an empty
 * (NULL) std::shared_ptr<@a Target>. This is analogous to dynamic_cast<T@amp> which
 * throws, versus dynamic_cast<T*> which yields NULL.
 * @return A std::shared_ptr<@a Target> storing a pointer to @a object or NULL.
 * @throws std::bad_weak_ptr if shared_from_this() throws, unless the @a Target* form is used.
 */
template<class Target, class Source> std::shared_ptr<typename std::remove_pointer<Target>::type>
shared_ptr_cast (Source *object)
{
  if (!object)
    return NULL;
  // construct shared_ptr if possible
  typedef decltype (object->shared_from_this()) ObjectP;
  ObjectP sptr;
  if (std::is_pointer<Target>::value)
    try {
      sptr = object->shared_from_this();
    } catch (const std::bad_weak_ptr&) {
      return NULL;
    }
  else // for non-pointers, allow bad_weak_ptr exceptions
    sptr = object->shared_from_this();
  // cast into target shared_ptr<> type
  return std::dynamic_pointer_cast<typename std::remove_pointer<Target>::type> (sptr);
}
/// See shared_ptr_cast(Source*).
template<class Target, class Source> const std::shared_ptr<typename std::remove_pointer<Target>::type>
shared_ptr_cast (const Source *object)
{
  return shared_ptr_cast<Target> (const_cast<Source*> (object));
}
/// See shared_ptr_cast(Source*).
template<class Target, class Source> std::shared_ptr<typename std::remove_pointer<Target>::type>
shared_ptr_cast (std::shared_ptr<Source> &sptr)
{
  return std::dynamic_pointer_cast<typename std::remove_pointer<Target>::type> (sptr);
}
/// See shared_ptr_cast(Source*).
template<class Target, class Source> const std::shared_ptr<typename std::remove_pointer<Target>::type>
shared_ptr_cast (const std::shared_ptr<Source> &sptr)
{
  return shared_ptr_cast<Target> (const_cast<std::shared_ptr<Source>&> (sptr));
}

/// Create a `std::array<F,N>`, where `F` is returned from `mkjump (INDICES...)`.
template<typename J, size_t ...INDICES> static auto
make_jump_table_indexed (const J &mkjump, std::index_sequence<INDICES...>)
{
  constexpr size_t N = sizeof... (INDICES);
  using F = decltype (mkjump (std::integral_constant<std::size_t, N-1>()));
  std::array<F, N> jumptable = {
    mkjump (std::integral_constant<std::size_t, INDICES>{})...
  };
  return jumptable;
}

/// Create a `std::array<F,N>`, where `F` is returned from `mkjump (0 .. N-1)`.
template<std::size_t N, typename J> static auto
make_jump_table (const J &mkjump)
{
  return make_jump_table_indexed (mkjump, std::make_index_sequence<N>());
}

} // Bse

#endif // __BSE_CXXAUX_HH__
<|endoftext|>


<commit_before>#include "Globals.h"
#include "Application.h"
#include "ModuleInput.h"

#include "HelperFoos.h"

#define MAX_KEYS 300

ModuleInput::ModuleInput(Application* app, bool start_enabled) : Module(app, start_enabled)
{
	name = "Input";

	keyboard = new KEY_STATE[MAX_KEYS];
	memset(keyboard, KEY_IDLE, sizeof(KEY_STATE) * MAX_KEYS);
	memset(mouse_buttons, KEY_IDLE, sizeof(KEY_STATE) * MAX_MOUSE_BUTTONS);
}

// Destructor
ModuleInput::~ModuleInput()
{
	delete[] keyboard;
}

// Called before render is available
bool ModuleInput::Init()
{
	LOG("Init SDL input event system");
	bool ret = true;
	SDL_Init(0);

	if(SDL_InitSubSystem(SDL_INIT_EVENTS) < 0)
	{
		LOG("SDL_EVENTS could not initialize! SDL_Error: %s\n", SDL_GetError());
		ret = false;
	}

	return ret;
}

// Called every draw update
update_status ModuleInput::PreUpdate(float dt)
{
	SDL_PumpEvents();

	const Uint8* keys = SDL_GetKeyboardState(NULL);

	for(int i = 0; i < MAX_KEYS; ++i)
	{
		if(keys[i] == 1)
		{
			if(keyboard[i] == KEY_IDLE)
				keyboard[i] = KEY_DOWN;
			else
				keyboard[i] = KEY_REPEAT;
		}
		else
		{
			if(keyboard[i] == KEY_REPEAT || keyboard[i] == KEY_DOWN)
				keyboard[i] = KEY_UP;
			else
				keyboard[i] = KEY_IDLE;
		}
	}

	Uint32 buttons = SDL_GetMouseState(&mouse_x, &mouse_y);

	mouse_x /= SCREEN_SIZE;
	mouse_y /= SCREEN_SIZE;
	mouse_z = 0;

	for(int i = 0; i < 5; ++i)
	{
		if(buttons & SDL_BUTTON(i))
		{
			if(mouse_buttons[i] == KEY_IDLE)
				mouse_buttons[i] = KEY_DOWN;
			else
				mouse_buttons[i] = KEY_REPEAT;
		}
		else
		{
			if(mouse_buttons[i] == KEY_REPEAT || mouse_buttons[i] == KEY_DOWN)
				mouse_buttons[i] = KEY_UP;
			else
				mouse_buttons[i] = KEY_IDLE;
		}
	}

	mouse_x_motion = mouse_y_motion = 0;

	SDL_Event e;

	mouse_wheel = false;

	while(SDL_PollEvent(&e))
	{
		switch(e.type)
		{
			case SDL_MOUSEWHEEL:
			mouse_z = e.wheel.y;
			mouse_wheel = true;
			break;

			case SDL_MOUSEMOTION:
			mouse_x = e.motion.x / SCREEN_SIZE;
			mouse_y = e.motion.y / SCREEN_SIZE;

			mouse_x_motion = e.motion.xrel / SCREEN_SIZE;
			mouse_y_motion = e.motion.yrel / SCREEN_SIZE;
			break;

			case SDL_QUIT:
			quit = true;
			break;

			case SDL_WINDOWEVENT:
			{
				if(e.window.event == SDL_WINDOWEVENT_RESIZED)
					App->renderer3D->OnResize(e.window.data1, e.window.data2);
			}
			break;
			case SDL_DROPFILE:
			{
				dropped_filedir = e.drop.file;
				char* filetext = Capitalize(strrchr(dropped_filedir, '.'));
				if (strncmp(filetext, ".FBX", 4) == 0) {
					GameObject* new_geo = nullptr;
					new_geo = App->assimp->LoadGeometry(dropped_filedir);
					if (new_geo != nullptr) {
						App->scene->AddGameObject(App->scene->GetRoot(), new_geo);
					}
					else {
						LOG("ERROR at Loading Geometry from FILE:\n\t%s", dropped_filedir);
					}
					LOG("File Loaded:\n\t%s", dropped_filedir);
				}
				if (strncmp(filetext, ".PNG", 4) == 0) {
					Texture* new_tex = App->tex->LoadTexture(dropped_filedir);
					//if (!App->scene->gameObjects.empty()) {
					//	GameObject* go = App->scene->gameObjects.front();
					//	go->AddComponent(componentType_Texture, App->tex->LoadTexture(dropped_filedir));
					//}
					//else {
					//	App->editor->ClearLog();
					//	LOG("WARNING! -> No GameObject to attach the Texture to");
					//}
				}
				SDL_free(dropped_filedir);
				break;
			}
		}
	}

	if(quit == true || keyboard[SDL_SCANCODE_ESCAPE] == KEY_UP)
		return UPDATE_STOP;

	return UPDATE_CONTINUE;
}

// Called before quitting
bool ModuleInput::CleanUp()
{
	LOG("Quitting SDL input event subsystem");
	SDL_QuitSubSystem(SDL_INIT_EVENTS);
	return true;
}

void ModuleInput::DrawConfigPanel()
{
	if (ImGui::CollapsingHeader("Input")) {
		int x, y;
		x = GetMouseX();
		y = GetMouseY();

		string mousepos = "Mouse Position: X = " + std::to_string(x) + " Y = " + std::to_string(y);

		ImGui::Text(mousepos.c_str());

	}
}
<commit_msg>Texture/Material Draw Testing<commit_after>#include "Globals.h"
#include "Application.h"
#include "ModuleInput.h"

#include "HelperFoos.h"

#define MAX_KEYS 300

ModuleInput::ModuleInput(Application* app, bool start_enabled) : Module(app, start_enabled)
{
	name = "Input";

	keyboard = new KEY_STATE[MAX_KEYS];
	memset(keyboard, KEY_IDLE, sizeof(KEY_STATE) * MAX_KEYS);
	memset(mouse_buttons, KEY_IDLE, sizeof(KEY_STATE) * MAX_MOUSE_BUTTONS);
}

// Destructor
ModuleInput::~ModuleInput()
{
	delete[] keyboard;
}

// Called before render is available
bool ModuleInput::Init()
{
	LOG("Init SDL input event system");
	bool ret = true;
	SDL_Init(0);

	if(SDL_InitSubSystem(SDL_INIT_EVENTS) < 0)
	{
		LOG("SDL_EVENTS could not initialize! SDL_Error: %s\n", SDL_GetError());
		ret = false;
	}

	return ret;
}

// Called every draw update
update_status ModuleInput::PreUpdate(float dt)
{
	SDL_PumpEvents();

	const Uint8* keys = SDL_GetKeyboardState(NULL);

	for(int i = 0; i < MAX_KEYS; ++i)
	{
		if(keys[i] == 1)
		{
			if(keyboard[i] == KEY_IDLE)
				keyboard[i] = KEY_DOWN;
			else
				keyboard[i] = KEY_REPEAT;
		}
		else
		{
			if(keyboard[i] == KEY_REPEAT || keyboard[i] == KEY_DOWN)
				keyboard[i] = KEY_UP;
			else
				keyboard[i] = KEY_IDLE;
		}
	}

	Uint32 buttons = SDL_GetMouseState(&mouse_x, &mouse_y);

	mouse_x /= SCREEN_SIZE;
	mouse_y /= SCREEN_SIZE;
	mouse_z = 0;

	for(int i = 0; i < 5; ++i)
	{
		if(buttons & SDL_BUTTON(i))
		{
			if(mouse_buttons[i] == KEY_IDLE)
				mouse_buttons[i] = KEY_DOWN;
			else
				mouse_buttons[i] = KEY_REPEAT;
		}
		else
		{
			if(mouse_buttons[i] == KEY_REPEAT || mouse_buttons[i] == KEY_DOWN)
				mouse_buttons[i] = KEY_UP;
			else
				mouse_buttons[i] = KEY_IDLE;
		}
	}

	mouse_x_motion = mouse_y_motion = 0;

	SDL_Event e;

	mouse_wheel = false;

	while(SDL_PollEvent(&e))
	{
		switch(e.type)
		{
			case SDL_MOUSEWHEEL:
			mouse_z = e.wheel.y;
			mouse_wheel = true;
			break;

			case SDL_MOUSEMOTION:
			mouse_x = e.motion.x / SCREEN_SIZE;
			mouse_y = e.motion.y / SCREEN_SIZE;

			mouse_x_motion = e.motion.xrel / SCREEN_SIZE;
			mouse_y_motion = e.motion.yrel / SCREEN_SIZE;
			break;

			case SDL_QUIT:
			quit = true;
			break;

			case SDL_WINDOWEVENT:
			{
				if(e.window.event == SDL_WINDOWEVENT_RESIZED)
					App->renderer3D->OnResize(e.window.data1, e.window.data2);
			}
			break;
			case SDL_DROPFILE:
			{
				dropped_filedir = e.drop.file;
				char* filetext = Capitalize(strrchr(dropped_filedir, '.'));
				if (strncmp(filetext, ".FBX", 4) == 0) {
					GameObject* new_geo = nullptr;
					new_geo = App->assimp->LoadGeometry(dropped_filedir);
					if (new_geo != nullptr) {
						App->scene->AddGameObject(App->scene->GetRoot(), new_geo);
					}
					else {
						LOG("ERROR at Loading Geometry from FILE:\n\t%s", dropped_filedir);
					}
					LOG("File Loaded:\n\t%s", dropped_filedir);
				}
				if (strncmp(filetext, ".PNG", 4) == 0) {
					Texture* new_tex = App->tex->LoadTexture(dropped_filedir);
					//HardCode for Testing [Assigning Textures]
					for (std::vector<GameObject*>::iterator it = App->scene->GetRoot()->children.begin(); it != App->scene->GetRoot()->children.end(); it++) {
						if ((*it) != nullptr) {
							std::vector<Component*> ms = (*it)->FindComponents(componentType_Material);
							for (std::vector<Component*>::iterator mit = ms.begin(); mit != ms.end(); mit++) {
								if ((*mit) != nullptr) {
									ComponentMaterial* mat = (ComponentMaterial*)(*mit);
									mat->SetTextureChannel(texType_Diffuse, new_tex);
								}
							}
						}
					}
					//!_HardCode for Testing [Assigning Textures]
				}
				SDL_free(dropped_filedir);
				break;
			}
		}
	}

	if(quit == true || keyboard[SDL_SCANCODE_ESCAPE] == KEY_UP)
		return UPDATE_STOP;

	return UPDATE_CONTINUE;
}

// Called before quitting
bool ModuleInput::CleanUp()
{
	LOG("Quitting SDL input event subsystem");
	SDL_QuitSubSystem(SDL_INIT_EVENTS);
	return true;
}

void ModuleInput::DrawConfigPanel()
{
	if (ImGui::CollapsingHeader("Input")) {
		int x, y;
		x = GetMouseX();
		y = GetMouseY();

		string mousepos = "Mouse Position: X = " + std::to_string(x) + " Y = " + std::to_string(y);

		ImGui::Text(mousepos.c_str());

	}
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
 *
 * Licensed under the BSD License, see LICENSE file for details.
 *
 */

#include <cstring>

#include <iostream>
#include <string>

#include "libxtreemfs/client.h"
#include "libxtreemfs/file_handle.h"
#include "libxtreemfs/options.h"
#include "libxtreemfs/volume.h"
#include "libxtreemfs/xtreemfs_exception.h"
#include "pbrpc/RPC.pb.h"  // xtreemfs::pbrpc::UserCredentials
#include "xtreemfs/MRC.pb.h"  // xtreemfs::pbrpc::Stat

using namespace std;

int main(int argc, char* argv[]) {
  // Every operation is executed in the context of a given user and his groups.
  // The UserCredentials object does store this information and is currently
  // (08/2011) *only* evaluated by the MRC (although the protocol requires to
  // send user_credentials to DIR and OSD, too).
  xtreemfs::pbrpc::UserCredentials user_credentials;
  user_credentials.set_username("example_libxtreemfs");
  user_credentials.add_groups("example_libxtreemfs");

  // Class which allows to change options of the library.
  xtreemfs::Options options;

  try {
    options.ParseCommandLine(argc, argv);
  } catch(const xtreemfs::XtreemFSException& e) {
    cout << "Invalid parameters found, error: " << e.what() << endl << endl;
  }

  try {
    // Create a new instance of a client using the DIR service at
    // 'demo.xtreemfs.org' (default port 32638).
    xtreemfs::Client* client = xtreemfs::Client::CreateClient(
        "demo.xtreemfs.org:32638",
        user_credentials,
        NULL,  // No SSL options.
        options);

    // Start the client (a connection to the DIR service will be setup).
    client->Start();

    // Open a volume named 'demo'.
    xtreemfs::Volume *volume = NULL;
    volume = client->OpenVolume("demo",
                                NULL,  // No SSL options.
                                options);

    // Open a file.
    xtreemfs::FileHandle* file = volume->OpenFile(
        user_credentials,
        "/example_libxtreemfs.txt",
        static_cast<xtreemfs::pbrpc::SYSTEM_V_FCNTL>(
            xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_CREAT |
            xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_TRUNC |
            xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_RDWR),
        511);  // = 777 Octal.

    // Write to file.
    cout << "Writing the string\n"
            "\n"
            "\t\"Accessed XtreemFS through the C++ libxtreemfs.\"\n"
            "\n"
            "to the file example_libxtreemfs.txt..." << endl;
    char write_buf[] = "Accessed XtreemFS through the C++ libxtreemfs.";
    file->Write(user_credentials,
                reinterpret_cast<const char*>(&write_buf),
                sizeof(write_buf),
                0);

    // Get file attributes.
    xtreemfs::pbrpc::Stat stat;
    volume->GetAttr(user_credentials, "/example_libxtreemfs.txt", &stat);
    cout << "\nNew file size of example_libxtreemfs.txt: "
         << stat.size() << " Bytes." << endl;
    // Once again, now hopefully from the Cache.
    volume->GetAttr(user_credentials, "/example_libxtreemfs.txt", &stat);
    cout << "\nFile size of example_libxtreemfs.txt again (this time retrieved"
            " from the enabled metadata cache): " << stat.size() << endl;

    // Read from the file.
    const size_t buffer_size = 128 * 1024;  // 128kB, default object size.
    char read_buf[buffer_size];
    memset(&read_buf, 0, buffer_size);
    file->Read(user_credentials,
               reinterpret_cast<char*>(&read_buf),
               buffer_size,  // Length.
               0);  // Offset.
    cout << "\nReading the content of the file example_libxtreemfs.txt:\n\n"
         << read_buf << endl;

    // Close the file (no need to delete it, see documentation volume.h).
    file->Close();

    // Shutdown() does also invoke a volume->Close().
    client->Shutdown();
    delete client;
  } catch(const xtreemfs::XtreemFSException& e) {
    cout << "An error occured:\n" << e.what() << endl;
    return 1;
  }

  return 0;
}
<commit_msg>client: Improved cleanup phase of example_libxtreemfs. Fixes boost assertion in case an error occurred.<commit_after>/*
 * Copyright (c) 2011 by Michael Berlin, Zuse Institute Berlin
 *
 * Licensed under the BSD License, see LICENSE file for details.
 *
 */

#include <cstring>

#include <iostream>
#include <string>

#include "libxtreemfs/client.h"
#include "libxtreemfs/file_handle.h"
#include "libxtreemfs/options.h"
#include "libxtreemfs/volume.h"
#include "libxtreemfs/xtreemfs_exception.h"
#include "pbrpc/RPC.pb.h"  // xtreemfs::pbrpc::UserCredentials
#include "xtreemfs/MRC.pb.h"  // xtreemfs::pbrpc::Stat

using namespace std;

int main(int argc, char* argv[]) {
  // Every operation is executed in the context of a given user and his groups.
  // The UserCredentials object does store this information and is currently
  // (08/2011) *only* evaluated by the MRC (although the protocol requires to
  // send user_credentials to DIR and OSD, too).
  xtreemfs::pbrpc::UserCredentials user_credentials;
  user_credentials.set_username("example_libxtreemfs");
  user_credentials.add_groups("example_libxtreemfs");

  // Class which allows to change options of the library.
  xtreemfs::Options options;

  try {
    options.ParseCommandLine(argc, argv);
  } catch(const xtreemfs::XtreemFSException& e) {
    cout << "Invalid parameters found, error: " << e.what() << endl << endl;
    return 1;
  }

  xtreemfs::Client* client = NULL;
  xtreemfs::FileHandle* file = NULL;
  int return_code = 0;
  try {
    // Create a new instance of a client using the DIR service at
    // 'demo.xtreemfs.org' (default port 32638).
    client = xtreemfs::Client::CreateClient(
        "demo.xtreemfs.org:32638",
        user_credentials,
        NULL,  // No SSL options.
        options);

    // Start the client (a connection to the DIR service will be setup).
    client->Start();

    // Open a volume named 'demo'.
    xtreemfs::Volume *volume = NULL;
    volume = client->OpenVolume("demo",
                                NULL,  // No SSL options.
                                options);

    // Open a file.
    file = volume->OpenFile(user_credentials,
                            "/example_libxtreemfs.txt",
                            static_cast<xtreemfs::pbrpc::SYSTEM_V_FCNTL>(
                                xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_CREAT |
                                xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_TRUNC |
                                xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_RDWR),
                            511);  // = 777 Octal.

    // Write to file.
    cout << "Writing the string\n"
            "\n"
            "\t\"Accessed XtreemFS through the C++ libxtreemfs.\"\n"
            "\n"
            "to the file example_libxtreemfs.txt..." << endl;
    char write_buf[] = "Accessed XtreemFS through the C++ libxtreemfs.";
    file->Write(user_credentials,
                reinterpret_cast<const char*>(&write_buf),
                sizeof(write_buf),
                0);

    // Get file attributes.
    xtreemfs::pbrpc::Stat stat;
    volume->GetAttr(user_credentials, "/example_libxtreemfs.txt", &stat);
    cout << "\nNew file size of example_libxtreemfs.txt: "
         << stat.size() << " Bytes." << endl;
    // Once again, now hopefully from the Cache.
    volume->GetAttr(user_credentials, "/example_libxtreemfs.txt", &stat);
    cout << "\nFile size of example_libxtreemfs.txt again (this time retrieved"
            " from the enabled metadata cache): " << stat.size() << endl;

    // Read from the file.
    const size_t buffer_size = 128 * 1024;  // 128kB, default object size.
    char read_buf[buffer_size];
    memset(&read_buf, 0, buffer_size);
    file->Read(user_credentials,
               reinterpret_cast<char*>(&read_buf),
               buffer_size,  // Length.
               0);  // Offset.
    cout << "\nReading the content of the file example_libxtreemfs.txt:\n\n"
         << read_buf << endl;
  } catch(const xtreemfs::XtreemFSException& e) {
    cout << "An error occured:\n" << e.what() << endl;
    return_code = 1;
  }

  if (file != NULL) {
    // Close the file (no need to delete it, see documentation volume.h).
    file->Close();
  }

  if (client != NULL) {
    // Shutdown() does also invoke a volume->Close().
    client->Shutdown();
    delete client;
  }

  return return_code;
}
<|endoftext|>