Skip to content

Commit

Permalink
Add return value option to counter_incr
Browse files Browse the repository at this point in the history
  • Loading branch information
mdecimus committed Jan 16, 2025
1 parent b325acf commit ef72141
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 33 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,28 @@

All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).

## [0.11.2] - 2025-01-17

To upgrade update the webadmin and then replace the `stalwart-mail` binary.

### Added
- Automatic revoking of access tokens when secrets, permissions, ACLs or group memberships change (#649).
- Cluster node roles.
- `config_get` expression function.

### Changed
- `lookup.default.hostname` is now `server.hostname`.
- `lookup.default.domain` is now `report.domain`.

### Fixed
- Distributed locking issues in non-Redis stores (#1066).
- Panic parsing broken HTMLs.
- Update CLI response serializer to v0.11.x (#1082).
- Histogram bucket counts (#1079).
- Do not rate limit trusted IPs (#1078).
- Avoid double encrypting PGP parts encoded as plain text (#1083).
- Return empty SASL challenge rather than "" (#1064).

## [0.11.0] - 2025-01-06

This version includes breaking changes to the configuration file, please read [UPGRADING.md](UPGRADING.md) for details.
Expand Down
1 change: 1 addition & 0 deletions crates/common/src/auth/access_token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ impl Server {
.counter_incr(
KeyValue::with_prefix(KV_PRINCIPAL_REVISION, id.to_be_bytes(), 1)
.expires(30 * 86400),
false,
)
.await
{
Expand Down
2 changes: 1 addition & 1 deletion crates/common/src/expr/functions/asynch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl Server {
let value = params.next_as_integer();

self.get_in_memory_store_or_default(store.as_ref(), session_id)
.counter_incr(KeyValue::new(key.into_owned(), value))
.counter_incr(KeyValue::new(key.into_owned(), value), true)
.await
.map(Variable::Integer)
.caused_by(trc::location!())
Expand Down
22 changes: 14 additions & 8 deletions crates/spam-filter/src/modules/bayes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,13 @@ impl BayesClassifier for Server {
};
for (hash, weights) in model.weights {
self.in_memory_store()
.counter_incr(KeyValue::new(
hash.serialize(prefix, ctx.input.account_id),
i64::from(weights),
))
.counter_incr(
KeyValue::new(
hash.serialize(prefix, ctx.input.account_id),
i64::from(weights),
),
false,
)
.await
.caused_by(trc::location!())?;
if is_global {
Expand All @@ -158,10 +161,13 @@ impl BayesClassifier for Server {
Weights { spam: 0, ham: 1 }
};
self.in_memory_store()
.counter_incr(KeyValue::new(
TokenHash::default().serialize(prefix, ctx.input.account_id),
i64::from(weights),
))
.counter_incr(
KeyValue::new(
TokenHash::default().serialize(prefix, ctx.input.account_id),
i64::from(weights),
),
false,
)
.await
.caused_by(trc::location!())
.map(|_| ())
Expand Down
29 changes: 19 additions & 10 deletions crates/store/src/dispatch/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl InMemoryStore {
.caused_by(trc::location!())
}

pub async fn counter_incr(&self, kv: KeyValue<i64>) -> trc::Result<i64> {
pub async fn counter_incr(&self, kv: KeyValue<i64>, return_value: bool) -> trc::Result<i64> {
match self {
InMemoryStore::Store(store) => {
let mut batch = BatchBuilder::new();
Expand All @@ -75,15 +75,24 @@ impl InMemoryStore {
});
}

batch.ops.push(Operation::Value {
class: ValueClass::InMemory(InMemoryClass::Counter(kv.key)),
op: ValueOp::AddAndGet(kv.value),
});
if return_value {
batch.ops.push(Operation::Value {
class: ValueClass::InMemory(InMemoryClass::Counter(kv.key)),
op: ValueOp::AddAndGet(kv.value),
});

store
.write(batch.build())
.await
.and_then(|r| r.last_counter_id())
store
.write(batch.build())
.await
.and_then(|r| r.last_counter_id())
} else {
batch.ops.push(Operation::Value {
class: ValueClass::InMemory(InMemoryClass::Counter(kv.key)),
op: ValueOp::AtomicAdd(kv.value),
});

store.write(batch.build()).await.map(|_| 0)
}
}
#[cfg(feature = "redis")]
InMemoryStore::Redis(store) => store.key_incr(&kv.key, kv.value, kv.expires).await,
Expand Down Expand Up @@ -260,7 +269,7 @@ impl InMemoryStore {
bucket.extend_from_slice(range_start.to_be_bytes().as_slice());

let requests = if !soft_check {
self.counter_incr(KeyValue::new(bucket, 1).expires(expires_in))
self.counter_incr(KeyValue::new(bucket, 1).expires(expires_in), true)
.await
.caused_by(trc::location!())?
} else {
Expand Down
25 changes: 11 additions & 14 deletions tests/src/store/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ pub async fn lookup_tests() {
};

for (store_id, store) in stores.in_memory_stores {
let is_mysql = store_id == "mysql";
println!("Testing in-memory store {}...", store_id);
if let InMemoryStore::Store(store) = &store {
store.destroy().await;
Expand Down Expand Up @@ -72,30 +71,25 @@ pub async fn lookup_tests() {
// Test counter
let key = "abc".as_bytes().to_vec();
store
.counter_incr(KeyValue::new(key.clone(), 1))
.counter_incr(KeyValue::new(key.clone(), 1), true)
.await
.unwrap();
assert_eq!(1, store.counter_get(key.clone()).await.unwrap());
store
.counter_incr(KeyValue::new(key.clone(), 2))
.counter_incr(KeyValue::new(key.clone(), 2), true)
.await
.unwrap();
assert_eq!(3, store.counter_get(key.clone()).await.unwrap());
if !is_mysql {
store
.counter_incr(KeyValue::new(key.clone(), -3))
.await
.unwrap();
} else {
// TODO: Detect mySQL version and use RETURNING
store.counter_delete(key.clone()).await.unwrap();
}
store
.counter_incr(KeyValue::new(key.clone(), -3), false)
.await
.unwrap();
assert_eq!(0, store.counter_get(key.clone()).await.unwrap());

// Test counter expiry
let key = "fgh".as_bytes().to_vec();
store
.counter_incr(KeyValue::new(key.clone(), 1).expires(1))
.counter_incr(KeyValue::new(key.clone(), 1).expires(1), false)
.await
.unwrap();
assert_eq!(1, store.counter_get(key.clone()).await.unwrap());
Expand Down Expand Up @@ -171,7 +165,10 @@ pub async fn lookup_tests() {
.await
.unwrap();
store
.counter_incr(KeyValue::with_prefix(0, pack_u32(1, v), 123).expires(3600))
.counter_incr(
KeyValue::with_prefix(0, pack_u32(1, v), 123).expires(3600),
false,
)
.await
.unwrap();
}
Expand Down

0 comments on commit ef72141

Please sign in to comment.