1*598139dcSAndroid Build Coastguard Worker /*
2*598139dcSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*598139dcSAndroid Build Coastguard Worker *
4*598139dcSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*598139dcSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*598139dcSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*598139dcSAndroid Build Coastguard Worker *
8*598139dcSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*598139dcSAndroid Build Coastguard Worker *
10*598139dcSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*598139dcSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*598139dcSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*598139dcSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*598139dcSAndroid Build Coastguard Worker * limitations under the License.
15*598139dcSAndroid Build Coastguard Worker */
16*598139dcSAndroid Build Coastguard Worker
17*598139dcSAndroid Build Coastguard Worker #include "SimpleLogBuffer.h"
18*598139dcSAndroid Build Coastguard Worker
19*598139dcSAndroid Build Coastguard Worker #include <android-base/logging.h>
20*598139dcSAndroid Build Coastguard Worker
21*598139dcSAndroid Build Coastguard Worker #include "LogBufferElement.h"
22*598139dcSAndroid Build Coastguard Worker #include "LogSize.h"
23*598139dcSAndroid Build Coastguard Worker
SimpleLogBuffer(LogReaderList * reader_list,LogTags * tags,LogStatistics * stats)24*598139dcSAndroid Build Coastguard Worker SimpleLogBuffer::SimpleLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats)
25*598139dcSAndroid Build Coastguard Worker : reader_list_(reader_list), tags_(tags), stats_(stats) {
26*598139dcSAndroid Build Coastguard Worker Init();
27*598139dcSAndroid Build Coastguard Worker }
28*598139dcSAndroid Build Coastguard Worker
~SimpleLogBuffer()29*598139dcSAndroid Build Coastguard Worker SimpleLogBuffer::~SimpleLogBuffer() {}
30*598139dcSAndroid Build Coastguard Worker
Init()31*598139dcSAndroid Build Coastguard Worker void SimpleLogBuffer::Init() {
32*598139dcSAndroid Build Coastguard Worker log_id_for_each(i) {
33*598139dcSAndroid Build Coastguard Worker if (!SetSize(i, GetBufferSizeFromProperties(i))) {
34*598139dcSAndroid Build Coastguard Worker SetSize(i, kLogBufferMinSize);
35*598139dcSAndroid Build Coastguard Worker }
36*598139dcSAndroid Build Coastguard Worker }
37*598139dcSAndroid Build Coastguard Worker
38*598139dcSAndroid Build Coastguard Worker // Release any sleeping reader threads to dump their current content.
39*598139dcSAndroid Build Coastguard Worker auto lock = std::lock_guard{logd_lock};
40*598139dcSAndroid Build Coastguard Worker for (const auto& reader_thread : reader_list_->running_reader_threads()) {
41*598139dcSAndroid Build Coastguard Worker reader_thread->TriggerReader();
42*598139dcSAndroid Build Coastguard Worker }
43*598139dcSAndroid Build Coastguard Worker }
44*598139dcSAndroid Build Coastguard Worker
GetOldest(log_id_t log_id)45*598139dcSAndroid Build Coastguard Worker std::list<LogBufferElement>::iterator SimpleLogBuffer::GetOldest(log_id_t log_id) {
46*598139dcSAndroid Build Coastguard Worker auto it = logs_.begin();
47*598139dcSAndroid Build Coastguard Worker if (oldest_[log_id]) {
48*598139dcSAndroid Build Coastguard Worker it = *oldest_[log_id];
49*598139dcSAndroid Build Coastguard Worker }
50*598139dcSAndroid Build Coastguard Worker while (it != logs_.end() && it->log_id() != log_id) {
51*598139dcSAndroid Build Coastguard Worker it++;
52*598139dcSAndroid Build Coastguard Worker }
53*598139dcSAndroid Build Coastguard Worker if (it != logs_.end()) {
54*598139dcSAndroid Build Coastguard Worker oldest_[log_id] = it;
55*598139dcSAndroid Build Coastguard Worker }
56*598139dcSAndroid Build Coastguard Worker return it;
57*598139dcSAndroid Build Coastguard Worker }
58*598139dcSAndroid Build Coastguard Worker
ShouldLog(log_id_t log_id,const char * msg,uint16_t len)59*598139dcSAndroid Build Coastguard Worker bool SimpleLogBuffer::ShouldLog(log_id_t log_id, const char* msg, uint16_t len) {
60*598139dcSAndroid Build Coastguard Worker if (log_id == LOG_ID_SECURITY) {
61*598139dcSAndroid Build Coastguard Worker return true;
62*598139dcSAndroid Build Coastguard Worker }
63*598139dcSAndroid Build Coastguard Worker
64*598139dcSAndroid Build Coastguard Worker int prio = ANDROID_LOG_INFO;
65*598139dcSAndroid Build Coastguard Worker const char* tag = nullptr;
66*598139dcSAndroid Build Coastguard Worker size_t tag_len = 0;
67*598139dcSAndroid Build Coastguard Worker if (IsBinary(log_id)) {
68*598139dcSAndroid Build Coastguard Worker int32_t numeric_tag = MsgToTag(msg, len);
69*598139dcSAndroid Build Coastguard Worker tag = tags_->tagToName(numeric_tag);
70*598139dcSAndroid Build Coastguard Worker if (tag) {
71*598139dcSAndroid Build Coastguard Worker tag_len = strlen(tag);
72*598139dcSAndroid Build Coastguard Worker }
73*598139dcSAndroid Build Coastguard Worker } else {
74*598139dcSAndroid Build Coastguard Worker prio = *msg;
75*598139dcSAndroid Build Coastguard Worker tag = msg + 1;
76*598139dcSAndroid Build Coastguard Worker tag_len = strnlen(tag, len - 1);
77*598139dcSAndroid Build Coastguard Worker }
78*598139dcSAndroid Build Coastguard Worker return __android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE);
79*598139dcSAndroid Build Coastguard Worker }
80*598139dcSAndroid Build Coastguard Worker
Log(log_id_t log_id,log_time realtime,uid_t uid,pid_t pid,pid_t tid,const char * msg,uint16_t len)81*598139dcSAndroid Build Coastguard Worker int SimpleLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
82*598139dcSAndroid Build Coastguard Worker const char* msg, uint16_t len) {
83*598139dcSAndroid Build Coastguard Worker if (!__android_log_id_is_valid(log_id)) {
84*598139dcSAndroid Build Coastguard Worker return -EINVAL;
85*598139dcSAndroid Build Coastguard Worker }
86*598139dcSAndroid Build Coastguard Worker
87*598139dcSAndroid Build Coastguard Worker if (!ShouldLog(log_id, msg, len)) {
88*598139dcSAndroid Build Coastguard Worker // Log traffic received to total
89*598139dcSAndroid Build Coastguard Worker stats_->AddTotal(log_id, len);
90*598139dcSAndroid Build Coastguard Worker return -EACCES;
91*598139dcSAndroid Build Coastguard Worker }
92*598139dcSAndroid Build Coastguard Worker
93*598139dcSAndroid Build Coastguard Worker // Slip the time by 1 nsec if the incoming lands on xxxxxx000 ns.
94*598139dcSAndroid Build Coastguard Worker // This prevents any chance that an outside source can request an
95*598139dcSAndroid Build Coastguard Worker // exact entry with time specified in ms or us precision.
96*598139dcSAndroid Build Coastguard Worker if ((realtime.tv_nsec % 1000) == 0) ++realtime.tv_nsec;
97*598139dcSAndroid Build Coastguard Worker
98*598139dcSAndroid Build Coastguard Worker auto lock = std::lock_guard{logd_lock};
99*598139dcSAndroid Build Coastguard Worker auto sequence = sequence_.fetch_add(1, std::memory_order_relaxed);
100*598139dcSAndroid Build Coastguard Worker LogInternal(LogBufferElement(log_id, realtime, uid, pid, tid, sequence, msg, len));
101*598139dcSAndroid Build Coastguard Worker return len;
102*598139dcSAndroid Build Coastguard Worker }
103*598139dcSAndroid Build Coastguard Worker
LogInternal(LogBufferElement && elem)104*598139dcSAndroid Build Coastguard Worker void SimpleLogBuffer::LogInternal(LogBufferElement&& elem) {
105*598139dcSAndroid Build Coastguard Worker log_id_t log_id = elem.log_id();
106*598139dcSAndroid Build Coastguard Worker
107*598139dcSAndroid Build Coastguard Worker logs_.emplace_back(std::move(elem));
108*598139dcSAndroid Build Coastguard Worker stats_->Add(logs_.back().ToLogStatisticsElement());
109*598139dcSAndroid Build Coastguard Worker MaybePrune(log_id);
110*598139dcSAndroid Build Coastguard Worker reader_list_->NotifyNewLog(1 << log_id);
111*598139dcSAndroid Build Coastguard Worker }
112*598139dcSAndroid Build Coastguard Worker
CreateFlushToState(uint64_t start,LogMask log_mask)113*598139dcSAndroid Build Coastguard Worker std::unique_ptr<FlushToState> SimpleLogBuffer::CreateFlushToState(uint64_t start,
114*598139dcSAndroid Build Coastguard Worker LogMask log_mask) {
115*598139dcSAndroid Build Coastguard Worker return std::make_unique<FlushToState>(start, log_mask);
116*598139dcSAndroid Build Coastguard Worker }
117*598139dcSAndroid Build Coastguard Worker
FlushTo(LogWriter * writer,FlushToState & abstract_state,const std::function<FilterResult (log_id_t log_id,pid_t pid,uint64_t sequence,log_time realtime)> & filter)118*598139dcSAndroid Build Coastguard Worker bool SimpleLogBuffer::FlushTo(
119*598139dcSAndroid Build Coastguard Worker LogWriter* writer, FlushToState& abstract_state,
120*598139dcSAndroid Build Coastguard Worker const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
121*598139dcSAndroid Build Coastguard Worker log_time realtime)>& filter) {
122*598139dcSAndroid Build Coastguard Worker auto& state = reinterpret_cast<FlushToState&>(abstract_state);
123*598139dcSAndroid Build Coastguard Worker
124*598139dcSAndroid Build Coastguard Worker std::list<LogBufferElement>::iterator it;
125*598139dcSAndroid Build Coastguard Worker if (state.start() <= 1) {
126*598139dcSAndroid Build Coastguard Worker // client wants to start from the beginning
127*598139dcSAndroid Build Coastguard Worker it = logs_.begin();
128*598139dcSAndroid Build Coastguard Worker } else {
129*598139dcSAndroid Build Coastguard Worker // Client wants to start from some specified time. Chances are
130*598139dcSAndroid Build Coastguard Worker // we are better off starting from the end of the time sorted list.
131*598139dcSAndroid Build Coastguard Worker for (it = logs_.end(); it != logs_.begin();
132*598139dcSAndroid Build Coastguard Worker /* do nothing */) {
133*598139dcSAndroid Build Coastguard Worker --it;
134*598139dcSAndroid Build Coastguard Worker if (it->sequence() == state.start()) {
135*598139dcSAndroid Build Coastguard Worker break;
136*598139dcSAndroid Build Coastguard Worker } else if (it->sequence() < state.start()) {
137*598139dcSAndroid Build Coastguard Worker it++;
138*598139dcSAndroid Build Coastguard Worker break;
139*598139dcSAndroid Build Coastguard Worker }
140*598139dcSAndroid Build Coastguard Worker }
141*598139dcSAndroid Build Coastguard Worker }
142*598139dcSAndroid Build Coastguard Worker
143*598139dcSAndroid Build Coastguard Worker for (; it != logs_.end(); ++it) {
144*598139dcSAndroid Build Coastguard Worker LogBufferElement& element = *it;
145*598139dcSAndroid Build Coastguard Worker
146*598139dcSAndroid Build Coastguard Worker state.set_start(element.sequence());
147*598139dcSAndroid Build Coastguard Worker
148*598139dcSAndroid Build Coastguard Worker if (!writer->privileged() && element.uid() != writer->uid()) {
149*598139dcSAndroid Build Coastguard Worker continue;
150*598139dcSAndroid Build Coastguard Worker }
151*598139dcSAndroid Build Coastguard Worker
152*598139dcSAndroid Build Coastguard Worker if (((1 << element.log_id()) & state.log_mask()) == 0) {
153*598139dcSAndroid Build Coastguard Worker continue;
154*598139dcSAndroid Build Coastguard Worker }
155*598139dcSAndroid Build Coastguard Worker
156*598139dcSAndroid Build Coastguard Worker if (filter) {
157*598139dcSAndroid Build Coastguard Worker FilterResult ret =
158*598139dcSAndroid Build Coastguard Worker filter(element.log_id(), element.pid(), element.sequence(), element.realtime());
159*598139dcSAndroid Build Coastguard Worker if (ret == FilterResult::kSkip) {
160*598139dcSAndroid Build Coastguard Worker continue;
161*598139dcSAndroid Build Coastguard Worker }
162*598139dcSAndroid Build Coastguard Worker if (ret == FilterResult::kStop) {
163*598139dcSAndroid Build Coastguard Worker break;
164*598139dcSAndroid Build Coastguard Worker }
165*598139dcSAndroid Build Coastguard Worker }
166*598139dcSAndroid Build Coastguard Worker
167*598139dcSAndroid Build Coastguard Worker logd_lock.unlock();
168*598139dcSAndroid Build Coastguard Worker // We never prune logs equal to or newer than any LogReaderThreads' `start` value, so the
169*598139dcSAndroid Build Coastguard Worker // `element` pointer is safe here without the lock
170*598139dcSAndroid Build Coastguard Worker if (!element.FlushTo(writer)) {
171*598139dcSAndroid Build Coastguard Worker logd_lock.lock();
172*598139dcSAndroid Build Coastguard Worker return false;
173*598139dcSAndroid Build Coastguard Worker }
174*598139dcSAndroid Build Coastguard Worker logd_lock.lock();
175*598139dcSAndroid Build Coastguard Worker }
176*598139dcSAndroid Build Coastguard Worker
177*598139dcSAndroid Build Coastguard Worker state.set_start(state.start() + 1);
178*598139dcSAndroid Build Coastguard Worker return true;
179*598139dcSAndroid Build Coastguard Worker }
180*598139dcSAndroid Build Coastguard Worker
Clear(log_id_t id,uid_t uid)181*598139dcSAndroid Build Coastguard Worker bool SimpleLogBuffer::Clear(log_id_t id, uid_t uid) {
182*598139dcSAndroid Build Coastguard Worker // Try three times to clear, then disconnect the readers and try one final time.
183*598139dcSAndroid Build Coastguard Worker for (int retry = 0; retry < 3; ++retry) {
184*598139dcSAndroid Build Coastguard Worker {
185*598139dcSAndroid Build Coastguard Worker auto lock = std::lock_guard{logd_lock};
186*598139dcSAndroid Build Coastguard Worker if (Prune(id, ULONG_MAX, uid)) {
187*598139dcSAndroid Build Coastguard Worker return true;
188*598139dcSAndroid Build Coastguard Worker }
189*598139dcSAndroid Build Coastguard Worker }
190*598139dcSAndroid Build Coastguard Worker sleep(1);
191*598139dcSAndroid Build Coastguard Worker }
192*598139dcSAndroid Build Coastguard Worker // Check if it is still busy after the sleep, we try to prune one entry, not another clear run,
193*598139dcSAndroid Build Coastguard Worker // so we are looking for the quick side effect of the return value to tell us if we have a
194*598139dcSAndroid Build Coastguard Worker // _blocked_ reader.
195*598139dcSAndroid Build Coastguard Worker bool busy = false;
196*598139dcSAndroid Build Coastguard Worker {
197*598139dcSAndroid Build Coastguard Worker auto lock = std::lock_guard{logd_lock};
198*598139dcSAndroid Build Coastguard Worker busy = !Prune(id, 1, uid);
199*598139dcSAndroid Build Coastguard Worker }
200*598139dcSAndroid Build Coastguard Worker // It is still busy, disconnect all readers.
201*598139dcSAndroid Build Coastguard Worker if (busy) {
202*598139dcSAndroid Build Coastguard Worker auto lock = std::lock_guard{logd_lock};
203*598139dcSAndroid Build Coastguard Worker for (const auto& reader_thread : reader_list_->running_reader_threads()) {
204*598139dcSAndroid Build Coastguard Worker if (reader_thread->IsWatching(id)) {
205*598139dcSAndroid Build Coastguard Worker LOG(WARNING) << "Kicking blocked reader, " << reader_thread->name()
206*598139dcSAndroid Build Coastguard Worker << ", from LogBuffer::clear()";
207*598139dcSAndroid Build Coastguard Worker reader_thread->Release();
208*598139dcSAndroid Build Coastguard Worker }
209*598139dcSAndroid Build Coastguard Worker }
210*598139dcSAndroid Build Coastguard Worker }
211*598139dcSAndroid Build Coastguard Worker auto lock = std::lock_guard{logd_lock};
212*598139dcSAndroid Build Coastguard Worker return Prune(id, ULONG_MAX, uid);
213*598139dcSAndroid Build Coastguard Worker }
214*598139dcSAndroid Build Coastguard Worker
215*598139dcSAndroid Build Coastguard Worker // get the total space allocated to "id"
GetSize(log_id_t id)216*598139dcSAndroid Build Coastguard Worker size_t SimpleLogBuffer::GetSize(log_id_t id) {
217*598139dcSAndroid Build Coastguard Worker auto lock = std::lock_guard{logd_lock};
218*598139dcSAndroid Build Coastguard Worker size_t retval = max_size_[id];
219*598139dcSAndroid Build Coastguard Worker return retval;
220*598139dcSAndroid Build Coastguard Worker }
221*598139dcSAndroid Build Coastguard Worker
222*598139dcSAndroid Build Coastguard Worker // set the total space allocated to "id"
SetSize(log_id_t id,size_t size)223*598139dcSAndroid Build Coastguard Worker bool SimpleLogBuffer::SetSize(log_id_t id, size_t size) {
224*598139dcSAndroid Build Coastguard Worker // Reasonable limits ...
225*598139dcSAndroid Build Coastguard Worker if (!IsValidBufferSize(size)) {
226*598139dcSAndroid Build Coastguard Worker return false;
227*598139dcSAndroid Build Coastguard Worker }
228*598139dcSAndroid Build Coastguard Worker
229*598139dcSAndroid Build Coastguard Worker auto lock = std::lock_guard{logd_lock};
230*598139dcSAndroid Build Coastguard Worker max_size_[id] = size;
231*598139dcSAndroid Build Coastguard Worker return true;
232*598139dcSAndroid Build Coastguard Worker }
233*598139dcSAndroid Build Coastguard Worker
MaybePrune(log_id_t id)234*598139dcSAndroid Build Coastguard Worker void SimpleLogBuffer::MaybePrune(log_id_t id) {
235*598139dcSAndroid Build Coastguard Worker unsigned long prune_rows;
236*598139dcSAndroid Build Coastguard Worker if (stats_->ShouldPrune(id, max_size_[id], &prune_rows)) {
237*598139dcSAndroid Build Coastguard Worker Prune(id, prune_rows, 0);
238*598139dcSAndroid Build Coastguard Worker }
239*598139dcSAndroid Build Coastguard Worker }
240*598139dcSAndroid Build Coastguard Worker
Prune(log_id_t id,unsigned long prune_rows,uid_t caller_uid)241*598139dcSAndroid Build Coastguard Worker bool SimpleLogBuffer::Prune(log_id_t id, unsigned long prune_rows, uid_t caller_uid) {
242*598139dcSAndroid Build Coastguard Worker // Don't prune logs that are newer than the point at which any reader threads are reading from.
243*598139dcSAndroid Build Coastguard Worker LogReaderThread* oldest = nullptr;
244*598139dcSAndroid Build Coastguard Worker for (const auto& reader_thread : reader_list_->running_reader_threads()) {
245*598139dcSAndroid Build Coastguard Worker if (!reader_thread->IsWatching(id)) {
246*598139dcSAndroid Build Coastguard Worker continue;
247*598139dcSAndroid Build Coastguard Worker }
248*598139dcSAndroid Build Coastguard Worker if (!oldest || oldest->start() > reader_thread->start() ||
249*598139dcSAndroid Build Coastguard Worker (oldest->start() == reader_thread->start() &&
250*598139dcSAndroid Build Coastguard Worker reader_thread->deadline().time_since_epoch().count() != 0)) {
251*598139dcSAndroid Build Coastguard Worker oldest = reader_thread.get();
252*598139dcSAndroid Build Coastguard Worker }
253*598139dcSAndroid Build Coastguard Worker }
254*598139dcSAndroid Build Coastguard Worker
255*598139dcSAndroid Build Coastguard Worker auto it = GetOldest(id);
256*598139dcSAndroid Build Coastguard Worker
257*598139dcSAndroid Build Coastguard Worker while (it != logs_.end()) {
258*598139dcSAndroid Build Coastguard Worker LogBufferElement& element = *it;
259*598139dcSAndroid Build Coastguard Worker
260*598139dcSAndroid Build Coastguard Worker if (element.log_id() != id) {
261*598139dcSAndroid Build Coastguard Worker ++it;
262*598139dcSAndroid Build Coastguard Worker continue;
263*598139dcSAndroid Build Coastguard Worker }
264*598139dcSAndroid Build Coastguard Worker
265*598139dcSAndroid Build Coastguard Worker if (caller_uid != 0 && element.uid() != caller_uid) {
266*598139dcSAndroid Build Coastguard Worker ++it;
267*598139dcSAndroid Build Coastguard Worker continue;
268*598139dcSAndroid Build Coastguard Worker }
269*598139dcSAndroid Build Coastguard Worker
270*598139dcSAndroid Build Coastguard Worker if (oldest && oldest->start() <= element.sequence()) {
271*598139dcSAndroid Build Coastguard Worker KickReader(oldest, id, prune_rows);
272*598139dcSAndroid Build Coastguard Worker return false;
273*598139dcSAndroid Build Coastguard Worker }
274*598139dcSAndroid Build Coastguard Worker
275*598139dcSAndroid Build Coastguard Worker stats_->Subtract(element.ToLogStatisticsElement());
276*598139dcSAndroid Build Coastguard Worker it = Erase(it);
277*598139dcSAndroid Build Coastguard Worker if (--prune_rows == 0) {
278*598139dcSAndroid Build Coastguard Worker return true;
279*598139dcSAndroid Build Coastguard Worker }
280*598139dcSAndroid Build Coastguard Worker }
281*598139dcSAndroid Build Coastguard Worker return true;
282*598139dcSAndroid Build Coastguard Worker }
283*598139dcSAndroid Build Coastguard Worker
Erase(std::list<LogBufferElement>::iterator it)284*598139dcSAndroid Build Coastguard Worker std::list<LogBufferElement>::iterator SimpleLogBuffer::Erase(
285*598139dcSAndroid Build Coastguard Worker std::list<LogBufferElement>::iterator it) {
286*598139dcSAndroid Build Coastguard Worker bool oldest_is_it[LOG_ID_MAX];
287*598139dcSAndroid Build Coastguard Worker log_id_for_each(i) { oldest_is_it[i] = oldest_[i] && it == *oldest_[i]; }
288*598139dcSAndroid Build Coastguard Worker
289*598139dcSAndroid Build Coastguard Worker it = logs_.erase(it);
290*598139dcSAndroid Build Coastguard Worker
291*598139dcSAndroid Build Coastguard Worker log_id_for_each(i) {
292*598139dcSAndroid Build Coastguard Worker if (oldest_is_it[i]) {
293*598139dcSAndroid Build Coastguard Worker if (__predict_false(it == logs_.end())) {
294*598139dcSAndroid Build Coastguard Worker oldest_[i] = std::nullopt;
295*598139dcSAndroid Build Coastguard Worker } else {
296*598139dcSAndroid Build Coastguard Worker oldest_[i] = it; // Store the next iterator even if it does not correspond to
297*598139dcSAndroid Build Coastguard Worker // the same log_id, as a starting point for GetOldest().
298*598139dcSAndroid Build Coastguard Worker }
299*598139dcSAndroid Build Coastguard Worker }
300*598139dcSAndroid Build Coastguard Worker }
301*598139dcSAndroid Build Coastguard Worker
302*598139dcSAndroid Build Coastguard Worker return it;
303*598139dcSAndroid Build Coastguard Worker }
304*598139dcSAndroid Build Coastguard Worker
305*598139dcSAndroid Build Coastguard Worker // If the selected reader is blocking our pruning progress, decide on
306*598139dcSAndroid Build Coastguard Worker // what kind of mitigation is necessary to unblock the situation.
KickReader(LogReaderThread * reader,log_id_t id,unsigned long prune_rows)307*598139dcSAndroid Build Coastguard Worker void SimpleLogBuffer::KickReader(LogReaderThread* reader, log_id_t id, unsigned long prune_rows) {
308*598139dcSAndroid Build Coastguard Worker if (stats_->Sizes(id) > (2 * max_size_[id])) { // +100%
309*598139dcSAndroid Build Coastguard Worker // A misbehaving or slow reader has its connection
310*598139dcSAndroid Build Coastguard Worker // dropped if we hit too much memory pressure.
311*598139dcSAndroid Build Coastguard Worker LOG(WARNING) << "Kicking blocked reader, " << reader->name()
312*598139dcSAndroid Build Coastguard Worker << ", from LogBuffer::kickMe()";
313*598139dcSAndroid Build Coastguard Worker reader->Release();
314*598139dcSAndroid Build Coastguard Worker } else if (reader->deadline().time_since_epoch().count() != 0) {
315*598139dcSAndroid Build Coastguard Worker // Allow a blocked WRAP deadline reader to trigger and start reporting the log data.
316*598139dcSAndroid Build Coastguard Worker reader->TriggerReader();
317*598139dcSAndroid Build Coastguard Worker } else {
318*598139dcSAndroid Build Coastguard Worker // tell slow reader to skip entries to catch up
319*598139dcSAndroid Build Coastguard Worker LOG(WARNING) << "Skipping " << prune_rows << " entries from slow reader, " << reader->name()
320*598139dcSAndroid Build Coastguard Worker << ", from LogBuffer::kickMe()";
321*598139dcSAndroid Build Coastguard Worker reader->TriggerSkip(id, prune_rows);
322*598139dcSAndroid Build Coastguard Worker }
323*598139dcSAndroid Build Coastguard Worker }
324