<commit_before>// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2020 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

// clang-format off
#include "main.h"
#include "activemasternode.h"
#include "masternode-sync.h"
#include "masternode-payments.h"
#include "masternode-budget.h"
#include "masternode.h"
#include "masternodeman.h"
#include "spork.h"
#include "util.h"
#include "addrman.h"
// clang-format on

class CMasternodeSync;
CMasternodeSync masternodeSync;

CMasternodeSync::CMasternodeSync()
{
    Reset();
}

bool CMasternodeSync::IsSynced()
{
    return RequestedMasternodeAssets == MASTERNODE_SYNC_FINISHED;
}

bool CMasternodeSync::IsSporkListSynced()
{
    return RequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS;
}

bool CMasternodeSync::IsMasternodeListSynced()
{
    return RequestedMasternodeAssets > MASTERNODE_SYNC_LIST;
}

bool CMasternodeSync::NotCompleted()
{
    return (!IsSynced() && (
            !IsSporkListSynced() ||
            sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) ||
            sporkManager.IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) ||
            sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)));
}

bool CMasternodeSync::IsBlockchainSynced()
{
    int64_t now = GetTime();

    // if the last call to this function was more than 60 minutes ago (client was in sleep mode) reset the sync process
    if (now > lastProcess + 60 * 60) {
        Reset();
        fBlockchainSynced = false;
    }
    lastProcess = now;

    if (fBlockchainSynced) return true;

    if (fImporting || fReindex) return false;

    int64_t blockTime = 0;
    {
        TRY_LOCK(cs_main, lockMain);
        if (!lockMain) return false;
        CBlockIndex *pindex = chainActive.Tip();
        if (pindex == nullptr) return false;
        blockTime = pindex->nTime;
    }

    if (blockTime + 60 * 60 < lastProcess)
        return false;

    fBlockchainSynced = true;

    return true;
}

void CMasternodeSync::Reset()
{
    fBlockchainSynced = false;
    lastProcess = 0;
    lastMasternodeList = 0;
    lastMasternodeWinner = 0;
    lastBudgetItem = 0;
    mapSeenSyncMNB.clear();
    mapSeenSyncMNW.clear();
    mapSeenSyncBudget.clear();
    lastFailure = 0;
    nCountFailures = 0;
    sumMasternodeList = 0;
    sumMasternodeWinner = 0;
    sumBudgetItemProp = 0;
    sumBudgetItemFin = 0;
    countMasternodeList = 0;
    countMasternodeWinner = 0;
    countBudgetItemProp = 0;
    countBudgetItemFin = 0;
    RequestedMasternodeAssets = MASTERNODE_SYNC_INITIAL;
    RequestedMasternodeAttempt = 0;
    nAssetSyncStarted = GetTime();
}

void CMasternodeSync::AddedMasternodeList(uint256 hash)
{
    if (mnodeman.mapSeenMasternodeBroadcast.count(hash)) {
        if (mapSeenSyncMNB[hash] < MASTERNODE_SYNC_THRESHOLD) {
            lastMasternodeList = GetTime();
            mapSeenSyncMNB[hash]++;
        }
    } else {
        lastMasternodeList = GetTime();
        mapSeenSyncMNB.insert(std::make_pair(hash, 1));
    }
}

void CMasternodeSync::AddedMasternodeWinner(uint256 hash)
{
    if (masternodePayments.mapMasternodePayeeVotes.count(hash)) {
        if (mapSeenSyncMNW[hash] < MASTERNODE_SYNC_THRESHOLD) {
            lastMasternodeWinner = GetTime();
            mapSeenSyncMNW[hash]++;
        }
    } else {
        lastMasternodeWinner = GetTime();
        mapSeenSyncMNW.insert(std::make_pair(hash, 1));
    }
}

void CMasternodeSync::AddedBudgetItem(uint256 hash)
{
    if (budget.mapSeenMasternodeBudgetProposals.count(hash) || budget.mapSeenMasternodeBudgetVotes.count(hash) ||
        budget.mapSeenFinalizedBudgets.count(hash) || budget.mapSeenFinalizedBudgetVotes.count(hash)) {
        if (mapSeenSyncBudget[hash] < MASTERNODE_SYNC_THRESHOLD) {
            lastBudgetItem = GetTime();
            mapSeenSyncBudget[hash]++;
        }
    } else {
        lastBudgetItem = GetTime();
        mapSeenSyncBudget.insert(std::make_pair(hash, 1));
    }
}

bool CMasternodeSync::IsBudgetPropEmpty()
{
    return sumBudgetItemProp == 0 && countBudgetItemProp > 0;
}

bool CMasternodeSync::IsBudgetFinEmpty()
{
    return sumBudgetItemFin == 0 && countBudgetItemFin > 0;
}

void CMasternodeSync::GetNextAsset()
{
    switch (RequestedMasternodeAssets) {
    case (MASTERNODE_SYNC_INITIAL):
    case (MASTERNODE_SYNC_FAILED): // should never be used here actually, use Reset() instead
        ClearFulfilledRequest();
        RequestedMasternodeAssets = MASTERNODE_SYNC_SPORKS;
        break;
    case (MASTERNODE_SYNC_SPORKS):
        RequestedMasternodeAssets = MASTERNODE_SYNC_LIST;
        break;
    case (MASTERNODE_SYNC_LIST):
        RequestedMasternodeAssets = MASTERNODE_SYNC_MNW;
        break;
    case (MASTERNODE_SYNC_MNW):
        RequestedMasternodeAssets = MASTERNODE_SYNC_BUDGET;
        break;
    case (MASTERNODE_SYNC_BUDGET):
        LogPrintf("CMasternodeSync::GetNextAsset - Sync has finished\n");
        RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
        break;
    }
    RequestedMasternodeAttempt = 0;
    nAssetSyncStarted = GetTime();
}

std::string CMasternodeSync::GetSyncStatus()
{
    switch (masternodeSync.RequestedMasternodeAssets) {
    case MASTERNODE_SYNC_INITIAL:
        return _("MNs synchronization pending...");
    case MASTERNODE_SYNC_SPORKS:
        return _("Synchronizing sporks...");
    case MASTERNODE_SYNC_LIST:
        return _("Synchronizing masternodes...");
    case MASTERNODE_SYNC_MNW:
        return _("Synchronizing masternode winners...");
    case MASTERNODE_SYNC_BUDGET:
        return _("Synchronizing budgets...");
    case MASTERNODE_SYNC_FAILED:
        return _("Synchronization failed");
    case MASTERNODE_SYNC_FINISHED:
        return _("Synchronization finished");
    }
    return "";
}

void CMasternodeSync::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
    if (strCommand == NetMsgType::SYNCSTATUSCOUNT) { //Sync status count
        int nItemID;
        int nCount;
        vRecv >> nItemID >> nCount;

        if (RequestedMasternodeAssets >= MASTERNODE_SYNC_FINISHED) return;

        //this means we will receive no further communication
        switch (nItemID) {
        case (MASTERNODE_SYNC_LIST):
            if (nItemID != RequestedMasternodeAssets) return;
            sumMasternodeList += nCount;
            countMasternodeList++;
            break;
        case (MASTERNODE_SYNC_MNW):
            if (nItemID != RequestedMasternodeAssets) return;
            sumMasternodeWinner += nCount;
            countMasternodeWinner++;
            break;
        case (MASTERNODE_SYNC_BUDGET_PROP):
            if (RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
            sumBudgetItemProp += nCount;
            countBudgetItemProp++;
            break;
        case (MASTERNODE_SYNC_BUDGET_FIN):
            if (RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
            sumBudgetItemFin += nCount;
            countBudgetItemFin++;
            break;
        }

        LogPrint(BCLog::MASTERNODE, "CMasternodeSync:ProcessMessage - ssc - got inventory count %d %d\n", nItemID, nCount);
    }
}

void CMasternodeSync::ClearFulfilledRequest()
{
    g_connman->ForEachNode([](CNode* pnode) {
        pnode->ClearFulfilledRequest("getspork");
        pnode->ClearFulfilledRequest("mnsync");
        pnode->ClearFulfilledRequest("mnwsync");
        pnode->ClearFulfilledRequest("busync");
    });
}

void CMasternodeSync::Process()
{
    static int tick = 0;
    const bool isRegTestNet = Params().IsRegTestNet();

    if (tick++ % MASTERNODE_SYNC_TIMEOUT != 0) return;

    if (IsSynced()) {
        /*
            Resync if we lose all masternodes from sleep/wake or failure to sync originally
        */
        if (mnodeman.CountEnabled() == 0) {
            Reset();
        } else
            return;
    }

    //try syncing again
    if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED && lastFailure + (1 * 60) < GetTime()) {
        Reset();
    } else if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED) {
        return;
    }

    LogPrint(BCLog::MASTERNODE, "CMasternodeSync::Process() - tick %d RequestedMasternodeAssets %d\n", tick, RequestedMasternodeAssets);

    if (RequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL) GetNextAsset();

    // sporks synced but blockchain is not, wait until we're almost at a recent block to continue
    if (!isRegTestNet && !IsBlockchainSynced() &&
        RequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS) return;

    std::vector<CNode*> vNodesCopy = g_connman->CopyNodeVector();
    for (CNode* pnode : vNodesCopy) {
        if (!SyncWithNode(pnode, isRegTestNet)) {
            g_connman->ReleaseNodeVector(vNodesCopy);
            return;
        }
    }
    g_connman->ReleaseNodeVector(vNodesCopy);
}

bool CMasternodeSync::SyncWithNode(CNode* pnode, bool isRegTestNet)
{
    if (isRegTestNet) {
        if (RequestedMasternodeAttempt <= 2) {
            pnode->PushMessage(NetMsgType::GETSPORKS); //get current network sporks
        } else if (RequestedMasternodeAttempt < 4) {
            mnodeman.DsegUpdate(pnode);
        } else if (RequestedMasternodeAttempt < 6) {
            int nMnCount = mnodeman.CountEnabled();
            pnode->PushMessage(NetMsgType::GETMNWINNERS, nMnCount); //sync payees
            uint256 n;
            pnode->PushMessage(NetMsgType::BUDGETVOTESYNC, n); //sync masternode votes
        } else {
            RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
        }
        RequestedMasternodeAttempt++;
        return false;
    }

    //set to synced
    if (RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS) {
        if (pnode->HasFulfilledRequest("getspork")) return true;
        pnode->FulfilledRequest("getspork");

        pnode->PushMessage(NetMsgType::GETSPORKS); //get current network sporks
        if (RequestedMasternodeAttempt >= 2) GetNextAsset();
        RequestedMasternodeAttempt++;
        return false;
    }

    if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) {
        if (RequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
            LogPrint(BCLog::MASTERNODE, "CMasternodeSync::Process() - lastMasternodeList %lld (GetTime() - MASTERNODE_SYNC_TIMEOUT) %lld\n", lastMasternodeList, GetTime() - MASTERNODE_SYNC_TIMEOUT);
            if (lastMasternodeList > 0 && lastMasternodeList < GetTime() - MASTERNODE_SYNC_TIMEOUT * 2 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) { //hasn't received a new item in the last five seconds, so we'll move to the
                GetNextAsset();
                return false;
            }

            if (pnode->HasFulfilledRequest("mnsync")) return true;
            pnode->FulfilledRequest("mnsync");

            // timeout
            if (lastMasternodeList == 0 &&
                (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) {
                if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
                    LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed on %s, will retry later\n", "MASTERNODE_SYNC_LIST");
                    RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED;
                    RequestedMasternodeAttempt = 0;
                    lastFailure = GetTime();
                    nCountFailures++;
                } else {
                    GetNextAsset();
                }
                return false;
            }

            if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3) return false;

            mnodeman.DsegUpdate(pnode);
            RequestedMasternodeAttempt++;
            return false;
        }

        if (RequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
            if (lastMasternodeWinner > 0 && lastMasternodeWinner < GetTime() - MASTERNODE_SYNC_TIMEOUT * 2 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) { //hasn't received a new item in the last five seconds, so we'll move to the
                GetNextAsset();
                return false;
            }

            if (pnode->HasFulfilledRequest("mnwsync")) return true;
            pnode->FulfilledRequest("mnwsync");

            // timeout
            if (lastMasternodeWinner == 0 &&
                (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) {
                if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
                    LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed on %s, will retry later\n", "MASTERNODE_SYNC_MNW");
                    RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED;
                    RequestedMasternodeAttempt = 0;
                    lastFailure = GetTime();
                    nCountFailures++;
                } else {
                    GetNextAsset();
                }
                return false;
            }

            if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3) return false;

            int nMnCount = mnodeman.CountEnabled();
            pnode->PushMessage(NetMsgType::GETMNWINNERS, nMnCount); //sync payees
            RequestedMasternodeAttempt++;
            return false;
        }
    }

    if (pnode->nVersion >= ActiveProtocol()) {
        if (RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET) {
            // We'll start rejecting votes if we accidentally get set as synced too soon
            if (lastBudgetItem > 0 && lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT * 2 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) {
                // Hasn't received a new item in the last five seconds, so we'll move to the
                GetNextAsset();

                // Try to activate our masternode if possible
                activeMasternode.ManageStatus();
                return false;
            }

            // timeout
            if (lastBudgetItem == 0 &&
                (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) {
                // maybe there is no budgets at all, so just finish syncing
                GetNextAsset();
                activeMasternode.ManageStatus();
                return false;
            }

            if (pnode->HasFulfilledRequest("busync")) return true;
            pnode->FulfilledRequest("busync");

            if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3) return false;

            uint256 n;
            pnode->PushMessage(NetMsgType::BUDGETVOTESYNC, n); //sync masternode votes
            RequestedMasternodeAttempt++;
            return false;
        }
    }

    return true;
}

<commit_msg>[Refactor] Proper CConnman encapsulation of mnsync<commit_after>// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2020 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

// clang-format off
#include "main.h"
#include "activemasternode.h"
#include "masternode-sync.h"
#include "masternode-payments.h"
#include "masternode-budget.h"
#include "masternode.h"
#include "masternodeman.h"
#include "spork.h"
#include "util.h"
#include "addrman.h"
// clang-format on

class CMasternodeSync;
CMasternodeSync masternodeSync;

CMasternodeSync::CMasternodeSync()
{
    Reset();
}

bool CMasternodeSync::IsSynced()
{
    return RequestedMasternodeAssets == MASTERNODE_SYNC_FINISHED;
}

bool CMasternodeSync::IsSporkListSynced()
{
    return RequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS;
}

bool CMasternodeSync::IsMasternodeListSynced()
{
    return RequestedMasternodeAssets > MASTERNODE_SYNC_LIST;
}

bool CMasternodeSync::NotCompleted()
{
    return (!IsSynced() && (
            !IsSporkListSynced() ||
            sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) ||
            sporkManager.IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) ||
            sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS)));
}

bool CMasternodeSync::IsBlockchainSynced()
{
    int64_t now = GetTime();

    // if the last call to this function was more than 60 minutes ago (client was in sleep mode) reset the sync process
    if (now > lastProcess + 60 * 60) {
        Reset();
        fBlockchainSynced = false;
    }
    lastProcess = now;

    if (fBlockchainSynced) return true;

    if (fImporting || fReindex) return false;

    int64_t blockTime = 0;
    {
        TRY_LOCK(cs_main, lockMain);
        if (!lockMain) return false;
        CBlockIndex *pindex = chainActive.Tip();
        if (pindex == nullptr) return false;
        blockTime = pindex->nTime;
    }

    if (blockTime + 60 * 60 < lastProcess)
        return false;

    fBlockchainSynced = true;

    return true;
}

void CMasternodeSync::Reset()
{
    fBlockchainSynced = false;
    lastProcess = 0;
    lastMasternodeList = 0;
    lastMasternodeWinner = 0;
    lastBudgetItem = 0;
    mapSeenSyncMNB.clear();
    mapSeenSyncMNW.clear();
    mapSeenSyncBudget.clear();
    lastFailure = 0;
    nCountFailures = 0;
    sumMasternodeList = 0;
    sumMasternodeWinner = 0;
    sumBudgetItemProp = 0;
    sumBudgetItemFin = 0;
    countMasternodeList = 0;
    countMasternodeWinner = 0;
    countBudgetItemProp = 0;
    countBudgetItemFin = 0;
    RequestedMasternodeAssets = MASTERNODE_SYNC_INITIAL;
    RequestedMasternodeAttempt = 0;
    nAssetSyncStarted = GetTime();
}

void CMasternodeSync::AddedMasternodeList(uint256 hash)
{
    if (mnodeman.mapSeenMasternodeBroadcast.count(hash)) {
        if (mapSeenSyncMNB[hash] < MASTERNODE_SYNC_THRESHOLD) {
            lastMasternodeList = GetTime();
            mapSeenSyncMNB[hash]++;
        }
    } else {
        lastMasternodeList = GetTime();
        mapSeenSyncMNB.insert(std::make_pair(hash, 1));
    }
}

void CMasternodeSync::AddedMasternodeWinner(uint256 hash)
{
    if (masternodePayments.mapMasternodePayeeVotes.count(hash)) {
        if (mapSeenSyncMNW[hash] < MASTERNODE_SYNC_THRESHOLD) {
            lastMasternodeWinner = GetTime();
            mapSeenSyncMNW[hash]++;
        }
    } else {
        lastMasternodeWinner = GetTime();
        mapSeenSyncMNW.insert(std::make_pair(hash, 1));
    }
}

void CMasternodeSync::AddedBudgetItem(uint256 hash)
{
    if (budget.mapSeenMasternodeBudgetProposals.count(hash) || budget.mapSeenMasternodeBudgetVotes.count(hash) ||
        budget.mapSeenFinalizedBudgets.count(hash) || budget.mapSeenFinalizedBudgetVotes.count(hash)) {
        if (mapSeenSyncBudget[hash] < MASTERNODE_SYNC_THRESHOLD) {
            lastBudgetItem = GetTime();
            mapSeenSyncBudget[hash]++;
        }
    } else {
        lastBudgetItem = GetTime();
        mapSeenSyncBudget.insert(std::make_pair(hash, 1));
    }
}

bool CMasternodeSync::IsBudgetPropEmpty()
{
    return sumBudgetItemProp == 0 && countBudgetItemProp > 0;
}

bool CMasternodeSync::IsBudgetFinEmpty()
{
    return sumBudgetItemFin == 0 && countBudgetItemFin > 0;
}

void CMasternodeSync::GetNextAsset()
{
    switch (RequestedMasternodeAssets) {
    case (MASTERNODE_SYNC_INITIAL):
    case (MASTERNODE_SYNC_FAILED): // should never be used here actually, use Reset() instead
        ClearFulfilledRequest();
        RequestedMasternodeAssets = MASTERNODE_SYNC_SPORKS;
        break;
    case (MASTERNODE_SYNC_SPORKS):
        RequestedMasternodeAssets = MASTERNODE_SYNC_LIST;
        break;
    case (MASTERNODE_SYNC_LIST):
        RequestedMasternodeAssets = MASTERNODE_SYNC_MNW;
        break;
    case (MASTERNODE_SYNC_MNW):
        RequestedMasternodeAssets = MASTERNODE_SYNC_BUDGET;
        break;
    case (MASTERNODE_SYNC_BUDGET):
        LogPrintf("CMasternodeSync::GetNextAsset - Sync has finished\n");
        RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
        break;
    }
    RequestedMasternodeAttempt = 0;
    nAssetSyncStarted = GetTime();
}

std::string CMasternodeSync::GetSyncStatus()
{
    switch (masternodeSync.RequestedMasternodeAssets) {
    case MASTERNODE_SYNC_INITIAL:
        return _("MNs synchronization pending...");
    case MASTERNODE_SYNC_SPORKS:
        return _("Synchronizing sporks...");
    case MASTERNODE_SYNC_LIST:
        return _("Synchronizing masternodes...");
    case MASTERNODE_SYNC_MNW:
        return _("Synchronizing masternode winners...");
    case MASTERNODE_SYNC_BUDGET:
        return _("Synchronizing budgets...");
    case MASTERNODE_SYNC_FAILED:
        return _("Synchronization failed");
    case MASTERNODE_SYNC_FINISHED:
        return _("Synchronization finished");
    }
    return "";
}

void CMasternodeSync::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
    if (strCommand == NetMsgType::SYNCSTATUSCOUNT) { //Sync status count
        int nItemID;
        int nCount;
        vRecv >> nItemID >> nCount;

        if (RequestedMasternodeAssets >= MASTERNODE_SYNC_FINISHED) return;

        //this means we will receive no further communication
        switch (nItemID) {
        case (MASTERNODE_SYNC_LIST):
            if (nItemID != RequestedMasternodeAssets) return;
            sumMasternodeList += nCount;
            countMasternodeList++;
            break;
        case (MASTERNODE_SYNC_MNW):
            if (nItemID != RequestedMasternodeAssets) return;
            sumMasternodeWinner += nCount;
            countMasternodeWinner++;
            break;
        case (MASTERNODE_SYNC_BUDGET_PROP):
            if (RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
            sumBudgetItemProp += nCount;
            countBudgetItemProp++;
            break;
        case (MASTERNODE_SYNC_BUDGET_FIN):
            if (RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
            sumBudgetItemFin += nCount;
            countBudgetItemFin++;
            break;
        }

        LogPrint(BCLog::MASTERNODE, "CMasternodeSync:ProcessMessage - ssc - got inventory count %d %d\n", nItemID, nCount);
    }
}

void CMasternodeSync::ClearFulfilledRequest()
{
    g_connman->ForEachNode([](CNode* pnode) {
        pnode->ClearFulfilledRequest("getspork");
        pnode->ClearFulfilledRequest("mnsync");
        pnode->ClearFulfilledRequest("mnwsync");
        pnode->ClearFulfilledRequest("busync");
    });
}

void CMasternodeSync::Process()
{
    static int tick = 0;
    const bool isRegTestNet = Params().IsRegTestNet();

    if (tick++ % MASTERNODE_SYNC_TIMEOUT != 0) return;

    if (IsSynced()) {
        /*
            Resync if we lose all masternodes from sleep/wake or failure to sync originally
        */
        if (mnodeman.CountEnabled() == 0) {
            Reset();
        } else
            return;
    }

    //try syncing again
    if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED && lastFailure + (1 * 60) < GetTime()) {
        Reset();
    } else if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED) {
        return;
    }

    LogPrint(BCLog::MASTERNODE, "CMasternodeSync::Process() - tick %d RequestedMasternodeAssets %d\n", tick, RequestedMasternodeAssets);

    if (RequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL) GetNextAsset();

    // sporks synced but blockchain is not, wait until we're almost at a recent block to continue
    if (!isRegTestNet && !IsBlockchainSynced() &&
        RequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS) return;

    CMasternodeSync* sync = this;
    g_connman->ForEachNodeContinueIf([sync, isRegTestNet](CNode* pnode){
        return sync->SyncWithNode(pnode, isRegTestNet);
    });
}

bool CMasternodeSync::SyncWithNode(CNode* pnode, bool isRegTestNet)
{
    if (isRegTestNet) {
        if (RequestedMasternodeAttempt <= 2) {
            pnode->PushMessage(NetMsgType::GETSPORKS); //get current network sporks
        } else if (RequestedMasternodeAttempt < 4) {
            mnodeman.DsegUpdate(pnode);
        } else if (RequestedMasternodeAttempt < 6) {
            int nMnCount = mnodeman.CountEnabled();
            pnode->PushMessage(NetMsgType::GETMNWINNERS, nMnCount); //sync payees
            uint256 n;
            pnode->PushMessage(NetMsgType::BUDGETVOTESYNC, n); //sync masternode votes
        } else {
            RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
        }
        RequestedMasternodeAttempt++;
        return false;
    }

    //set to synced
    if (RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS) {
        if (pnode->HasFulfilledRequest("getspork")) return true;
        pnode->FulfilledRequest("getspork");

        pnode->PushMessage(NetMsgType::GETSPORKS); //get current network sporks
        if (RequestedMasternodeAttempt >= 2) GetNextAsset();
        RequestedMasternodeAttempt++;
        return false;
    }

    if (pnode->nVersion >= masternodePayments.GetMinMasternodePaymentsProto()) {
        if (RequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
            LogPrint(BCLog::MASTERNODE, "CMasternodeSync::Process() - lastMasternodeList %lld (GetTime() - MASTERNODE_SYNC_TIMEOUT) %lld\n", lastMasternodeList, GetTime() - MASTERNODE_SYNC_TIMEOUT);
            if (lastMasternodeList > 0 && lastMasternodeList < GetTime() - MASTERNODE_SYNC_TIMEOUT * 2 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) { //hasn't received a new item in the last five seconds, so we'll move to the
                GetNextAsset();
                return false;
            }

            if (pnode->HasFulfilledRequest("mnsync")) return true;
            pnode->FulfilledRequest("mnsync");

            // timeout
            if (lastMasternodeList == 0 &&
                (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) {
                if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
                    LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed on %s, will retry later\n", "MASTERNODE_SYNC_LIST");
                    RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED;
                    RequestedMasternodeAttempt = 0;
                    lastFailure = GetTime();
                    nCountFailures++;
                } else {
                    GetNextAsset();
                }
                return false;
            }

            if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3) return false;

            mnodeman.DsegUpdate(pnode);
            RequestedMasternodeAttempt++;
            return false;
        }

        if (RequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
            if (lastMasternodeWinner > 0 && lastMasternodeWinner < GetTime() - MASTERNODE_SYNC_TIMEOUT * 2 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) { //hasn't received a new item in the last five seconds, so we'll move to the
                GetNextAsset();
                return false;
            }

            if (pnode->HasFulfilledRequest("mnwsync")) return true;
            pnode->FulfilledRequest("mnwsync");

            // timeout
            if (lastMasternodeWinner == 0 &&
                (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) {
                if (sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)) {
                    LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed on %s, will retry later\n", "MASTERNODE_SYNC_MNW");
                    RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED;
                    RequestedMasternodeAttempt = 0;
                    lastFailure = GetTime();
                    nCountFailures++;
                } else {
                    GetNextAsset();
                }
                return false;
            }

            if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3) return false;

            int nMnCount = mnodeman.CountEnabled();
            pnode->PushMessage(NetMsgType::GETMNWINNERS, nMnCount); //sync payees
            RequestedMasternodeAttempt++;
            return false;
        }
    }

    if (pnode->nVersion >= ActiveProtocol()) {
        if (RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET) {
            // We'll start rejecting votes if we accidentally get set as synced too soon
            if (lastBudgetItem > 0 && lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT * 2 && RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD) {
                // Hasn't received a new item in the last five seconds, so we'll move to the
                GetNextAsset();

                // Try to activate our masternode if possible
                activeMasternode.ManageStatus();
                return false;
            }

            // timeout
            if (lastBudgetItem == 0 &&
                (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3 || GetTime() - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5)) {
                // maybe there is no budgets at all, so just finish syncing
                GetNextAsset();
                activeMasternode.ManageStatus();
                return false;
            }

            if (pnode->HasFulfilledRequest("busync")) return true;
            pnode->FulfilledRequest("busync");

            if (RequestedMasternodeAttempt >= MASTERNODE_SYNC_THRESHOLD * 3) return false;

            uint256 n;
            pnode->PushMessage(NetMsgType::BUDGETVOTESYNC, n); //sync masternode votes
            RequestedMasternodeAttempt++;
            return false;
        }
    }

    return true;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2016, Andrej Kislovskij
 *
 * This is PUBLIC DOMAIN software so use at your own risk as it comes
 * with no warranties. This code is yours to share, use and modify without
 * any restrictions or obligations.
 *
 * For more information see conwrap/LICENSE or refer refer to http://unlicense.org
 *
 * Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)
 */

#pragma once

#include <condition_variable>
#include <exception>
#include <queue>
#include <mutex>

namespace conwrap
{

	template<typename ResourceType1, typename Container1 = std::deque<ResourceType1>>
	class ConcurrentQueue
	{
		public:
			typedef typename Container1::iterator       iterator;
			typedef typename Container1::const_iterator const_iterator;

			ConcurrentQueue() {}

			ConcurrentQueue(const ConcurrentQueue&) = delete;

			ConcurrentQueue &operator=(const ConcurrentQueue&) = delete;

			virtual ~ConcurrentQueue() {}

			iterator begin()
			{
				return queue_.c.begin();
			}

			const_iterator begin() const
			{
				return queue_.c.begin();
			}

			bool empty() const
			{
				std::lock_guard<std::mutex> lock(m_);
				return queue_.empty();
			}

			iterator end()
			{
				return queue_.c.end();
			}

			const_iterator end() const
			{
				return queue_.c.end();
			}

			void flush()
			{
				{
					std::unique_lock<std::mutex> lock(m_);
					data_cond_.wait(lock, [&] { return queue_.empty();});
				}
			}

			ResourceType1* get()
			{
				ResourceType1* result = nullptr;
				{
					std::lock_guard<std::mutex> lock(m_);
					if (!queue_.empty()) {
						result = &queue_.front();
					}
				}
				return result;
			}

			void push(ResourceType1 item)
			{
				{
					std::lock_guard<std::mutex> lock(m_);
					queue_.push(std::move(item));
				}
				data_cond_.notify_all();
			}

			bool remove() {
				auto result = false;
				{
					std::lock_guard<std::mutex> lock(m_);
					if (!queue_.empty()) {

						// remove the first item in the queue
						queue_.pop();
						data_cond_.notify_all();
						result = true;
					}
				}
				return result;
			}

			unsigned size() const
			{
				std::lock_guard<std::mutex> lock(m_);
				return queue_.size();
			}

			void wait()
			{
				{
					std::unique_lock<std::mutex> lock(m_);
					data_cond_.wait(lock, [&] {return !queue_.empty();});
				}
			}

		protected:
			// defining internal struct to gain access to sequence of elements in a std::queue
			template<typename ResourceType2, typename Container2>
			struct IterableQueue : public std::queue<ResourceType2, Container2>
			{
				using std::queue<ResourceType2, Container2>::c;
			};

		private:
			IterableQueue<ResourceType1, Container1> queue_;
			mutable std::mutex                       m_;
			std::condition_variable                  data_cond_;
	};
}
<commit_msg>Refactoring<commit_after>/*
 * Copyright 2016, Andrej Kislovskij
 *
 * This is PUBLIC DOMAIN software so use at your own risk as it comes
 * with no warranties. This code is yours to share, use and modify without
 * any restrictions or obligations.
 *
 * For more information see conwrap/LICENSE or refer refer to http://unlicense.org
 *
 * Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)
 */

#pragma once

#include <condition_variable>
#include <exception>
#include <queue>
#include <mutex>

namespace conwrap
{

	template<typename ResourceType1, typename Container1 = std::deque<ResourceType1>>
	class ConcurrentQueue
	{
		public:
			typedef typename Container1::iterator       iterator;
			typedef typename Container1::const_iterator const_iterator;

			ConcurrentQueue() {}

			ConcurrentQueue(const ConcurrentQueue&) = delete;

			ConcurrentQueue &operator=(const ConcurrentQueue&) = delete;

			virtual ~ConcurrentQueue() {}

			iterator begin()
			{
				return queue.c.begin();
			}

			const_iterator begin() const
			{
				return queue.c.begin();
			}

			bool empty() const
			{
				std::lock_guard<std::mutex> lock(queueMutex);
				return queue.empty();
			}

			iterator end()
			{
				return queue.c.end();
			}

			const_iterator end() const
			{
				return queue.c.end();
			}

			void flush()
			{
				{
					std::unique_lock<std::mutex> lock(queueMutex);
					conditionVariable.wait(lock, [&]
					{
						return queue.empty();
					});
				}
			}

			ResourceType1* get()
			{
				ResourceType1* resultPtr = nullptr;
				{
					std::lock_guard<std::mutex> lock(queueMutex);
					if (!queue.empty()) {
						resultPtr = &queue.front();
					}
				}
				return resultPtr;
			}

			void push(ResourceType1 item)
			{
				{
					std::lock_guard<std::mutex> lock(queueMutex);
					queue.push(std::move(item));
				}
				conditionVariable.notify_all();
			}

			bool remove() {
				auto result = false;
				{
					std::lock_guard<std::mutex> lock(queueMutex);
					if (!queue.empty()) {

						// remove the first item in the queue
						queue.pop();
						conditionVariable.notify_all();
						result = true;
					}
				}
				return result;
			}

			unsigned size() const
			{
				std::lock_guard<std::mutex> lock(queueMutex);
				return queue.size();
			}

			void wait()
			{
				{
					std::unique_lock<std::mutex> lock(queueMutex);
					conditionVariable.wait(lock, [&]
					{
						return !queue.empty();
					});
				}
			}

		protected:
			// defining internal struct to gain access to sequence of elements in a std::queue
			template<typename ResourceType2, typename Container2>
			struct IterableQueue : public std::queue<ResourceType2, Container2>
			{
				using std::queue<ResourceType2, Container2>::c;
			};

		private:
			IterableQueue<ResourceType1, Container1> queue;
			mutable std::mutex                       queueMutex;
			std::condition_variable                  conditionVariable;
	};
}
<|endoftext|>


<commit_before>/**
 * Created by Jian Chen
 * @since  2016.04.12
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#ifdef CHEN_OS_UNIX

#include "so_socket_unix.hpp"
#include <chen/net/tcp/tcp_server.hpp>
#include <chen/net/so/so_error.hpp>
#include <sys/socket.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <cstring>
#include <cerrno>

using namespace chen;
using namespace chen::so;
using namespace chen::tcp;

// -----------------------------------------------------------------------------
// server
void server::bind(const std::string &addr, std::uint16_t port)
{
    // check already bind
    if (!this->_impl->_socket || this->localPort())
        this->build();  // rebuild

    // bind address and port
    struct sockaddr_in in;
    ::memset(&in, 0, sizeof(in));

    in.sin_family      = AF_INET;
    in.sin_addr.s_addr = ::inet_addr(addr.c_str());
    in.sin_port        = htons(port);

    if (::bind(this->_impl->_socket, (struct sockaddr*)&in, sizeof(in)) == -1)
        throw error_bind(std::strerror(errno));
}

void server::listen()
{
    if (::listen(this->_impl->_socket, SOMAXCONN) == -1)
        throw error_listen(std::strerror(errno));
}

std::unique_ptr<chen::tcp::conn> server::accept(float timeout)
{
    struct timeval tv;
    tv.tv_sec  = static_cast<int>(timeout);
    tv.tv_usec = static_cast<int>((timeout - tv.tv_sec) * 1000000);

    fd_set set;

    FD_ZERO(&set);
    FD_SET(this->_impl->_socket, &set);

    auto ret = ::select(this->_impl->_socket + 1, &set, nullptr, nullptr, timeout ? &tv : nullptr);

    if (ret == 1)
    {
        struct sockaddr_in in;
        socklen_t len = sizeof(in);

        auto so = ::accept(this->_impl->_socket, (struct sockaddr*)&in, &len);

        if (so != -1)
            return std::unique_ptr<chen::tcp::conn>(new chen::tcp::conn(&so));
        else
            throw error_accept(std::strerror(errno));
    }
    else if (!ret || (errno == EBADF))
    {
        // timeout or shutdown or close
        return nullptr;
    }
    else
    {
        throw error_accept(std::strerror(errno));
    }
}

#endif<commit_msg>tcp: use poll instead of select in accept<commit_after>/**
 * Created by Jian Chen
 * @since  2016.04.12
 * @author Jian Chen <admin@chensoft.com>
 * @link   http://chensoft.com
 */
#ifdef CHEN_OS_UNIX

#include "so_socket_unix.hpp"
#include <chen/net/tcp/tcp_server.hpp>
#include <chen/net/so/so_error.hpp>
#include <sys/socket.h>
#include <sys/poll.h>
#include <arpa/inet.h>
#include <cstring>
#include <cerrno>

using namespace chen;
using namespace chen::so;
using namespace chen::tcp;

// -----------------------------------------------------------------------------
// server
void server::bind(const std::string &addr, std::uint16_t port)
{
    // check already bind
    if (!this->_impl->_socket || this->localPort())
        this->build();  // rebuild

    // bind address and port
    struct sockaddr_in in;
    ::memset(&in, 0, sizeof(in));

    in.sin_family      = AF_INET;
    in.sin_addr.s_addr = ::inet_addr(addr.c_str());
    in.sin_port        = htons(port);

    if (::bind(this->_impl->_socket, (struct sockaddr*)&in, sizeof(in)) == -1)
        throw error_bind(std::strerror(errno));
}

void server::listen()
{
    if (::listen(this->_impl->_socket, SOMAXCONN) == -1)
        throw error_listen(std::strerror(errno));
}

std::unique_ptr<chen::tcp::conn> server::accept(float timeout)
{
    struct pollfd poll;

    poll.fd     = this->_impl->_socket;
    poll.events = POLLIN;

    auto ret = ::poll(&poll, 1, timeout ? static_cast<int>(timeout * 1000) : -1);

    if ((ret == 1) && (poll.revents & POLLIN))
    {
        struct sockaddr_in in;
        socklen_t len = sizeof(in);

        auto so = ::accept(this->_impl->_socket, (struct sockaddr*)&in, &len);

        if (so != -1)
            return std::unique_ptr<chen::tcp::conn>(new chen::tcp::conn(&so));
        else
            throw error_accept(std::strerror(errno));
    }
    else if (!ret || (errno == EBADF))
    {
        // timeout or shutdown or close
        return nullptr;
    }
    else
    {
        throw error_accept(std::strerror(errno));
    }
}

#endif<|endoftext|>


<commit_before>#include "material/layer.h"
#include "scene/hitable.h"

namespace aten
{
	vec3 LayeredBSDF::sampleAlbedoMap(real u, real v) const
	{
		auto num = m_layer.size();

		vec3 albedo(1);

		for (int i = 0; i < num; i++) {
			auto mtrl = m_layer[i];

			// TODO
			auto c = mtrl->color();
			auto a = mtrl->sampleAlbedoMap(u, v);

			albedo *= c * a;
		}

		return std::move(albedo);
	}

	void LayeredBSDF::applyNormalMap(
		const vec3& orgNml,
		vec3& newNml,
		real u, real v) const
	{
		auto num = m_layer.size();

		if (num == 0) {
			newNml = orgNml;
		}
		else {
			// ŕ\w NormalMap Kp.
			auto mtrl = m_layer[0];
			mtrl->applyNormalMap(orgNml, newNml, u, v);
		}
	}

	real LayeredBSDF::computeFresnel(
		const vec3& normal,
		const vec3& wi,
		const vec3& wo,
		real outsideIor/*= 1*/) const
	{
		// TODO
		AT_ASSERT(false);

		auto num = m_layer.size();

		if (num == 0) {
			return real(1);
		}
		else {
			// ŕ\w̃tlԂ.
			auto mtrl = m_layer[0];
			auto f = mtrl->computeFresnel(normal, wi, wo, outsideIor);
			return f;
		}
	}

	void LayeredBSDF::add(material* mtrl)
	{
		m_layer.push_back(mtrl);
	}

	material::sampling LayeredBSDF::sample(
		const ray& ray,
		const vec3& normal,
		const hitrecord& hitrec,
		sampler* sampler,
		real u, real v) const
	{
		sampling ret;

		auto num = m_layer.size();

		if (num == 0) {
			AT_ASSERT(false);
			return std::move(ret);
		}

		real sumW = 0;

		for (int i = 0; i < num; i++) {
			auto mtrl = m_layer[i];

			vec3 appliedNml = normal;

			// NOTE
			// Oł͍ŕ\w NormalMap KpĂ.
			if (i > 0) {
				mtrl->applyNormalMap(normal, appliedNml, u, v);
			}

			auto sampleres = mtrl->sample(ray, appliedNml, hitrec, sampler, u, v);

			const auto weight = sampleres.fresnel;

			ret.pdf += weight * sampleres.pdf;
			ret.bsdf += weight * sampleres.bsdf;

			// TODO
			// ret.fresnel

			sumW += weight;

			if (i == 0) {
				ret.dir = sampleres.dir;
			}
		}

		ret.pdf /= sumW;
		ret.bsdf /= sumW;

		return std::move(ret);
	}

	real LayeredBSDF::pdf(
		const vec3& normal,
		const vec3& wi,
		const vec3& wo,
		real u, real v,
		sampler* sampler) const
	{
		auto num = m_layer.size();

		real pdf = 0;

		real sumW = 0;
		real ior = 1;

		for (int i = 0; i < num; i++) {
			auto mtrl = m_layer[i];

			vec3 appliedNml = normal;

			// NOTE
			// Oł͍ŕ\w NormalMap KpĂ.
			if (i > 0) {
				mtrl->applyNormalMap(normal, appliedNml, u, v);
			}

			auto p = mtrl->pdf(appliedNml, wi, wo, u, v, sampler);
			auto f = mtrl->computeFresnel(appliedNml, wi, wo, ior);

			ior = mtrl->ior();

			pdf += f * p;

			sumW += f;
		}

		pdf /= sumW;

		return pdf;
	}

	vec3 LayeredBSDF::sampleDirection(
		const ray& ray,
		const vec3& normal,
		real u, real v,
		sampler* sampler) const
	{
		auto num = m_layer.size();
		AT_ASSERT(num > 0);

		auto mtrl = m_layer[0];

		auto dir = mtrl->sampleDirection(ray, normal, u, v, sampler);

		return std::move(dir);
	}

	vec3 LayeredBSDF::bsdf(
		const vec3& normal,
		const vec3& wi,
		const vec3& wo,
		real u, real v) const
	{
		auto num = m_layer.size();

		vec3 bsdf;

		real sumW = 0;
		real ior = 1;

		for (int i = 0; i < num; i++) {
			auto mtrl = m_layer[i];

			vec3 appliedNml = normal;

			// NOTE
			// Oł͍ŕ\w NormalMap KpĂ.
			if (i > 0) {
				mtrl->applyNormalMap(normal, appliedNml, u, v);
			}

			auto b = mtrl->bsdf(appliedNml, wi, wo, u, v);
			auto f = mtrl->computeFresnel(appliedNml, wi, wo, ior);

			ior = mtrl->ior();

			bsdf += f * b;

			sumW += f;
		}

		bsdf /= sumW;

		return std::move(bsdf);
	}
}
<commit_msg>Modify to compute weight.<commit_after>#include "material/layer.h"
#include "scene/hitable.h"

namespace aten
{
	vec3 LayeredBSDF::sampleAlbedoMap(real u, real v) const
	{
		auto num = m_layer.size();

		vec3 albedo(1);

		for (int i = 0; i < num; i++) {
			auto mtrl = m_layer[i];

			// TODO
			auto c = mtrl->color();
			auto a = mtrl->sampleAlbedoMap(u, v);

			albedo *= c * a;
		}

		return std::move(albedo);
	}

	void LayeredBSDF::applyNormalMap(
		const vec3& orgNml,
		vec3& newNml,
		real u, real v) const
	{
		auto num = m_layer.size();

		if (num == 0) {
			newNml = orgNml;
		}
		else {
			// ŕ\w NormalMap Kp.
			auto mtrl = m_layer[0];
			mtrl->applyNormalMap(orgNml, newNml, u, v);
		}
	}

	real LayeredBSDF::computeFresnel(
		const vec3& normal,
		const vec3& wi,
		const vec3& wo,
		real outsideIor/*= 1*/) const
	{
		// TODO
		AT_ASSERT(false);

		auto num = m_layer.size();

		if (num == 0) {
			return real(1);
		}
		else {
			// ŕ\w̃tlԂ.
			auto mtrl = m_layer[0];
			auto f = mtrl->computeFresnel(normal, wi, wo, outsideIor);
			return f;
		}
	}

	void LayeredBSDF::add(material* mtrl)
	{
		m_layer.push_back(mtrl);
	}

	material::sampling LayeredBSDF::sample(
		const ray& ray,
		const vec3& normal,
		const hitrecord& hitrec,
		sampler* sampler,
		real u, real v) const
	{
		sampling ret;

		auto num = m_layer.size();

		if (num == 0) {
			AT_ASSERT(false);
			return std::move(ret);
		}

		real weight = 1;

		for (int i = 0; i < num; i++) {
			auto mtrl = m_layer[i];

			vec3 appliedNml = normal;

			// NOTE
			// Oł͍ŕ\w NormalMap KpĂ.
			if (i > 0) {
				mtrl->applyNormalMap(normal, appliedNml, u, v);
			}

			auto sampleres = mtrl->sample(ray, appliedNml, hitrec, sampler, u, v);

			const auto f = aten::clamp<real>(sampleres.fresnel, 0, 1);

			ret.pdf += weight * f * sampleres.pdf;
			ret.bsdf += weight * f * sampleres.bsdf;

			// TODO
			// ret.fresnel

			weight = aten::clamp<real>(weight - f, 0, 1);
			if (weight <= 0) {
				break;
			}

			if (i == 0) {
				ret.dir = sampleres.dir;
			}
		}

		return std::move(ret);
	}

	real LayeredBSDF::pdf(
		const vec3& normal,
		const vec3& wi,
		const vec3& wo,
		real u, real v,
		sampler* sampler) const
	{
		auto num = m_layer.size();

		real pdf = 0;

		real weight = 1;
		real ior = 1;	// ^󂩂n߂.

		for (int i = 0; i < num; i++) {
			auto mtrl = m_layer[i];

			vec3 appliedNml = normal;

			// NOTE
			// Oł͍ŕ\w NormalMap KpĂ.
			if (i > 0) {
				mtrl->applyNormalMap(normal, appliedNml, u, v);
			}

			auto p = mtrl->pdf(appliedNml, wi, wo, u, v, sampler);
			auto f = mtrl->computeFresnel(appliedNml, wi, wo, ior);

			f = aten::clamp<real>(f, 0, 1);

			pdf += weight * f * p;

			weight = aten::clamp<real>(weight - f, 0, 1);
			if (weight <= 0) {
				break;
			}

			// w̒lwɎg.
			ior = mtrl->ior();
		}

		return pdf;
	}

	vec3 LayeredBSDF::sampleDirection(
		const ray& ray,
		const vec3& normal,
		real u, real v,
		sampler* sampler) const
	{
		auto num = m_layer.size();
		AT_ASSERT(num > 0);

		auto mtrl = m_layer[0];

		auto dir = mtrl->sampleDirection(ray, normal, u, v, sampler);

		return std::move(dir);
	}

	vec3 LayeredBSDF::bsdf(
		const vec3& normal,
		const vec3& wi,
		const vec3& wo,
		real u, real v) const
	{
		auto num = m_layer.size();

		vec3 bsdf;

		real weight = 1;
		real ior = 1;	// ^󂩂n߂.

		for (int i = 0; i < num; i++) {
			auto mtrl = m_layer[i];

			vec3 appliedNml = normal;

			// NOTE
			// Oł͍ŕ\w NormalMap KpĂ.
			if (i > 0) {
				mtrl->applyNormalMap(normal, appliedNml, u, v);
			}

			auto b = mtrl->bsdf(appliedNml, wi, wo, u, v);
			auto f = mtrl->computeFresnel(appliedNml, wi, wo, ior);

			f = aten::clamp<real>(f, 0, 1);

			bsdf += weight * f * b;

			weight = aten::clamp<real>(weight - f, 0, 1);
			if (weight <= 0) {
				break;
			}

			// w̒lwɎg.
			ior = mtrl->ior();
		}

		return std::move(bsdf);
	}
}
<|endoftext|>


<commit_before>#include <lib/battery/battery.h>
#include "analog_battery.h"

// Defaults to use if the parameters are not set
#if BOARD_NUMBER_BRICKS > 0
#if defined(BOARD_BATT_V_LIST) && defined(BOARD_BATT_I_LIST)
static constexpr int   DEFAULT_V_CHANNEL[BOARD_NUMBER_BRICKS] = BOARD_BATT_V_LIST;
static constexpr int   DEFAULT_I_CHANNEL[BOARD_NUMBER_BRICKS] = BOARD_BATT_I_LIST;
#else
static constexpr int   DEFAULT_V_CHANNEL[BOARD_NUMBER_BRICKS] = {0};
static constexpr int   DEFAULT_I_CHANNEL[BOARD_NUMBER_BRICKS] = {0};
#endif
#else
static constexpr int DEFAULT_V_CHANNEL[1] = {0};
static constexpr int DEFAULT_I_CHANNEL[1] = {0};
#endif

AnalogBattery::AnalogBattery(int index, ModuleParams *parent, const int sample_interval_us) :
	Battery(index, parent, sample_interval_us)
{
	char param_name[17];

	_analog_param_handles.v_offs_cur = param_find("BAT_V_OFFS_CURR");

	snprintf(param_name, sizeof(param_name), "BAT%d_V_DIV", index);
	_analog_param_handles.v_div = param_find(param_name);

	snprintf(param_name, sizeof(param_name), "BAT%d_A_PER_V", index);
	_analog_param_handles.a_per_v = param_find(param_name);

	snprintf(param_name, sizeof(param_name), "BAT%d_V_CHANNEL", index);
	_analog_param_handles.v_channel = param_find(param_name);

	snprintf(param_name, sizeof(param_name), "BAT%d_I_CHANNEL", index);
	_analog_param_handles.i_channel = param_find(param_name);

	_analog_param_handles.v_div_old = param_find("BAT_V_DIV");
	_analog_param_handles.a_per_v_old = param_find("BAT_A_PER_V");
	_analog_param_handles.adc_channel_old = param_find("BAT_ADC_CHANNEL");
}

void
AnalogBattery::updateBatteryStatusADC(hrt_abstime timestamp, float voltage_raw, float current_raw,
				      int source, int priority, float throttle_normalized)
{
	float voltage_v = voltage_raw * _analog_params.v_div;
	float current_a = (current_raw - _analog_params.v_offs_cur) * _analog_params.a_per_v;

	bool connected = voltage_v > BOARD_ADC_OPEN_CIRCUIT_V &&
			 (BOARD_ADC_OPEN_CIRCUIT_V <= BOARD_VALID_UV || is_valid());

	Battery::updateBatteryStatus(timestamp, voltage_v, current_a, connected,
				     source, priority, throttle_normalized);
}

bool AnalogBattery::is_valid()
{
#ifdef BOARD_BRICK_VALID_LIST
	bool valid[BOARD_NUMBER_BRICKS] = BOARD_BRICK_VALID_LIST;
	return valid[_index - 1];
#else
	// TODO: Maybe return false instead?
	return true;
#endif
}

int AnalogBattery::get_voltage_channel()
{
	if (_analog_params.v_channel >= 0) {
		return _analog_params.v_channel;

	} else {
		return DEFAULT_V_CHANNEL[_index - 1];
	}
}

int AnalogBattery::get_current_channel()
{
	if (_analog_params.i_channel >= 0) {
		return _analog_params.i_channel;

	} else {
		return DEFAULT_I_CHANNEL[_index - 1];
	}
}

void
AnalogBattery::updateParams()
{
	if (_index == 1) {
		migrateParam<float>(_analog_param_handles.v_div_old, _analog_param_handles.v_div, &_analog_params.v_div_old,
				    &_analog_params.v_div, _first_parameter_update);
		migrateParam<float>(_analog_param_handles.a_per_v_old, _analog_param_handles.a_per_v, &_analog_params.a_per_v_old,
				    &_analog_params.a_per_v, _first_parameter_update);
		migrateParam<int>(_analog_param_handles.adc_channel_old, _analog_param_handles.v_channel,
				  &_analog_params.adc_channel_old, &_analog_params.v_channel, _first_parameter_update);

	} else {
		param_get(_analog_param_handles.v_div, &_analog_params.v_div);
		param_get(_analog_param_handles.a_per_v, &_analog_params.a_per_v);
		param_get(_analog_param_handles.v_channel, &_analog_params.v_channel);
	}

	param_get(_analog_param_handles.i_channel, &_analog_params.i_channel);
	param_get(_analog_param_handles.v_offs_cur, &_analog_params.v_offs_cur);

	if (_analog_params.v_div <= 0.0f) {
		/* apply scaling according to defaults if set to default */
		_analog_params.v_div = BOARD_BATTERY1_V_DIV;
		param_set_no_notification(_analog_param_handles.v_div, &_analog_params.v_div);

		if (_index == 1) {
			_analog_params.v_div_old = BOARD_BATTERY1_V_DIV;
			param_set_no_notification(_analog_param_handles.v_div_old, &_analog_params.v_div_old);
		}
	}

	if (_analog_params.a_per_v <= 0.0f) {
		/* apply scaling according to defaults if set to default */

		_analog_params.a_per_v = BOARD_BATTERY1_A_PER_V;
		param_set_no_notification(_analog_param_handles.a_per_v, &_analog_params.a_per_v);

		if (_index == 1) {
			_analog_params.a_per_v_old = BOARD_BATTERY1_A_PER_V;
			param_set_no_notification(_analog_param_handles.a_per_v_old, &_analog_params.a_per_v_old);
		}
	}

	Battery::updateParams();
}
<commit_msg>batterry_status: fix checking default a_per_v<commit_after>#include <lib/battery/battery.h>
#include "analog_battery.h"

// Defaults to use if the parameters are not set
#if BOARD_NUMBER_BRICKS > 0
#if defined(BOARD_BATT_V_LIST) && defined(BOARD_BATT_I_LIST)
static constexpr int   DEFAULT_V_CHANNEL[BOARD_NUMBER_BRICKS] = BOARD_BATT_V_LIST;
static constexpr int   DEFAULT_I_CHANNEL[BOARD_NUMBER_BRICKS] = BOARD_BATT_I_LIST;
#else
static constexpr int   DEFAULT_V_CHANNEL[BOARD_NUMBER_BRICKS] = {0};
static constexpr int   DEFAULT_I_CHANNEL[BOARD_NUMBER_BRICKS] = {0};
#endif
#else
static constexpr int DEFAULT_V_CHANNEL[1] = {0};
static constexpr int DEFAULT_I_CHANNEL[1] = {0};
#endif

AnalogBattery::AnalogBattery(int index, ModuleParams *parent, const int sample_interval_us) :
	Battery(index, parent, sample_interval_us)
{
	char param_name[17];

	_analog_param_handles.v_offs_cur = param_find("BAT_V_OFFS_CURR");

	snprintf(param_name, sizeof(param_name), "BAT%d_V_DIV", index);
	_analog_param_handles.v_div = param_find(param_name);

	snprintf(param_name, sizeof(param_name), "BAT%d_A_PER_V", index);
	_analog_param_handles.a_per_v = param_find(param_name);

	snprintf(param_name, sizeof(param_name), "BAT%d_V_CHANNEL", index);
	_analog_param_handles.v_channel = param_find(param_name);

	snprintf(param_name, sizeof(param_name), "BAT%d_I_CHANNEL", index);
	_analog_param_handles.i_channel = param_find(param_name);

	_analog_param_handles.v_div_old = param_find("BAT_V_DIV");
	_analog_param_handles.a_per_v_old = param_find("BAT_A_PER_V");
	_analog_param_handles.adc_channel_old = param_find("BAT_ADC_CHANNEL");
}

void
AnalogBattery::updateBatteryStatusADC(hrt_abstime timestamp, float voltage_raw, float current_raw,
				      int source, int priority, float throttle_normalized)
{
	float voltage_v = voltage_raw * _analog_params.v_div;
	float current_a = (current_raw - _analog_params.v_offs_cur) * _analog_params.a_per_v;

	bool connected = voltage_v > BOARD_ADC_OPEN_CIRCUIT_V &&
			 (BOARD_ADC_OPEN_CIRCUIT_V <= BOARD_VALID_UV || is_valid());

	Battery::updateBatteryStatus(timestamp, voltage_v, current_a, connected,
				     source, priority, throttle_normalized);
}

bool AnalogBattery::is_valid()
{
#ifdef BOARD_BRICK_VALID_LIST
	bool valid[BOARD_NUMBER_BRICKS] = BOARD_BRICK_VALID_LIST;
	return valid[_index - 1];
#else
	// TODO: Maybe return false instead?
	return true;
#endif
}

int AnalogBattery::get_voltage_channel()
{
	if (_analog_params.v_channel >= 0) {
		return _analog_params.v_channel;

	} else {
		return DEFAULT_V_CHANNEL[_index - 1];
	}
}

int AnalogBattery::get_current_channel()
{
	if (_analog_params.i_channel >= 0) {
		return _analog_params.i_channel;

	} else {
		return DEFAULT_I_CHANNEL[_index - 1];
	}
}

void
AnalogBattery::updateParams()
{
	if (_index == 1) {
		migrateParam<float>(_analog_param_handles.v_div_old, _analog_param_handles.v_div, &_analog_params.v_div_old,
				    &_analog_params.v_div, _first_parameter_update);
		migrateParam<float>(_analog_param_handles.a_per_v_old, _analog_param_handles.a_per_v, &_analog_params.a_per_v_old,
				    &_analog_params.a_per_v, _first_parameter_update);
		migrateParam<int>(_analog_param_handles.adc_channel_old, _analog_param_handles.v_channel,
				  &_analog_params.adc_channel_old, &_analog_params.v_channel, _first_parameter_update);

	} else {
		param_get(_analog_param_handles.v_div, &_analog_params.v_div);
		param_get(_analog_param_handles.a_per_v, &_analog_params.a_per_v);
		param_get(_analog_param_handles.v_channel, &_analog_params.v_channel);
	}

	param_get(_analog_param_handles.i_channel, &_analog_params.i_channel);
	param_get(_analog_param_handles.v_offs_cur, &_analog_params.v_offs_cur);

	if (_analog_params.v_div <= 0.0f) {
		/* apply scaling according to defaults if set to default */
		_analog_params.v_div = BOARD_BATTERY1_V_DIV;
		param_set_no_notification(_analog_param_handles.v_div, &_analog_params.v_div);

		if (_index == 1) {
			_analog_params.v_div_old = BOARD_BATTERY1_V_DIV;
			param_set_no_notification(_analog_param_handles.v_div_old, &_analog_params.v_div_old);
		}
	}

	if (_analog_params.a_per_v < 0.0f) {
		/* apply scaling according to defaults if set to default */

		_analog_params.a_per_v = BOARD_BATTERY1_A_PER_V;
		param_set_no_notification(_analog_param_handles.a_per_v, &_analog_params.a_per_v);

		if (_index == 1) {
			_analog_params.a_per_v_old = BOARD_BATTERY1_A_PER_V;
			param_set_no_notification(_analog_param_handles.a_per_v_old, &_analog_params.a_per_v_old);
		}
	}

	Battery::updateParams();
}
<|endoftext|>


<commit_before>//
//  main_test.cpp
//  RosterDesNurses
//
//  Created by Jeremy Omer on 04/03/2015.
//  Copyright (c) 2015 Jeremy Omer. All rights reserved.
//

#include "main_test.h"
#include "ReadWrite.h"
#include "Greedy.h"
#include "MasterProblem.h"
#include "SubProblem.h"
#include "CbcModeler.h"
#include "MyTools.h"

void main_test()
{
	testFunction_Antoine();
	// testFunction_Jeremy();
	//testFunction_Samuel();
}

// Function for testing parts of the code (Antoine)
void testFunction_Antoine(){

   // Time the complete execution of the algorithm
   Tools::Timer* timertotal = new Tools::Timer();
   timertotal->init();
   timertotal->start();

   // Create a log file
   string logFile = "logs/test.log";
   Tools::LogOutput logStream(logFile);

   //Create an output file
   string outFile = "outfiles/test.out";
   Tools::LogOutput outStream(outFile);

   string data = "testdatasets/";// testdatasets datasets
   const char* inst = "n012w8";// n100w4 n030w4 n005w4

   string scenarPath = data + inst + "/Sc-" + inst + ".txt";
   //n005w4: {1, 2, 3, 3}
   //n012w8: {3, 5, 0, 2, 0, 4, 5, 2}
   vector<int> numberWeek = {3, 5, 0, 2, 0, 4, 5, 2};
   vector<string> weekPaths(numberWeek.size());
   for(int i=0; i<numberWeek.size(); ++i){
      string path = data + inst + "/WD-" + inst + "-"+std::to_string(numberWeek[i])+".txt";
      weekPaths[i] = path;
   }
   string firstHistoryPath = data + inst + "/H0-" + inst + "-0.txt";

   // Read the input data from files
   Scenario* pScen = ReadWrite::readScenario(scenarPath);
   Preferences preferences;
   Demand* pWeekDemand = ReadWrite::readWeeks(weekPaths, pScen);
   ReadWrite::readHistory(firstHistoryPath,pScen);

   // Check that the scenario was read properly
   //
   // logStream << *pScen << std::endl;
   logStream << pScen->toString() << std::endl;
   logStream << pWeekDemand->toString(true) << std::endl;

   // Write the aggregate information on the demand
   //

   // Write aggregate information on the cover capacity of the staff
   // (TBD)

   //Compute initial solution
   //
   Greedy* pGreedy =
      new Greedy(pScen, pWeekDemand,   pScen->pWeekPreferences(), pScen->pInitialState());
   pGreedy->constructiveGreedy();
   outStream << pGreedy->solutionToLogString();

   // Instantiate the solver class as a test
   //
   MasterProblem* pBCP =
      new MasterProblem(pScen, pWeekDemand,   pScen->pWeekPreferences(), pScen->pInitialState(), S_BCP, pGreedy->getSolution());
   pBCP->solve();

   // Write the solution in the required output format
   vector<string> solutions = pBCP->solutionToString(pScen->nbWeeks());
   for(int w=0; w<pScen->nbWeeks(); ++w){
      int thisWeek = w+pScen->thisWeek();
      char solutionFile[30];
      snprintf ( solutionFile, 30, "outfiles/Sol-%s-%d-%d.txt", inst, numberWeek[w], thisWeek );
      Tools::LogOutput solutionStream(solutionFile);
      solutionStream << solutions[w];
   }

   // Write the solution in an output file
   outStream << pBCP->solutionToLogString();

   // Display the total time spent in the algorithm
   timertotal->stop();
   logStream.print("Total time spent in the algorithm : ");
   logStream.print(timertotal->dSinceInit());
   logStream.print("\n");

   // free the allocated pointers
   //
   //   delete vrp;
   delete timertotal;
   delete pWeekDemand;
   delete pScen;
   delete pGreedy;
   delete pBCP;
}

// Function for testing parts of the code (Jeremy)
void testFunction_Jeremy(){

   // Time the complete execution of the algorithm
   Tools::Timer* timertotal = new Tools::Timer();
   timertotal->init();
   timertotal->start();

   // Create a log file
   string logFile = "../logfiles/test.log";
   Tools::LogOutput logStream(logFile);

   // Read the input data from files
   Scenario* pScen = ReadWrite::readScenario("datasets/n030w4/Sc-n030w4.txt");
   Demand* pWeekDemand = ReadWrite::readWeek("datasets/n030w4/WD-n030w4-1.txt", pScen);
   ReadWrite::readHistory("datasets/n030w4/H0-n030w4-0.txt",pScen);

   // Check that the scenario was read properly
   //
   // logStream << *pScen << std::endl;
   logStream << pScen->toString() << std::endl;
   logStream << pWeekDemand->toString(true) << std::endl;

   // Write the aggregate information on the demand
   //

   // Write aggregate information on the cover capacity of the staff
   // (TBD)

   // Instantiate the solver class as a test
   //
   Greedy* pGreedy =
      new Greedy(pScen, pWeekDemand,	pScen->pWeekPreferences(), pScen->pInitialState());
   pGreedy->constructiveGreedy();

	/****************************************
	* Test the CBC modeler
	*****************************************/

	// Instantiate a master problem to create the mathematical programming model
	// with the columns deduced from the solution of the greedy
	MasterProblem* pSolverMP =
		new MasterProblem(pScen, pWeekDemand, pScen->pWeekPreferences(),
		pScen->pInitialState(), S_CBC, pGreedy->getSolution());
	pSolverMP->solve();

	CoinModeler* coinModel = (CoinModeler*) pSolverMP->getModel();
	CbcModeler* cbcModel =
		new CbcModeler(coinModel->getCoreVars(),coinModel->getColumns(),coinModel->getCons());

	// cbcModel->setModel();
	cbcModel->solve();

   // Write the solution in the required output format
   string outFile = "outfiles/solution.out";
   Tools::LogOutput outStream(outFile);
   outStream << pGreedy->solutionToString();

   // Write the solution and advanced information in a more convenient format
   string outLog = "outfiles/log.out";
   Tools::LogOutput outLogStream(outLog);
   outLogStream << pGreedy->solutionToLogString();

   // Display the total time spent in the algorithm
   timertotal->stop();
   logStream.print("Total time spent in the algorithm : ");
   logStream.print(timertotal->dSinceInit());
   logStream.print("\n");

   // free the allocated pointers
   //
   delete timertotal;
   delete pWeekDemand;
   delete pScen;
   delete pGreedy;
	delete pSolverMP;
	delete cbcModel;

}

// Function for testing parts of the code (Samuel)
void testFunction_Samuel(){

   Tools::Timer* timertest = new Tools::Timer();
   timertest->init();
   timertest->start();

   // log + output
   //
   string logFile = "../logfiles/samuel_test.log";
   Tools::LogOutput logStream(logFile);
   string outFile = "outfiles/test.out";
   Tools::LogOutput outStream(outFile);

   // Instances
   //
   string data = "datasets/";
   string inst = "n100w4";			// n100w4 n030w4 n005w4

   // Paths
   //
   string scenarPath = data + inst + "/Sc-" + inst + ".txt";
   vector<int> numberWeek = {1, 2, 3, 3};
   vector<string> weekPaths(numberWeek.size());
   for(int i=0; i<numberWeek.size(); ++i){
      string path = data + inst + "/WD-" + inst + "-"+std::to_string(numberWeek[i])+".txt";
      weekPaths[i] = path;
   }
   string firstHistoryPath = data + inst + "/H0-" + inst + "-0.txt";

   // Read the input data from files
   //
   Scenario* pScen = ReadWrite::readScenario(scenarPath);
   Preferences preferences;
   Demand* pWeekDemand = ReadWrite::readWeeks(weekPaths, pScen);
   ReadWrite::readHistory(firstHistoryPath,pScen);

   // Check that the scenario was read properly
   //
   logStream << pScen->toString() << std::endl;
   logStream << pWeekDemand->toString(true) << std::endl;

   //Compute initial solution
   //
   Greedy* pGreedy =
      new Greedy(pScen, pWeekDemand,   pScen->pWeekPreferences(), pScen->pInitialState());
   pGreedy->constructiveGreedy();
   outStream << pGreedy->solutionToLogString();

   // Instantiate solver + solve the instance
   //
   MasterProblem* pSolverTest = new MasterProblem(pScen, pWeekDemand,   pScen->pWeekPreferences(), pScen->pInitialState(), S_BCP, pGreedy->getSolution());
   pSolverTest->solve();

   // Write the solution in an output file
   //
   outStream << pSolverTest->solutionToLogString();

   // Display the total time spent in the algorithm
   //
   timertest->stop();
   logStream.print("Total time spent in the algorithm : ");
   logStream.print(timertest->dSinceInit());
   logStream.print("\n");

   // Delete
   //
   delete timertest;
   delete pWeekDemand;
   delete pScen;
   delete pGreedy;
   delete pSolverTest;

}
<commit_msg>AL: my main<commit_after>//
//  main_test.cpp
//  RosterDesNurses
//
//  Created by Jeremy Omer on 04/03/2015.
//  Copyright (c) 2015 Jeremy Omer. All rights reserved.
//

#include "main_test.h"
#include "ReadWrite.h"
#include "Greedy.h"
#include "MasterProblem.h"
#include "SubProblem.h"
#include "CbcModeler.h"
#include "MyTools.h"

void main_test()
{
	testFunction_Antoine();
	// testFunction_Jeremy();
	//testFunction_Samuel();
}

// Function for testing parts of the code (Antoine)
void testFunction_Antoine(){

   // Time the complete execution of the algorithm
   Tools::Timer* timertotal = new Tools::Timer();
   timertotal->init();
   timertotal->start();

   // Create a log file
   string logFile = "logs/test.log";
   Tools::LogOutput logStream(logFile);

   //Create an output file
   string outFile = "outfiles/test.out";
   Tools::LogOutput outStream(outFile);

   string data = "testdatasets/";// testdatasets datasets
   const char* inst = "n005w4";// n100w4 n030w4 n005w4

   string scenarPath = data + inst + "/Sc-" + inst + ".txt";
   //n005w4: {1, 2, 3, 3}
   //n012w8: {3, 5, 0, 2, 0, 4, 5, 2}
   vector<int> numberWeek = {1, 2, 3, 3};
   vector<string> weekPaths(numberWeek.size());
   for(int i=0; i<numberWeek.size(); ++i){
      string path = data + inst + "/WD-" + inst + "-"+std::to_string(numberWeek[i])+".txt";
      weekPaths[i] = path;
   }
   string firstHistoryPath = data + inst + "/H0-" + inst + "-0.txt";

   // Read the input data from files
   Scenario* pScen = ReadWrite::readScenario(scenarPath);
   Preferences preferences;
   Demand* pWeekDemand = ReadWrite::readWeeks(weekPaths, pScen);
   ReadWrite::readHistory(firstHistoryPath,pScen);

   // Check that the scenario was read properly
   //
   // logStream << *pScen << std::endl;
   logStream << pScen->toString() << std::endl;
   logStream << pWeekDemand->toString(true) << std::endl;

   // Write the aggregate information on the demand
   //

   // Write aggregate information on the cover capacity of the staff
   // (TBD)

   //Compute initial solution
   //
   Greedy* pGreedy =
      new Greedy(pScen, pWeekDemand,   pScen->pWeekPreferences(), pScen->pInitialState());
   pGreedy->constructiveGreedy();
   outStream << pGreedy->solutionToLogString();

   // Instantiate the solver class as a test
   //
   MasterProblem* pBCP =
      new MasterProblem(pScen, pWeekDemand,   pScen->pWeekPreferences(), pScen->pInitialState(), S_BCP, pGreedy->getSolution());
   pBCP->solve();

   // Write the solution in the required output format
   vector<string> solutions = pBCP->solutionToString(pScen->nbWeeks());
   for(int w=0; w<pScen->nbWeeks(); ++w){
      int thisWeek = w+pScen->thisWeek();
      char solutionFile[30];
      snprintf ( solutionFile, 30, "outfiles/Sol-%s-%d-%d.txt", inst, numberWeek[w], thisWeek );
      Tools::LogOutput solutionStream(solutionFile);
      solutionStream << solutions[w];
   }

   // Write the solution in an output file
   outStream << pBCP->solutionToLogString();

   // Display the total time spent in the algorithm
   timertotal->stop();
   logStream.print("Total time spent in the algorithm : ");
   logStream.print(timertotal->dSinceInit());
   logStream.print("\n");

   // free the allocated pointers
   //
   //   delete vrp;
   delete timertotal;
   delete pWeekDemand;
   delete pScen;
   delete pGreedy;
   delete pBCP;
}

// Function for testing parts of the code (Jeremy)
void testFunction_Jeremy(){

   // Time the complete execution of the algorithm
   Tools::Timer* timertotal = new Tools::Timer();
   timertotal->init();
   timertotal->start();

   // Create a log file
   string logFile = "../logfiles/test.log";
   Tools::LogOutput logStream(logFile);

   // Read the input data from files
   Scenario* pScen = ReadWrite::readScenario("datasets/n030w4/Sc-n030w4.txt");
   Demand* pWeekDemand = ReadWrite::readWeek("datasets/n030w4/WD-n030w4-1.txt", pScen);
   ReadWrite::readHistory("datasets/n030w4/H0-n030w4-0.txt",pScen);

   // Check that the scenario was read properly
   //
   // logStream << *pScen << std::endl;
   logStream << pScen->toString() << std::endl;
   logStream << pWeekDemand->toString(true) << std::endl;

   // Write the aggregate information on the demand
   //

   // Write aggregate information on the cover capacity of the staff
   // (TBD)

   // Instantiate the solver class as a test
   //
   Greedy* pGreedy =
      new Greedy(pScen, pWeekDemand,	pScen->pWeekPreferences(), pScen->pInitialState());
   pGreedy->constructiveGreedy();

	/****************************************
	* Test the CBC modeler
	*****************************************/

	// Instantiate a master problem to create the mathematical programming model
	// with the columns deduced from the solution of the greedy
	MasterProblem* pSolverMP =
		new MasterProblem(pScen, pWeekDemand, pScen->pWeekPreferences(),
		pScen->pInitialState(), S_CBC, pGreedy->getSolution());
	pSolverMP->solve();

	CoinModeler* coinModel = (CoinModeler*) pSolverMP->getModel();
	CbcModeler* cbcModel =
		new CbcModeler(coinModel->getCoreVars(),coinModel->getColumns(),coinModel->getCons());

	// cbcModel->setModel();
	cbcModel->solve();

   // Write the solution in the required output format
   string outFile = "outfiles/solution.out";
   Tools::LogOutput outStream(outFile);
   outStream << pGreedy->solutionToString();

   // Write the solution and advanced information in a more convenient format
   string outLog = "outfiles/log.out";
   Tools::LogOutput outLogStream(outLog);
   outLogStream << pGreedy->solutionToLogString();

   // Display the total time spent in the algorithm
   timertotal->stop();
   logStream.print("Total time spent in the algorithm : ");
   logStream.print(timertotal->dSinceInit());
   logStream.print("\n");

   // free the allocated pointers
   //
   delete timertotal;
   delete pWeekDemand;
   delete pScen;
   delete pGreedy;
	delete pSolverMP;
	delete cbcModel;

}

// Function for testing parts of the code (Samuel)
void testFunction_Samuel(){

   Tools::Timer* timertest = new Tools::Timer();
   timertest->init();
   timertest->start();

   // log + output
   //
   string logFile = "../logfiles/samuel_test.log";
   Tools::LogOutput logStream(logFile);
   string outFile = "outfiles/test.out";
   Tools::LogOutput outStream(outFile);

   // Instances
   //
   string data = "datasets/";
   string inst = "n100w4";			// n100w4 n030w4 n005w4

   // Paths
   //
   string scenarPath = data + inst + "/Sc-" + inst + ".txt";
   vector<int> numberWeek = {1, 2, 3, 3};
   vector<string> weekPaths(numberWeek.size());
   for(int i=0; i<numberWeek.size(); ++i){
      string path = data + inst + "/WD-" + inst + "-"+std::to_string(numberWeek[i])+".txt";
      weekPaths[i] = path;
   }
   string firstHistoryPath = data + inst + "/H0-" + inst + "-0.txt";

   // Read the input data from files
   //
   Scenario* pScen = ReadWrite::readScenario(scenarPath);
   Preferences preferences;
   Demand* pWeekDemand = ReadWrite::readWeeks(weekPaths, pScen);
   ReadWrite::readHistory(firstHistoryPath,pScen);

   // Check that the scenario was read properly
   //
   logStream << pScen->toString() << std::endl;
   logStream << pWeekDemand->toString(true) << std::endl;

   //Compute initial solution
   //
   Greedy* pGreedy =
      new Greedy(pScen, pWeekDemand,   pScen->pWeekPreferences(), pScen->pInitialState());
   pGreedy->constructiveGreedy();
   outStream << pGreedy->solutionToLogString();

   // Instantiate solver + solve the instance
   //
   MasterProblem* pSolverTest = new MasterProblem(pScen, pWeekDemand,   pScen->pWeekPreferences(), pScen->pInitialState(), S_BCP, pGreedy->getSolution());
   pSolverTest->solve();

   // Write the solution in an output file
   //
   outStream << pSolverTest->solutionToLogString();

   // Display the total time spent in the algorithm
   //
   timertest->stop();
   logStream.print("Total time spent in the algorithm : ");
   logStream.print(timertest->dSinceInit());
   logStream.print("\n");

   // Delete
   //
   delete timertest;
   delete pWeekDemand;
   delete pScen;
   delete pGreedy;
   delete pSolverTest;

}
<|endoftext|>


<commit_before>#include <parseopt.h>
#include <arpc.h>
#include "lsdctl_prot.h"

/* Much of the structure and code here is taken from sfskey.C which is GPL2'd.
 * See http://www.fs.net/ */

bool opt_verbose;
bool opt_quiet;
char *control_socket = "/tmp/lsdctl-sock";

/* Prototypes for table. */
void lsdctl_help (int argc, char *argv[]);
void lsdctl_exit (int argc, char *argv[]);
void lsdctl_trace (int argc, char *argv[]);
void lsdctl_stabilize (int argc, char *argv[]);
void lsdctl_replicate (int argc, char *argv[]);
void lsdctl_getloctab (int argc, char *argv[]);
void lsdctl_getrpcstats (int argc, char *argv[]);
void lsdctl_getmyids (int argc, char *argv[]);
void lsdctl_getdhashstats (int argc, char *argv[]);

struct modevec {
  const char *name;
  void (*fn) (int argc, char **argv);
  const char *usage;
};
const modevec modes[] = {
  { "help", lsdctl_help, "help" },
  { "exit", lsdctl_exit, "exit" },
  { "trace", lsdctl_trace, "trace crit|warning|info|trace" },
  { "stabilize", lsdctl_stabilize, "stabilize start|stop" },
  { "replicate", lsdctl_replicate, "replicate [-r] start|stop" },
  { "loctab", lsdctl_getloctab, "loctab [vnodenum]" },
  { "rpcstats", lsdctl_getrpcstats, "rpcstats [-rf]" },
  { "myids", lsdctl_getmyids, "myids" },
  { "dhashstats", lsdctl_getdhashstats, "dhashstats [vnodenum]" },
  { NULL, NULL, NULL }
};

static const modevec *lsdctl_mode;

void
usage (void)
{
  warnx << "usage: " << progname << " [-S sock] [-vq] ";
  if (lsdctl_mode && lsdctl_mode->usage)
    warnx << lsdctl_mode->usage << "\n";
  else
    warnx << "command [args]\n";
  exit (1);
}

/**************************************/
/* The commands that do the real work */
/**************************************/

void
lsdctl_help (int argc, char *argv[])
{
  strbuf msg;
  msg << "usage: " << progname << " [-S sock] [-vq] command [args]\n";
  for (const modevec *mp = modes; mp->name; mp++)
    if (mp->usage)
      msg << "	 " << progname << " " << mp->usage << "\n";
  make_sync (1);
  msg.tosuio ()->output (1);
  exit (0);
}

ptr<aclnt>
lsdctl_connect (str sockname)
{
  int fd = unixsocket_connect (sockname);
  if (fd < 0) {
    fatal ("lsdctl_connect: Error connecting to %s: %s\n",
	   sockname.cstr (), strerror (errno));
  }

  ptr<aclnt> c = aclnt::alloc (axprt_unix::alloc (fd, 1024*1025),
			       lsdctl_prog_1);
  return c;
}

void
lsdctl_exit (int argc, char *argv[])
{
  // Ignore arguments
  ptr<aclnt> c = lsdctl_connect (control_socket);
  clnt_stat err = c->scall (LSDCTL_EXIT, NULL, NULL);
  if (err)
    fatal << "lsdctl_exit: " << err << "\n";
  exit (0);
}

void
lsdctl_trace (int argc, char *argv[])
{
  if (optind + 1 != argc)
    usage ();

  char *level = argv[optind];
  int lvl = 0;
  // XXX wouldn't it be nice to cleanly derive from utils/modlogger.h?
  if (!strcmp ("crit", level))
    lvl = -1;
  else if (!strcmp ("warning", level))
    lvl = 0;
  else if (!strcmp ("info", level))
    lvl = 1;
  else if (!strcmp ("trace", level))
    lvl = 2;
  else
    usage ();

  ptr<aclnt> c = lsdctl_connect (control_socket);
  clnt_stat err = c->scall (LSDCTL_SETTRACELEVEL, &lvl, NULL);
  if (err)
    fatal << "lsdctl_trace: " << err << "\n";
  exit (0);
}

void
lsdctl_stabilize (int argc, char *argv[])
{
  if (optind + 1 != argc)
    usage ();

  bool t = false;
  char *toggle = argv[optind];
  if (!strcmp ("start", toggle))
    t = true;
  else if (!strcmp ("stop", toggle))
    t = false;

  ptr<aclnt> c = lsdctl_connect (control_socket);
  bool res = !t;
  clnt_stat err = c->scall (LSDCTL_SETSTABILIZE, &t, &res);
  if (err)
    fatal << "lsdctl_stabilize: " << err << "\n";
  if (res != t)
    warnx << "lsdctl_stabilize: lsd did not switch to new state.\n";
  exit (0);
}

void
lsdctl_replicate (int argc, char *argv[])
{
  ptr<lsdctl_setreplicate_arg> t = New refcounted<lsdctl_setreplicate_arg> ();
  t->randomize = false;

  int ch;
  while ((ch = getopt (argc, argv, "r")) != -1)
    switch (ch) {
    case 'r':
      t->randomize = true;
      break;
    default:
      usage ();
      break;
    }

  if (optind + 1 != argc)
    usage ();

  char *toggle = argv[optind];
  if (!strcmp ("start", toggle))
    t->enable = true;
  else if (!strcmp ("stop", toggle))
    t->enable = false;

  ptr<aclnt> c = lsdctl_connect (control_socket);
  bool res = !t;
  clnt_stat err = c->scall (LSDCTL_SETREPLICATE, t, &res);
  if (err)
    fatal << "lsdctl_replicate: " << err << "\n";
  if (res != t->enable)
    warnx << "lsdctl_replicate: lsd did not switch to new state.\n";
  exit (0);
}

strbuf
lsdctl_nlist_printer (ptr<lsdctl_nodeinfolist> nl)
{
  strbuf out;
  for (size_t i = 0; i < nl->nlist.size (); i++) {
    out << nl->nlist[i].n << " "
        << nl->nlist[i].addr.hostname << " "
        << nl->nlist[i].addr.port << " "
        << nl->nlist[i].vnode_num << " ";
    for (size_t j = 0; j < nl->nlist[i].coords.size (); j++)
      out << nl->nlist[i].coords[j] << " ";
    out << nl->nlist[i].a_lat << " "
        << nl->nlist[i].a_var << " "
        << nl->nlist[i].nrpc << " "
        << nl->nlist[i].pinned << " "
        << nl->nlist[i].alive << " "
        << nl->nlist[i].dead_time << "\n";
  }
  return out;
}

void
lsdctl_getmyids (int argc, char *argv[])
{
  ptr<lsdctl_nodeinfolist> nl = New refcounted <lsdctl_nodeinfolist> ();
  ptr<aclnt> c = lsdctl_connect (control_socket);

  clnt_stat err = c->scall (LSDCTL_GETMYIDS, NULL, nl);
  if (err)
    fatal << "lsdctl_loctab: " << err << "\n";
  strbuf out (lsdctl_nlist_printer (nl));
  make_sync (1);
  out.tosuio ()->output (1);
  exit (0);
}

void
lsdctl_getloctab (int argc, char *argv[])
{
  int vnode = 0; // XXX should actually get vnode from cmd line.
  ptr<lsdctl_nodeinfolist> nl = New refcounted <lsdctl_nodeinfolist> ();
  ptr<aclnt> c = lsdctl_connect (control_socket);

  clnt_stat err = c->scall (LSDCTL_GETLOCTABLE, &vnode, nl);
  if (err)
    fatal << "lsdctl_loctab: " << err << "\n";
  strbuf out (lsdctl_nlist_printer (nl));
  make_sync (1);
  out.tosuio ()->output (1);
  exit (0);
}

static int
statcmp (const void *a, const void *b)
{
  return strcmp (((lsdctl_rpcstat *) a)->key.cstr (),
		 ((lsdctl_rpcstat *) b)->key.cstr ());
}
void
lsdctl_getrpcstats (int argc, char *argv[])
{
  int ch;
  bool clear = false;
  bool formatted = false;
  while ((ch = getopt (argc, argv, "rf")) != -1)
    switch (ch) {
    case 'r':
      clear = true;
      break;
    case 'f':
      formatted = true;
      break;
    default:
      usage ();
      break;
    }

  ptr<lsdctl_rpcstatlist> nl = New refcounted <lsdctl_rpcstatlist> ();
  ptr<aclnt> c = lsdctl_connect (control_socket);

  clnt_stat err = c->scall (LSDCTL_GETRPCSTATS, &clear, nl);
  if (err)
    fatal << "lsdctl_rpcstats: " << err << "\n";
  strbuf out;
  out.fmt ("Interval %llu.%llu s\n",
	   nl->interval / 1000000, nl->interval % 1000000);
  if (formatted)
    out.fmt ("%54s | %-15s | %-15s | %-15s\n",
	     "Proc", "Calls (bytes/#)", "Rexmits", "Replies");

  lsdctl_rpcstat *ndx = New lsdctl_rpcstat[nl->stats.size ()];
  for (size_t i = 0; i < nl->stats.size (); i++)
    ndx[i] = nl->stats[i];
  qsort (ndx, nl->stats.size (), sizeof (lsdctl_rpcstat), &statcmp);

  str fmt;
  if (formatted)
    fmt = "%-54s | %7llu %7llu | %7llu %7llu | %7llu %7llu\n";
  else
    fmt = "%s %llu %llu %llu %llu %llu %llu\n";
  for (size_t i = 0; i < nl->stats.size (); i++) {
    out.fmt (fmt,
	     ndx[i].key.cstr (),
	     ndx[i].call_bytes,
	     ndx[i].ncall,
	     ndx[i].rexmit_bytes,
	     ndx[i].nrexmit,
	     ndx[i].reply_bytes,
	     ndx[i].nreply);
  }
  delete[] ndx;
  make_sync (1);
  out.tosuio ()->output (1);
  exit (0);
}

void
lsdctl_getdhashstats (int argc, char *argv[])
{
  int vnode (0);

  if (optind != argc)
    if (!convertint (argv[optind], &vnode))
      usage ();

  ptr<aclnt> c = lsdctl_connect (control_socket);
  ptr<lsdctl_dhashstats> ds = New refcounted <lsdctl_dhashstats> ();
  clnt_stat err = c->scall (LSDCTL_GETDHASHSTATS, &vnode, ds);
  if (err)
    fatal << "lsdctl_getdhashstats: " << err << "\n";

  strbuf out;
  out << "Statistics:\n";
  for (size_t i = 0; i < ds->stats.size (); i++)
    out << "  " << ds->stats[i].desc << " " << ds->stats[i].value << "\n";
  for (size_t i = 0; i < ds->blocks.size (); i++)
    out << ds->blocks[i].id << "\t" << ds->blocks[i].missing.size () << "\n";
  out << ds->hack;
  make_sync (1);
  out.tosuio ()->output (1);
  exit (0);
}

int
main (int argc, char *argv[])
{
  setprogname (argv[0]);
  putenv ("POSIXLY_CORRECT=1"); // Prevents Linux from reordering options

  int ch;
  while ((ch = getopt (argc, argv, "S:vq")) != -1)
    switch (ch) {
    case 'S':
      control_socket = optarg;
      break;
    case 'v':
      opt_verbose = true;
      break;
    case 'q':
      opt_quiet = true;
      break;
    default:
      usage ();
      break;
    }
  if (optind >= argc)
    usage ();

  // Prepare to dispatch on command name
  const modevec *mp;
  for (mp = modes; mp->name; mp++)
    if (!strcmp (argv[optind], mp->name))
      break;
  if (!mp->name)
    usage ();
  lsdctl_mode = mp;

  // Skip over command name...
  optind++;

  mp->fn (argc, argv);
  // amain ();

  return 0;
}
<commit_msg>Fix some error message strings.<commit_after>#include <parseopt.h>
#include <arpc.h>
#include "lsdctl_prot.h"

/* Much of the structure and code here is taken from sfskey.C which is GPL2'd.
 * See http://www.fs.net/ */

bool opt_verbose;
bool opt_quiet;
char *control_socket = "/tmp/lsdctl-sock";

/* Prototypes for table. */
void lsdctl_help (int argc, char *argv[]);
void lsdctl_exit (int argc, char *argv[]);
void lsdctl_trace (int argc, char *argv[]);
void lsdctl_stabilize (int argc, char *argv[]);
void lsdctl_replicate (int argc, char *argv[]);
void lsdctl_getloctab (int argc, char *argv[]);
void lsdctl_getrpcstats (int argc, char *argv[]);
void lsdctl_getmyids (int argc, char *argv[]);
void lsdctl_getdhashstats (int argc, char *argv[]);

struct modevec {
  const char *name;
  void (*fn) (int argc, char **argv);
  const char *usage;
};
const modevec modes[] = {
  { "help", lsdctl_help, "help" },
  { "exit", lsdctl_exit, "exit" },
  { "trace", lsdctl_trace, "trace crit|warning|info|trace" },
  { "stabilize", lsdctl_stabilize, "stabilize start|stop" },
  { "replicate", lsdctl_replicate, "replicate [-r] start|stop" },
  { "loctab", lsdctl_getloctab, "loctab [vnodenum]" },
  { "rpcstats", lsdctl_getrpcstats, "rpcstats [-rf]" },
  { "myids", lsdctl_getmyids, "myids" },
  { "dhashstats", lsdctl_getdhashstats, "dhashstats [vnodenum]" },
  { NULL, NULL, NULL }
};

static const modevec *lsdctl_mode;

void
usage (void)
{
  warnx << "usage: " << progname << " [-S sock] [-vq] ";
  if (lsdctl_mode && lsdctl_mode->usage)
    warnx << lsdctl_mode->usage << "\n";
  else
    warnx << "command [args]\n";
  exit (1);
}

/**************************************/
/* The commands that do the real work */
/**************************************/

void
lsdctl_help (int argc, char *argv[])
{
  strbuf msg;
  msg << "usage: " << progname << " [-S sock] [-vq] command [args]\n";
  for (const modevec *mp = modes; mp->name; mp++)
    if (mp->usage)
      msg << "	 " << progname << " " << mp->usage << "\n";
  make_sync (1);
  msg.tosuio ()->output (1);
  exit (0);
}

ptr<aclnt>
lsdctl_connect (str sockname)
{
  int fd = unixsocket_connect (sockname);
  if (fd < 0) {
    fatal ("lsdctl_connect: Error connecting to %s: %s\n",
	   sockname.cstr (), strerror (errno));
  }

  ptr<aclnt> c = aclnt::alloc (axprt_unix::alloc (fd, 1024*1025),
			       lsdctl_prog_1);
  return c;
}

void
lsdctl_exit (int argc, char *argv[])
{
  // Ignore arguments
  ptr<aclnt> c = lsdctl_connect (control_socket);
  clnt_stat err = c->scall (LSDCTL_EXIT, NULL, NULL);
  if (err)
    fatal << "lsdctl_exit: " << err << "\n";
  exit (0);
}

void
lsdctl_trace (int argc, char *argv[])
{
  if (optind + 1 != argc)
    usage ();

  char *level = argv[optind];
  int lvl = 0;
  // XXX wouldn't it be nice to cleanly derive from utils/modlogger.h?
  if (!strcmp ("crit", level))
    lvl = -1;
  else if (!strcmp ("warning", level))
    lvl = 0;
  else if (!strcmp ("info", level))
    lvl = 1;
  else if (!strcmp ("trace", level))
    lvl = 2;
  else
    usage ();

  ptr<aclnt> c = lsdctl_connect (control_socket);
  clnt_stat err = c->scall (LSDCTL_SETTRACELEVEL, &lvl, NULL);
  if (err)
    fatal << "lsdctl_trace: " << err << "\n";
  exit (0);
}

void
lsdctl_stabilize (int argc, char *argv[])
{
  if (optind + 1 != argc)
    usage ();

  bool t = false;
  char *toggle = argv[optind];
  if (!strcmp ("start", toggle))
    t = true;
  else if (!strcmp ("stop", toggle))
    t = false;

  ptr<aclnt> c = lsdctl_connect (control_socket);
  bool res = !t;
  clnt_stat err = c->scall (LSDCTL_SETSTABILIZE, &t, &res);
  if (err)
    fatal << "lsdctl_stabilize: " << err << "\n";
  if (res != t)
    warnx << "lsdctl_stabilize: lsd did not switch to new state.\n";
  exit (0);
}

void
lsdctl_replicate (int argc, char *argv[])
{
  ptr<lsdctl_setreplicate_arg> t = New refcounted<lsdctl_setreplicate_arg> ();
  t->randomize = false;

  int ch;
  while ((ch = getopt (argc, argv, "r")) != -1)
    switch (ch) {
    case 'r':
      t->randomize = true;
      break;
    default:
      usage ();
      break;
    }

  if (optind + 1 != argc)
    usage ();

  char *toggle = argv[optind];
  if (!strcmp ("start", toggle))
    t->enable = true;
  else if (!strcmp ("stop", toggle))
    t->enable = false;

  ptr<aclnt> c = lsdctl_connect (control_socket);
  bool res = !t;
  clnt_stat err = c->scall (LSDCTL_SETREPLICATE, t, &res);
  if (err)
    fatal << "lsdctl_replicate: " << err << "\n";
  if (res != t->enable)
    warnx << "lsdctl_replicate: lsd did not switch to new state.\n";
  exit (0);
}

strbuf
lsdctl_nlist_printer (ptr<lsdctl_nodeinfolist> nl)
{
  strbuf out;
  for (size_t i = 0; i < nl->nlist.size (); i++) {
    out << nl->nlist[i].n << " "
        << nl->nlist[i].addr.hostname << " "
        << nl->nlist[i].addr.port << " "
        << nl->nlist[i].vnode_num << " ";
    for (size_t j = 0; j < nl->nlist[i].coords.size (); j++)
      out << nl->nlist[i].coords[j] << " ";
    out << nl->nlist[i].a_lat << " "
        << nl->nlist[i].a_var << " "
        << nl->nlist[i].nrpc << " "
        << nl->nlist[i].pinned << " "
        << nl->nlist[i].alive << " "
        << nl->nlist[i].dead_time << "\n";
  }
  return out;
}

void
lsdctl_getmyids (int argc, char *argv[])
{
  ptr<lsdctl_nodeinfolist> nl = New refcounted <lsdctl_nodeinfolist> ();
  ptr<aclnt> c = lsdctl_connect (control_socket);

  clnt_stat err = c->scall (LSDCTL_GETMYIDS, NULL, nl);
  if (err)
    fatal << "lsdctl_getmyids: " << err << "\n";
  strbuf out (lsdctl_nlist_printer (nl));
  make_sync (1);
  out.tosuio ()->output (1);
  exit (0);
}

void
lsdctl_getloctab (int argc, char *argv[])
{
  int vnode = 0; // XXX should actually get vnode from cmd line.
  ptr<lsdctl_nodeinfolist> nl = New refcounted <lsdctl_nodeinfolist> ();
  ptr<aclnt> c = lsdctl_connect (control_socket);

  clnt_stat err = c->scall (LSDCTL_GETLOCTABLE, &vnode, nl);
  if (err)
    fatal << "lsdctl_getloctab: " << err << "\n";
  strbuf out (lsdctl_nlist_printer (nl));
  make_sync (1);
  out.tosuio ()->output (1);
  exit (0);
}

static int
statcmp (const void *a, const void *b)
{
  return strcmp (((lsdctl_rpcstat *) a)->key.cstr (),
		 ((lsdctl_rpcstat *) b)->key.cstr ());
}
void
lsdctl_getrpcstats (int argc, char *argv[])
{
  int ch;
  bool clear = false;
  bool formatted = false;
  while ((ch = getopt (argc, argv, "rf")) != -1)
    switch (ch) {
    case 'r':
      clear = true;
      break;
    case 'f':
      formatted = true;
      break;
    default:
      usage ();
      break;
    }

  ptr<lsdctl_rpcstatlist> nl = New refcounted <lsdctl_rpcstatlist> ();
  ptr<aclnt> c = lsdctl_connect (control_socket);

  clnt_stat err = c->scall (LSDCTL_GETRPCSTATS, &clear, nl);
  if (err)
    fatal << "lsdctl_rpcstats: " << err << "\n";
  strbuf out;
  out.fmt ("Interval %llu.%llu s\n",
	   nl->interval / 1000000, nl->interval % 1000000);
  if (formatted)
    out.fmt ("%54s | %-15s | %-15s | %-15s\n",
	     "Proc", "Calls (bytes/#)", "Rexmits", "Replies");

  lsdctl_rpcstat *ndx = New lsdctl_rpcstat[nl->stats.size ()];
  for (size_t i = 0; i < nl->stats.size (); i++)
    ndx[i] = nl->stats[i];
  qsort (ndx, nl->stats.size (), sizeof (lsdctl_rpcstat), &statcmp);

  str fmt;
  if (formatted)
    fmt = "%-54s | %7llu %7llu | %7llu %7llu | %7llu %7llu\n";
  else
    fmt = "%s %llu %llu %llu %llu %llu %llu\n";
  for (size_t i = 0; i < nl->stats.size (); i++) {
    out.fmt (fmt,
	     ndx[i].key.cstr (),
	     ndx[i].call_bytes,
	     ndx[i].ncall,
	     ndx[i].rexmit_bytes,
	     ndx[i].nrexmit,
	     ndx[i].reply_bytes,
	     ndx[i].nreply);
  }
  delete[] ndx;
  make_sync (1);
  out.tosuio ()->output (1);
  exit (0);
}

void
lsdctl_getdhashstats (int argc, char *argv[])
{
  int vnode (0);

  if (optind != argc)
    if (!convertint (argv[optind], &vnode))
      usage ();

  ptr<aclnt> c = lsdctl_connect (control_socket);
  ptr<lsdctl_dhashstats> ds = New refcounted <lsdctl_dhashstats> ();
  clnt_stat err = c->scall (LSDCTL_GETDHASHSTATS, &vnode, ds);
  if (err)
    fatal << "lsdctl_getdhashstats: " << err << "\n";

  strbuf out;
  out << "Statistics:\n";
  for (size_t i = 0; i < ds->stats.size (); i++)
    out << "  " << ds->stats[i].desc << " " << ds->stats[i].value << "\n";
  for (size_t i = 0; i < ds->blocks.size (); i++)
    out << ds->blocks[i].id << "\t" << ds->blocks[i].missing.size () << "\n";
  out << ds->hack;
  make_sync (1);
  out.tosuio ()->output (1);
  exit (0);
}

int
main (int argc, char *argv[])
{
  setprogname (argv[0]);
  putenv ("POSIXLY_CORRECT=1"); // Prevents Linux from reordering options

  int ch;
  while ((ch = getopt (argc, argv, "S:vq")) != -1)
    switch (ch) {
    case 'S':
      control_socket = optarg;
      break;
    case 'v':
      opt_verbose = true;
      break;
    case 'q':
      opt_quiet = true;
      break;
    default:
      usage ();
      break;
    }
  if (optind >= argc)
    usage ();

  // Prepare to dispatch on command name
  const modevec *mp;
  for (mp = modes; mp->name; mp++)
    if (!strcmp (argv[optind], mp->name))
      break;
  if (!mp->name)
    usage ();
  lsdctl_mode = mp;

  // Skip over command name...
  optind++;

  mp->fn (argc, argv);
  // amain ();

  return 0;
}
<|endoftext|>