risingwave_storage/hummock/event_handler/
version_update.rs1use std::collections::VecDeque;
16use std::future::poll_fn;
17use std::task::Poll;
18
19use futures::FutureExt;
20use futures::future::BoxFuture;
21use risingwave_hummock_sdk::HummockVersionId;
22use risingwave_hummock_sdk::version::{HummockVersion, HummockVersionDelta};
23
24use super::HummockVersionUpdate;
25use crate::hummock::local_version::pinned_version::PinnedVersion;
26use crate::monitor::GLOBAL_CACHE_REFILL_METRICS;
27
28pub(super) type VersionUpdateCondition = BoxFuture<'static, ()>;
32
33pub(super) struct VersionUpdateEvent {
35 pub prev_version_id: HummockVersionId,
37 pub new_pinned_version: PinnedVersion,
39}
40
41struct PendingVersion {
42 condition: VersionUpdateCondition,
43 event: VersionUpdateEvent,
44}
45
46pub(super) struct VersionUpdateQueue {
49 latest_received: PinnedVersion,
51 queue: VecDeque<PendingVersion>,
52}
53
54impl VersionUpdateQueue {
55 pub fn new(version: PinnedVersion) -> Self {
56 Self {
57 latest_received: version,
58 queue: VecDeque::new(),
59 }
60 }
61
62 pub fn resolve_update(
71 &self,
72 payload: HummockVersionUpdate,
73 mut before_apply: impl FnMut(&HummockVersion, &HummockVersionDelta),
74 ) -> Option<VersionUpdateEvent> {
75 let pinned_version = &self.latest_received;
76 let new_pinned_version = match payload {
77 HummockVersionUpdate::VersionDeltas(deltas) => {
78 let mut version = (**pinned_version).clone();
79 for delta in &deltas {
80 assert_eq!(version.id, delta.prev_id);
81 before_apply(&version, delta);
82 version.apply_version_delta(delta);
83 }
84 pinned_version.new_with_local_version(version)?
85 }
86 HummockVersionUpdate::PinnedVersion(version) => {
87 pinned_version.new_pin_version(*version)?
88 }
89 };
90 Some(VersionUpdateEvent {
91 prev_version_id: pinned_version.id(),
92 new_pinned_version,
93 })
94 }
95
96 pub fn enqueue(&mut self, event: VersionUpdateEvent, condition: VersionUpdateCondition) {
102 assert_eq!(event.prev_version_id, self.latest_received.id());
103 self.latest_received = event.new_pinned_version.clone();
104 self.queue.push_back(PendingVersion { condition, event });
105 GLOBAL_CACHE_REFILL_METRICS.refill_queue_total.inc();
106 }
107
108 pub async fn next_events(&mut self) -> Vec<VersionUpdateEvent> {
112 poll_fn(|cx| {
113 const MAX_BATCH_SIZE: usize = 16;
114 let mut events = None;
115 while let Some(pending) = self.queue.front_mut()
116 && pending.condition.poll_unpin(cx).is_ready()
117 {
118 let pending = self.queue.pop_front().unwrap();
119 GLOBAL_CACHE_REFILL_METRICS.refill_queue_total.dec();
120 let events = events.get_or_insert_with(|| Vec::with_capacity(MAX_BATCH_SIZE));
121 events.push(pending.event);
122 if events.len() >= MAX_BATCH_SIZE {
123 break;
124 }
125 }
126 match events {
127 Some(events) => Poll::Ready(events),
128 None => Poll::Pending,
129 }
130 })
131 .await
132 }
133}
134
135impl Drop for VersionUpdateQueue {
136 fn drop(&mut self) {
137 GLOBAL_CACHE_REFILL_METRICS
138 .refill_queue_total
139 .sub(self.queue.len() as i64);
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use tokio::sync::mpsc::unbounded_channel;
146
147 use super::*;
148
149 #[tokio::test]
150 async fn test_ready_prefix_limit_and_delta_observation() {
151 let version = PinnedVersion::new(HummockVersion::default(), unbounded_channel().0);
152 let mut queue = VersionUpdateQueue::new(version);
153 for id in 1..=17 {
154 let deltas = (id * 2 - 1..=id * 2)
155 .map(|raw_id| {
156 let mut delta = HummockVersionDelta::default();
157 delta.prev_id = (raw_id - 1).into();
158 delta.id = raw_id.into();
159 delta
160 })
161 .collect();
162 let mut observed = Vec::new();
163 let event = queue
164 .resolve_update(
165 HummockVersionUpdate::VersionDeltas(deltas),
166 |before, delta| {
167 observed.push((before.id.as_raw_id(), delta.id.as_raw_id()));
168 },
169 )
170 .unwrap();
171 assert_eq!(
172 observed,
173 vec![(id * 2 - 2, id * 2 - 1), (id * 2 - 1, id * 2)]
174 );
175 queue.enqueue(event, std::future::ready(()).boxed());
176 }
177 let first = queue.next_events().await;
178 assert_eq!(first.len(), 16);
179 assert_eq!(
180 first
181 .iter()
182 .map(|event| event.new_pinned_version.id().as_raw_id())
183 .collect::<Vec<_>>(),
184 (1..=16).map(|id| id * 2).collect::<Vec<_>>()
185 );
186 let last = queue.next_events().await;
187 assert_eq!(last.len(), 1);
188 assert_eq!(last[0].new_pinned_version.id().as_raw_id(), 34);
189 }
190}