<commit_before>//---------------------------------------------------------- -*- Mode: C++ -*-
// $Id$
//
// Created 2006/03/14
// Author: Sriram Rao
//
// Copyright 2008 Quantcast Corp.
// Copyright 2006-2008 Kosmix Corp.
//
// This file is part of Kosmos File System (KFS).
//
// Licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//
//----------------------------------------------------------------------------

#include <sys/poll.h>
#include <cerrno>
#include <boost/scoped_array.hpp>

#include "NetManager.h"
#include "TcpSocket.h"
#include "Globals.h"

#include "common/log.h"
#include "kfsutils.h"

using std::mem_fun;
using std::list;

using namespace KFS;
using namespace KFS::libkfsio;

NetManager::NetManager(int timeoutMs)
    : mRemove(),
      mTimerWheelBucketItr(mRemove.end()),
      mCurConnection(0),
      mCurTimerWheelSlot(0),
      mConnectionsCount(0),
      mDiskOverloaded(false),
      mNetworkOverloaded(false),
      mIsOverloaded(false),
      mRunFlag(true),
      mTimerRunningFlag(false),
      mTimeoutMs(timeoutMs),
      mNow(time(0)),
      mMaxOutgoingBacklog(0),
      mNumBytesToSend(0),
      mPoll(*(new FdPoll()))
{}

NetManager::~NetManager()
{
    NetManager::CleanUp();
    delete &mPoll;
}

void
NetManager::AddConnection(NetConnectionPtr &conn)
{
    NetConnection::NetManagerEntry* const entry =
        conn->GetNetMangerEntry(*this);
    if (! entry) {
        return;
    }
    if (! entry->mAdded) {
        entry->mTimerWheelSlot = kTimerWheelSize;
        entry->mListIt = mTimerWheel[kTimerWheelSize].insert(
            mTimerWheel[kTimerWheelSize].end(), conn);
        mConnectionsCount++;
        assert(mConnectionsCount > 0);
        entry->mAdded = true;
    }
    conn->Update();
}

void
NetManager::RegisterTimeoutHandler(ITimeout *handler)
{
    list<ITimeout *>::iterator iter;
    for (iter = mTimeoutHandlers.begin(); iter != mTimeoutHandlers.end();
         ++iter) {
        if (*iter == handler) {
            return;
        }
    }
    mTimeoutHandlers.push_back(handler);
}

void
NetManager::UnRegisterTimeoutHandler(ITimeout *handler)
{
    if (handler == NULL)
        return;

    list<ITimeout *>::iterator iter;
    for (iter = mTimeoutHandlers.begin(); iter != mTimeoutHandlers.end();
            ++iter) {
        if (*iter == handler) {
            // Not not remove list element: this can be called when iterating
            // trough the list.
            *iter = 0;
            return;
        }
    }
}

inline void
NetManager::UpdateTimer(NetConnection::NetManagerEntry& entry, int timeOut)
{
    assert(entry.mAdded);

    int timerWheelSlot;
    if (timeOut < 0) {
        timerWheelSlot = kTimerWheelSize;
    } else if ((timerWheelSlot = mCurTimerWheelSlot +
            // When the timer is running the effective wheel size "grows" by 1:
            // leave (move) entries with timeouts >= kTimerWheelSize in (to) the
            // current slot.
            std::min((kTimerWheelSize - mTimerRunningFlag ? 0 : 1), timeOut)) >=
            kTimerWheelSize) {
        timerWheelSlot -= kTimerWheelSize;
    }
    // This method can be invoked from timeout handler.
    // Make sure  that the entry doesn't get moved to the end of the current
    // list, which can be traversed by the timer.
    if (timerWheelSlot != entry.mTimerWheelSlot) {
        if (mTimerWheelBucketItr == entry.mListIt) {
            ++mTimerWheelBucketItr;
        }
        mTimerWheel[timerWheelSlot].splice(
            mTimerWheel[timerWheelSlot].end(),
            mTimerWheel[entry.mTimerWheelSlot], entry.mListIt);
        entry.mTimerWheelSlot = timerWheelSlot;
    }
}

inline static int CheckFatalSysError(int err, const char* msg)
{
    if (err) {
        std::string const msg = KFSUtils::SysError(err);
        KFS_LOG_VA_FATAL("%s: %d %s", err, msg.c_str());
        abort();
    }
    return err;
}

void
NetManager::Update(NetConnection::NetManagerEntry& entry, int fd, bool resetTimer)
{
    if (! entry.mAdded) {
        return;
    }
    assert(*entry.mListIt);
    NetConnection& conn = **entry.mListIt;
    assert(fd >= 0 || ! conn.IsGood());
    // Always check if connection has to be removed: this method always
    // called before socket fd gets closed.
    if (! conn.IsGood() || fd < 0) {
        if (entry.mFd >= 0) {
            CheckFatalSysError(
                mPoll.Remove(entry.mFd),
                "failed to removed fd from poll set"
            );
            entry.mFd = -1;
        }
        assert(mConnectionsCount > 0 &&
            entry.mWriteByteCount >= 0 &&
            entry.mWriteByteCount <= mNumBytesToSend);
        entry.mAdded = false;
        mConnectionsCount--;
        mNumBytesToSend -= entry.mWriteByteCount;
        if (mTimerWheelBucketItr == entry.mListIt) {
            ++mTimerWheelBucketItr;
        }
        mRemove.splice(mRemove.end(),
            mTimerWheel[entry.mTimerWheelSlot], entry.mListIt);
        return;
    }
    if (&conn == mCurConnection) {
        // Defer all updates for the currently dispatched connection until the
        // end of the event dispatch loop.
        return;
    }
    // Update timer.
    if (resetTimer) {
        const int timeOut = conn.GetInactivityTimeout();
        if (timeOut >= 0) {
            entry.mExpirationTime = mNow + timeOut;
        }
        UpdateTimer(entry, timeOut);
    }
    // Update pending send.
    assert(entry.mWriteByteCount >= 0 &&
        entry.mWriteByteCount <= mNumBytesToSend);
    mNumBytesToSend -= entry.mWriteByteCount;
    entry.mWriteByteCount = std::max(0, conn.GetNumBytesToWrite());
    mNumBytesToSend += entry.mWriteByteCount;
    // Update poll set.
    const bool in  = conn.IsReadReady() &&
        (! mIsOverloaded || entry.mEnableReadIfOverloaded);
    const bool out = conn.IsWriteReady() || entry.mConnectPending;
    if (in != entry.mIn || out != entry.mOut) {
        assert(fd >= 0);
        const int op =
            (in ? FdPoll::kOpTypeIn : 0) + (out ? FdPoll::kOpTypeOut : 0);
        if (fd != entry.mFd && entry.mFd >= 0) {
            CheckFatalSysError(
                mPoll.Remove(entry.mFd),
                "failed to removed fd from poll set"
            );
            entry.mFd = -1;
        }
        if (entry.mFd < 0) {
            if (op && CheckFatalSysError(
                    mPoll.Add(fd, op, &conn),
                    "failed to add fd to poll set") == 0) {
                entry.mFd = fd;
            }
        } else {
            CheckFatalSysError(
                mPoll.Set(fd, op, &conn),
                "failed to change pool flags"
            );
        }
        entry.mIn  = in  && entry.mFd >= 0;
        entry.mOut = out && entry.mFd >= 0;
    }
}

void
NetManager::MainLoop()
{
    mNow = time(0);
    time_t lastTimerTime = mNow;
    CheckFatalSysError(
        mPoll.Add(globals().netKicker.GetFd(), FdPoll::kOpTypeIn),
        "failed to add net kicker's fd to poll set"
    );
    const int timerOverrunWarningTime(mTimeoutMs / (1000/2));
    while (mRunFlag) {
        const bool wasOverloaded = mIsOverloaded;
        CheckIfOverloaded();
        if (mIsOverloaded != wasOverloaded) {
            KFS_LOG_VA_INFO(
                "%s (%0.f bytes to send; %d disk IO's) ",
                mIsOverloaded ?
                    "System is now in overloaded state " :
                    "Clearing system overload state",
                double(mNumBytesToSend),
                globals().diskManager.NumDiskIOOutstanding());
            for (int i = 0; i <= kTimerWheelSize; i++) {
                for (List::iterator c = mTimerWheel[i].begin();
                        c != mTimerWheel[i].end(); ) {
                    assert(*c);
                    NetConnection& conn = **c;
                    ++c;
                    conn.Update(false);
                }
            }
        }
        const int ret = mPoll.Poll(mConnectionsCount + 1, mTimeoutMs);
        if (ret < 0 && ret != -EINTR && ret != -EAGAIN) {
            std::string const msg = KFSUtils::SysError(-ret);
            KFS_LOG_VA_ERROR("poll errror %d %s",  -ret, msg.c_str());
        }
        globals().netKicker.Drain();
        const int64_t nowMs = ITimeout::NowMs();
        mNow = time_t(nowMs / 1000);
        globals().diskManager.ReapCompletedIOs();
        // Unregister will set pointer to 0, but will never remove the list
        // node, so that the iterator always remains valid.
        for (std::list<ITimeout *>::iterator it = mTimeoutHandlers.begin();
                it != mTimeoutHandlers.end(); ) {
            if (*it) {
                (*it)->TimerExpired(nowMs);
            }
            if (*it) {
                ++it;
            } else {
                it = mTimeoutHandlers.erase(it);
            }
        }
        /// Process poll events.
        int   op;
        void* ptr;
        while (mPoll.Next(op, ptr)) {
            if (op == 0 || ! ptr) {
                continue;
            }
            NetConnection& conn = *reinterpret_cast<NetConnection*>(ptr);
            assert(conn.GetNetMangerEntry(*this)->mAdded);
            // Defer update for this connection.
            mCurConnection = &conn;
            if ((op & FdPoll::kOpTypeIn) != 0 && conn.IsGood()) {
                conn.HandleReadEvent();
            }
            if ((op & FdPoll::kOpTypeOut) != 0 && conn.IsGood()) {
                conn.HandleWriteEvent();
            }
            if ((op & (FdPoll::kOpTypeError | FdPoll::kOpTypeHup)) != 0 &&
                    conn.IsGood()) {
                conn.HandleErrorEvent();
            }
            // Try to write, if the last write was sucessfull.
            conn.StartFlush();
            // Update the connection.
            mCurConnection = 0;
            conn.Update();
        }
        mRemove.clear();
        mNow = time(0);
        int slotCnt = std::min(int(kTimerWheelSize), int(mNow - lastTimerTime));
        if (slotCnt > timerOverrunWarningTime) {
            KFS_LOG_VA_DEBUG("Timer overrun %d seconds detected", slotCnt - 1);
        }
        mTimerRunningFlag = true;
        while (slotCnt-- > 0) {
            List& bucket = mTimerWheel[mCurTimerWheelSlot];
            mTimerWheelBucketItr = bucket.begin();
            while (mTimerWheelBucketItr != bucket.end()) {
                assert(*mTimerWheelBucketItr);
                NetConnection& conn = **mTimerWheelBucketItr;
                assert(conn.IsGood());
                ++mTimerWheelBucketItr;
                NetConnection::NetManagerEntry& entry =
                    *conn.GetNetMangerEntry(*this);
                const int timeOut = conn.GetInactivityTimeout();
                if (timeOut < 0) {
                    // No timeout, move it to the corresponding list.
                    UpdateTimer(entry, timeOut);
                } else if (entry.mExpirationTime <= mNow) {
                    conn.HandleTimeoutEvent();
                } else {
                    // Not expired yet, move to the new slot, taking into the
                    // account possible timer overrun.
                    UpdateTimer(entry,
                        slotCnt + int(entry.mExpirationTime - mNow));
                }
            }
            if (++mCurTimerWheelSlot >= kTimerWheelSize) {
                mCurTimerWheelSlot = 0;
            }
            mRemove.clear();
        }
        mTimerRunningFlag = false;
        lastTimerTime = mNow;
        mTimerWheelBucketItr = mRemove.end();
    }
    CheckFatalSysError(
        mPoll.Remove(globals().netKicker.GetFd()),
        "failed to removed net kicker's fd from poll set"
    );
    CleanUp();
}

void
NetManager::CheckIfOverloaded()
{
    if (mMaxOutgoingBacklog > 0) {
        if (!mNetworkOverloaded) {
            mNetworkOverloaded = (mNumBytesToSend > mMaxOutgoingBacklog);
        } else if (mNumBytesToSend <= mMaxOutgoingBacklog / 2) {
            // network was overloaded and that has now cleared
            mNetworkOverloaded = false;
        }
    }
    mIsOverloaded = mDiskOverloaded || mNetworkOverloaded;
}

void
NetManager::ChangeDiskOverloadState(bool v)
{
    if (mDiskOverloaded == v)
        return;
    mDiskOverloaded = v;
}

void
NetManager::CleanUp()
{
    mTimeoutHandlers.clear();
    for (int i = 0; i <= kTimerWheelSize; i++) {
        for (mTimerWheelBucketItr = mTimerWheel[i].begin();
                mTimerWheelBucketItr != mTimerWheel[i].end(); ) {
            NetConnection* const conn = mTimerWheelBucketItr->get();
            ++mTimerWheelBucketItr;
            if (conn) {
                if (conn->IsGood()) {
                    conn->HandleErrorEvent();
                }
                conn->Close();
            }
        }
        assert(mTimerWheel[i].empty());
        mRemove.clear();
    }
    mTimerWheelBucketItr = mRemove.end();
}
<commit_msg> -- Remove an invalid assertion: when stale events are received on a connection  that is closed, ignore the event; previously, we were incorrectly asserting.<commit_after>//---------------------------------------------------------- -*- Mode: C++ -*-
// $Id$
//
// Created 2006/03/14
// Author: Sriram Rao
//
// Copyright 2008 Quantcast Corp.
// Copyright 2006-2008 Kosmix Corp.
//
// This file is part of Kosmos File System (KFS).
//
// Licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//
//----------------------------------------------------------------------------

#include <sys/poll.h>
#include <cerrno>
#include <boost/scoped_array.hpp>

#include "NetManager.h"
#include "TcpSocket.h"
#include "Globals.h"

#include "common/log.h"
#include "kfsutils.h"

using std::mem_fun;
using std::list;

using namespace KFS;
using namespace KFS::libkfsio;

NetManager::NetManager(int timeoutMs)
    : mRemove(),
      mTimerWheelBucketItr(mRemove.end()),
      mCurConnection(0),
      mCurTimerWheelSlot(0),
      mConnectionsCount(0),
      mDiskOverloaded(false),
      mNetworkOverloaded(false),
      mIsOverloaded(false),
      mRunFlag(true),
      mTimerRunningFlag(false),
      mTimeoutMs(timeoutMs),
      mNow(time(0)),
      mMaxOutgoingBacklog(0),
      mNumBytesToSend(0),
      mPoll(*(new FdPoll()))
{}

NetManager::~NetManager()
{
    NetManager::CleanUp();
    delete &mPoll;
}

void
NetManager::AddConnection(NetConnectionPtr &conn)
{
    NetConnection::NetManagerEntry* const entry =
        conn->GetNetMangerEntry(*this);
    if (! entry) {
        return;
    }
    if (! entry->mAdded) {
        entry->mTimerWheelSlot = kTimerWheelSize;
        entry->mListIt = mTimerWheel[kTimerWheelSize].insert(
            mTimerWheel[kTimerWheelSize].end(), conn);
        mConnectionsCount++;
        assert(mConnectionsCount > 0);
        entry->mAdded = true;
    }
    conn->Update();
}

void
NetManager::RegisterTimeoutHandler(ITimeout *handler)
{
    list<ITimeout *>::iterator iter;
    for (iter = mTimeoutHandlers.begin(); iter != mTimeoutHandlers.end();
         ++iter) {
        if (*iter == handler) {
            return;
        }
    }
    mTimeoutHandlers.push_back(handler);
}

void
NetManager::UnRegisterTimeoutHandler(ITimeout *handler)
{
    if (handler == NULL)
        return;

    list<ITimeout *>::iterator iter;
    for (iter = mTimeoutHandlers.begin(); iter != mTimeoutHandlers.end();
            ++iter) {
        if (*iter == handler) {
            // Not not remove list element: this can be called when iterating
            // trough the list.
            *iter = 0;
            return;
        }
    }
}

inline void
NetManager::UpdateTimer(NetConnection::NetManagerEntry& entry, int timeOut)
{
    assert(entry.mAdded);

    int timerWheelSlot;
    if (timeOut < 0) {
        timerWheelSlot = kTimerWheelSize;
    } else if ((timerWheelSlot = mCurTimerWheelSlot +
            // When the timer is running the effective wheel size "grows" by 1:
            // leave (move) entries with timeouts >= kTimerWheelSize in (to) the
            // current slot.
            std::min((kTimerWheelSize - mTimerRunningFlag ? 0 : 1), timeOut)) >=
            kTimerWheelSize) {
        timerWheelSlot -= kTimerWheelSize;
    }
    // This method can be invoked from timeout handler.
    // Make sure  that the entry doesn't get moved to the end of the current
    // list, which can be traversed by the timer.
    if (timerWheelSlot != entry.mTimerWheelSlot) {
        if (mTimerWheelBucketItr == entry.mListIt) {
            ++mTimerWheelBucketItr;
        }
        mTimerWheel[timerWheelSlot].splice(
            mTimerWheel[timerWheelSlot].end(),
            mTimerWheel[entry.mTimerWheelSlot], entry.mListIt);
        entry.mTimerWheelSlot = timerWheelSlot;
    }
}

inline static int CheckFatalSysError(int err, const char* msg)
{
    if (err) {
        std::string const msg = KFSUtils::SysError(err);
        KFS_LOG_VA_FATAL("%s: %d %s", err, msg.c_str());
        abort();
    }
    return err;
}

void
NetManager::Update(NetConnection::NetManagerEntry& entry, int fd, bool resetTimer)
{
    if (! entry.mAdded) {
        return;
    }
    assert(*entry.mListIt);
    NetConnection& conn = **entry.mListIt;
    assert(fd >= 0 || ! conn.IsGood());
    // Always check if connection has to be removed: this method always
    // called before socket fd gets closed.
    if (! conn.IsGood() || fd < 0) {
        if (entry.mFd >= 0) {
            CheckFatalSysError(
                mPoll.Remove(entry.mFd),
                "failed to removed fd from poll set"
            );
            entry.mFd = -1;
        }
        assert(mConnectionsCount > 0 &&
            entry.mWriteByteCount >= 0 &&
            entry.mWriteByteCount <= mNumBytesToSend);
        entry.mAdded = false;
        mConnectionsCount--;
        mNumBytesToSend -= entry.mWriteByteCount;
        if (mTimerWheelBucketItr == entry.mListIt) {
            ++mTimerWheelBucketItr;
        }
        mRemove.splice(mRemove.end(),
            mTimerWheel[entry.mTimerWheelSlot], entry.mListIt);
        return;
    }
    if (&conn == mCurConnection) {
        // Defer all updates for the currently dispatched connection until the
        // end of the event dispatch loop.
        return;
    }
    // Update timer.
    if (resetTimer) {
        const int timeOut = conn.GetInactivityTimeout();
        if (timeOut >= 0) {
            entry.mExpirationTime = mNow + timeOut;
        }
        UpdateTimer(entry, timeOut);
    }
    // Update pending send.
    assert(entry.mWriteByteCount >= 0 &&
        entry.mWriteByteCount <= mNumBytesToSend);
    mNumBytesToSend -= entry.mWriteByteCount;
    entry.mWriteByteCount = std::max(0, conn.GetNumBytesToWrite());
    mNumBytesToSend += entry.mWriteByteCount;
    // Update poll set.
    const bool in  = conn.IsReadReady() &&
        (! mIsOverloaded || entry.mEnableReadIfOverloaded);
    const bool out = conn.IsWriteReady() || entry.mConnectPending;
    if (in != entry.mIn || out != entry.mOut) {
        assert(fd >= 0);
        const int op =
            (in ? FdPoll::kOpTypeIn : 0) + (out ? FdPoll::kOpTypeOut : 0);
        if (fd != entry.mFd && entry.mFd >= 0) {
            CheckFatalSysError(
                mPoll.Remove(entry.mFd),
                "failed to removed fd from poll set"
            );
            entry.mFd = -1;
        }
        if (entry.mFd < 0) {
            if (op && CheckFatalSysError(
                    mPoll.Add(fd, op, &conn),
                    "failed to add fd to poll set") == 0) {
                entry.mFd = fd;
            }
        } else {
            CheckFatalSysError(
                mPoll.Set(fd, op, &conn),
                "failed to change pool flags"
            );
        }
        entry.mIn  = in  && entry.mFd >= 0;
        entry.mOut = out && entry.mFd >= 0;
    }
}

void
NetManager::MainLoop()
{
    mNow = time(0);
    time_t lastTimerTime = mNow;
    CheckFatalSysError(
        mPoll.Add(globals().netKicker.GetFd(), FdPoll::kOpTypeIn),
        "failed to add net kicker's fd to poll set"
    );
    const int timerOverrunWarningTime(mTimeoutMs / (1000/2));
    while (mRunFlag) {
        const bool wasOverloaded = mIsOverloaded;
        CheckIfOverloaded();
        if (mIsOverloaded != wasOverloaded) {
            KFS_LOG_VA_INFO(
                "%s (%0.f bytes to send; %d disk IO's) ",
                mIsOverloaded ?
                    "System is now in overloaded state " :
                    "Clearing system overload state",
                double(mNumBytesToSend),
                globals().diskManager.NumDiskIOOutstanding());
            for (int i = 0; i <= kTimerWheelSize; i++) {
                for (List::iterator c = mTimerWheel[i].begin();
                        c != mTimerWheel[i].end(); ) {
                    assert(*c);
                    NetConnection& conn = **c;
                    ++c;
                    conn.Update(false);
                }
            }
        }
        const int ret = mPoll.Poll(mConnectionsCount + 1, mTimeoutMs);
        if (ret < 0 && ret != -EINTR && ret != -EAGAIN) {
            std::string const msg = KFSUtils::SysError(-ret);
            KFS_LOG_VA_ERROR("poll errror %d %s",  -ret, msg.c_str());
        }
        globals().netKicker.Drain();
        const int64_t nowMs = ITimeout::NowMs();
        mNow = time_t(nowMs / 1000);
        globals().diskManager.ReapCompletedIOs();
        // Unregister will set pointer to 0, but will never remove the list
        // node, so that the iterator always remains valid.
        for (std::list<ITimeout *>::iterator it = mTimeoutHandlers.begin();
                it != mTimeoutHandlers.end(); ) {
            if (*it) {
                (*it)->TimerExpired(nowMs);
            }
            if (*it) {
                ++it;
            } else {
                it = mTimeoutHandlers.erase(it);
            }
        }
        /// Process poll events.
        int   op;
        void* ptr;
        while (mPoll.Next(op, ptr)) {
            if (op == 0 || ! ptr) {
                continue;
            }
            NetConnection& conn = *reinterpret_cast<NetConnection*>(ptr);
            if (! conn.GetNetMangerEntry(*this)->mAdded) {
                // Skip stale event, the conection should be in mRemove list.
                continue;
            }
            // Defer update for this connection.
            mCurConnection = &conn;
            if ((op & FdPoll::kOpTypeIn) != 0 && conn.IsGood()) {
                conn.HandleReadEvent();
            }
            if ((op & FdPoll::kOpTypeOut) != 0 && conn.IsGood()) {
                conn.HandleWriteEvent();
            }
            if ((op & (FdPoll::kOpTypeError | FdPoll::kOpTypeHup)) != 0 &&
                    conn.IsGood()) {
                conn.HandleErrorEvent();
            }
            // Try to write, if the last write was sucessfull.
            conn.StartFlush();
            // Update the connection.
            mCurConnection = 0;
            conn.Update();
        }
        mRemove.clear();
        mNow = time(0);
        int slotCnt = std::min(int(kTimerWheelSize), int(mNow - lastTimerTime));
        if (slotCnt > timerOverrunWarningTime) {
            KFS_LOG_VA_DEBUG("Timer overrun %d seconds detected", slotCnt - 1);
        }
        mTimerRunningFlag = true;
        while (slotCnt-- > 0) {
            List& bucket = mTimerWheel[mCurTimerWheelSlot];
            mTimerWheelBucketItr = bucket.begin();
            while (mTimerWheelBucketItr != bucket.end()) {
                assert(*mTimerWheelBucketItr);
                NetConnection& conn = **mTimerWheelBucketItr;
                assert(conn.IsGood());
                ++mTimerWheelBucketItr;
                NetConnection::NetManagerEntry& entry =
                    *conn.GetNetMangerEntry(*this);
                const int timeOut = conn.GetInactivityTimeout();
                if (timeOut < 0) {
                    // No timeout, move it to the corresponding list.
                    UpdateTimer(entry, timeOut);
                } else if (entry.mExpirationTime <= mNow) {
                    conn.HandleTimeoutEvent();
                } else {
                    // Not expired yet, move to the new slot, taking into the
                    // account possible timer overrun.
                    UpdateTimer(entry,
                        slotCnt + int(entry.mExpirationTime - mNow));
                }
            }
            if (++mCurTimerWheelSlot >= kTimerWheelSize) {
                mCurTimerWheelSlot = 0;
            }
            mRemove.clear();
        }
        mTimerRunningFlag = false;
        lastTimerTime = mNow;
        mTimerWheelBucketItr = mRemove.end();
    }
    CheckFatalSysError(
        mPoll.Remove(globals().netKicker.GetFd()),
        "failed to removed net kicker's fd from poll set"
    );
    CleanUp();
}

void
NetManager::CheckIfOverloaded()
{
    if (mMaxOutgoingBacklog > 0) {
        if (!mNetworkOverloaded) {
            mNetworkOverloaded = (mNumBytesToSend > mMaxOutgoingBacklog);
        } else if (mNumBytesToSend <= mMaxOutgoingBacklog / 2) {
            // network was overloaded and that has now cleared
            mNetworkOverloaded = false;
        }
    }
    mIsOverloaded = mDiskOverloaded || mNetworkOverloaded;
}

void
NetManager::ChangeDiskOverloadState(bool v)
{
    if (mDiskOverloaded == v)
        return;
    mDiskOverloaded = v;
}

void
NetManager::CleanUp()
{
    mTimeoutHandlers.clear();
    for (int i = 0; i <= kTimerWheelSize; i++) {
        for (mTimerWheelBucketItr = mTimerWheel[i].begin();
                mTimerWheelBucketItr != mTimerWheel[i].end(); ) {
            NetConnection* const conn = mTimerWheelBucketItr->get();
            ++mTimerWheelBucketItr;
            if (conn) {
                if (conn->IsGood()) {
                    conn->HandleErrorEvent();
                }
                conn->Close();
            }
        }
        assert(mTimerWheel[i].empty());
        mRemove.clear();
    }
    mTimerWheelBucketItr = mRemove.end();
}
<|endoftext|>


<commit_before>//---------------------------------------------------------- -*- Mode: C++ -*-
// $Id$
//
// Created 2006/03/14
// Author: Sriram Rao
//
// Copyright 2008 Quantcast Corp.
// Copyright 2006-2008 Kosmix Corp.
//
// This file is part of Kosmos File System (KFS).
//
// Licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//
//----------------------------------------------------------------------------

#include <sys/poll.h>
#include <cerrno>
#include <boost/scoped_array.hpp>

#include "NetManager.h"
#include "TcpSocket.h"
#include "Globals.h"

#include "common/log.h"
#include "kfsutils.h"

using std::mem_fun;
using std::list;

using namespace KFS;
using namespace KFS::libkfsio;

NetManager::NetManager(int timeoutMs)
    : mRemove(),
      mTimerWheelBucketItr(mRemove.end()),
      mCurConnection(0),
      mCurTimerWheelSlot(0),
      mConnectionsCount(0),
      mDiskOverloaded(false),
      mNetworkOverloaded(false),
      mIsOverloaded(false),
      mRunFlag(true),
      mTimerRunningFlag(false),
      mIsForkedChild(false),
      mTimeoutMs(timeoutMs),
      mNow(time(0)),
      mMaxOutgoingBacklog(0),
      mNumBytesToSend(0),
      mPoll(*(new FdPoll()))
{}

NetManager::~NetManager()
{
    NetManager::CleanUp();
    delete &mPoll;
}

void
NetManager::AddConnection(NetConnectionPtr &conn)
{
    NetConnection::NetManagerEntry* const entry =
        conn->GetNetMangerEntry(*this);
    if (! entry) {
        return;
    }
    if (! entry->mAdded) {
        entry->mTimerWheelSlot = kTimerWheelSize;
        entry->mListIt = mTimerWheel[kTimerWheelSize].insert(
            mTimerWheel[kTimerWheelSize].end(), conn);
        mConnectionsCount++;
        assert(mConnectionsCount > 0);
        entry->mAdded = true;
    }
    conn->Update();
}

void
NetManager::RegisterTimeoutHandler(ITimeout *handler)
{
    list<ITimeout *>::iterator iter;
    for (iter = mTimeoutHandlers.begin(); iter != mTimeoutHandlers.end();
         ++iter) {
        if (*iter == handler) {
            return;
        }
    }
    mTimeoutHandlers.push_back(handler);
}

void
NetManager::UnRegisterTimeoutHandler(ITimeout *handler)
{
    if (handler == NULL)
        return;

    list<ITimeout *>::iterator iter;
    for (iter = mTimeoutHandlers.begin(); iter != mTimeoutHandlers.end();
            ++iter) {
        if (*iter == handler) {
            // Not not remove list element: this can be called when iterating
            // trough the list.
            *iter = 0;
            return;
        }
    }
}

inline void
NetManager::UpdateTimer(NetConnection::NetManagerEntry& entry, int timeOut)
{
    assert(entry.mAdded);

    int timerWheelSlot;
    if (timeOut < 0) {
        timerWheelSlot = kTimerWheelSize;
    } else if ((timerWheelSlot = mCurTimerWheelSlot +
            // When the timer is running the effective wheel size "grows" by 1:
            // leave (move) entries with timeouts >= kTimerWheelSize in (to) the
            // current slot.
            std::min((kTimerWheelSize - mTimerRunningFlag ? 0 : 1), timeOut)) >=
            kTimerWheelSize) {
        timerWheelSlot -= kTimerWheelSize;
    }
    // This method can be invoked from timeout handler.
    // Make sure  that the entry doesn't get moved to the end of the current
    // list, which can be traversed by the timer.
    if (timerWheelSlot != entry.mTimerWheelSlot) {
        if (mTimerWheelBucketItr == entry.mListIt) {
            ++mTimerWheelBucketItr;
        }
        mTimerWheel[timerWheelSlot].splice(
            mTimerWheel[timerWheelSlot].end(),
            mTimerWheel[entry.mTimerWheelSlot], entry.mListIt);
        entry.mTimerWheelSlot = timerWheelSlot;
    }
}

inline static int CheckFatalSysError(int err, const char* msg)
{
    if (err) {
        std::string const sysMsg = KFSUtils::SysError(err);
        KFS_LOG_VA_FATAL("%s: %d %s", msg ? msg : "", err, sysMsg.c_str());
        abort();
    }
    return err;
}

void
NetManager::Update(NetConnection::NetManagerEntry& entry, int fd, bool resetTimer)
{
    if ((! entry.mAdded) || (mIsForkedChild)) {
        return;
    }
    assert(*entry.mListIt);
    NetConnection& conn = **entry.mListIt;
    assert(fd >= 0 || ! conn.IsGood());
    // Always check if connection has to be removed: this method always
    // called before socket fd gets closed.
    if (! conn.IsGood() || fd < 0) {
        if (entry.mFd >= 0) {
            CheckFatalSysError(
                mPoll.Remove(entry.mFd),
                "failed to removed fd from poll set"
            );
            entry.mFd = -1;
        }
        assert(mConnectionsCount > 0 &&
            entry.mWriteByteCount >= 0 &&
            entry.mWriteByteCount <= mNumBytesToSend);
        entry.mAdded = false;
        mConnectionsCount--;
        mNumBytesToSend -= entry.mWriteByteCount;
        if (mTimerWheelBucketItr == entry.mListIt) {
            ++mTimerWheelBucketItr;
        }
        mRemove.splice(mRemove.end(),
            mTimerWheel[entry.mTimerWheelSlot], entry.mListIt);
        return;
    }
    if (&conn == mCurConnection) {
        // Defer all updates for the currently dispatched connection until the
        // end of the event dispatch loop.
        return;
    }
    // Update timer.
    if (resetTimer) {
        const int timeOut = conn.GetInactivityTimeout();
        if (timeOut >= 0) {
            entry.mExpirationTime = mNow + timeOut;
        }
        UpdateTimer(entry, timeOut);
    }
    // Update pending send.
    assert(entry.mWriteByteCount >= 0 &&
        entry.mWriteByteCount <= mNumBytesToSend);
    mNumBytesToSend -= entry.mWriteByteCount;
    entry.mWriteByteCount = std::max(0, conn.GetNumBytesToWrite());
    mNumBytesToSend += entry.mWriteByteCount;
    // Update poll set.
    const bool in  = conn.IsReadReady() &&
        (! mIsOverloaded || entry.mEnableReadIfOverloaded);
    const bool out = conn.IsWriteReady() || entry.mConnectPending;
    if (in != entry.mIn || out != entry.mOut) {
        assert(fd >= 0);
        const int op =
            (in ? FdPoll::kOpTypeIn : 0) + (out ? FdPoll::kOpTypeOut : 0);
        if (fd != entry.mFd && entry.mFd >= 0) {
            CheckFatalSysError(
                mPoll.Remove(entry.mFd),
                "failed to removed fd from poll set"
            );
            entry.mFd = -1;
        }
        if (entry.mFd < 0) {
            if (op && CheckFatalSysError(
                    mPoll.Add(fd, op, &conn),
                    "failed to add fd to poll set") == 0) {
                entry.mFd = fd;
            }
        } else {
            CheckFatalSysError(
                mPoll.Set(fd, op, &conn),
                "failed to change pool flags"
            );
        }
        entry.mIn  = in  && entry.mFd >= 0;
        entry.mOut = out && entry.mFd >= 0;
    }
}

void
NetManager::MainLoop()
{
    mNow = time(0);
    time_t lastTimerTime = mNow;
    CheckFatalSysError(
        mPoll.Add(globals().netKicker.GetFd(), FdPoll::kOpTypeIn),
        "failed to add net kicker's fd to poll set"
    );
    const int timerOverrunWarningTime(mTimeoutMs / (1000/2));
    while (mRunFlag) {
        const bool wasOverloaded = mIsOverloaded;
        CheckIfOverloaded();
        if (mIsOverloaded != wasOverloaded) {
            KFS_LOG_VA_INFO(
                "%s (%0.f bytes to send; %d disk IO's) ",
                mIsOverloaded ?
                    "System is now in overloaded state " :
                    "Clearing system overload state",
                double(mNumBytesToSend),
                globals().diskManager.NumDiskIOOutstanding());
            for (int i = 0; i <= kTimerWheelSize; i++) {
                for (List::iterator c = mTimerWheel[i].begin();
                        c != mTimerWheel[i].end(); ) {
                    assert(*c);
                    NetConnection& conn = **c;
                    ++c;
                    conn.Update(false);
                }
            }
        }
        const int ret = mPoll.Poll(mConnectionsCount + 1, mTimeoutMs);
        if (ret < 0 && ret != -EINTR && ret != -EAGAIN) {
            std::string const msg = KFSUtils::SysError(-ret);
            KFS_LOG_VA_ERROR("poll errror %d %s",  -ret, msg.c_str());
        }
        globals().netKicker.Drain();
        const int64_t nowMs = ITimeout::NowMs();
        mNow = time_t(nowMs / 1000);
        globals().diskManager.ReapCompletedIOs();
        // Unregister will set pointer to 0, but will never remove the list
        // node, so that the iterator always remains valid.
        for (std::list<ITimeout *>::iterator it = mTimeoutHandlers.begin();
                it != mTimeoutHandlers.end(); ) {
            if (*it) {
                (*it)->TimerExpired(nowMs);
            }
            if (*it) {
                ++it;
            } else {
                it = mTimeoutHandlers.erase(it);
            }
        }
        /// Process poll events.
        int   op;
        void* ptr;
        while (mPoll.Next(op, ptr)) {
            if (op == 0 || ! ptr) {
                continue;
            }
            NetConnection& conn = *reinterpret_cast<NetConnection*>(ptr);
            if (! conn.GetNetMangerEntry(*this)->mAdded) {
                // Skip stale event, the conection should be in mRemove list.
                continue;
            }
            // Defer update for this connection.
            mCurConnection = &conn;
            if ((op & FdPoll::kOpTypeIn) != 0 && conn.IsGood()) {
                conn.HandleReadEvent();
            }
            if ((op & FdPoll::kOpTypeOut) != 0 && conn.IsGood()) {
                conn.HandleWriteEvent();
            }
            if ((op & (FdPoll::kOpTypeError | FdPoll::kOpTypeHup)) != 0 &&
                    conn.IsGood()) {
                conn.HandleErrorEvent();
            }
            // Try to write, if the last write was sucessfull.
            conn.StartFlush();
            // Update the connection.
            mCurConnection = 0;
            conn.Update();
        }
        mRemove.clear();
        mNow = time(0);
        int slotCnt = std::min(int(kTimerWheelSize), int(mNow - lastTimerTime));
        if (slotCnt > timerOverrunWarningTime) {
            KFS_LOG_VA_DEBUG("Timer overrun %d seconds detected", slotCnt - 1);
        }
        mTimerRunningFlag = true;
        while (slotCnt-- > 0) {
            List& bucket = mTimerWheel[mCurTimerWheelSlot];
            mTimerWheelBucketItr = bucket.begin();
            while (mTimerWheelBucketItr != bucket.end()) {
                assert(*mTimerWheelBucketItr);
                NetConnection& conn = **mTimerWheelBucketItr;
                assert(conn.IsGood());
                ++mTimerWheelBucketItr;
                NetConnection::NetManagerEntry& entry =
                    *conn.GetNetMangerEntry(*this);
                const int timeOut = conn.GetInactivityTimeout();
                if (timeOut < 0) {
                    // No timeout, move it to the corresponding list.
                    UpdateTimer(entry, timeOut);
                } else if (entry.mExpirationTime <= mNow) {
                    conn.HandleTimeoutEvent();
                } else {
                    // Not expired yet, move to the new slot, taking into the
                    // account possible timer overrun.
                    UpdateTimer(entry,
                        slotCnt + int(entry.mExpirationTime - mNow));
                }
            }
            if (++mCurTimerWheelSlot >= kTimerWheelSize) {
                mCurTimerWheelSlot = 0;
            }
            mRemove.clear();
        }
        mTimerRunningFlag = false;
        lastTimerTime = mNow;
        mTimerWheelBucketItr = mRemove.end();
    }
    CheckFatalSysError(
        mPoll.Remove(globals().netKicker.GetFd()),
        "failed to removed net kicker's fd from poll set"
    );
    CleanUp();
}

void
NetManager::CheckIfOverloaded()
{
    if (mMaxOutgoingBacklog > 0) {
        if (!mNetworkOverloaded) {
            mNetworkOverloaded = (mNumBytesToSend > mMaxOutgoingBacklog);
        } else if (mNumBytesToSend <= mMaxOutgoingBacklog / 2) {
            // network was overloaded and that has now cleared
            mNetworkOverloaded = false;
        }
    }
    mIsOverloaded = mDiskOverloaded || mNetworkOverloaded;
}

void
NetManager::ChangeDiskOverloadState(bool v)
{
    if (mDiskOverloaded == v)
        return;
    mDiskOverloaded = v;
}

void
NetManager::CleanUp()
{
    mTimeoutHandlers.clear();
    for (int i = 0; i <= kTimerWheelSize; i++) {
        for (mTimerWheelBucketItr = mTimerWheel[i].begin();
                mTimerWheelBucketItr != mTimerWheel[i].end(); ) {
            NetConnection* const conn = mTimerWheelBucketItr->get();
            ++mTimerWheelBucketItr;
            if (conn) {
                if (conn->IsGood()) {
                    conn->HandleErrorEvent();
                }
                conn->Close();
            }
        }
        assert(mTimerWheel[i].empty());
        mRemove.clear();
    }
    mTimerWheelBucketItr = mRemove.end();
}
<commit_msg> -- Fix timer wheel slot calculation.<commit_after>//---------------------------------------------------------- -*- Mode: C++ -*-
// $Id$
//
// Created 2006/03/14
// Author: Sriram Rao
//
// Copyright 2008 Quantcast Corp.
// Copyright 2006-2008 Kosmix Corp.
//
// This file is part of Kosmos File System (KFS).
//
// Licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
//
//----------------------------------------------------------------------------

#include <sys/poll.h>
#include <cerrno>
#include <boost/scoped_array.hpp>

#include "NetManager.h"
#include "TcpSocket.h"
#include "Globals.h"

#include "common/log.h"
#include "kfsutils.h"

using std::mem_fun;
using std::list;

using namespace KFS;
using namespace KFS::libkfsio;

NetManager::NetManager(int timeoutMs)
    : mRemove(),
      mTimerWheelBucketItr(mRemove.end()),
      mCurConnection(0),
      mCurTimerWheelSlot(0),
      mConnectionsCount(0),
      mDiskOverloaded(false),
      mNetworkOverloaded(false),
      mIsOverloaded(false),
      mRunFlag(true),
      mTimerRunningFlag(false),
      mIsForkedChild(false),
      mTimeoutMs(timeoutMs),
      mNow(time(0)),
      mMaxOutgoingBacklog(0),
      mNumBytesToSend(0),
      mPoll(*(new FdPoll()))
{}

NetManager::~NetManager()
{
    NetManager::CleanUp();
    delete &mPoll;
}

void
NetManager::AddConnection(NetConnectionPtr &conn)
{
    NetConnection::NetManagerEntry* const entry =
        conn->GetNetMangerEntry(*this);
    if (! entry) {
        return;
    }
    if (! entry->mAdded) {
        entry->mTimerWheelSlot = kTimerWheelSize;
        entry->mListIt = mTimerWheel[kTimerWheelSize].insert(
            mTimerWheel[kTimerWheelSize].end(), conn);
        mConnectionsCount++;
        assert(mConnectionsCount > 0);
        entry->mAdded = true;
    }
    conn->Update();
}

void
NetManager::RegisterTimeoutHandler(ITimeout *handler)
{
    list<ITimeout *>::iterator iter;
    for (iter = mTimeoutHandlers.begin(); iter != mTimeoutHandlers.end();
         ++iter) {
        if (*iter == handler) {
            return;
        }
    }
    mTimeoutHandlers.push_back(handler);
}

void
NetManager::UnRegisterTimeoutHandler(ITimeout *handler)
{
    if (handler == NULL)
        return;

    list<ITimeout *>::iterator iter;
    for (iter = mTimeoutHandlers.begin(); iter != mTimeoutHandlers.end();
            ++iter) {
        if (*iter == handler) {
            // Not not remove list element: this can be called when iterating
            // trough the list.
            *iter = 0;
            return;
        }
    }
}

inline void
NetManager::UpdateTimer(NetConnection::NetManagerEntry& entry, int timeOut)
{
    assert(entry.mAdded);

    int timerWheelSlot;
    if (timeOut < 0) {
        timerWheelSlot = kTimerWheelSize;
    } else if ((timerWheelSlot = mCurTimerWheelSlot +
            // When the timer is running the effective wheel size "grows" by 1:
            // leave (move) entries with timeouts >= kTimerWheelSize in (to) the
            // current slot.
            std::min((kTimerWheelSize - (mTimerRunningFlag ? 0 : 1)), timeOut)) >=
            kTimerWheelSize) {
        timerWheelSlot -= kTimerWheelSize;
    }
    // This method can be invoked from timeout handler.
    // Make sure  that the entry doesn't get moved to the end of the current
    // list, which can be traversed by the timer.
    if (timerWheelSlot != entry.mTimerWheelSlot) {
        if (mTimerWheelBucketItr == entry.mListIt) {
            ++mTimerWheelBucketItr;
        }
        mTimerWheel[timerWheelSlot].splice(
            mTimerWheel[timerWheelSlot].end(),
            mTimerWheel[entry.mTimerWheelSlot], entry.mListIt);
        entry.mTimerWheelSlot = timerWheelSlot;
    }
}

inline static int CheckFatalSysError(int err, const char* msg)
{
    if (err) {
        std::string const sysMsg = KFSUtils::SysError(err);
        KFS_LOG_VA_FATAL("%s: %d %s", msg ? msg : "", err, sysMsg.c_str());
        abort();
    }
    return err;
}

void
NetManager::Update(NetConnection::NetManagerEntry& entry, int fd, bool resetTimer)
{
    if ((! entry.mAdded) || (mIsForkedChild)) {
        return;
    }
    assert(*entry.mListIt);
    NetConnection& conn = **entry.mListIt;
    assert(fd >= 0 || ! conn.IsGood());
    // Always check if connection has to be removed: this method always
    // called before socket fd gets closed.
    if (! conn.IsGood() || fd < 0) {
        if (entry.mFd >= 0) {
            CheckFatalSysError(
                mPoll.Remove(entry.mFd),
                "failed to removed fd from poll set"
            );
            entry.mFd = -1;
        }
        assert(mConnectionsCount > 0 &&
            entry.mWriteByteCount >= 0 &&
            entry.mWriteByteCount <= mNumBytesToSend);
        entry.mAdded = false;
        mConnectionsCount--;
        mNumBytesToSend -= entry.mWriteByteCount;
        if (mTimerWheelBucketItr == entry.mListIt) {
            ++mTimerWheelBucketItr;
        }
        mRemove.splice(mRemove.end(),
            mTimerWheel[entry.mTimerWheelSlot], entry.mListIt);
        return;
    }
    if (&conn == mCurConnection) {
        // Defer all updates for the currently dispatched connection until the
        // end of the event dispatch loop.
        return;
    }
    // Update timer.
    if (resetTimer) {
        const int timeOut = conn.GetInactivityTimeout();
        if (timeOut >= 0) {
            entry.mExpirationTime = mNow + timeOut;
        }
        UpdateTimer(entry, timeOut);
    }
    // Update pending send.
    assert(entry.mWriteByteCount >= 0 &&
        entry.mWriteByteCount <= mNumBytesToSend);
    mNumBytesToSend -= entry.mWriteByteCount;
    entry.mWriteByteCount = std::max(0, conn.GetNumBytesToWrite());
    mNumBytesToSend += entry.mWriteByteCount;
    // Update poll set.
    const bool in  = conn.IsReadReady() &&
        (! mIsOverloaded || entry.mEnableReadIfOverloaded);
    const bool out = conn.IsWriteReady() || entry.mConnectPending;
    if (in != entry.mIn || out != entry.mOut) {
        assert(fd >= 0);
        const int op =
            (in ? FdPoll::kOpTypeIn : 0) + (out ? FdPoll::kOpTypeOut : 0);
        if (fd != entry.mFd && entry.mFd >= 0) {
            CheckFatalSysError(
                mPoll.Remove(entry.mFd),
                "failed to removed fd from poll set"
            );
            entry.mFd = -1;
        }
        if (entry.mFd < 0) {
            if (op && CheckFatalSysError(
                    mPoll.Add(fd, op, &conn),
                    "failed to add fd to poll set") == 0) {
                entry.mFd = fd;
            }
        } else {
            CheckFatalSysError(
                mPoll.Set(fd, op, &conn),
                "failed to change pool flags"
            );
        }
        entry.mIn  = in  && entry.mFd >= 0;
        entry.mOut = out && entry.mFd >= 0;
    }
}

void
NetManager::MainLoop()
{
    mNow = time(0);
    time_t lastTimerTime = mNow;
    CheckFatalSysError(
        mPoll.Add(globals().netKicker.GetFd(), FdPoll::kOpTypeIn),
        "failed to add net kicker's fd to poll set"
    );
    const int timerOverrunWarningTime(mTimeoutMs / (1000/2));
    while (mRunFlag) {
        const bool wasOverloaded = mIsOverloaded;
        CheckIfOverloaded();
        if (mIsOverloaded != wasOverloaded) {
            KFS_LOG_VA_INFO(
                "%s (%0.f bytes to send; %d disk IO's) ",
                mIsOverloaded ?
                    "System is now in overloaded state " :
                    "Clearing system overload state",
                double(mNumBytesToSend),
                globals().diskManager.NumDiskIOOutstanding());
            for (int i = 0; i <= kTimerWheelSize; i++) {
                for (List::iterator c = mTimerWheel[i].begin();
                        c != mTimerWheel[i].end(); ) {
                    assert(*c);
                    NetConnection& conn = **c;
                    ++c;
                    conn.Update(false);
                }
            }
        }
        const int ret = mPoll.Poll(mConnectionsCount + 1, mTimeoutMs);
        if (ret < 0 && ret != -EINTR && ret != -EAGAIN) {
            std::string const msg = KFSUtils::SysError(-ret);
            KFS_LOG_VA_ERROR("poll errror %d %s",  -ret, msg.c_str());
        }
        globals().netKicker.Drain();
        const int64_t nowMs = ITimeout::NowMs();
        mNow = time_t(nowMs / 1000);
        globals().diskManager.ReapCompletedIOs();
        // Unregister will set pointer to 0, but will never remove the list
        // node, so that the iterator always remains valid.
        for (std::list<ITimeout *>::iterator it = mTimeoutHandlers.begin();
                it != mTimeoutHandlers.end(); ) {
            if (*it) {
                (*it)->TimerExpired(nowMs);
            }
            if (*it) {
                ++it;
            } else {
                it = mTimeoutHandlers.erase(it);
            }
        }
        /// Process poll events.
        int   op;
        void* ptr;
        while (mPoll.Next(op, ptr)) {
            if (op == 0 || ! ptr) {
                continue;
            }
            NetConnection& conn = *reinterpret_cast<NetConnection*>(ptr);
            if (! conn.GetNetMangerEntry(*this)->mAdded) {
                // Skip stale event, the conection should be in mRemove list.
                continue;
            }
            // Defer update for this connection.
            mCurConnection = &conn;
            if ((op & FdPoll::kOpTypeIn) != 0 && conn.IsGood()) {
                conn.HandleReadEvent();
            }
            if ((op & FdPoll::kOpTypeOut) != 0 && conn.IsGood()) {
                conn.HandleWriteEvent();
            }
            if ((op & (FdPoll::kOpTypeError | FdPoll::kOpTypeHup)) != 0 &&
                    conn.IsGood()) {
                conn.HandleErrorEvent();
            }
            // Try to write, if the last write was sucessfull.
            conn.StartFlush();
            // Update the connection.
            mCurConnection = 0;
            conn.Update();
        }
        mRemove.clear();
        mNow = time(0);
        int slotCnt = std::min(int(kTimerWheelSize), int(mNow - lastTimerTime));
        if (slotCnt > timerOverrunWarningTime) {
            KFS_LOG_VA_DEBUG("Timer overrun %d seconds detected", slotCnt - 1);
        }
        mTimerRunningFlag = true;
        while (slotCnt-- > 0) {
            List& bucket = mTimerWheel[mCurTimerWheelSlot];
            mTimerWheelBucketItr = bucket.begin();
            while (mTimerWheelBucketItr != bucket.end()) {
                assert(*mTimerWheelBucketItr);
                NetConnection& conn = **mTimerWheelBucketItr;
                assert(conn.IsGood());
                ++mTimerWheelBucketItr;
                NetConnection::NetManagerEntry& entry =
                    *conn.GetNetMangerEntry(*this);
                const int timeOut = conn.GetInactivityTimeout();
                if (timeOut < 0) {
                    // No timeout, move it to the corresponding list.
                    UpdateTimer(entry, timeOut);
                } else if (entry.mExpirationTime <= mNow) {
                    conn.HandleTimeoutEvent();
                } else {
                    // Not expired yet, move to the new slot, taking into the
                    // account possible timer overrun.
                    UpdateTimer(entry,
                        slotCnt + int(entry.mExpirationTime - mNow));
                }
            }
            if (++mCurTimerWheelSlot >= kTimerWheelSize) {
                mCurTimerWheelSlot = 0;
            }
            mRemove.clear();
        }
        mTimerRunningFlag = false;
        lastTimerTime = mNow;
        mTimerWheelBucketItr = mRemove.end();
    }
    CheckFatalSysError(
        mPoll.Remove(globals().netKicker.GetFd()),
        "failed to removed net kicker's fd from poll set"
    );
    CleanUp();
}

void
NetManager::CheckIfOverloaded()
{
    if (mMaxOutgoingBacklog > 0) {
        if (!mNetworkOverloaded) {
            mNetworkOverloaded = (mNumBytesToSend > mMaxOutgoingBacklog);
        } else if (mNumBytesToSend <= mMaxOutgoingBacklog / 2) {
            // network was overloaded and that has now cleared
            mNetworkOverloaded = false;
        }
    }
    mIsOverloaded = mDiskOverloaded || mNetworkOverloaded;
}

void
NetManager::ChangeDiskOverloadState(bool v)
{
    if (mDiskOverloaded == v)
        return;
    mDiskOverloaded = v;
}

void
NetManager::CleanUp()
{
    mTimeoutHandlers.clear();
    for (int i = 0; i <= kTimerWheelSize; i++) {
        for (mTimerWheelBucketItr = mTimerWheel[i].begin();
                mTimerWheelBucketItr != mTimerWheel[i].end(); ) {
            NetConnection* const conn = mTimerWheelBucketItr->get();
            ++mTimerWheelBucketItr;
            if (conn) {
                if (conn->IsGood()) {
                    conn->HandleErrorEvent();
                }
                conn->Close();
            }
        }
        assert(mTimerWheel[i].empty());
        mRemove.clear();
    }
    mTimerWheelBucketItr = mRemove.end();
}
<|endoftext|>


<commit_before><commit_msg>Dreamview: fix format string for unsigned int (#10134)<commit_after><|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/planning/common/planning_gflags.h"

DEFINE_bool(planning_test_mode, false, "Enable planning test mode.");

DEFINE_int32(planning_loop_rate, 10, "Loop rate for planning node");

DEFINE_string(planning_adapter_config_filename,
              "modules/planning/conf/adapter.conf",
              "The adapter configuration file");

DEFINE_string(rtk_trajectory_filename, "modules/planning/data/garage.csv",
              "Loop rate for planning node");

DEFINE_uint64(rtk_trajectory_forward, 800,
              "The number of points to be included in RTK trajectory "
              "after the matched point");

DEFINE_double(rtk_trajectory_resolution, 0.01,
              "The time resolution of output trajectory for rtk planner.");

DEFINE_bool(publish_estop, false, "publish estop decision in planning");
DEFINE_bool(enable_trajectory_stitcher, true, "enable stitching trajectory");

DEFINE_double(
    look_backward_distance, 30,
    "look backward this distance when creating reference line from routing");

DEFINE_double(look_forward_short_distance, 150,
              "short look forward this distance when creating reference line "
              "from routing when ADC is slow");
DEFINE_double(
    look_forward_long_distance, 250,
    "look forward this distance when creating reference line from routing");
DEFINE_double(look_forward_time_sec, 8.0,
              "look forward time times adc speed to calculate this distance "
              "when creating reference line from routing");
DEFINE_bool(enable_reference_line_stitching, true,
            "Enable stitching reference line, which can reducing computing "
            "time and improve stabilty");
DEFINE_double(look_forward_extend_distance, 50,
              "The step size when extending reference line.");
DEFINE_double(reference_line_stitch_overlap_distance, 20,
              "The overlap distance with the existing reference line when "
              "stitching the existing reference line");
DEFINE_double(reference_line_lateral_buffer, 1.0,
              "When creating reference line, the minimum distance with road "
              "curb for a vehicle driving on this line.");
DEFINE_double(prepare_rerouting_time, 2.0,
              "If there are this amount of seconds left to finish driving on "
              "current route, and there is no routing, do rerouting");

DEFINE_double(rerouting_cooldown_time, 0.6,
              "Wait for at least this amount of seconds before send another "
              "rerouting request");

DEFINE_bool(enable_smooth_reference_line, true,
            "enable smooth the map reference line");

DEFINE_bool(enable_spiral_reference_line, false,
            "enable new spiral based reference line");
DEFINE_double(spiral_smoother_max_deviation, 0.1,
              "The max deviation of spiral reference line smoother.");
DEFINE_int32(spiral_smoother_num_iteration, 1000,
             "The iteration num of spiral reference line smoother.");
DEFINE_double(spiral_smoother_piecewise_length, 10.0,
              "The piecewise length of spiral smoother.");
DEFINE_double(spiral_reference_line_resolution, 0.02,
              "The output resolution for reference line.");
DEFINE_bool(prioritize_change_lane, false,
            "change lane strategy has higher priority, always use a valid "
            "change lane path if such path exists");
DEFINE_bool(reckless_change_lane, false,
            "Alway allow the vehicle change lane. The vehicle may contineous "
            "change lane. This is mainly test purpose");
DEFINE_double(change_lane_fail_freeze_time, 3.0,
              "seconds. Not allowed to change lane this amount of time "
              "if it just finished change lane or failed to change lane");
DEFINE_double(change_lane_success_freeze_time, 3.0,
              "seconds. Not allowed to change lane this amount of time "
              "if it just finished change lane or failed to change lane");
DEFINE_double(change_lane_min_length, 30.0,
              "meters. If the change lane target has longer length than this "
              "threshold, it can shortcut the default lane.");
DEFINE_bool(enable_change_lane_decider, false,
            "True to use change lane state machine decider.");

DEFINE_int32(max_history_frame_num, 1, "The maximum history frame number");

DEFINE_double(max_collision_distance, 0.1,
              "considered as collision if distance (meters) is smaller than or "
              "equal to this (meters)");

DEFINE_double(replan_lateral_distance_threshold, 5.0,
              "The distance threshold of replan");
DEFINE_double(replan_longitudinal_distance_threshold, 5.0,
              "The distance threshold of replan");
DEFINE_bool(estimate_current_vehicle_state, true,
            "Estimate current vehicle state.");

DEFINE_bool(enable_reference_line_provider_thread, true,
            "Enable reference line provider thread.");

DEFINE_double(default_reference_line_width, 4.0,
              "Default reference line width");

DEFINE_double(smoothed_reference_line_max_diff, 5.0,
              "Maximum position difference between the smoothed and the raw "
              "reference lines.");

DEFINE_double(planning_upper_speed_limit, 31.3,
              "Maximum speed (m/s) in planning.");

DEFINE_double(trajectory_time_length, 8.0, "Trajectory time length");

// planning trajectory output time density control
DEFINE_double(
    trajectory_time_min_interval, 0.02,
    "(seconds) Trajectory time interval when publish. The is the min value.");
DEFINE_double(
    trajectory_time_max_interval, 0.1,
    "(seconds) Trajectory time interval when publish. The is the max value.");
DEFINE_double(
    trajectory_time_high_density_period, 1.0,
    "(seconds) Keep high density in the next this amount of seconds. ");

DEFINE_bool(enable_trajectory_check, false,
            "Enable sanity check for planning trajectory.");

DEFINE_double(speed_lower_bound, -0.02, "The lowest speed allowed.");
DEFINE_double(speed_upper_bound, 40.0, "The highest speed allowed.");

DEFINE_double(longitudinal_acceleration_lower_bound, -4.5,
              "The lowest longitudinal acceleration allowed.");
DEFINE_double(longitudinal_acceleration_upper_bound, 4.0,
              "The highest longitudinal acceleration allowed.");

DEFINE_double(lateral_jerk_bound, 4.0,
              "Bound of lateral jerk; symmetric for left and right");

DEFINE_double(longitudinal_jerk_lower_bound, -4.0,
              "The lower bound of longitudinal jerk.");
DEFINE_double(longitudinal_jerk_upper_bound, 4.0,
              "The upper bound of longitudinal jerk.");

DEFINE_double(dl_bound, 0.10,
              "The bound for derivative l in s-l coordinate system.");
DEFINE_double(kappa_bound, 0.20, "The bound for vehicle curvature");
DEFINE_double(dkappa_bound, 0.02,
              "The bound for vehicle curvature change rate");

// ST Boundary
DEFINE_double(st_max_s, 100, "the maximum s of st boundary");
DEFINE_double(st_max_t, 8, "the maximum t of st boundary");

// Decision Part
DEFINE_double(static_obstacle_speed_threshold, 1.0,
              "obstacles are considered as static obstacle if its speed is "
              "less than this value (m/s)");
DEFINE_bool(enable_nudge_decision, true, "enable nudge decision");
DEFINE_bool(enable_nudge_slowdown, true,
            "True to slow down when nudge obstacles.");

DEFINE_double(static_decision_nudge_l_buffer, 0.3, "l buffer for nudge");
DEFINE_double(longitudinal_ignore_buffer, 10.0,
              "If an obstacle's longitudinal distance is further away "
              "than this distance, ignore it");
DEFINE_double(lateral_ignore_buffer, 3.0,
              "If an obstacle's lateral distance is further away than this "
              "distance, ignore it");
DEFINE_double(max_stop_distance_obstacle, 10.0,
              "max stop distance from in-lane obstacle (meters)");
DEFINE_double(min_stop_distance_obstacle, 3.0,
              "min stop distance from in-lane obstacle (meters)");
DEFINE_double(stop_distance_destination, 0.5,
              "stop distance from destination line");
DEFINE_double(stop_distance_traffic_light, 3.0,
              "stop distance from traffic light line");
DEFINE_double(destination_check_distance, 5.0,
              "if the distance between destination and ADC is less than this,"
              " it is considered to reach destination");
DEFINE_double(nudge_distance_obstacle, 0.3,
              "minimum distance to nudge a obstacle (meters)");
DEFINE_double(follow_min_distance, 3.0,
              "min follow distance for vehicles/bicycles/moving objects");
DEFINE_double(yield_min_distance, 3.0,
              "min yield distance for vehicles/bicycles/moving objects");
DEFINE_double(
    follow_time_buffer, 2.0,
    "follow time buffer (in second) to calculate the following distance.");
DEFINE_double(
    follow_min_time_sec, 0.1,
    "min following time in st region before considering a valid follow");

DEFINE_string(destination_obstacle_id, "DEST",
              "obstacle id for converting destination to an obstacle");
DEFINE_double(virtual_stop_wall_length, 0.1,
              "virtual stop wall length (meters)");
DEFINE_double(virtual_stop_wall_height, 2.0,
              "virtual stop wall height (meters)");
DEFINE_string(reference_line_end_obstacle_id, "REF_END",
              "Obstacle id for the end of reference line obstacle");
DEFINE_double(signal_expire_time_sec, 5.0,
              "consider the signal msg is expired if its timestamp over "
              "this threshold (second)");

// Speed Decider
DEFINE_double(low_speed_obstacle_threshold, 2.0,
              "speed lower than this value is considered as low speed");
DEFINE_double(
    decelerating_obstacle_threshold, -0.25,
    "acceleration lower than this value is considered as decelerating");

// Prediction Part
DEFINE_double(prediction_total_time, 5.0, "Total prediction time");
DEFINE_bool(align_prediction_time, false,
            "enable align prediction data based planning time");

// Trajectory
DEFINE_bool(enable_rule_layer, true,
            "enable rule for trajectory before model computation");

// Traffic decision
/// common
DEFINE_double(stop_max_distance_buffer, 4.0,
              "distance buffer of passing stop line");
DEFINE_double(stop_min_speed, 0.2, "min speed(m/s) for computing stop");
DEFINE_double(stop_max_deceleration, 6.0, "max deceleration");
DEFINE_double(max_valid_stop_distance, 2.0,
              "max distance(m) to the stop line to be "
              "considered as a valid stop");

/// Clear Zone
DEFINE_string(clear_zone_virtual_object_id_prefix, "CZ_",
              "prefix for converting clear zone id to virtual object id");
/// traffic light
DEFINE_string(signal_light_virtual_object_id_prefix, "SL_",
              "prefix for converting signal id to virtual object id");
DEFINE_double(max_deacceleration_for_yellow_light_stop, 2.0,
              "treat yellow light as red when deceleration (abstract value"
              " in m/s^2) is less than this threshold; otherwise treated"
              " as green light");
/// crosswalk
DEFINE_bool(enable_crosswalk, false, "enable crosswalk");
DEFINE_string(crosswalk_virtual_object_id_prefix, "CW_",
              "prefix for converting crosswalk id to virtual object id");
DEFINE_double(crosswalk_expand_distance, 2.0,
              "crosswalk expand distance(meter) "
              "for pedestrian/bicycle detection");
DEFINE_double(crosswalk_strick_l_distance, 4.0,
              "strick stop rule within this l_distance");
DEFINE_double(crosswalk_loose_l_distance, 5.0,
              "loose stop rule beyond this l_distance");
/// stop_sign
DEFINE_bool(enable_stop_sign, false, "enable stop_sign");
DEFINE_string(stop_sign_virtual_object_id_prefix, "SS_",
              "prefix for converting stop_sign id to virtual object id");
DEFINE_double(stop_duration_for_stop_sign, 3,
              "min time(second) to stop at stop sign");
DEFINE_double(max_distance_stop_sign_waiting_area, 3,
              "max distance(meter) to be considered as "
              "having arrived stop sign waiting area");

// according to DMV's rule, turn signal should be on within 200 ft from
// intersection.
DEFINE_double(
    turn_signal_distance, 60.96,
    "In meters. If there is a turn within this distance, use turn signal");
DEFINE_bool(right_turn_creep_forward, false,
            "Creep forward at right turn when the signal is red and traffic "
            "rule is not violated.");

// planning config file
DEFINE_string(planning_config_file,
              "modules/planning/conf/planning_config.pb.txt",
              "planning config file");

DEFINE_int32(trajectory_point_num_for_debug, 10,
             "number of output trajectory points for debugging");

DEFINE_double(decision_valid_stop_range, 0.5,
              "The valid stop range in decision.");
DEFINE_bool(enable_record_debug, true,
            "True to enable record debug into debug protobuf.");
DEFINE_bool(enable_prediction, true, "True to enable prediction input.");

DEFINE_bool(enable_lag_prediction, true,
            "Enable lagged prediction, which is more tolerant to obstacles "
            "that appear and disappear dequeickly");
DEFINE_int32(lag_prediction_min_appear_num, 5,
             "The minimum of appearance of the obstacle for lagged prediction");
DEFINE_double(lag_prediction_max_disappear_num, 3,
              "In lagged prediction, ingnore obstacle disappeared for more "
              "than this value");
DEFINE_bool(enable_traffic_light, true, "True to enable traffic light input.");

// QpSt optimizer
DEFINE_bool(enable_slowdown_profile_generator, true,
            "True to enable slowdown speed profile generator.");
DEFINE_double(slowdown_profile_deceleration, -1.0,
              "The deceleration to generate slowdown profile. unit: m/s^2.");
DEFINE_bool(enable_follow_accel_constraint, true,
            "Enable follow acceleration constraint.");

// SQP solver
DEFINE_bool(enable_sqp_solver, true, "True to enable SQP solver.");
<commit_msg>planning: changed max stop acc limit for yellow light.<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/planning/common/planning_gflags.h"

DEFINE_bool(planning_test_mode, false, "Enable planning test mode.");

DEFINE_int32(planning_loop_rate, 10, "Loop rate for planning node");

DEFINE_string(planning_adapter_config_filename,
              "modules/planning/conf/adapter.conf",
              "The adapter configuration file");

DEFINE_string(rtk_trajectory_filename, "modules/planning/data/garage.csv",
              "Loop rate for planning node");

DEFINE_uint64(rtk_trajectory_forward, 800,
              "The number of points to be included in RTK trajectory "
              "after the matched point");

DEFINE_double(rtk_trajectory_resolution, 0.01,
              "The time resolution of output trajectory for rtk planner.");

DEFINE_bool(publish_estop, false, "publish estop decision in planning");
DEFINE_bool(enable_trajectory_stitcher, true, "enable stitching trajectory");

DEFINE_double(
    look_backward_distance, 30,
    "look backward this distance when creating reference line from routing");

DEFINE_double(look_forward_short_distance, 150,
              "short look forward this distance when creating reference line "
              "from routing when ADC is slow");
DEFINE_double(
    look_forward_long_distance, 250,
    "look forward this distance when creating reference line from routing");
DEFINE_double(look_forward_time_sec, 8.0,
              "look forward time times adc speed to calculate this distance "
              "when creating reference line from routing");
DEFINE_bool(enable_reference_line_stitching, true,
            "Enable stitching reference line, which can reducing computing "
            "time and improve stabilty");
DEFINE_double(look_forward_extend_distance, 50,
              "The step size when extending reference line.");
DEFINE_double(reference_line_stitch_overlap_distance, 20,
              "The overlap distance with the existing reference line when "
              "stitching the existing reference line");
DEFINE_double(reference_line_lateral_buffer, 1.0,
              "When creating reference line, the minimum distance with road "
              "curb for a vehicle driving on this line.");
DEFINE_double(prepare_rerouting_time, 2.0,
              "If there are this amount of seconds left to finish driving on "
              "current route, and there is no routing, do rerouting");

DEFINE_double(rerouting_cooldown_time, 0.6,
              "Wait for at least this amount of seconds before send another "
              "rerouting request");

DEFINE_bool(enable_smooth_reference_line, true,
            "enable smooth the map reference line");

DEFINE_bool(enable_spiral_reference_line, false,
            "enable new spiral based reference line");
DEFINE_double(spiral_smoother_max_deviation, 0.1,
              "The max deviation of spiral reference line smoother.");
DEFINE_int32(spiral_smoother_num_iteration, 1000,
             "The iteration num of spiral reference line smoother.");
DEFINE_double(spiral_smoother_piecewise_length, 10.0,
              "The piecewise length of spiral smoother.");
DEFINE_double(spiral_reference_line_resolution, 0.02,
              "The output resolution for reference line.");
DEFINE_bool(prioritize_change_lane, false,
            "change lane strategy has higher priority, always use a valid "
            "change lane path if such path exists");
DEFINE_bool(reckless_change_lane, false,
            "Alway allow the vehicle change lane. The vehicle may contineous "
            "change lane. This is mainly test purpose");
DEFINE_double(change_lane_fail_freeze_time, 3.0,
              "seconds. Not allowed to change lane this amount of time "
              "if it just finished change lane or failed to change lane");
DEFINE_double(change_lane_success_freeze_time, 3.0,
              "seconds. Not allowed to change lane this amount of time "
              "if it just finished change lane or failed to change lane");
DEFINE_double(change_lane_min_length, 30.0,
              "meters. If the change lane target has longer length than this "
              "threshold, it can shortcut the default lane.");
DEFINE_bool(enable_change_lane_decider, false,
            "True to use change lane state machine decider.");

DEFINE_int32(max_history_frame_num, 1, "The maximum history frame number");

DEFINE_double(max_collision_distance, 0.1,
              "considered as collision if distance (meters) is smaller than or "
              "equal to this (meters)");

DEFINE_double(replan_lateral_distance_threshold, 5.0,
              "The distance threshold of replan");
DEFINE_double(replan_longitudinal_distance_threshold, 5.0,
              "The distance threshold of replan");
DEFINE_bool(estimate_current_vehicle_state, true,
            "Estimate current vehicle state.");

DEFINE_bool(enable_reference_line_provider_thread, true,
            "Enable reference line provider thread.");

DEFINE_double(default_reference_line_width, 4.0,
              "Default reference line width");

DEFINE_double(smoothed_reference_line_max_diff, 5.0,
              "Maximum position difference between the smoothed and the raw "
              "reference lines.");

DEFINE_double(planning_upper_speed_limit, 31.3,
              "Maximum speed (m/s) in planning.");

DEFINE_double(trajectory_time_length, 8.0, "Trajectory time length");

// planning trajectory output time density control
DEFINE_double(
    trajectory_time_min_interval, 0.02,
    "(seconds) Trajectory time interval when publish. The is the min value.");
DEFINE_double(
    trajectory_time_max_interval, 0.1,
    "(seconds) Trajectory time interval when publish. The is the max value.");
DEFINE_double(
    trajectory_time_high_density_period, 1.0,
    "(seconds) Keep high density in the next this amount of seconds. ");

DEFINE_bool(enable_trajectory_check, false,
            "Enable sanity check for planning trajectory.");

DEFINE_double(speed_lower_bound, -0.02, "The lowest speed allowed.");
DEFINE_double(speed_upper_bound, 40.0, "The highest speed allowed.");

DEFINE_double(longitudinal_acceleration_lower_bound, -4.5,
              "The lowest longitudinal acceleration allowed.");
DEFINE_double(longitudinal_acceleration_upper_bound, 4.0,
              "The highest longitudinal acceleration allowed.");

DEFINE_double(lateral_jerk_bound, 4.0,
              "Bound of lateral jerk; symmetric for left and right");

DEFINE_double(longitudinal_jerk_lower_bound, -4.0,
              "The lower bound of longitudinal jerk.");
DEFINE_double(longitudinal_jerk_upper_bound, 4.0,
              "The upper bound of longitudinal jerk.");

DEFINE_double(dl_bound, 0.10,
              "The bound for derivative l in s-l coordinate system.");
DEFINE_double(kappa_bound, 0.20, "The bound for vehicle curvature");
DEFINE_double(dkappa_bound, 0.02,
              "The bound for vehicle curvature change rate");

// ST Boundary
DEFINE_double(st_max_s, 100, "the maximum s of st boundary");
DEFINE_double(st_max_t, 8, "the maximum t of st boundary");

// Decision Part
DEFINE_double(static_obstacle_speed_threshold, 1.0,
              "obstacles are considered as static obstacle if its speed is "
              "less than this value (m/s)");
DEFINE_bool(enable_nudge_decision, true, "enable nudge decision");
DEFINE_bool(enable_nudge_slowdown, true,
            "True to slow down when nudge obstacles.");

DEFINE_double(static_decision_nudge_l_buffer, 0.3, "l buffer for nudge");
DEFINE_double(longitudinal_ignore_buffer, 10.0,
              "If an obstacle's longitudinal distance is further away "
              "than this distance, ignore it");
DEFINE_double(lateral_ignore_buffer, 3.0,
              "If an obstacle's lateral distance is further away than this "
              "distance, ignore it");
DEFINE_double(max_stop_distance_obstacle, 10.0,
              "max stop distance from in-lane obstacle (meters)");
DEFINE_double(min_stop_distance_obstacle, 3.0,
              "min stop distance from in-lane obstacle (meters)");
DEFINE_double(stop_distance_destination, 0.5,
              "stop distance from destination line");
DEFINE_double(stop_distance_traffic_light, 3.0,
              "stop distance from traffic light line");
DEFINE_double(destination_check_distance, 5.0,
              "if the distance between destination and ADC is less than this,"
              " it is considered to reach destination");
DEFINE_double(nudge_distance_obstacle, 0.3,
              "minimum distance to nudge a obstacle (meters)");
DEFINE_double(follow_min_distance, 3.0,
              "min follow distance for vehicles/bicycles/moving objects");
DEFINE_double(yield_min_distance, 3.0,
              "min yield distance for vehicles/bicycles/moving objects");
DEFINE_double(
    follow_time_buffer, 2.0,
    "follow time buffer (in second) to calculate the following distance.");
DEFINE_double(
    follow_min_time_sec, 0.1,
    "min following time in st region before considering a valid follow");

DEFINE_string(destination_obstacle_id, "DEST",
              "obstacle id for converting destination to an obstacle");
DEFINE_double(virtual_stop_wall_length, 0.1,
              "virtual stop wall length (meters)");
DEFINE_double(virtual_stop_wall_height, 2.0,
              "virtual stop wall height (meters)");
DEFINE_string(reference_line_end_obstacle_id, "REF_END",
              "Obstacle id for the end of reference line obstacle");
DEFINE_double(signal_expire_time_sec, 5.0,
              "consider the signal msg is expired if its timestamp over "
              "this threshold (second)");

// Speed Decider
DEFINE_double(low_speed_obstacle_threshold, 2.0,
              "speed lower than this value is considered as low speed");
DEFINE_double(
    decelerating_obstacle_threshold, -0.25,
    "acceleration lower than this value is considered as decelerating");

// Prediction Part
DEFINE_double(prediction_total_time, 5.0, "Total prediction time");
DEFINE_bool(align_prediction_time, false,
            "enable align prediction data based planning time");

// Trajectory
DEFINE_bool(enable_rule_layer, true,
            "enable rule for trajectory before model computation");

// Traffic decision
/// common
DEFINE_double(stop_max_distance_buffer, 4.0,
              "distance buffer of passing stop line");
DEFINE_double(stop_min_speed, 0.2, "min speed(m/s) for computing stop");
DEFINE_double(stop_max_deceleration, 6.0, "max deceleration");
DEFINE_double(max_valid_stop_distance, 2.0,
              "max distance(m) to the stop line to be "
              "considered as a valid stop");

/// Clear Zone
DEFINE_string(clear_zone_virtual_object_id_prefix, "CZ_",
              "prefix for converting clear zone id to virtual object id");
/// traffic light
DEFINE_string(signal_light_virtual_object_id_prefix, "SL_",
              "prefix for converting signal id to virtual object id");
DEFINE_double(max_deacceleration_for_yellow_light_stop, 3.0,
              "treat yellow light as red when deceleration (abstract value"
              " in m/s^2) is less than this threshold; otherwise treated"
              " as green light");
/// crosswalk
DEFINE_bool(enable_crosswalk, false, "enable crosswalk");
DEFINE_string(crosswalk_virtual_object_id_prefix, "CW_",
              "prefix for converting crosswalk id to virtual object id");
DEFINE_double(crosswalk_expand_distance, 2.0,
              "crosswalk expand distance(meter) "
              "for pedestrian/bicycle detection");
DEFINE_double(crosswalk_strick_l_distance, 4.0,
              "strick stop rule within this l_distance");
DEFINE_double(crosswalk_loose_l_distance, 5.0,
              "loose stop rule beyond this l_distance");
/// stop_sign
DEFINE_bool(enable_stop_sign, false, "enable stop_sign");
DEFINE_string(stop_sign_virtual_object_id_prefix, "SS_",
              "prefix for converting stop_sign id to virtual object id");
DEFINE_double(stop_duration_for_stop_sign, 3,
              "min time(second) to stop at stop sign");
DEFINE_double(max_distance_stop_sign_waiting_area, 3,
              "max distance(meter) to be considered as "
              "having arrived stop sign waiting area");

// according to DMV's rule, turn signal should be on within 200 ft from
// intersection.
DEFINE_double(
    turn_signal_distance, 60.96,
    "In meters. If there is a turn within this distance, use turn signal");
DEFINE_bool(right_turn_creep_forward, false,
            "Creep forward at right turn when the signal is red and traffic "
            "rule is not violated.");

// planning config file
DEFINE_string(planning_config_file,
              "modules/planning/conf/planning_config.pb.txt",
              "planning config file");

DEFINE_int32(trajectory_point_num_for_debug, 10,
             "number of output trajectory points for debugging");

DEFINE_double(decision_valid_stop_range, 0.5,
              "The valid stop range in decision.");
DEFINE_bool(enable_record_debug, true,
            "True to enable record debug into debug protobuf.");
DEFINE_bool(enable_prediction, true, "True to enable prediction input.");

DEFINE_bool(enable_lag_prediction, true,
            "Enable lagged prediction, which is more tolerant to obstacles "
            "that appear and disappear dequeickly");
DEFINE_int32(lag_prediction_min_appear_num, 5,
             "The minimum of appearance of the obstacle for lagged prediction");
DEFINE_double(lag_prediction_max_disappear_num, 3,
              "In lagged prediction, ingnore obstacle disappeared for more "
              "than this value");
DEFINE_bool(enable_traffic_light, true, "True to enable traffic light input.");

// QpSt optimizer
DEFINE_bool(enable_slowdown_profile_generator, true,
            "True to enable slowdown speed profile generator.");
DEFINE_double(slowdown_profile_deceleration, -1.0,
              "The deceleration to generate slowdown profile. unit: m/s^2.");
DEFINE_bool(enable_follow_accel_constraint, true,
            "Enable follow acceleration constraint.");

// SQP solver
DEFINE_bool(enable_sqp_solver, true, "True to enable SQP solver.");
<|endoftext|>