Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_log_multisink / log_queue.cc
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_log_multisink/log_queue.h"
16
17 #include "pw_log/levels.h"
18 #include "pw_log_proto/log.pwpb.h"
19 #include "pw_protobuf/wire_format.h"
20 #include "pw_status/try.h"
21
22 namespace pw::log_rpc {
23 namespace {
24
25 using pw::protobuf::WireType;
26 constexpr std::byte kLogKey = static_cast<std::byte>(pw::protobuf::MakeKey(
27     static_cast<uint32_t>(pw::log::LogEntries::Fields::ENTRIES),
28     WireType::kDelimited));
29
30 }  // namespace
31
32 Status LogQueue::PushTokenizedMessage(ConstByteSpan message,
33                                       uint32_t flags,
34                                       uint32_t level,
35                                       uint32_t line,
36                                       uint32_t thread,
37                                       int64_t timestamp) {
38   pw::protobuf::NestedEncoder nested_encoder(encode_buffer_);
39   pw::log::LogEntry::Encoder encoder(&nested_encoder);
40   Status status;
41
42   encoder.WriteMessageTokenized(message);
43   encoder.WriteLineLevel(
44       (level & PW_LOG_LEVEL_BITMASK) |
45       ((line << PW_LOG_LEVEL_BITWIDTH) & ~PW_LOG_LEVEL_BITMASK));
46   encoder.WriteFlags(flags);
47   encoder.WriteThreadTokenized(thread);
48
49   // TODO(prashanthsw): Add support for delta encoding of the timestamp.
50   encoder.WriteTimestamp(timestamp);
51
52   if (dropped_entries_ > 0) {
53     encoder.WriteDropped(dropped_entries_);
54   }
55
56   ConstByteSpan log_entry;
57   status = nested_encoder.Encode(&log_entry);
58   if (!status.ok() || log_entry.size_bytes() > max_log_entry_size_) {
59     // If an encoding failure occurs or the constructed log entry is larger
60     // than the configured max size, map the error to INTERNAL. If the
61     // underlying allocation of this encode buffer or the nested encoding
62     // sequencing are at fault, they are not the caller's responsibility. If
63     // the log entry is larger than the max allowed size, the log is dropped
64     // intentionally, and it is expected that the caller accepts this
65     // possibility.
66     status = PW_STATUS_INTERNAL;
67   } else {
68     // Try to push back the encoded log entry.
69     status = ring_buffer_.TryPushBack(log_entry, std::byte(kLogKey));
70   }
71
72   if (!status.ok()) {
73     // The ring buffer may hit the RESOURCE_EXHAUSTED state, causing us
74     // to drop packets. However, this check captures all failures from
75     // Encode and TryPushBack, as any failure here causes packet drop.
76     dropped_entries_++;
77     latest_dropped_timestamp_ = timestamp;
78     return status;
79   }
80
81   dropped_entries_ = 0;
82   return OkStatus();
83 }
84
85 Result<LogEntries> LogQueue::Pop(LogEntriesBuffer entry_buffer) {
86   size_t ring_buffer_entry_size = 0;
87   PW_TRY(pop_status_for_test_);
88   // The caller must provide a buffer that is at minimum max_log_entry_size, to
89   // ensure that the front entry of the ring buffer can be popped.
90   PW_DCHECK_UINT_GE(entry_buffer.size_bytes(), max_log_entry_size_);
91   PW_TRY(ring_buffer_.PeekFrontWithPreamble(entry_buffer,
92                                             &ring_buffer_entry_size));
93   PW_DCHECK_OK(ring_buffer_.PopFront());
94
95   return LogEntries{
96       .entries = ConstByteSpan(entry_buffer.first(ring_buffer_entry_size)),
97       .entry_count = 1};
98 }
99
100 LogEntries LogQueue::PopMultiple(LogEntriesBuffer entries_buffer) {
101   size_t offset = 0;
102   size_t entry_count = 0;
103
104   // The caller must provide a buffer that is at minimum max_log_entry_size, to
105   // ensure that the front entry of the ring buffer can be popped.
106   PW_DCHECK_UINT_GE(entries_buffer.size_bytes(), max_log_entry_size_);
107
108   while (ring_buffer_.EntryCount() > 0 &&
109          (entries_buffer.size_bytes() - offset) > max_log_entry_size_) {
110     const Result<LogEntries> result = Pop(entries_buffer.subspan(offset));
111     if (!result.ok()) {
112       break;
113     }
114     offset += result.value().entries.size_bytes();
115     entry_count += result.value().entry_count;
116   }
117
118   return LogEntries{.entries = ConstByteSpan(entries_buffer.first(offset)),
119                     .entry_count = entry_count};
120 }
121
122 }  // namespace pw::log_rpc