Skip to content

Commit 73c3833

Browse files
[testnet] backport multi_get changes to MapView and protocol code (#4789, #4788, #4634) (#4804)
Backport #4789, #4788, #4634 ## Motivation The `multi_get` was introduced in `MapView`, which provides some improvement to the protocol code. The most affected is maybe `block_hashes`, which showed up as a slow part in the benchmarks. ## Proposal The backport is clear. ## Test Plan The CI. ## Release Plan The backport to Conway is the point. ## Links None
1 parent da944d4 commit 73c3833

File tree

2 files changed

+127
-42
lines changed

2 files changed

+127
-42
lines changed

linera-chain/src/chain.rs

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -822,32 +822,44 @@ where
822822
}
823823

824824
let recipients = block_execution_tracker.recipients();
825-
let mut previous_message_blocks = BTreeMap::new();
826-
for recipient in recipients {
827-
if let Some(height) = previous_message_blocks_view.get(&recipient).await? {
828-
let hash = confirmed_log
829-
.get(usize::try_from(height.0).map_err(|_| ArithmeticError::Overflow)?)
830-
.await?
831-
.ok_or_else(|| {
832-
ChainError::InternalError("missing entry in confirmed_log".into())
833-
})?;
834-
previous_message_blocks.insert(recipient, (hash, height));
825+
let heights = previous_message_blocks_view.multi_get(&recipients).await?;
826+
let mut recipient_heights = Vec::new();
827+
let mut indices = Vec::new();
828+
for (height, recipient) in heights.into_iter().zip(recipients) {
829+
if let Some(height) = height {
830+
let index = usize::try_from(height.0).map_err(|_| ArithmeticError::Overflow)?;
831+
indices.push(index);
832+
recipient_heights.push((recipient, height));
835833
}
836834
}
835+
let hashes = confirmed_log.multi_get(indices).await?;
836+
let mut previous_message_blocks = BTreeMap::new();
837+
for (hash, (recipient, height)) in hashes.into_iter().zip(recipient_heights) {
838+
let hash = hash.ok_or_else(|| {
839+
ChainError::InternalError("missing entry in confirmed_log".into())
840+
})?;
841+
previous_message_blocks.insert(recipient, (hash, height));
842+
}
837843

838844
let streams = block_execution_tracker.event_streams();
839-
let mut previous_event_blocks = BTreeMap::new();
840-
for stream in streams {
841-
if let Some(height) = previous_event_blocks_view.get(&stream).await? {
842-
let hash = confirmed_log
843-
.get(usize::try_from(height.0).map_err(|_| ArithmeticError::Overflow)?)
844-
.await?
845-
.ok_or_else(|| {
846-
ChainError::InternalError("missing entry in confirmed_log".into())
847-
})?;
848-
previous_event_blocks.insert(stream, (hash, height));
845+
let heights = previous_event_blocks_view.multi_get(&streams).await?;
846+
let mut stream_heights = Vec::new();
847+
let mut indices = Vec::new();
848+
for (stream, height) in streams.into_iter().zip(heights) {
849+
if let Some(height) = height {
850+
let index = usize::try_from(height.0).map_err(|_| ArithmeticError::Overflow)?;
851+
indices.push(index);
852+
stream_heights.push((stream, height));
849853
}
850854
}
855+
let hashes = confirmed_log.multi_get(indices).await?;
856+
let mut previous_event_blocks = BTreeMap::new();
857+
for (hash, (stream, height)) in hashes.into_iter().zip(stream_heights) {
858+
let hash = hash.ok_or_else(|| {
859+
ChainError::InternalError("missing entry in confirmed_log".into())
860+
})?;
861+
previous_event_blocks.insert(stream, (hash, height));
862+
}
851863

852864
let state_hash = {
853865
#[cfg(with_metrics)]
@@ -1068,10 +1080,17 @@ where
10681080
Vec::new()
10691081
};
10701082
// Everything after (including) next_height in preprocessed_blocks if we have it.
1071-
for height in start.max(next_height).0..=end.0 {
1072-
if let Some(hash) = self.preprocessed_blocks.get(&BlockHeight(height)).await? {
1073-
hashes.push(hash);
1074-
}
1083+
let block_heights = (start.max(next_height).0..=end.0)
1084+
.map(BlockHeight)
1085+
.collect::<Vec<_>>();
1086+
for hash in self
1087+
.preprocessed_blocks
1088+
.multi_get(&block_heights)
1089+
.await?
1090+
.into_iter()
1091+
.flatten()
1092+
{
1093+
hashes.push(hash);
10751094
}
10761095
Ok(hashes)
10771096
}

linera-views/src/views/map_view.rs

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,44 @@ where
11551155
self.map.get(&short_key).await
11561156
}
11571157

1158+
/// Reads values at given positions, if any.
1159+
/// ```rust
1160+
/// # tokio_test::block_on(async {
1161+
/// # use linera_views::context::MemoryContext;
1162+
/// # use linera_views::map_view::MapView;
1163+
/// # use linera_views::views::View;
1164+
/// # let context = MemoryContext::new_for_testing(());
1165+
/// let mut map: MapView<_, u32, _> = MapView::load(context).await.unwrap();
1166+
/// map.insert(&(37 as u32), String::from("Hello"));
1167+
/// map.insert(&(49 as u32), String::from("Bonjour"));
1168+
/// assert_eq!(
1169+
/// map.multi_get(&[37 as u32, 49 as u32, 64 as u32])
1170+
/// .await
1171+
/// .unwrap(),
1172+
/// [
1173+
/// Some(String::from("Hello")),
1174+
/// Some(String::from("Bonjour")),
1175+
/// None
1176+
/// ]
1177+
/// );
1178+
/// assert_eq!(map.get(&(34 as u32)).await.unwrap(), None);
1179+
/// # })
1180+
/// ```
1181+
pub async fn multi_get<'a, Q>(
1182+
&self,
1183+
indices: impl IntoIterator<Item = &'a Q>,
1184+
) -> Result<Vec<Option<V>>, ViewError>
1185+
where
1186+
I: Borrow<Q>,
1187+
Q: Serialize + 'a,
1188+
{
1189+
let short_keys = indices
1190+
.into_iter()
1191+
.map(|index| BaseKey::derive_short_key(index))
1192+
.collect::<Result<_, _>>()?;
1193+
self.map.multi_get(short_keys).await
1194+
}
1195+
11581196
/// Obtains a mutable reference to a value at a given position if available
11591197
/// ```rust
11601198
/// # tokio_test::block_on(async {
@@ -1636,6 +1674,40 @@ where
16361674
self.map.get(&short_key).await
16371675
}
16381676

1677+
/// Read values at several positions, if any.
1678+
/// ```rust
1679+
/// # tokio_test::block_on(async {
1680+
/// # use linera_views::context::MemoryContext;
1681+
/// # use linera_views::map_view::CustomMapView;
1682+
/// # use linera_views::views::View;
1683+
/// # let context = MemoryContext::new_for_testing(());
1684+
/// let mut map: CustomMapView<MemoryContext<()>, u128, String> =
1685+
/// CustomMapView::load(context).await.unwrap();
1686+
/// map.insert(&(34 as u128), String::from("Hello"));
1687+
/// map.insert(&(12 as u128), String::from("Hi"));
1688+
/// assert_eq!(
1689+
/// map.multi_get(&[34 as u128, 12 as u128, 89 as u128])
1690+
/// .await
1691+
/// .unwrap(),
1692+
/// [Some(String::from("Hello")), Some(String::from("Hi")), None]
1693+
/// );
1694+
/// # })
1695+
/// ```
1696+
pub async fn multi_get<'a, Q>(
1697+
&self,
1698+
indices: impl IntoIterator<Item = &'a Q>,
1699+
) -> Result<Vec<Option<V>>, ViewError>
1700+
where
1701+
I: Borrow<Q>,
1702+
Q: CustomSerialize + 'a,
1703+
{
1704+
let short_keys = indices
1705+
.into_iter()
1706+
.map(|index| index.to_custom_bytes())
1707+
.collect::<Result<_, _>>()?;
1708+
self.map.multi_get(short_keys).await
1709+
}
1710+
16391711
/// Obtains a mutable reference to a value at a given position if available
16401712
/// ```rust
16411713
/// # tokio_test::block_on(async {
@@ -2108,15 +2180,12 @@ mod graphql {
21082180
self.indices().await?
21092181
};
21102182

2111-
let mut values = vec![];
2112-
for key in keys {
2113-
values.push(Entry {
2114-
value: self.get(&key).await?,
2115-
key,
2116-
})
2117-
}
2118-
2119-
Ok(values)
2183+
let values = self.multi_get(&keys).await?;
2184+
Ok(values
2185+
.into_iter()
2186+
.zip(keys)
2187+
.map(|(value, key)| Entry { value, key })
2188+
.collect())
21202189
}
21212190
}
21222191

@@ -2184,15 +2253,12 @@ mod graphql {
21842253
self.indices().await?
21852254
};
21862255

2187-
let mut values = vec![];
2188-
for key in keys {
2189-
values.push(Entry {
2190-
value: self.get(&key).await?,
2191-
key,
2192-
})
2193-
}
2194-
2195-
Ok(values)
2256+
let values = self.multi_get(&keys).await?;
2257+
Ok(values
2258+
.into_iter()
2259+
.zip(keys)
2260+
.map(|(value, key)| Entry { value, key })
2261+
.collect())
21962262
}
21972263
}
21982264
}

0 commit comments

Comments
 (0)