-
Notifications
You must be signed in to change notification settings - Fork 15
feat: momento apis - set_if_absent, set_if_present_and_not_equal, item_get_type #372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| use super::*; | ||
| use ::momento::cache::ItemGetTypeResponse; | ||
|
|
||
| pub async fn item_get_type( | ||
| client: &mut CacheClient, | ||
| config: &Config, | ||
| cache_name: &str, | ||
| request: workload::client::ItemGetType, | ||
| ) -> std::result::Result<(), ResponseError> { | ||
| ITEM_GET_TYPE.increment(); | ||
|
|
||
| match timeout( | ||
| config.client().unwrap().request_timeout(), | ||
| client.item_get_type(cache_name, (*request.key).to_owned()), | ||
| ) | ||
| .await | ||
| { | ||
| Ok(Ok(r)) => match r { | ||
| ItemGetTypeResponse::Hit { .. } => { | ||
| ITEM_GET_TYPE_HIT.increment(); | ||
| Ok(()) | ||
| } | ||
| ItemGetTypeResponse::Miss => { | ||
| ITEM_GET_TYPE_MISS.increment(); | ||
| Ok(()) | ||
| } | ||
| }, | ||
| Ok(Err(e)) => { | ||
| ITEM_GET_TYPE_EX.increment(); | ||
| Err(e.into()) | ||
| } | ||
| Err(_) => { | ||
| ITEM_GET_TYPE_TIMEOUT.increment(); | ||
| Err(ResponseError::Timeout) | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| use super::*; | ||
| use ::momento::cache::SetIfAbsentResponse; | ||
|
|
||
| pub async fn set_if_absent( | ||
| client: &mut CacheClient, | ||
| config: &Config, | ||
| cache_name: &str, | ||
| request: workload::client::SetIfAbsent, | ||
| ) -> std::result::Result<(), ResponseError> { | ||
| SET_IF_ABSENT.increment(); | ||
|
|
||
| match timeout( | ||
| config.client().unwrap().request_timeout(), | ||
| client.set_if_absent( | ||
| cache_name, | ||
| (*request.key).to_owned(), | ||
| (*request.value).to_owned(), | ||
| ), | ||
| ) | ||
| .await | ||
| { | ||
| Ok(Ok(r)) => match r { | ||
| SetIfAbsentResponse::Stored { .. } => { | ||
| SET_IF_ABSENT_STORED.increment(); | ||
| Ok(()) | ||
| } | ||
| SetIfAbsentResponse::NotStored => { | ||
| SET_IF_ABSENT_NOT_STORED.increment(); | ||
| Ok(()) | ||
| } | ||
| }, | ||
| Ok(Err(e)) => { | ||
| SET_IF_ABSENT_EX.increment(); | ||
| Err(e.into()) | ||
| } | ||
| Err(_) => { | ||
| SET_IF_ABSENT_TIMEOUT.increment(); | ||
| Err(ResponseError::Timeout) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| use super::*; | ||
| use ::momento::cache::SetIfPresentAndNotEqualResponse; | ||
|
|
||
| pub async fn set_if_present_and_not_equal( | ||
| client: &mut CacheClient, | ||
| config: &Config, | ||
| cache_name: &str, | ||
| request: workload::client::SetIfPresentAndNotEqual, | ||
| ) -> std::result::Result<(), ResponseError> { | ||
| SET_IF_PRESENT_AND_NOT_EQUAL.increment(); | ||
|
|
||
| match timeout( | ||
| config.client().unwrap().request_timeout(), | ||
| client.set_if_present_and_not_equal( | ||
| cache_name, | ||
| (*request.key).to_owned(), | ||
| (*request.new_value).to_owned(), | ||
| (*request.old_value).to_owned(), | ||
| ), | ||
| ) | ||
| .await | ||
| { | ||
| Ok(Ok(r)) => match r { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here as with my comment above. record_result + if let might make this cleaner) |
||
| SetIfPresentAndNotEqualResponse::Stored { .. } => { | ||
| SET_IF_PRESENT_AND_NOT_EQUAL_STORED.increment(); | ||
| Ok(()) | ||
| } | ||
| SetIfPresentAndNotEqualResponse::NotStored => { | ||
| SET_IF_PRESENT_AND_NOT_EQUAL_NOT_STORED.increment(); | ||
| Ok(()) | ||
| } | ||
| }, | ||
| Ok(Err(e)) => { | ||
| SET_IF_PRESENT_AND_NOT_EQUAL_EX.increment(); | ||
| Err(e.into()) | ||
| } | ||
| Err(_) => { | ||
| SET_IF_PRESENT_AND_NOT_EQUAL_TIMEOUT.increment(); | ||
| Err(ResponseError::Timeout) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -370,6 +370,20 @@ impl Generator { | |
| Verb::Delete => ClientRequest::Delete(client::Delete { | ||
| key: keyspace.sample(rng), | ||
| }), | ||
| Verb::SetIfAbsent => ClientRequest::SetIfAbsent(client::SetIfAbsent { | ||
| key: keyspace.sample(rng), | ||
| value: keyspace.gen_value(sequence as _, rng), | ||
| }), | ||
| Verb::SetIfPresentAndNotEqual => { | ||
| ClientRequest::SetIfPresentAndNotEqual(client::SetIfPresentAndNotEqual { | ||
| key: keyspace.sample(rng), | ||
| new_value: keyspace.gen_value(sequence as _, rng), | ||
| old_value: keyspace.gen_value(sequence as _, rng), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you generate different values for old_value and new_value, the result will always be
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There might not be a good alternative. We don't really have any place we're keeping history for each key to do some % of overwrite. Similar problem as testing something like a CAS operation. You might be able to fake something with two keyspaces? But the workload generation isn't really designed with this in mind. If there's need in the future, what I'd consider is some mechanism for playing workload from a file and trying to make that flexible in terms of whether exact or random out of N values are used in each place. Then you could dial in some very specific patterns by generating that file or getting some prod trace and replaying it. For now, maybe a comment acknowledging this behavior and that it's expected would be good?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sounds good |
||
| }) | ||
| } | ||
| Verb::ItemGetType => ClientRequest::ItemGetType(client::ItemGetType { | ||
| key: keyspace.sample(rng), | ||
| }), | ||
| Verb::Replace => ClientRequest::Replace(client::Replace { | ||
| key: keyspace.sample(rng), | ||
| value: keyspace.gen_value(sequence as _, rng), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we could move some of this boilerplate code into
record_result!. Especially for conditional write responses where we do not care about the actual value of the item in the response and just want to record metrics for stored vs not_stored. The macro already seems to have some logic based on 3 arguments being passed to itThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could, but it'd need enough other code to support inspecting arbitrary enums to check stored/not_stored (some sort of trait that's implemented for each conditional write response enum?) that I don't know if it'd save any real code.
record_result!() could maybe still be used here for the EX and TIMEOUT - it'd expect to increment something like SET_IF_ABSENT_OK - which should exist since the
request!macro does somepastemagic to generate _OK, _EX, and _TIMEOUT metrics for the same base request type. Then this could be a record_result!() and anMight be worth making that change