Skip to content

Commit 722efa4

Browse files
committed
refactgor
1 parent 446405d commit 722efa4

6 files changed

Lines changed: 66 additions & 19 deletions

File tree

duva/src/domains/caches/actor.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,16 @@ impl CacheActor {
225225
&mut self,
226226
key: String,
227227
index: isize,
228-
value: String,
228+
val: String,
229229
) -> Result<(), anyhow::Error> {
230-
let Some(CacheValue { value: TypedValue::List(list), .. }) = self.cache.get_mut(&key)
231-
else {
230+
let Some(var) = self.cache.get_mut(&key) else {
231+
return Err(anyhow::anyhow!("ERR no such key"));
232+
};
233+
let CacheValue { value: TypedValue::List(list), .. } = var else {
232234
return Err(anyhow::anyhow!(WRONG_TYPE_ERR_MSG));
233235
};
234-
list.lset(index, value)
236+
237+
list.lset(index, val)
235238
}
236239
}
237240

duva/src/domains/caches/cache_manager.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ impl CacheManager {
198198
| WriteRequest::LPushX { key, value } => {
199199
self.route_lpushx(key, value, log_index).await?;
200200
},
201+
| WriteRequest::LSet { key, index, value } => {
202+
self.route_lset(key, index, value, log_index).await?;
203+
},
201204
};
202205

203206
// * This is to wake up the cache actors to process the pending read requests
@@ -432,10 +435,10 @@ impl CacheManager {
432435
) -> Result<String> {
433436
let (tx, rx) = tokio::sync::oneshot::channel();
434437
self.select_shard(key.as_str())
435-
.send(CacheCommand::LSet { key, index, value: value.clone(), callback: tx.into() })
438+
.send(CacheCommand::LSet { key, index, value, callback: tx.into() })
436439
.await?;
437440
rx.await??;
438-
Ok(IndexedValueCodec::encode(value, current_idx))
441+
Ok(IndexedValueCodec::encode("", current_idx))
439442
}
440443
}
441444

duva/src/domains/caches/cache_objects/types/quicklist.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -537,28 +537,57 @@ impl QuickList {
537537
return Err(anyhow::anyhow!("List is empty"));
538538
}
539539

540-
// Calculate absolute index
540+
// Convert to absolute index
541541
let len = self.len as isize;
542-
let index = if index < 0 { (len + index).max(0) } else { index } as usize;
542+
let abs_index = if index < 0 { (len + index).max(0) } else { index } as usize;
543543

544-
if index >= self.len {
544+
if abs_index >= self.len {
545545
return Err(anyhow::anyhow!("Index out of bounds"));
546546
}
547547

548+
// Find the node containing this index
548549
let mut current_index = 0;
549550
for node in &mut self.nodes {
550-
if current_index + node.entry_count > index {
551+
if current_index + node.entry_count > abs_index {
552+
let local_index = abs_index - current_index;
553+
551554
node.ensure_decompressed(&self.fill_factor);
552555
if let NodeData::Uncompressed(ziplist) = &mut node.data {
553-
let mut entries = ziplist.to_vec();
554-
if let Some(entry) = entries.get_mut(index - current_index) {
555-
*entry = Bytes::from(value.clone());
556-
return Ok(());
556+
let new_bytes = Bytes::from(value);
557+
let mut cursor = 0;
558+
559+
// Skip to the target entry
560+
for _ in 0..local_index {
561+
let entry_len =
562+
u32::from_le_bytes(ziplist[cursor..cursor + 4].try_into().unwrap())
563+
as usize;
564+
cursor += 4 + entry_len;
557565
}
566+
567+
let old_entry_len =
568+
u32::from_le_bytes(ziplist[cursor..cursor + 4].try_into().unwrap())
569+
as usize;
570+
571+
if new_bytes.len() == old_entry_len {
572+
// Same size - overwrite in place
573+
ziplist[cursor + 4..cursor + 4 + old_entry_len].copy_from_slice(&new_bytes);
574+
} else {
575+
// Different size - rebuild ziplist
576+
let mut new_ziplist =
577+
Vec::with_capacity(ziplist.len() - old_entry_len + new_bytes.len());
578+
new_ziplist.extend_from_slice(&ziplist[0..cursor]);
579+
new_ziplist.extend_from_slice(&(new_bytes.len() as u32).to_le_bytes());
580+
new_ziplist.extend_from_slice(&new_bytes);
581+
new_ziplist.extend_from_slice(&ziplist[cursor + 4 + old_entry_len..]);
582+
ziplist.0 = new_ziplist;
583+
}
584+
585+
return Ok(());
558586
}
559587
}
560588
current_index += node.entry_count;
561589
}
590+
562591
Err(anyhow::anyhow!("Index not found"))
563592
}
564593
}

duva/src/domains/operation_logs/operation.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub enum WriteRequest {
2626
RPush { key: String, value: Vec<String> },
2727
LTrim { key: String, start: isize, end: isize },
2828
LPushX { key: String, value: Vec<String> },
29+
LSet { key: String, index: isize, value: String },
2930
}
3031

3132
impl WriteOperation {
@@ -66,6 +67,7 @@ impl WriteRequest {
6667
| WriteRequest::RPush { key, .. } => vec![key],
6768
| WriteRequest::LTrim { key, .. } => vec![key],
6869
| WriteRequest::LPushX { key, .. } => vec![key],
70+
| WriteRequest::LSet { key, .. } => vec![key],
6971
}
7072
}
7173
}

duva/src/presentation/clients/request.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ impl ClientAction {
7979
| ClientAction::RPushX { key, value } => WriteRequest::RPush { key, value },
8080
| ClientAction::RPop { key, count } => WriteRequest::LPop { key, count },
8181
| ClientAction::LTrim { key, start, end } => WriteRequest::LTrim { key, start, end },
82-
82+
| ClientAction::LSet { key, index, value } => WriteRequest::LSet { key, index, value },
8383
| _ => {
8484
debug_assert!(false, "to_write_request called on non-write action: {self:?}");
8585
unreachable!(
@@ -108,6 +108,7 @@ impl ClientAction {
108108
| ClientAction::RPushX { .. }
109109
| ClientAction::RPop { .. }
110110
| ClientAction::LTrim { .. }
111+
| ClientAction::LSet { .. }
111112
)
112113
}
113114
}
@@ -386,6 +387,13 @@ pub fn extract_action(action: &str, args: &[&str]) -> anyhow::Result<ClientActio
386387
let index = args[1].parse::<isize>().context("Invalid index")?;
387388
Ok(ClientAction::LIndex { key, index })
388389
},
390+
| "LSET" => {
391+
require_exact_args(3)?;
392+
let key = args[0].to_string();
393+
let index = args[1].parse::<isize>().context("Invalid index")?;
394+
let value = args[2].to_string();
395+
Ok(ClientAction::LSet { key, index, value })
396+
},
389397

390398
// Add other commands as needed
391399
| unknown_cmd => Err(anyhow::anyhow!(

duva/tests/client_ops/test_lset.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,22 @@ fn run_lset(env: ServerEnv) -> anyhow::Result<()> {
66

77
let mut h = Client::new(process.port);
88
let res = h.send_and_get(format!("RPUSH test one two three"));
9-
assert_eq!(res, "(integer) 5");
9+
assert_eq!(res, "(integer) 3");
1010

1111
//WHEN & ASSERT
1212
assert_eq!(h.send_and_get(format!("LSET test 0 four")), "OK");
1313
assert_eq!(h.send_and_get(format!("LSET test -2 five")), "OK");
1414
assert_eq!(
15-
h.send_and_get(format!("LRANGE test 0 -1")),
16-
"1) \"four\"\n2) \"five\"\n3) \"three\""
15+
h.send_and_get_vec(format!("LRANGE test 0 -1"), 3),
16+
vec!["1) \"four\"", "2) \"five\"", "3) \"three\""]
1717
);
1818

1919
// ERROR CASE
20+
21+
assert_eq!(h.send_and_get(format!("LSET test 10 error")), "(error) Index out of bounds");
2022
assert_eq!(h.send_and_get(format!("LSET x 1 2")), "(error) ERR no such key");
2123

22-
assert_eq!(h.send_and_get(format!("SET x 1 2")), "OK");
24+
assert_eq!(h.send_and_get(format!("SET x 1")), "OK");
2325
assert_eq!(
2426
h.send_and_get(format!("LSET x 0 2")),
2527
"(error) WRONGTYPE Operation against a key holding the wrong kind of value"

0 commit comments

Comments
 (0)