diff options
| author | Valentin Popov <valentin@popov.link> | 2026-06-22 15:36:50 +0300 |
|---|---|---|
| committer | Valentin Popov <valentin@popov.link> | 2026-06-22 15:36:50 +0300 |
| commit | fb97405e0c47dadf656e5c92c76ddaff95d78222 (patch) | |
| tree | 9faf092f019e1773bdc2c6116091fdcfaf586547 /crates | |
| parent | d579b696e6056ca5c6456baca2edad516658d18c (diff) | |
| download | fparkan-fb97405e0c47dadf656e5c92c76ddaff95d78222.tar.xz fparkan-fb97405e0c47dadf656e5c92c76ddaff95d78222.zip | |
fix: decode payloads outside resource lock
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/fparkan-resource/src/lib.rs | 59 |
1 files changed, 40 insertions, 19 deletions
diff --git a/crates/fparkan-resource/src/lib.rs b/crates/fparkan-resource/src/lib.rs index 0ab6b80..b09c946 100644 --- a/crates/fparkan-resource/src/lib.rs +++ b/crates/fparkan-resource/src/lib.rs @@ -210,7 +210,7 @@ struct ArchiveSlot { fingerprint: Sha256Digest, generation: u64, kind: ArchiveKind, - document: ArchiveDocument, + document: Arc<ArchiveDocument>, } enum ArchiveDocument { @@ -218,6 +218,11 @@ enum ArchiveDocument { Rsli(fparkan_rsli::RsliDocument), } +struct PayloadDecodeTask { + document: Arc<ArchiveDocument>, + key: ResourceKey, +} + #[derive(Debug, Default)] struct DecodedPayloadCache { max_entries: usize, @@ -320,7 +325,7 @@ impl ResourceRepository for CachedResourceRepository { ) -> Result<Option<EntryHandle>, ResourceError> { let state = self.state.lock().map_err(|_| ResourceError::Poisoned)?; let slot = state.archive(archive)?; - let local = match &slot.document { + let local = match slot.document.as_ref() { ArchiveDocument::Nres(document) => document.find_bytes(&name.0).map(|id| id.0), ArchiveDocument::Rsli(document) => document.find_bytes(&name.0).map(|id| id.0), }; @@ -334,7 +339,7 @@ impl ResourceRepository for CachedResourceRepository { fn first_entry(&self, archive: ArchiveId) -> Result<Option<EntryHandle>, ResourceError> { let state = self.state.lock().map_err(|_| ResourceError::Poisoned)?; let slot = state.archive(archive)?; - let local = match &slot.document { + let local = match slot.document.as_ref() { ArchiveDocument::Nres(document) => document.entries().first().map(|entry| entry.id().0), ArchiveDocument::Rsli(document) => document.entry(fparkan_rsli::EntryId(0)).map(|_| 0), }; @@ -346,21 +351,27 @@ impl ResourceRepository for CachedResourceRepository { } fn read(&self, entry: EntryHandle) -> Result<ResourceBytes, ResourceError> { + let task = { + let mut state = self.state.lock().map_err(|_| ResourceError::Poisoned)?; + if let Some(bytes) = state.payload_cache.get(entry) { + return Ok(ResourceBytes::Shared(bytes)); + } + state.payload_decode_task(entry)? + }; + let payload = + task.document + .read_payload(entry.local) + .map_err(|source| ResourceError::EntryRead { + key: task.key, + source, + })?; + let shared = Arc::from(payload.into_boxed_slice()); + let mut state = self.state.lock().map_err(|_| ResourceError::Poisoned)?; if let Some(bytes) = state.payload_cache.get(entry) { return Ok(ResourceBytes::Shared(bytes)); } - - let payload = { - let slot = state.entry_archive(entry)?; - let key = slot.entry_key(entry.local)?; - slot.read_payload(entry.local) - .map_err(|source| ResourceError::EntryRead { - key: key.clone(), - source, - })? - }; - let shared = Arc::from(payload.into_boxed_slice()); + state.entry_archive(entry)?; state.payload_cache.insert(entry, Arc::clone(&shared)); Ok(ResourceBytes::Shared(shared)) } @@ -368,7 +379,7 @@ impl ResourceRepository for CachedResourceRepository { fn entry_info(&self, entry: EntryHandle) -> Result<ResourceEntryInfo, ResourceError> { let state = self.state.lock().map_err(|_| ResourceError::Poisoned)?; let slot = state.entry_archive(entry)?; - match &slot.document { + match slot.document.as_ref() { ArchiveDocument::Nres(document) => { let local = usize::try_from(entry.local).map_err(|_| ResourceError::InvalidHandle)?; @@ -512,11 +523,19 @@ impl RepositoryState { } Ok(slot) } + + fn payload_decode_task(&self, entry: EntryHandle) -> Result<PayloadDecodeTask, ResourceError> { + let slot = self.entry_archive(entry)?; + Ok(PayloadDecodeTask { + document: Arc::clone(&slot.document), + key: slot.entry_key(entry.local)?, + }) + } } impl ArchiveSlot { fn entry_key(&self, local: u32) -> Result<ResourceKey, ResourceError> { - match &self.document { + match self.document.as_ref() { ArchiveDocument::Nres(document) => { let local = usize::try_from(local).map_err(|_| ResourceError::InvalidHandle)?; let entry = document @@ -541,9 +560,11 @@ impl ArchiveSlot { } } } +} +impl ArchiveDocument { fn read_payload(&self, local: u32) -> Result<Vec<u8>, String> { - match &self.document { + match self { ArchiveDocument::Nres(document) => document .payload(fparkan_nres::EntryId(local)) .map(<[u8]>::to_vec) @@ -568,7 +589,7 @@ fn decode_archive( fingerprint, generation: 0, kind: ArchiveKind::Nres, - document: ArchiveDocument::Nres(document), + document: Arc::new(ArchiveDocument::Nres(document)), }); } if bytes.get(0..4) == Some(b"NL\0\x01") { @@ -579,7 +600,7 @@ fn decode_archive( fingerprint, generation: 0, kind: ArchiveKind::Rsli, - document: ArchiveDocument::Rsli(document), + document: Arc::new(ArchiveDocument::Rsli(document)), }); } Err(ResourceError::Format( |
