diff --git a/crates/ember-core/src/keyspace.rs b/crates/ember-core/src/keyspace.rs index 88aa86a9..7a0691c4 100644 --- a/crates/ember-core/src/keyspace.rs +++ b/crates/ember-core/src/keyspace.rs @@ -386,10 +386,16 @@ impl Keyspace { /// Measures entry size before and after a mutation, adjusting the /// memory tracker for the difference. Touches the entry afterwards. fn track_size(&mut self, key: &str, f: impl FnOnce(&mut Entry) -> T) -> T { - let entry = self.entries.get_mut(key).expect("caller verified key exists"); + let entry = self + .entries + .get_mut(key) + .expect("caller verified key exists"); let old_size = memory::entry_size(key, &entry.value); let result = f(entry); - let entry = self.entries.get(key).expect("mutation should not remove key"); + let entry = self + .entries + .get(key) + .expect("mutation should not remove key"); let new_size = memory::entry_size(key, &entry.value); self.memory.adjust(old_size, new_size); result @@ -1128,7 +1134,12 @@ impl Keyspace { .iter() .map(|v| memory::VECDEQUE_ELEMENT_OVERHEAD + v.len()) .sum(); - self.reserve_memory(is_new, key, memory::VECDEQUE_BASE_OVERHEAD, element_increase)?; + self.reserve_memory( + is_new, + key, + memory::VECDEQUE_BASE_OVERHEAD, + element_increase, + )?; if is_new { self.insert_empty(key, Value::List(VecDeque::new())); @@ -1201,8 +1212,7 @@ impl Keyspace { ) -> Result { self.remove_if_expired(key); - let is_new = - self.ensure_collection_type(key, |v| matches!(v, Value::SortedSet(_)))?; + let is_new = self.ensure_collection_type(key, |v| matches!(v, Value::SortedSet(_)))?; // worst-case estimate: assume all members are new let member_increase: usize = members @@ -1260,7 +1270,9 @@ impl Keyspace { return Ok(vec![]); } - let Some(entry) = self.entries.get(key) else { return Ok(vec![]) }; + let Some(entry) = self.entries.get(key) else { + return Ok(vec![]); + }; if !matches!(entry.value, Value::SortedSet(_)) { return Err(WrongType); } diff --git a/crates/ember-persistence/src/aof.rs b/crates/ember-persistence/src/aof.rs index 99dc0698..9c67d23a 100644 --- a/crates/ember-persistence/src/aof.rs +++ b/crates/ember-persistence/src/aof.rs @@ -360,15 +360,13 @@ impl AofRecord { format::write_bytes(&mut buf, key.as_bytes())?; format::write_i64(&mut buf, *milliseconds as i64)?; } - AofRecord::IncrBy { key, delta } - | AofRecord::DecrBy { key, delta } => { + AofRecord::IncrBy { key, delta } | AofRecord::DecrBy { key, delta } => { format::write_bytes(&mut buf, key.as_bytes())?; format::write_i64(&mut buf, *delta)?; } // key + byte list - AofRecord::LPush { key, values } - | AofRecord::RPush { key, values } => { + AofRecord::LPush { key, values } | AofRecord::RPush { key, values } => { format::write_bytes(&mut buf, key.as_bytes())?; format::write_len(&mut buf, values.len())?; for v in values { diff --git a/crates/ember-server/src/cluster.rs b/crates/ember-server/src/cluster.rs index 842d49c2..46cdfab8 100644 --- a/crates/ember-server/src/cluster.rs +++ b/crates/ember-server/src/cluster.rs @@ -53,8 +53,11 @@ impl ClusterCoordinator { let (event_tx, event_rx) = mpsc::channel(256); let port_offset = gossip_config.gossip_port_offset; - let gossip_addr = - SocketAddr::new(bind_addr.ip(), bind_addr.port().saturating_add(port_offset)); + let gossip_port = bind_addr + .port() + .checked_add(port_offset) + .expect("gossip port offset overflows u16"); + let gossip_addr = SocketAddr::new(bind_addr.ip(), gossip_port); let gossip = GossipEngine::new(local_id, gossip_addr, gossip_config, event_tx); @@ -420,10 +423,14 @@ impl ClusterCoordinator { bind_addr: SocketAddr, mut event_rx: mpsc::Receiver, ) { - let gossip_addr = SocketAddr::new( - bind_addr.ip(), - bind_addr.port().saturating_add(self.gossip_port_offset), - ); + let gossip_port = match bind_addr.port().checked_add(self.gossip_port_offset) { + Some(p) => p, + None => { + error!("gossip port offset overflows u16"); + return; + } + }; + let gossip_addr = SocketAddr::new(bind_addr.ip(), gossip_port); let socket = match UdpSocket::bind(gossip_addr).await { Ok(s) => Arc::new(s), diff --git a/crates/ember-server/src/connection.rs b/crates/ember-server/src/connection.rs index 11996b56..756f9640 100644 --- a/crates/ember-server/src/connection.rs +++ b/crates/ember-server/src/connection.rs @@ -1249,9 +1249,7 @@ async fn resolve_response( fn resolve_shard_response(resp: ShardResponse, tag: ResponseTag) -> Frame { match tag { // Value(Some(String)) → Bulk, Value(None) → Null - ResponseTag::Get - | ResponseTag::PopResult - | ResponseTag::HGetResult => match resp { + ResponseTag::Get | ResponseTag::PopResult | ResponseTag::HGetResult => match resp { ShardResponse::Value(Some(Value::String(data))) => Frame::Bulk(data), ShardResponse::Value(None) => Frame::Null, ShardResponse::WrongType => wrongtype_error(), @@ -1273,8 +1271,7 @@ fn resolve_shard_response(resp: ShardResponse, tag: ResponseTag) -> Frame { }, // Bool → Integer(0/1), with WrongType - ResponseTag::HExistsResult - | ResponseTag::SIsMemberResult => match resp { + ResponseTag::HExistsResult | ResponseTag::SIsMemberResult => match resp { ShardResponse::Bool(b) => Frame::Integer(i64::from(b)), ShardResponse::WrongType => wrongtype_error(), other => Frame::Error(format!("ERR unexpected shard response: {other:?}")), @@ -1310,8 +1307,7 @@ fn resolve_shard_response(resp: ShardResponse, tag: ResponseTag) -> Frame { }, // Len → Integer, with WrongType + OOM - ResponseTag::LenResultOom - | ResponseTag::HSetResult => match resp { + ResponseTag::LenResultOom | ResponseTag::HSetResult => match resp { ShardResponse::Len(n) => Frame::Integer(n as i64), ShardResponse::WrongType => wrongtype_error(), ShardResponse::OutOfMemory => oom_error(), @@ -1327,8 +1323,7 @@ fn resolve_shard_response(resp: ShardResponse, tag: ResponseTag) -> Frame { }, // Array of Bytes → Array of Bulk - ResponseTag::ArrayResult - | ResponseTag::HValsResult => match resp { + ResponseTag::ArrayResult | ResponseTag::HValsResult => match resp { ShardResponse::Array(items) => { Frame::Array(items.into_iter().map(Frame::Bulk).collect()) } diff --git a/crates/ember-server/src/grpc.rs b/crates/ember-server/src/grpc.rs index 6b07a022..65d6f4ca 100644 --- a/crates/ember-server/src/grpc.rs +++ b/crates/ember-server/src/grpc.rs @@ -43,6 +43,8 @@ impl EmberService { /// Build this service into a tonic router, optionally with auth. pub fn into_service(self) -> proto::ember_cache_server::EmberCacheServer { proto::ember_cache_server::EmberCacheServer::new(self) + .max_decoding_message_size(4 * 1024 * 1024) // 4 MB + .max_encoding_message_size(4 * 1024 * 1024) } /// Routes a single-key request through the engine. @@ -110,6 +112,7 @@ const MAX_HNSW_M: u32 = 1_024; #[cfg(feature = "vector")] const MAX_HNSW_EF: u32 = 1_024; +#[allow(clippy::result_large_err)] // Status is tonic's idiomatic error type fn validate_key(key: &str) -> Result<(), Status> { if key.is_empty() { return Err(Status::invalid_argument("key must not be empty")); @@ -123,6 +126,7 @@ fn validate_key(key: &str) -> Result<(), Status> { Ok(()) } +#[allow(clippy::result_large_err)] // Status is tonic's idiomatic error type fn validate_value(value: &[u8]) -> Result<(), Status> { if value.len() > MAX_VALUE_LEN { return Err(Status::invalid_argument(format!( @@ -165,9 +169,7 @@ impl EmberCache for EmberService { value: Some(value_to_bytes(v)), })), ShardResponse::Value(None) => Ok(Response::new(GetResponse { value: None })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -196,9 +198,7 @@ impl EmberCache for EmberService { ShardResponse::Ok => Ok(Response::new(SetResponse { ok: true })), ShardResponse::Value(None) => Ok(Response::new(SetResponse { ok: false })), ShardResponse::OutOfMemory => Err(Status::resource_exhausted("OOM")), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -309,9 +309,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Integer(v) => Ok(Response::new(IntResponse { value: v })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -334,9 +332,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Integer(v) => Ok(Response::new(IntResponse { value: v })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -359,9 +355,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Integer(v) => Ok(Response::new(IntResponse { value: v })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -384,9 +378,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::BulkString(s) => Ok(Response::new(FloatResponse { value: s })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -409,9 +401,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -428,9 +418,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -480,9 +468,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Bool(v) => Ok(Response::new(BoolResponse { value: v })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -505,9 +491,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Bool(v) => Ok(Response::new(BoolResponse { value: v })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -524,9 +508,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Bool(v) => Ok(Response::new(BoolResponse { value: v })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -547,9 +529,7 @@ impl EmberCache for EmberService { })), ShardResponse::Ttl(TtlResult::NoExpiry) => Ok(Response::new(TtlResponse { value: -1 })), ShardResponse::Ttl(TtlResult::NotFound) => Ok(Response::new(TtlResponse { value: -2 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -570,9 +550,7 @@ impl EmberCache for EmberService { })), ShardResponse::Ttl(TtlResult::NoExpiry) => Ok(Response::new(TtlResponse { value: -1 })), ShardResponse::Ttl(TtlResult::NotFound) => Ok(Response::new(TtlResponse { value: -2 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -646,9 +624,7 @@ impl EmberCache for EmberService { status: "OK".to_string(), })), ShardResponse::Err(msg) => Err(Status::not_found(msg)), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -658,7 +634,7 @@ impl EmberCache for EmberService { let count = if req.count == 0 { 10 } else { - req.count as usize + (req.count as usize).min(10_000) }; // the global cursor encodes both which shard we're scanning and where @@ -735,9 +711,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -761,9 +735,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -780,9 +752,7 @@ impl EmberCache for EmberService { value: Some(value_to_bytes(v)), })), ShardResponse::Value(None) => Ok(Response::new(GetResponse { value: None })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -799,9 +769,7 @@ impl EmberCache for EmberService { value: Some(value_to_bytes(v)), })), ShardResponse::Value(None) => Ok(Response::new(GetResponse { value: None })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -827,9 +795,7 @@ impl EmberCache for EmberService { ShardResponse::Array(arr) => Ok(Response::new(ArrayResponse { values: arr.into_iter().map(|b| b.to_vec()).collect(), })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -843,9 +809,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -874,9 +838,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -899,9 +861,7 @@ impl EmberCache for EmberService { value: Some(value_to_bytes(v)), })), ShardResponse::Value(None) => Ok(Response::new(GetResponse { value: None })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -926,9 +886,7 @@ impl EmberCache for EmberService { }) .collect(), })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -950,9 +908,7 @@ impl EmberCache for EmberService { ShardResponse::HDelLen { count, .. } => Ok(Response::new(IntResponse { value: count as i64, })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -975,9 +931,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Bool(v) => Ok(Response::new(BoolResponse { value: v })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -991,9 +945,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1017,9 +969,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Integer(v) => Ok(Response::new(IntResponse { value: v })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1036,9 +986,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::StringArray(keys) => Ok(Response::new(KeysResponse { keys })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1057,9 +1005,7 @@ impl EmberCache for EmberService { ShardResponse::Array(arr) => Ok(Response::new(ArrayResponse { values: arr.into_iter().map(|b| b.to_vec()).collect(), })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1089,9 +1035,7 @@ impl EmberCache for EmberService { }) .collect(), })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1115,9 +1059,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1137,9 +1079,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1158,9 +1098,7 @@ impl EmberCache for EmberService { ShardResponse::StringArray(members) => { Ok(Response::new(KeysResponse { keys: members })) } - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1183,9 +1121,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Bool(v) => Ok(Response::new(BoolResponse { value: v })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1202,9 +1138,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1240,9 +1174,7 @@ impl EmberCache for EmberService { ShardResponse::ZAddLen { count, .. } => Ok(Response::new(IntResponse { value: count as i64, })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1264,9 +1196,7 @@ impl EmberCache for EmberService { ShardResponse::ZRemLen { count, .. } => Ok(Response::new(IntResponse { value: count as i64, })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1289,9 +1219,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Score(s) => Ok(Response::new(OptionalFloatResponse { value: s })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1316,9 +1244,7 @@ impl EmberCache for EmberService { ShardResponse::Rank(r) => Ok(Response::new(OptionalIntResponse { value: r.map(|n| n as i64), })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1335,9 +1261,7 @@ impl EmberCache for EmberService { match resp { ShardResponse::Len(n) => Ok(Response::new(IntResponse { value: n as i64 })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } } @@ -1376,9 +1300,7 @@ impl EmberCache for EmberService { }) .collect(), })), - other => { - Err(unexpected_response(&other)) - } + other => Err(unexpected_response(&other)), } }