v0.4.3: Lock contention overhaul, StoragePool, mobile bottom nav, text scaling
Eliminate all conn_mgr lock holds during network I/O across 14 actor commands and bi-stream handlers. PostFetch, TcpPunch, PullFromPeer, FetchEngagement, ResolveAddress, AnchorProbe use brief locks for data gathering only. WormLookup, ContentSearch, WormQuery use connection snapshots for lock-free cascade fan-out. RelayIntroduce extracts forwarding data under brief lock, does I/O outside. BlobRequest, PostFetchRequest, ManifestRefresh use Arc clones instead of conn_mgr lock. ConnectionActor hoists shared Arcs (storage, blob_store, endpoint) for lock-free access. ResolveAddress adds 5s per-query timeout (was unbounded). Initial exchange failure now aborts mesh upgrade (was silently continuing with broken connection). connect_to_peer/connect_to_anchor use consistent 15s timeout. Rebalance connects outside the lock via pending_connects pattern. StoragePool: 8 concurrent SQLite connections in WAL mode replace single Mutex<Storage>. Reads run fully parallel; writes serialize at SQLite level only. PRAGMA busy_timeout=5000 for graceful write contention. Mobile bottom nav bar (<=768px) with icon tabs. Text sizes: XS/S/M/L/XL (75%/100%/125%/150%/200%), default M. localStorage persistence for instant restore. Toast repositioned above mobile nav. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f17535d61d
commit
43adbbdf7d
15 changed files with 1546 additions and 618 deletions
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "itsgoin-desktop"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ async fn post_to_dto(
|
|||
|
||||
// Resolve intent kind from storage
|
||||
let intent_kind = {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
match storage.get_post_intent(id) {
|
||||
Ok(Some(intent)) => match intent {
|
||||
VisibilityIntent::Public => "public".to_string(),
|
||||
|
|
@ -237,14 +237,14 @@ async fn post_to_dto(
|
|||
.collect();
|
||||
// Engagement data
|
||||
let reaction_counts = {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
storage.get_reaction_counts(id, &node.node_id).unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(|(emoji, count, reacted_by_me)| ReactionCountDto { emoji, count, reacted_by_me })
|
||||
.collect()
|
||||
};
|
||||
let comment_count = {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
storage.get_comment_count(id).unwrap_or(0)
|
||||
};
|
||||
|
||||
|
|
@ -286,7 +286,7 @@ async fn decrypt_just_created(
|
|||
}
|
||||
PostVisibility::GroupEncrypted { group_id, epoch, wrapped_cek } => {
|
||||
let seed_info = {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
storage.get_all_group_seeds_map().ok()
|
||||
.and_then(|map| map.get(&(*group_id, *epoch)).copied())
|
||||
};
|
||||
|
|
@ -319,7 +319,7 @@ async fn get_node_info(state: State<'_, AppState>) -> Result<NodeInfoDto, String
|
|||
// Prefer external address (UPnP, public IPv6, observed) over local bind address
|
||||
let external_addr = node.network.http_addr();
|
||||
let observed_addr = if external_addr.is_none() {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
storage.get_peer_record(&node.node_id).ok().flatten()
|
||||
.and_then(|r| r.addresses.first().map(|a| a.to_string()))
|
||||
} else {
|
||||
|
|
@ -475,7 +475,7 @@ async fn get_blob_path(
|
|||
if let Some(ref pid_hex) = post_id_hex {
|
||||
if let Ok(pid_bytes) = hex::decode(pid_hex) {
|
||||
if let Ok(post_id) = <[u8; 32]>::try_from(pid_bytes.as_slice()) {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
if let Ok(Some((_post, vis))) = storage.get_post_with_visibility(&post_id) {
|
||||
if !matches!(vis, PostVisibility::Public) {
|
||||
return Ok(None);
|
||||
|
|
@ -524,7 +524,7 @@ async fn resolve_blob_data(
|
|||
// Try fetching from network if post_id provided
|
||||
if let Some(pid) = post_id {
|
||||
let post = {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
storage.get_post(&pid).map_err(|e| e.to_string())?
|
||||
};
|
||||
if let Some(post) = post {
|
||||
|
|
@ -665,7 +665,7 @@ async fn connect_peer(
|
|||
// Store peer with addresses
|
||||
let ip_addrs: Vec<_> = addr.ip_addrs().copied().collect();
|
||||
{
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
if ip_addrs.is_empty() {
|
||||
storage.add_peer(&nid).map_err(|e| e.to_string())?;
|
||||
} else {
|
||||
|
|
@ -720,7 +720,7 @@ async fn list_follows(state: State<'_, AppState>) -> Result<Vec<PeerDto>, String
|
|||
_ => None,
|
||||
};
|
||||
// Try to get peer record for address info
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
let rec = storage.get_peer_record(nid).ok().flatten();
|
||||
drop(storage);
|
||||
let is_online = node.network.is_connected(nid).await
|
||||
|
|
@ -766,7 +766,7 @@ async fn list_peers(state: State<'_, AppState>) -> Result<Vec<PeerDto>, String>
|
|||
.map(|(nid, _, _)| nid)
|
||||
.collect();
|
||||
let (social_ids, n2_ids, n3_ids) = {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
let social: std::collections::HashSet<_> = storage
|
||||
.list_social_routes()
|
||||
.unwrap_or_default()
|
||||
|
|
@ -994,7 +994,7 @@ async fn set_anchors(
|
|||
#[tauri::command]
|
||||
async fn list_anchor_peers(state: State<'_, AppState>) -> Result<Vec<PeerDto>, String> {
|
||||
let node = state.inner();
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
let records = storage.list_anchor_peers().map_err(|e| e.to_string())?;
|
||||
drop(storage);
|
||||
let mut dtos = Vec::with_capacity(records.len());
|
||||
|
|
@ -1026,7 +1026,7 @@ struct KnownAnchorDto {
|
|||
#[tauri::command]
|
||||
async fn list_known_anchors(state: State<'_, AppState>) -> Result<Vec<KnownAnchorDto>, String> {
|
||||
let node = state.inner();
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
let anchors = storage.list_known_anchors().map_err(|e| e.to_string())?;
|
||||
drop(storage);
|
||||
let mut dtos = Vec::with_capacity(anchors.len());
|
||||
|
|
@ -1444,7 +1444,7 @@ async fn get_badge_counts(
|
|||
last_feed_view_ms: u64,
|
||||
) -> Result<BadgeCountsDto, String> {
|
||||
let node = state.inner();
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
|
||||
// Feed badge: count non-DM posts from others newer than last_feed_view_ms
|
||||
let feed_posts = storage.get_feed().map_err(|e| e.to_string())?;
|
||||
|
|
@ -1588,7 +1588,7 @@ async fn get_network_summary(state: State<'_, AppState>) -> Result<NetworkSummar
|
|||
}
|
||||
}
|
||||
let (n2, n3) = {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
let n2 = storage.count_distinct_n2().unwrap_or(0);
|
||||
let n3 = storage.count_distinct_n3().unwrap_or(0);
|
||||
(n2, n3)
|
||||
|
|
@ -1664,7 +1664,7 @@ async fn request_referrals(state: State<'_, AppState>) -> Result<String, String>
|
|||
// Try known_anchors table first (populated by anchor register cycle),
|
||||
// fall back to anchor peers from the peers table (is_anchor = true)
|
||||
let anchors: Vec<(NodeId, Vec<std::net::SocketAddr>)> = {
|
||||
let storage = node.storage.lock().await;
|
||||
let storage = node.storage.get().await;
|
||||
let known = storage.list_known_anchors().unwrap_or_default();
|
||||
if !known.is_empty() {
|
||||
known
|
||||
|
|
@ -2096,7 +2096,7 @@ pub fn run() {
|
|||
|
||||
// Start blob eviction cycle (every 5 min)
|
||||
let cache_max_bytes: u64 = {
|
||||
let storage = n.storage.lock().await;
|
||||
let storage = n.storage.get().await;
|
||||
storage.get_setting("cache_size_bytes")
|
||||
.ok()
|
||||
.flatten()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"productName": "itsgoin",
|
||||
"version": "0.4.2",
|
||||
"version": "0.4.3",
|
||||
"identifier": "com.itsgoin.app",
|
||||
"build": {
|
||||
"frontendDist": "../../frontend",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue