安卓Android log的插入过程中按时间排序过程解析

这部分代码已经是最终插入的那部分代码,在这之前还有很多流程是在其它文章分析。
log按时间进行排序很重要,时间乱序的的log可能会干扰查问题。所以安卓系统对log的时间戳进行了一些特别的设计

// assumes LogBuffer::wrlock() held, owns elem, look after garbage collection
//这里假设已经加锁了
void LogBuffer::log(LogBufferElement* elem) {
    // cap on how far back we will sort in-place, otherwise append
   //log插入需要按时间排序,但是如果时间差超过一定限度too_far_back之后就不排序,直接插到队列尾部
    static uint32_t too_far_back = 5;  // five seconds
    // Insert elements in time sorted order if possible
    //要尽可能的按照时间顺序插入log
    //  NB: if end is region locked, place element at end of list
    LogBufferElementCollection::iterator it = mLogElements.end();
    LogBufferElementCollection::iterator last = it;
    if (__predict_true(it != mLogElements.begin())) --it;
    if (__predict_false(it == mLogElements.begin()) ||
        __predict_true((*it)->getRealTime() <= elem->getRealTime()) ||
        __predict_false((((*it)->getRealTime().tv_sec - too_far_back) >
                         elem->getRealTime().tv_sec) &&
                        (elem->getLogId() != LOG_ID_KERNEL) &&
                        ((*it)->getLogId() != LOG_ID_KERNEL))) {
        mLogElements.push_back(elem);
    } else {
        log_time end(log_time::EPOCH);
        //log_time::EPOCH = {0, 0};
        bool end_set = false;
        bool end_always = false;

        LogTimeEntry::rdlock();

        LastLogTimes::iterator times = mTimes.begin();
        //mTimes保存的是reader客户端创建的时间
        while (times != mTimes.end()) {
            LogTimeEntry* entry = times->get();
            if (!entry->mNonBlock) {
                end_always = true;//只要有一个客户端以堵塞模式读的话就直接插入到尾部,详见后文
                break;
            }
            // it passing mEnd is blocked by the following checks.
            if (!end_set || (end <= entry->mEnd)) {
                end = entry->mEnd;
                end_set = true;
            }
            times++;
        }

        if (end_always || (end_set && (end > (*it)->getRealTime()))) {
            mLogElements.push_back(elem);
        } else {
            // should be short as timestamps are localized near end()
            //找到要插入的位置
            do {
                last = it;
                if (__predict_false(it == mLogElements.begin())) {
                    break;
                }
                --it;
            } while (((*it)->getRealTime() > elem->getRealTime()) &&
                     (!end_set || (end <= (*it)->getRealTime())));
            mLogElements.insert(last, elem);
        }
        LogTimeEntry::unlock();
    }

    stats.add(elem);
    maybePrune(elem->getLogId());
}



客户端堵塞读的处理
源码中我们看到如果 !entry->mNonBlock 为真,即有客户端在阻塞地读取 log时,就把把新的 log 直接插入列表的末尾,没有进行排序。这主要是考虑这样一种比较极端的情况,它已经读取了所有的 log 并等待新的 log,我们又没有把新的 log 放入列表的末尾,就会导致客户端无法读取新写入的这条 log,毕竟,此时它应该读列表最后面的 log。另一种情况是,有客户端在读 log,并且它读到的最后一条 log 已经超过了我们正要写入的 log。此时最简单的做法就是把新 log 放到末尾,这样客户才能读取到新写入的 log。
其它知识点:
__predict_true 和 __predict_false
__predict_true 和 __predict_false 用来提示编译器对应的判断很可能是 true/false,类似于 Linux 内核的 likely/unlikely。如果判断正确,可以得到很大的性能提升。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值