-
Notifications
You must be signed in to change notification settings - Fork 115
fix(mem-leak): running_swap never shrinks
#2301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
0890de8
fbd5e9f
f5ac03d
6f157d6
dd5418f
64a0012
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,7 +88,7 @@ use std::convert::TryFrom; | |
| use std::num::NonZeroUsize; | ||
| use std::path::PathBuf; | ||
| use std::str::FromStr; | ||
| use std::sync::{Arc, Mutex, Weak}; | ||
| use std::sync::{Arc, Mutex}; | ||
| use std::time::Duration; | ||
| use uuid::Uuid; | ||
|
|
||
|
|
@@ -518,7 +518,7 @@ struct LockedAmountInfo { | |
| } | ||
|
|
||
| struct SwapsContext { | ||
| running_swaps: Mutex<Vec<Weak<dyn AtomicSwap>>>, | ||
| running_swaps: Mutex<HashMap<Uuid, Arc<dyn AtomicSwap>>>, | ||
| active_swaps_v2_infos: Mutex<HashMap<Uuid, ActiveSwapV2Info>>, | ||
| banned_pubkeys: Mutex<HashMap<H256Json, BanReason>>, | ||
| swap_msgs: Mutex<HashMap<Uuid, SwapMsgStore>>, | ||
|
|
@@ -534,7 +534,7 @@ impl SwapsContext { | |
| fn from_ctx(ctx: &MmArc) -> Result<Arc<SwapsContext>, String> { | ||
| Ok(try_s!(from_ctx(&ctx.swaps_ctx, move || { | ||
| Ok(SwapsContext { | ||
| running_swaps: Mutex::new(vec![]), | ||
| running_swaps: Mutex::new(HashMap::new()), | ||
| active_swaps_v2_infos: Mutex::new(HashMap::new()), | ||
| banned_pubkeys: Mutex::new(HashMap::new()), | ||
| swap_msgs: Mutex::new(HashMap::new()), | ||
|
|
@@ -619,21 +619,21 @@ pub fn get_locked_amount(ctx: &MmArc, coin: &str) -> MmNumber { | |
| let swap_ctx = SwapsContext::from_ctx(ctx).unwrap(); | ||
| let swap_lock = swap_ctx.running_swaps.lock().unwrap(); | ||
|
|
||
| let mut locked = swap_lock | ||
| .iter() | ||
| .filter_map(|swap| swap.upgrade()) | ||
| .flat_map(|swap| swap.locked_amount()) | ||
| .fold(MmNumber::from(0), |mut total_amount, locked| { | ||
| if locked.coin == coin { | ||
| total_amount += locked.amount; | ||
| } | ||
| if let Some(trade_fee) = locked.trade_fee { | ||
| if trade_fee.coin == coin && !trade_fee.paid_from_trading_vol { | ||
| total_amount += trade_fee.amount; | ||
| let mut locked = | ||
| swap_lock | ||
| .values() | ||
| .flat_map(|swap| swap.locked_amount()) | ||
| .fold(MmNumber::from(0), |mut total_amount, locked| { | ||
| if locked.coin == coin { | ||
| total_amount += locked.amount; | ||
| } | ||
| } | ||
| total_amount | ||
| }); | ||
| if let Some(trade_fee) = locked.trade_fee { | ||
| if trade_fee.coin == coin && !trade_fee.paid_from_trading_vol { | ||
| total_amount += trade_fee.amount; | ||
| } | ||
| } | ||
| total_amount | ||
| }); | ||
| drop(swap_lock); | ||
|
|
||
| let locked_amounts = swap_ctx.locked_amounts.lock().unwrap(); | ||
|
|
@@ -654,14 +654,12 @@ pub fn get_locked_amount(ctx: &MmArc, coin: &str) -> MmNumber { | |
| locked | ||
| } | ||
|
|
||
| /// Get number of currently running swaps | ||
| pub fn running_swaps_num(ctx: &MmArc) -> u64 { | ||
| /// Clear up all the running swaps. | ||
| /// | ||
| /// This also auto-stops any running swaps since their abort handles will get triggered (assuming these abort handles aren't already triggered by other means). | ||
| pub fn clear_running_swaps(ctx: &MmArc) { | ||
| let swap_ctx = SwapsContext::from_ctx(ctx).unwrap(); | ||
| let swaps = swap_ctx.running_swaps.lock().unwrap(); | ||
| swaps.iter().fold(0, |total, swap| match swap.upgrade() { | ||
| Some(_) => total + 1, | ||
| None => total, | ||
| }) | ||
| swap_ctx.running_swaps.lock().unwrap().clear(); | ||
|
Comment on lines
+660
to
+662
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does clearing the map stops swap processes?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please mention that on the code?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's already in the doc comment. or u mean somewhere else? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah didn't see that. I was referring to caller side but it's fine
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. big ooops:
this is completely wrong. this feat is in another PR. i mixed things up. no, clearing the running swaps will not stop these swaps. (though could be stopped via other means, e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok that is def. worth to mention that on the line.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried this code, looks like clear_running_swaps fn is needed to clear swaps_ctx in MmCtx to allow to release ctx so stop_and_wait_for_ctx_is_dropped fn can finish (used in wasm tests). (this note to memorise)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated the doc comment accordingly till the other PR that stores the abort handle lands in. |
||
| } | ||
|
|
||
| /// Get total amount of selected coin locked by all currently ongoing swaps except the one with selected uuid | ||
|
|
@@ -670,8 +668,7 @@ fn get_locked_amount_by_other_swaps(ctx: &MmArc, except_uuid: &Uuid, coin: &str) | |
| let swap_lock = swap_ctx.running_swaps.lock().unwrap(); | ||
|
|
||
| swap_lock | ||
| .iter() | ||
| .filter_map(|swap| swap.upgrade()) | ||
| .values() | ||
| .filter(|swap| swap.uuid() != except_uuid) | ||
| .flat_map(|swap| swap.locked_amount()) | ||
| .fold(MmNumber::from(0), |mut total_amount, locked| { | ||
|
|
@@ -691,11 +688,9 @@ pub fn active_swaps_using_coins(ctx: &MmArc, coins: &HashSet<String>) -> Result< | |
| let swap_ctx = try_s!(SwapsContext::from_ctx(ctx)); | ||
| let swaps = try_s!(swap_ctx.running_swaps.lock()); | ||
| let mut uuids = vec![]; | ||
| for swap in swaps.iter() { | ||
| if let Some(swap) = swap.upgrade() { | ||
| if coins.contains(&swap.maker_coin().to_string()) || coins.contains(&swap.taker_coin().to_string()) { | ||
| uuids.push(*swap.uuid()) | ||
| } | ||
| for swap in swaps.values() { | ||
| if coins.contains(&swap.maker_coin().to_string()) || coins.contains(&swap.taker_coin().to_string()) { | ||
| uuids.push(*swap.uuid()) | ||
| } | ||
| } | ||
| drop(swaps); | ||
|
|
@@ -711,15 +706,13 @@ pub fn active_swaps_using_coins(ctx: &MmArc, coins: &HashSet<String>) -> Result< | |
|
|
||
| pub fn active_swaps(ctx: &MmArc) -> Result<Vec<(Uuid, u8)>, String> { | ||
| let swap_ctx = try_s!(SwapsContext::from_ctx(ctx)); | ||
| let swaps = swap_ctx.running_swaps.lock().unwrap(); | ||
| let mut uuids = vec![]; | ||
| for swap in swaps.iter() { | ||
| if let Some(swap) = swap.upgrade() { | ||
| uuids.push((*swap.uuid(), LEGACY_SWAP_TYPE)) | ||
| } | ||
| } | ||
|
|
||
| drop(swaps); | ||
| let mut uuids: Vec<_> = swap_ctx | ||
| .running_swaps | ||
| .lock() | ||
| .unwrap() | ||
| .keys() | ||
| .map(|uuid| (*uuid, LEGACY_SWAP_TYPE)) | ||
| .collect(); | ||
|
|
||
| let swaps_v2 = swap_ctx.active_swaps_v2_infos.lock().unwrap(); | ||
| uuids.extend(swaps_v2.iter().map(|(uuid, info)| (*uuid, info.swap_type))); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we intentionally chose a weak reference instead of
Arcas it might avoid cyclic references (similar to how it's done forMmArcwithMmWeakin coins) 🤔There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suspect this could be the reason of https://github.com/KomodoPlatform/komodo-defi-framework/actions/runs/12666194163/job/35297118282?pr=2301#step:9:895 failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not that i can trivially find the
AtomicSwappointing back to it self (points to mmctx tho: https://github.com/KomodoPlatform/komodo-defi-framework/blob/0a9410258c7bf58e78d26b33b7a0ffb749c7ba16/mm2src/mm2_main/src/lp_swap/maker_swap.rs#L213)you see, such questions are really hard to answer in such a codebase and require digging xD
it's much easier/managable to avoid the arc/weak model and use our abortable systems to make sure cyclic refs aren't problematic.
i went for arc here tho since we already manually remove the swap after it finishes or after stopping it. since we drop the thing manually we don't need to complicate it with weak refs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's worth to test that change (by using
test_mm2_stops_immediatelytest) to make sure that's not the case.