xref: /aosp_15_r20/external/pigweed/seed/0124.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _seed-0124:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker===============================================================
4*61c4878aSAndroid Build Coastguard Worker0124: Interfaces for Retrieving Size Information from Multisink
5*61c4878aSAndroid Build Coastguard Worker===============================================================
6*61c4878aSAndroid Build Coastguard Worker.. seed::
7*61c4878aSAndroid Build Coastguard Worker   :number: 124
8*61c4878aSAndroid Build Coastguard Worker   :name: Interfaces for Retrieving Size Information from Multisink
9*61c4878aSAndroid Build Coastguard Worker   :status: open_for_comments
10*61c4878aSAndroid Build Coastguard Worker   :proposal_date: 2024-01-22
11*61c4878aSAndroid Build Coastguard Worker   :cl: 188670
12*61c4878aSAndroid Build Coastguard Worker   :authors: Jiacheng Lu
13*61c4878aSAndroid Build Coastguard Worker   :facilitator: Carlos Chinchilla
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker-------
16*61c4878aSAndroid Build Coastguard WorkerSummary
17*61c4878aSAndroid Build Coastguard Worker-------
18*61c4878aSAndroid Build Coastguard WorkerThis SEED proposes adding interfaces to :ref:`module-pw_multisink` to retrieve
19*61c4878aSAndroid Build Coastguard Workerthe capacity and filled size from its underlying buffer.
20*61c4878aSAndroid Build Coastguard Worker
21*61c4878aSAndroid Build Coastguard Worker----------
22*61c4878aSAndroid Build Coastguard WorkerMotivation
23*61c4878aSAndroid Build Coastguard Worker----------
24*61c4878aSAndroid Build Coastguard WorkerCurrently, ``pw_multisink`` provides ``Listener`` to help schedule draining of
25*61c4878aSAndroid Build Coastguard Workerentries. Interfaces of ``pw_multisink`` and its ``Listener`` provides no
26*61c4878aSAndroid Build Coastguard Workerinformation about capacity or consumed size of the underlying buffer.
27*61c4878aSAndroid Build Coastguard Worker
28*61c4878aSAndroid Build Coastguard WorkerBy adding interfaces to ``pw_multisink`` to provide size information of its
29*61c4878aSAndroid Build Coastguard Workerunderlying buffer, scheduling policies can be implemented to trigger draining
30*61c4878aSAndroid Build Coastguard Workerbased on, for example, the size of unread data in the buffer.
31*61c4878aSAndroid Build Coastguard Worker
32*61c4878aSAndroid Build Coastguard Worker--------
33*61c4878aSAndroid Build Coastguard WorkerProposal
34*61c4878aSAndroid Build Coastguard Worker--------
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard WorkerAdd new interface ``UnsafeGetUnreadEntriesSize()`` to
37*61c4878aSAndroid Build Coastguard Worker``pw_multisink::MultiSink::Drain`` that reports size of unread data in the
38*61c4878aSAndroid Build Coastguard Workerunderlying buffer.
39*61c4878aSAndroid Build Coastguard Worker
40*61c4878aSAndroid Build Coastguard Worker  .. code-block:: cpp
41*61c4878aSAndroid Build Coastguard Worker
42*61c4878aSAndroid Build Coastguard Worker     class MutilSink {
43*61c4878aSAndroid Build Coastguard Worker      public:
44*61c4878aSAndroid Build Coastguard Worker      ...
45*61c4878aSAndroid Build Coastguard Worker
46*61c4878aSAndroid Build Coastguard Worker        class Drain {
47*61c4878aSAndroid Build Coastguard Worker           ...
48*61c4878aSAndroid Build Coastguard Worker
49*61c4878aSAndroid Build Coastguard Worker           // Both two APIs beturn size in bytes of the valid data in the
50*61c4878aSAndroid Build Coastguard Worker           // underlying buffer that has not been read by this drain.
51*61c4878aSAndroid Build Coastguard Worker
52*61c4878aSAndroid Build Coastguard Worker           // This is a thread unsafe version. It requires the `lock` of
53*61c4878aSAndroid Build Coastguard Worker           // `multisink` being held. For example, it can be used inside
54*61c4878aSAndroid Build Coastguard Worker           // Listeners' methods, where lock already held, to check size
55*61c4878aSAndroid Build Coastguard Worker           // on handling each new entry.
56*61c4878aSAndroid Build Coastguard Worker           size_t UnsafeGetUnreadEntriesSize() PW_NO_LOCK_SAFETY_ANALYSIS;
57*61c4878aSAndroid Build Coastguard Worker
58*61c4878aSAndroid Build Coastguard Worker           // A thread-safe verson.
59*61c4878aSAndroid Build Coastguard Worker           size_t GetUnreadEntriesSize() PW_LOCKS_EXCLUDED(multisink_->lock_);
60*61c4878aSAndroid Build Coastguard Worker
61*61c4878aSAndroid Build Coastguard Worker           ...
62*61c4878aSAndroid Build Coastguard Worker
63*61c4878aSAndroid Build Coastguard Worker         protected:
64*61c4878aSAndroid Build Coastguard Worker           friend class MultiSink;
65*61c4878aSAndroid Build Coastguard Worker
66*61c4878aSAndroid Build Coastguard Worker           MultiSink* multisink_;
67*61c4878aSAndroid Build Coastguard Worker        };
68*61c4878aSAndroid Build Coastguard Worker
69*61c4878aSAndroid Build Coastguard Worker      ...
70*61c4878aSAndroid Build Coastguard Worker
71*61c4878aSAndroid Build Coastguard Worker      private:
72*61c4878aSAndroid Build Coastguard Worker        LockType lock_;
73*61c4878aSAndroid Build Coastguard Worker     };
74*61c4878aSAndroid Build Coastguard Worker
75*61c4878aSAndroid Build Coastguard Worker
76*61c4878aSAndroid Build Coastguard Worker---------------------
77*61c4878aSAndroid Build Coastguard WorkerProblem investigation
78*61c4878aSAndroid Build Coastguard Worker---------------------
79*61c4878aSAndroid Build Coastguard Worker``pw_multisink`` is a popular choice to buffer data from logs for Pigweed based
80*61c4878aSAndroid Build Coastguard Workersoftwares. An example is :ref:`module-pw_log_rpc` where an instance of
81*61c4878aSAndroid Build Coastguard Worker``pw_multisink`` is used to buffer logs before they are drained and transmitted.
82*61c4878aSAndroid Build Coastguard WorkerMake sure ``pw_multisink`` are drained in time is important to reduce the
83*61c4878aSAndroid Build Coastguard Workerchances of dropping logs because of running out of space.
84*61c4878aSAndroid Build Coastguard WorkerHowever, the draining and transmission behavior may be constrained by the
85*61c4878aSAndroid Build Coastguard Workerproperty of underlying physical channels. For certain physical channels, there
86*61c4878aSAndroid Build Coastguard Workerare tradeoffs between frequency of transmission and costs.
87*61c4878aSAndroid Build Coastguard Worker
88*61c4878aSAndroid Build Coastguard WorkerPCI is one of the example of physical channels that have the above mentioned
89*61c4878aSAndroid Build Coastguard Workertradeoffs. PCI implementation normally have different levels of power states for
90*61c4878aSAndroid Build Coastguard Workerpower efficiency. Transmitting data over PCI continuously may result to it not
91*61c4878aSAndroid Build Coastguard Workerbeing able to enter deep sleep states. Also, PCI are normally have a high
92*61c4878aSAndroid Build Coastguard Workertransmission bandwidth. Buffering data to a certain threshold and then
93*61c4878aSAndroid Build Coastguard Workersending them all over in a single transmission fits better with its design.
94*61c4878aSAndroid Build Coastguard Worker
95*61c4878aSAndroid Build Coastguard WorkerThe ``OnNewEntryAvailable`` on the current ``Listener`` interfaces does not
96*61c4878aSAndroid Build Coastguard Workerprovide enough information about buffered data size because the current
97*61c4878aSAndroid Build Coastguard Workerimplementation of underlying buffer is :ref:`module-pw_ring_buffer`, it stores
98*61c4878aSAndroid Build Coastguard Workeradditional, variable lenghted data for its internal for each entry.
99*61c4878aSAndroid Build Coastguard Worker
100*61c4878aSAndroid Build Coastguard Worker
101*61c4878aSAndroid Build Coastguard WorkerAssuming the proposed interface is avaible, the imagined use case looks like:
102*61c4878aSAndroid Build Coastguard Worker
103*61c4878aSAndroid Build Coastguard Worker  .. code-block:: cpp
104*61c4878aSAndroid Build Coastguard Worker
105*61c4878aSAndroid Build Coastguard Worker     class DrainThread: public pw::thread::ThreadCore,
106*61c4878aSAndroid Build Coastguard Worker                        public pw::multisink::MultiSink::Listener {
107*61c4878aSAndroid Build Coastguard Worker      public:
108*61c4878aSAndroid Build Coastguard Worker
109*61c4878aSAndroid Build Coastguard Worker        ... // initialize with drain
110*61c4878aSAndroid Build Coastguard Worker
111*61c4878aSAndroid Build Coastguard Worker        bool NeedFlush(size_t unread_entries_size) {
112*61c4878aSAndroid Build Coastguard Worker           ...
113*61c4878aSAndroid Build Coastguard Worker        }
114*61c4878aSAndroid Build Coastguard Worker
115*61c4878aSAndroid Build Coastguard Worker        void Flush(pw::multisink::MultiSink::Drain& drain) {
116*61c4878aSAndroid Build Coastguard Worker          ...
117*61c4878aSAndroid Build Coastguard Worker        }
118*61c4878aSAndroid Build Coastguard Worker
119*61c4878aSAndroid Build Coastguard Worker        void OnNewEntryAvailable() override {
120*61c4878aSAndroid Build Coastguard Worker           if (NeedFlush(drain_.UnsafeGetUnreadEntriesSize())) {
121*61c4878aSAndroid Build Coastguard Worker              flush_threshold_reached_notification_.release();
122*61c4878aSAndroid Build Coastguard Worker           }
123*61c4878aSAndroid Build Coastguard Worker        }
124*61c4878aSAndroid Build Coastguard Worker
125*61c4878aSAndroid Build Coastguard Worker        void Run() override {
126*61c4878aSAndroid Build Coastguard Worker           multisink_.AttachListner(*this);
127*61c4878aSAndroid Build Coastguard Worker
128*61c4878aSAndroid Build Coastguard Worker           while (true) {
129*61c4878aSAndroid Build Coastguard Worker              flush_threshold_reached_notification_.acquire();
130*61c4878aSAndroid Build Coastguard Worker              Flush(drain_);
131*61c4878aSAndroid Build Coastguard Worker           }
132*61c4878aSAndroid Build Coastguard Worker        }
133*61c4878aSAndroid Build Coastguard Worker
134*61c4878aSAndroid Build Coastguard Worker
135*61c4878aSAndroid Build Coastguard Worker      private:
136*61c4878aSAndroid Build Coastguard Worker        pw::multisink::MultiSink& multisink_;
137*61c4878aSAndroid Build Coastguard Worker        pw::multisink::MultiSink::Drain& drain_;
138*61c4878aSAndroid Build Coastguard Worker        pw::ThreadNotification flush_threshold_reached_notification_;
139*61c4878aSAndroid Build Coastguard Worker     };
140*61c4878aSAndroid Build Coastguard Worker
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker---------------
143*61c4878aSAndroid Build Coastguard WorkerDetailed design
144*61c4878aSAndroid Build Coastguard Worker---------------
145*61c4878aSAndroid Build Coastguard Worker
146*61c4878aSAndroid Build Coastguard WorkerImplement ``EntriesSize()`` in
147*61c4878aSAndroid Build Coastguard Worker``pw_ring_buffer::PrefixedEntryRingBufferMulti::Reader`` to provide the number
148*61c4878aSAndroid Build Coastguard Workerof bytes between its reader pointer and ring buffer's writer pointer.
149*61c4878aSAndroid Build Coastguard Worker
150*61c4878aSAndroid Build Coastguard Worker  .. code-block:: cpp
151*61c4878aSAndroid Build Coastguard Worker
152*61c4878aSAndroid Build Coastguard Worker     class PrefixedEntryRingBufferMulti {
153*61c4878aSAndroid Build Coastguard Worker       class Reader : public IntrusiveList<Reader>::Item {
154*61c4878aSAndroid Build Coastguard Worker        public:
155*61c4878aSAndroid Build Coastguard Worker
156*61c4878aSAndroid Build Coastguard Worker         // Get the size of the unread entries currently in the ring buffer.
157*61c4878aSAndroid Build Coastguard Worker         // Return value:
158*61c4878aSAndroid Build Coastguard Worker         // Number of bytes
159*61c4878aSAndroid Build Coastguard Worker         size_t EntriesSize() const {
160*61c4878aSAndroid Build Coastguard Worker           // Case: Not wrapped.
161*61c4878aSAndroid Build Coastguard Worker           if (read_idx_ < buffer_->write_idx_) {
162*61c4878aSAndroid Build Coastguard Worker             return buffer_->write_idx_ - read_idx_;
163*61c4878aSAndroid Build Coastguard Worker           }
164*61c4878aSAndroid Build Coastguard Worker           // Case: Wrapped.
165*61c4878aSAndroid Build Coastguard Worker           if (read_idx_ > buffer_->write_idx_) {
166*61c4878aSAndroid Build Coastguard Worker             return buffer_->buffer_bytes_ - (read_idx_ - buffer_->write_idx_);
167*61c4878aSAndroid Build Coastguard Worker           }
168*61c4878aSAndroid Build Coastguard Worker
169*61c4878aSAndroid Build Coastguard Worker           // No entries remaining.
170*61c4878aSAndroid Build Coastguard Worker           if (entry_count_ == 0) {
171*61c4878aSAndroid Build Coastguard Worker             return 0;
172*61c4878aSAndroid Build Coastguard Worker           }
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker           return buffer_->buffer_bytes_;
175*61c4878aSAndroid Build Coastguard Worker         }
176*61c4878aSAndroid Build Coastguard Worker
177*61c4878aSAndroid Build Coastguard Worker        private:
178*61c4878aSAndroid Build Coastguard Worker         PrefixedEntryRingBufferMulti* buffer_;
179*61c4878aSAndroid Build Coastguard Worker         size_t read_idx_;
180*61c4878aSAndroid Build Coastguard Worker       };
181*61c4878aSAndroid Build Coastguard Worker
182*61c4878aSAndroid Build Coastguard Worker      private:
183*61c4878aSAndroid Build Coastguard Worker       size_t write_idx_;
184*61c4878aSAndroid Build Coastguard Worker       size_t buffer_bytes_;
185*61c4878aSAndroid Build Coastguard Worker     };
186*61c4878aSAndroid Build Coastguard Worker
187*61c4878aSAndroid Build Coastguard Worker
188*61c4878aSAndroid Build Coastguard WorkerThe unread data size of ``Drain`` is directly fetched from ring buffer's
189*61c4878aSAndroid Build Coastguard Worker``Reader``. Because ``pw_multisink`` uses ``lock_`` to protect accesses to all
190*61c4878aSAndroid Build Coastguard Workerlisteners' methods already, in order to support calling the proposed interfaces
191*61c4878aSAndroid Build Coastguard Workerfrom listeners, this design introduces two versions of API, one thread-safe
192*61c4878aSAndroid Build Coastguard Workerversion that is intended to be used outside of listeners, and one thread-unsafe
193*61c4878aSAndroid Build Coastguard Workerversion requires that ``lock_`` of ``pw_multisink`` being held when invoking.
194*61c4878aSAndroid Build Coastguard Worker
195*61c4878aSAndroid Build Coastguard Worker  .. code-block:: cpp
196*61c4878aSAndroid Build Coastguard Worker
197*61c4878aSAndroid Build Coastguard Worker     namespace pw {
198*61c4878aSAndroid Build Coastguard Worker     namespace multisink {
199*61c4878aSAndroid Build Coastguard Worker
200*61c4878aSAndroid Build Coastguard Worker     class MutilSink {
201*61c4878aSAndroid Build Coastguard Worker      public:
202*61c4878aSAndroid Build Coastguard Worker       ...
203*61c4878aSAndroid Build Coastguard Worker
204*61c4878aSAndroid Build Coastguard Worker        class Drain {
205*61c4878aSAndroid Build Coastguard Worker         public:
206*61c4878aSAndroid Build Coastguard Worker
207*61c4878aSAndroid Build Coastguard Worker           // Both two APIs beturn size in bytes of the valid data in the
208*61c4878aSAndroid Build Coastguard Worker           // underlying buffer that has not been read by this drain.
209*61c4878aSAndroid Build Coastguard Worker
210*61c4878aSAndroid Build Coastguard Worker           // Ideally it should use annotation
211*61c4878aSAndroid Build Coastguard Worker           //     PW_EXCLUSIVE_LOCKS_REQUIRED(multisink_->lock_)
212*61c4878aSAndroid Build Coastguard Worker           // however, Listener interfaces, where it is intended to be called,
213*61c4878aSAndroid Build Coastguard Worker           // cannot be annotated using multisink's lock. Static analysis is not
214*61c4878aSAndroid Build Coastguard Worker           // doable.
215*61c4878aSAndroid Build Coastguard Worker           size_t UnsafeGetUnreadEntriesSize() PW_NO_LOCK_SAFETY_ANALYSIS {
216*61c4878aSAndroid Build Coastguard Worker              return reader_.EntriesSize();
217*61c4878aSAndroid Build Coastguard Worker           }
218*61c4878aSAndroid Build Coastguard Worker
219*61c4878aSAndroid Build Coastguard Worker           size_t GetUnreadEntriesSize() PW_LOCKS_EXCLUDED(multisink_->lock_) {
220*61c4878aSAndroid Build Coastguard Worker              std::lock_guard lock(multisink_->lock_);
221*61c4878aSAndroid Build Coastguard Worker              return UnsafeGetUnreadEntriesSize();
222*61c4878aSAndroid Build Coastguard Worker           }
223*61c4878aSAndroid Build Coastguard Worker
224*61c4878aSAndroid Build Coastguard Worker         protected:
225*61c4878aSAndroid Build Coastguard Worker           friend class MultiSink;
226*61c4878aSAndroid Build Coastguard Worker
227*61c4878aSAndroid Build Coastguard Worker           MultiSink* multisink_;
228*61c4878aSAndroid Build Coastguard Worker           ring_buffer::PrefixedEntryRingBufferMulti::Reader reader_;
229*61c4878aSAndroid Build Coastguard Worker        };
230*61c4878aSAndroid Build Coastguard Worker
231*61c4878aSAndroid Build Coastguard Worker      ...
232*61c4878aSAndroid Build Coastguard Worker
233*61c4878aSAndroid Build Coastguard Worker      private:
234*61c4878aSAndroid Build Coastguard Worker        LockType lock_;
235*61c4878aSAndroid Build Coastguard Worker        ring_buffer::PrefixedEntryRingBufferMulti ring_buffer_
236*61c4878aSAndroid Build Coastguard Worker           PW_GUARDED_BY(lock_);
237*61c4878aSAndroid Build Coastguard Worker     };
238*61c4878aSAndroid Build Coastguard Worker
239*61c4878aSAndroid Build Coastguard Worker     }  // namespace multisink
240*61c4878aSAndroid Build Coastguard Worker     }  // namespace pw
241*61c4878aSAndroid Build Coastguard Worker
242*61c4878aSAndroid Build Coastguard Worker------------
243*61c4878aSAndroid Build Coastguard WorkerAlternatives
244*61c4878aSAndroid Build Coastguard Worker------------
245*61c4878aSAndroid Build Coastguard Worker
246*61c4878aSAndroid Build Coastguard WorkerAdd on buffer size change interface to listener
247*61c4878aSAndroid Build Coastguard Worker===============================================
248*61c4878aSAndroid Build Coastguard WorkerAdd ``OnBufferSizeChange`` interface to ``pw_multisink::MultiSinkListener``. The
249*61c4878aSAndroid Build Coastguard Workernew interface gets invoked when the available size of the underlying buffer
250*61c4878aSAndroid Build Coastguard Workerchanges.
251*61c4878aSAndroid Build Coastguard Worker
252*61c4878aSAndroid Build Coastguard WorkerInterface example:
253*61c4878aSAndroid Build Coastguard Worker
254*61c4878aSAndroid Build Coastguard Worker  .. code-block:: cpp
255*61c4878aSAndroid Build Coastguard Worker
256*61c4878aSAndroid Build Coastguard Worker     class MultiSink {
257*61c4878aSAndroid Build Coastguard Worker      public:
258*61c4878aSAndroid Build Coastguard Worker       class Listener {
259*61c4878aSAndroid Build Coastguard Worker        public:
260*61c4878aSAndroid Build Coastguard Worker
261*61c4878aSAndroid Build Coastguard Worker         ...
262*61c4878aSAndroid Build Coastguard Worker
263*61c4878aSAndroid Build Coastguard Worker         virtual void OnNewEntryAvailable() = 0;
264*61c4878aSAndroid Build Coastguard Worker
265*61c4878aSAndroid Build Coastguard Worker         virtual void OnBufferSizeChange(size_t total_size, size_t used_sized);
266*61c4878aSAndroid Build Coastguard Worker       };
267*61c4878aSAndroid Build Coastguard Worker
268*61c4878aSAndroid Build Coastguard Worker       ...
269*61c4878aSAndroid Build Coastguard Worker     }
270*61c4878aSAndroid Build Coastguard Worker
271*61c4878aSAndroid Build Coastguard Worker
272*61c4878aSAndroid Build Coastguard WorkerImagined implementation of ``OnBufferSizeChange`` being invoked after an entry
273*61c4878aSAndroid Build Coastguard Workerpush or pop. It uses existing interfaces of the underlying
274*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_ring_buffer`. In reality, this implementation does not work well,
275*61c4878aSAndroid Build Coastguard Workerexplained in the **problems** sections below.
276*61c4878aSAndroid Build Coastguard Worker
277*61c4878aSAndroid Build Coastguard Worker  .. code-block:: cpp
278*61c4878aSAndroid Build Coastguard Worker
279*61c4878aSAndroid Build Coastguard Worker     void MutilSink::HandleEntry(ConstByteSpan entry) {
280*61c4878aSAndroid Build Coastguard Worker       std::lock_guard lock(lock_);
281*61c4878aSAndroid Build Coastguard Worker       ...
282*61c4878aSAndroid Build Coastguard Worker       ring_buffer_.PushBack(entry);
283*61c4878aSAndroid Build Coastguard Worker       NotifyListenersBufferSizeChanged(
284*61c4878aSAndroid Build Coastguard Worker         ring_buffer_.TotalSizeBytes(),
285*61c4878aSAndroid Build Coastguard Worker         ring_buffer_.TotalUsedBytes());
286*61c4878aSAndroid Build Coastguard Worker       ...
287*61c4878aSAndroid Build Coastguard Worker     }
288*61c4878aSAndroid Build Coastguard Worker
289*61c4878aSAndroid Build Coastguard Worker  .. code-block:: cpp
290*61c4878aSAndroid Build Coastguard Worker
291*61c4878aSAndroid Build Coastguard Worker    void MutilSink::PopEntry(Drain& drain, ConstByteSpan entry) {
292*61c4878aSAndroid Build Coastguard Worker      std::lock_guard lock(lock_);
293*61c4878aSAndroid Build Coastguard Worker      ...
294*61c4878aSAndroid Build Coastguard Worker      const size_t used_size_before_pop = ring_buffer_.TotalUsedBytes();
295*61c4878aSAndroid Build Coastguard Worker      drain.reader_.PopFront();
296*61c4878aSAndroid Build Coastguard Worker      const size_t used_size_after_pop = ring_buffer_.TotalUsedBytes();
297*61c4878aSAndroid Build Coastguard Worker      if (used_size_before_pop != used_size_after_pop) {
298*61c4878aSAndroid Build Coastguard Worker        NotifyListenersBufferSizeChanged(
299*61c4878aSAndroid Build Coastguard Worker          ring_buffer_.TotalSizeBytes(),
300*61c4878aSAndroid Build Coastguard Worker          used_size_after_pop);
301*61c4878aSAndroid Build Coastguard Worker      }
302*61c4878aSAndroid Build Coastguard Worker      ...
303*61c4878aSAndroid Build Coastguard Worker    }
304*61c4878aSAndroid Build Coastguard Worker
305*61c4878aSAndroid Build Coastguard Worker
306*61c4878aSAndroid Build Coastguard WorkerProblem 1. Find the slowest drain
307*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
308*61c4878aSAndroid Build Coastguard WorkerWhen there are multiple drains attached to ``pw_multisink``, only the slowest
309*61c4878aSAndroid Build Coastguard Workerdrain(s) frees space from the underlying ``pw_ring_buffer`` when pops.
310*61c4878aSAndroid Build Coastguard Worker
311*61c4878aSAndroid Build Coastguard Worker``pw_multisink`` supports :ref:`module-pw_multisink-late_drain_attach` which
312*61c4878aSAndroid Build Coastguard Workerattaches an internal drain that never pops. The ``TotalUsedBytes()`` reported by
313*61c4878aSAndroid Build Coastguard Workerunderlying ``pw_ring_buffer`` counts from the slowest drain and always reports
314*61c4878aSAndroid Build Coastguard Workerthe full capacity instead of the real used size.
315*61c4878aSAndroid Build Coastguard Worker
316*61c4878aSAndroid Build Coastguard Worker
317*61c4878aSAndroid Build Coastguard WorkerProblem 2. Push a entry when buffer is full may decrease used size
318*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
319*61c4878aSAndroid Build Coastguard WorkerWhen the pushing of a new entry exceeds the remaining free space of the
320*61c4878aSAndroid Build Coastguard Workerunderlying buffer, the push can still succeed, by silent dropping entries from
321*61c4878aSAndroid Build Coastguard Workerthe slowest drain. However, depending on the size of dropped entries and the
322*61c4878aSAndroid Build Coastguard Workersize of the new entry, the used buffer size may increase, decrease or stay the
323*61c4878aSAndroid Build Coastguard Workersame.
324*61c4878aSAndroid Build Coastguard Worker
325*61c4878aSAndroid Build Coastguard WorkerIf the user of the proposed ``OnBufferSizeChange`` interface is comparing the
326*61c4878aSAndroid Build Coastguard Workerreported used bytes with a threshold value, it is likely that the moment of
327*61c4878aSAndroid Build Coastguard Workerunderlying buffer being full may not be catched.
328*61c4878aSAndroid Build Coastguard Worker
329*61c4878aSAndroid Build Coastguard WorkerAlthough it is possible to also trigger ``OnBufferSizeChange`` with
330*61c4878aSAndroid Build Coastguard Worker``used_size == total_size`` when the above situation happens, the implementation
331*61c4878aSAndroid Build Coastguard Workermay also require exposing internal states of ``pw_ring_buffer``.
332*61c4878aSAndroid Build Coastguard Worker
333*61c4878aSAndroid Build Coastguard Worker--------------
334*61c4878aSAndroid Build Coastguard WorkerOpen questions
335*61c4878aSAndroid Build Coastguard Worker--------------
336