Repository: web3infra-foundation/mega (language: rust)

Issue:
Mercury decode panics when mem_limit is set to None
It seems to be introduced a long time ago. I'm bisecting.

Steps to reproduce:

1. navigate to `mercury/src/internal/pack/decode.rs:test_pack_decode_with_ref_delta`
2. set te second parameter of `Pack::new()` to `None`
3. run the test and observe the crash

Environment: 
```
cargo 1.85.0-nightly (20a443231 2024-12-06)
release: 1.85.0-nightly
commit-hash: 20a443231846b81c7b909691ec3f15eb173f2b18
commit-date: 2024-12-06
host: x86_64-unknown-linux-gnu
libgit2: 1.8.1 (sys:0.19.0 vendored)
libcurl: 8.9.0-DEV (sys:0.4.74+curl-8.9.0 vendored ssl:OpenSSL/1.1.1w)
ssl: OpenSSL 1.1.1w  11 Sep 2023
os: Arch Linux [64-bit]
```

Stacktrace: 
```
---- internal::pack::decode::tests::test_pack_decode_without_delta stdout ----
thread '<unnamed>' panicked at mercury/src/internal/pack/cache.rs:84:35:
called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }
stack backtrace:
   0: rust_begin_unwind
             at /rustc/21fe748be15271ea5804e0507cd699b675efe038/library/std/src/panicking.rs:681:5
   1: core::panicking::panic_fmt
             at /rustc/21fe748be15271ea5804e0507cd699b675efe038/library/core/src/panicking.rs:75:14
   2: core::result::unwrap_failed
             at /rustc/21fe748be15271ea5804e0507cd699b675efe038/library/core/src/result.rs:1699:5
   3: core::result::Result<T,E>::unwrap
             at /home/iz0/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs:1104:23
   4: mercury::internal::pack::cache::Caches::generate_temp_path
             at ./src/internal/pack/cache.rs:84:13
   5: <mercury::internal::pack::cache::Caches as mercury::internal::pack::cache::_Cache>::insert
             at ./src/internal/pack/cache.rs:156:34
   6: mercury::internal::pack::decode::<impl mercury::internal::pack::Pack>::cache_obj_and_process_waitlist
             at ./src/internal/pack/decode.rs:535:23
   7: mercury::internal::pack::decode::<impl mercury::internal::pack::Pack>::decode::{{closure}}
             at ./src/internal/pack/decode.rs:391:33
   8: <F as threadpool::FnBox>::call_box
             at /home/iz0/.cargo/registry/src/index.crates.io-6f17d22bba15001f/threadpool-1.8.1/src/lib.rs:95:9
   9: threadpool::spawn_in_pool::{{closure}}
 
thread '<unnamed>' panicked at mercury/src/internal/pack/cache.rs:150:49:
called `Result::unwrap()` on an `Err` value: PoisonError { .. }
```


Discussion / hints:
Found. Introduced by #382 979d2cf8dc900ddcef55af1393b67917860a810b.
I'm working on a fix.
A new test could be added to prevent regression.

Fix patch:
diff --git a/mercury/src/internal/pack/cache.rs b/mercury/src/internal/pack/cache.rs
index 64c4cd40..244a12f3 100644
--- a/mercury/src/internal/pack/cache.rs
+++ b/mercury/src/internal/pack/cache.rs
@@ -159,7 +159,9 @@ impl _Cache for Caches {
                 self.complete_signal.clone(),
                 Some(self.pool.clone()),
             );
-            a_obj.set_store_path(Caches::generate_temp_path(&self.tmp_path, hash));
+            if self.mem_size.is_some() {
+                a_obj.set_store_path(Caches::generate_temp_path(&self.tmp_path, hash));
+            }
             let _ = map.insert(hash, a_obj);
         }
         //order maters as for reading in 'get_by_offset()'
diff --git a/mercury/src/internal/pack/decode.rs b/mercury/src/internal/pack/decode.rs
index 2766e596..7755a03e 100644
--- a/mercury/src/internal/pack/decode.rs
+++ b/mercury/src/internal/pack/decode.rs
@@ -75,7 +75,7 @@ impl Pack {
             pool: Arc::new(ThreadPool::new(thread_num)),
             waitlist: Arc::new(Waitlist::new()),
             caches:  Arc::new(Caches::new(cache_mem_size, temp_path, thread_num)),
-            mem_limit: mem_limit.unwrap_or(usize::MAX),
+            mem_limit,
             cache_objs_mem: Arc::new(AtomicUsize::default()),
             clean_tmp,
         }
@@ -363,7 +363,8 @@ impl Pack {
             }
             // 3 parts: Waitlist + TheadPool + Caches
             // hardcode the limit of the tasks of threads_pool queue, to limit memory
-            while self.memory_used() > self.mem_limit || self.pool.queued_count() > 2000 {
+            while self.pool.queued_count() > 2000 
+                || self.mem_limit.map(|limit| self.memory_used() > limit).unwrap_or(false) {
                 thread::yield_now();
             }
             let r: Result<CacheObject, GitError> = self.decode_pack_object(&mut reader, &mut offset);
@@ -709,6 +710,19 @@ mod tests {
         p.decode(&mut buffered,|_,_|{}).unwrap();
     }
 
+    #[test]
+    fn test_pack_decode_no_mem_limit() {
+        let mut source = PathBuf::from(env::current_dir().unwrap().parent().unwrap());
+        source.push("tests/data/packs/pack-1d0e6c14760c956c173ede71cb28f33d921e232f.pack");
+
+        let tmp = PathBuf::from("/tmp/.cache_temp");
+
+        let f = fs::File::open(source).unwrap();
+        let mut buffered = BufReader::new(f);
+        let mut p = Pack::new(None, None, Some(tmp), true);
+        p.decode(&mut buffered, |_,_|{}).unwrap();
+    }
+
     #[test]
     fn test_pack_decode_with_large_file_with_delta_without_ref() {
         init_logger();
diff --git a/mercury/src/internal/pack/mod.rs b/mercury/src/internal/pack/mod.rs
index 3f942ca2..360204ce 100644
--- a/mercury/src/internal/pack/mod.rs
+++ b/mercury/src/internal/pack/mod.rs
@@ -29,7 +29,7 @@ pub struct Pack {
     pub pool: Arc<ThreadPool>,
     pub waitlist: Arc<Waitlist>,
     pub caches: Arc<Caches>,
-    pub mem_limit: usize,
+    pub mem_limit: Option<usize>,
     pub cache_objs_mem: Arc<AtomicUsize>, // the memory size of CacheObjects in this Pack
     pub clean_tmp: bool,
 }


Test patch: