Skip to content
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

Refactor unwrap to improve error handling #937

Merged
merged 1 commit into from
Jan 3, 2025
Merged

Conversation

BLYKIM
Copy link
Contributor

@BLYKIM BLYKIM commented Dec 23, 2024

Close: #899

Copy link

codecov bot commented Dec 23, 2024

Codecov Report

Attention: Patch coverage is 30.76923% with 18 lines in your changes missing coverage. Please review.

Project coverage is 77.18%. Comparing base (ffef4d1) to head (c2392e1).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/peer.rs 0.00% 5 Missing ⚠️
src/storage.rs 0.00% 4 Missing ⚠️
src/graphql/export.rs 0.00% 3 Missing ⚠️
src/main.rs 0.00% 3 Missing ⚠️
src/graphql/statistics.rs 0.00% 1 Missing ⚠️
src/lib.rs 75.00% 1 Missing ⚠️
src/publish/implement.rs 75.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #937      +/-   ##
==========================================
+ Coverage   77.17%   77.18%   +0.01%     
==========================================
  Files          32       32              
  Lines       25723    25722       -1     
==========================================
+ Hits        19851    19854       +3     
+ Misses       5872     5868       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

*iter_next_values.get_mut(idx).unwrap() = item;
*iter_next_values
.get_mut(idx)
.expect("value is always exist") = item;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to suggest fixing grammar: is always exist -> always exists

src/lib.rs Outdated
@@ -166,7 +166,7 @@ extern crate proc_macro;
#[proc_macro_derive(ConvertGraphQLEdgesNode, attributes(graphql_client_type))]
pub fn derive_from_graphql_client_autogen(input: TokenStream) -> TokenStream {
derive_from_graphql_client_autogen_2(input.into())
.unwrap()
.expect("valid input struct")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you handle this with panic! macro, instead of expect please? The file lib.rs is the code for proc-macro , which runs against the Giganto codebase, during compile time only, to generate code from our custom macro. And this part can panic, when the Giganto codebase uses the custom macro incorrectly. My personal idea is that the message could be something like "ConvertGraphQLEdgesNode macro is not correctly used for {input}"

@@ -13,14 +13,16 @@ pub trait RequestStreamMessage {

impl RequestStreamMessage for RequestHogStream {
fn channel_key(&self, sensor: Option<String>, record_type: &str) -> Result<Vec<String>> {
let sensor = sensor
.ok_or_else(|| anyhow!("Failed to generate hog channel key, sensor is required."))?;
Copy link
Contributor

@sophie-cluml sophie-cluml Dec 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use supervised model as the term. Or any other terms that refers to the supervised engine, that can be used in public space.

@sophie-cluml
Copy link
Contributor

Could you check the commit message title's length?

@BLYKIM BLYKIM changed the title Refactor unwrap usage to improve error handling and prevent panic Refactor unwrap to improve error handling Dec 24, 2024
*iter_next_values.get_mut(min_index).unwrap() = item;
*iter_next_values
.get_mut(min_index)
.expect("min_index's vector value always exists") = item;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this message is clear enough. I suggest:

"The index is one of the actual elements in the vector, so it is always valid."

@sehkone sehkone requested a review from kimhanbeom December 24, 2024 07:32
@@ -224,8 +224,7 @@ fn gen_statistics(
for idx in next_candidate {
if let Some(iter) = stats_iters.get_mut(idx) {
if let Some(item) = iter.next() {
// replace new value (value is always exist)
*iter_next_values.get_mut(idx).unwrap() = item;
*iter_next_values.get_mut(idx).expect("value always exists") = item;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to specify the reason as clearly as possible, for example:

"`next_candidate` is generated while iterating over `iter_next_value`, so any index of the former is always valid within the latter."

src/main.rs Outdated
@@ -313,7 +313,7 @@ async fn main() -> Result<()> {
if is_reboot || is_power_off || is_reload_config {
loop {
{
let retain_flag = retain_flag.lock().unwrap();
let retain_flag = retain_flag.lock().expect("Mutex lock is safe");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why this is safe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the message in expect about why the retain_flag is always safe needs to change, please also change the message about the running_flag in the retain_periodically function as well.

src/publish.rs Outdated
@@ -528,8 +528,7 @@ where
info!("start hog's publish stream : {:?}", record_type);
}
NodeType::Crusher => {
// crusher's policy Id always exists.
let id = msg.id().unwrap();
let id = msg.id().expect("crusher's policy Id always exists");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why this always exists?

Copy link
Contributor

@kimhanbeom kimhanbeom Dec 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The id is a method that gets the value of the id field of the RequestCrusherStream structure that cruhser sends to giganto.
    pub struct RequestCrusherStream {
        pub start: i64,
        pub id: String,
        pub src_ip: Option<IpAddr>,
        pub dst_ip: Option<IpAddr>,
        pub sensor: Option<String>,
    }
  • When crusher sends the value of that structure to giganto, it always includes the id value, so the value always exists.

Apart from this issue, the return value was Option because we used to call one method, source_id, to get the source or id values from the RequestStreamMessage trait, but now we have separated them into sensor and id. Id always has a value, so I think we can remove Option from the return value of the id method of the RequestStreamMessage trait in the future.

@@ -196,7 +196,7 @@ where
continue;
};
let new_key = StorageKey::builder()
.start_key(&netflow_raw_event.sensor().unwrap())
.start_key(&netflow_raw_event.sensor().expect("always exists"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why this is safe?

Copy link
Contributor

@kimhanbeom kimhanbeom Dec 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • The sensor is a method to get the value of the source field of Netflow5BeforeV23 and Netflow9BeforeV23.
     pub struct Netflow5BeforeV23 {
         pub source: String,
         .....
     }
     pub struct Netflow9BeforeV23 {
         pub source: String,
         .....
     }
  • In earlier versions of giganto, before the structure of netflow5 and netflow9 was changed, saving Netflow5BeforeV23 and Netflow9BeforeV23 to the DB was done in the following order
    • Receive netflow5, netflow9 from REproduce. (via ingest)
    • Extract the source from the certificate in REproduce and store the value in the source field of each structure.
    • Store the final struct values to the DB.
  • Due to the above processing order, the source value always exists, and so do the results of the sensor that fetch them.

src/main.rs Outdated
@@ -313,7 +313,7 @@ async fn main() -> Result<()> {
if is_reboot || is_power_off || is_reload_config {
loop {
{
let retain_flag = retain_flag.lock().unwrap();
let retain_flag = retain_flag.lock().expect("Mutex lock is safe because it only guards a simple boolean flag without complex operations.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this message sufficiently explains why we can always expect safe results.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, I used the “always safe” message in expect because the Mutex only protects a simple boolean flag, which makes it unlikely to panic within the lock scope.
However, after considering the possibility of other parts of the system panicking while holding the lock, I decided to replace expect with unwrap_or_else.
In case of poisoning, the value is now safely recovered, and a warning message is logged to aid debugging.

src/storage.rs Outdated
@@ -1038,7 +1041,10 @@ pub async fn retain_periodically(
}
info!("Database cleanup completed.");
{
let mut running_flag = running_flag.lock().unwrap();
let mut running_flag = running_flag.lock().unwrap_or_else(|e| {
warn!("Poisoned Mutex. Recovering the boolean flag.");
Copy link
Contributor

@sophie-cluml sophie-cluml Dec 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use AtomicBool type instead of Mutex for the running_flag. I think we can avoid potential panicking from the mutex behavior, and achieve simpler code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the suggestion!

@sophie-cluml
Copy link
Contributor

@BLYKIM Could you check the line length of the commit content?

- Refactor `Mutex<bool>` to `AtomicBool` to prevent potential panics
  and enhance performance.
@BLYKIM BLYKIM force-pushed the bly/remove_unwrap branch from eab96b0 to c2392e1 Compare January 3, 2025 04:27
@sophie-cluml sophie-cluml merged commit b096c59 into main Jan 3, 2025
9 of 10 checks passed
@sophie-cluml sophie-cluml deleted the bly/remove_unwrap branch January 3, 2025 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Remove unwrap
4 participants