diff --git a/Cargo.lock b/Cargo.lock
index cc82983..f639d11 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1721,9 +1721,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.16.0"
+version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "opaque-debug"
@@ -2937,9 +2937,9 @@ dependencies = [
[[package]]
name = "toml_edit"
-version = "0.16.2"
+version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd30deba9a1cd7153c22aecf93e86df639e7b81c622b0af8d9255e989991a7b7"
+checksum = "a34cc558345efd7e88b9eda9626df2138b80bb46a7606f695e751c892bc7dac6"
dependencies = [
"indexmap",
"itertools",
@@ -3003,9 +3003,9 @@ dependencies = [
[[package]]
name = "typed-sled"
-version = "0.2.1"
+version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32b903ab728fcd56542a5c538dfc3d196aeffcdb1dc37e34c49f61782adc5cfa"
+checksum = "1060f05a4450ec5b758da60951b04f225a93a62079316630e76cf25c4034500d"
dependencies = [
"bincode",
"pin-project",
diff --git a/Cargo.toml b/Cargo.toml
index a36724b..db7ae3d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,8 +29,8 @@ sled = "0.34.7"
tera = { version = "1.17.1", features = ["builtins", "date-locale"] }
tide = { version = "0.16.0", default-features = false, features = ["h1-server", "cookies", "logger"] }
tokio = { version = "1.23.0", features = ["macros", "rt-multi-thread"] }
-toml_edit = { version = "0.16.2", features = ["easy"] }
-typed-sled = "0.2.1"
+toml_edit = { version = "0.17.1", features = ["easy"] }
+typed-sled = "0.2.3"
unic-langid = { version = "0.9.1", features = ["macros"] }
[features]
diff --git a/src/db.rs b/src/db.rs
index c4b08f7..8fc1f72 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -2,6 +2,10 @@ use base64::engine::Engine;
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::{net::IpAddr, path::Path};
+
+pub use sled::transaction::{
+ ConflictableTransactionError, ConflictableTransactionResult, TransactionError,
+};
pub use typed_sled::Tree;
const DB_DIR: &str = "db";
diff --git a/src/helpers.rs b/src/helpers.rs
index 8ca1b6a..ee3c369 100644
--- a/src/helpers.rs
+++ b/src/helpers.rs
@@ -3,6 +3,7 @@ use crate::{config::Config, db::*, locales::Locales, queries::*};
use fluent_bundle::FluentArgs;
use log::error;
use std::{net::IpAddr, str::FromStr};
+use typed_sled::transaction::Transactional;
use unic_langid::LanguageIdentifier;
pub fn new_pending_comment(
@@ -11,16 +12,21 @@ pub fn new_pending_comment(
dbs: &Dbs,
) -> Result<CommentId, sled::Error> {
let comment_id = CommentId::new();
- dbs.comment
- .insert(&comment_id, &(comment.clone(), CommentStatus::Pending))?;
- dbs.comment_pending.insert(
- &(
- comment.topic_hash.clone(),
- comment.post_time,
- comment_id.clone(),
- ),
- &(addr, false),
- )?;
+ (&dbs.comment, &dbs.comment_pending)
+ .transaction(|(db_comment, db_comment_pending)| {
+ db_comment.insert(&comment_id, &(comment.clone(), CommentStatus::Pending))?;
+ db_comment_pending.insert(
+ &(
+ comment.topic_hash.clone(),
+ comment.post_time,
+ comment_id.clone(),
+ ),
+ &(addr, false),
+ )?;
+ ConflictableTransactionResult::<_>::Ok(())
+ })
+ .unwrap();
+
Ok(comment_id)
}
@@ -40,18 +46,26 @@ pub fn edit_comment(
// TODO should we update ip address in comment_pending?
}
CommentStatus::Approved => {
- dbs.comment_pending.insert(
- &(
- edited_comment.topic_hash.clone(),
- edited_comment.post_time,
- comment_id.clone(),
- ),
- &(addr, true),
- )?;
- dbs.comment.insert(
- &comment_id,
- &(old_comment, CommentStatus::ApprovedEdited(edited_comment)),
- )?;
+ (&dbs.comment, &dbs.comment_pending)
+ .transaction(|(db_comment, db_comment_pending)| {
+ db_comment_pending.insert(
+ &(
+ edited_comment.topic_hash.clone(),
+ edited_comment.post_time,
+ comment_id.clone(),
+ ),
+ &(addr, true),
+ )?;
+ db_comment.insert(
+ &comment_id,
+ &(
+ old_comment.clone(),
+ CommentStatus::ApprovedEdited(edited_comment.clone()),
+ ),
+ )?;
+ ConflictableTransactionResult::<_>::Ok(())
+ })
+ .unwrap();
}
CommentStatus::ApprovedEdited(_old_edited_comment) => {
dbs.comment.insert(
@@ -65,94 +79,108 @@ pub fn edit_comment(
}
pub fn approve_comment(comment_id: CommentId, dbs: &Dbs) -> Result<(), sled::Error> {
- if let Some((comment, CommentStatus::Pending)) = dbs.comment.get(&comment_id)? {
- dbs.comment_pending.remove(&(
- comment.topic_hash.clone(),
- comment.post_time,
- comment_id.clone(),
- ))?;
- dbs.comment_approved.insert(
- &(
- comment.topic_hash.clone(),
- comment.post_time,
- comment_id.clone(),
- ),
- &(),
- )?;
- dbs.comment
- .insert(&comment_id, &(comment, CommentStatus::Approved))?;
- }
+ (&dbs.comment, &dbs.comment_approved, &dbs.comment_pending)
+ .transaction(|(db_comment, db_comment_approved, db_comment_pending)| {
+ if let Some((comment, CommentStatus::Pending)) = db_comment.get(&comment_id)? {
+ db_comment_pending.remove(&(
+ comment.topic_hash.clone(),
+ comment.post_time,
+ comment_id.clone(),
+ ))?;
+ db_comment_approved.insert(
+ &(
+ comment.topic_hash.clone(),
+ comment.post_time,
+ comment_id.clone(),
+ ),
+ &(),
+ )?;
+ db_comment.insert(&comment_id, &(comment, CommentStatus::Approved))?;
+ }
+ ConflictableTransactionResult::<_>::Ok(())
+ })
+ .unwrap();
Ok(())
}
pub fn approve_edit(comment_id: CommentId, dbs: &Dbs) -> Result<Option<Comment>, sled::Error> {
- if let Some((comment, CommentStatus::ApprovedEdited(edited_comment))) =
- dbs.comment.get(&comment_id)?
- {
- dbs.comment_pending.remove(&(
- edited_comment.topic_hash.clone(),
- edited_comment.post_time,
- comment_id.clone(),
- ))?;
- dbs.comment
- .insert(&comment_id, &(edited_comment, CommentStatus::Approved))?;
- return Ok(Some(comment));
- }
- Ok(None)
+ Ok((&dbs.comment, &dbs.comment_pending)
+ .transaction(|(db_comment, db_comment_pending)| {
+ if let Some((comment, CommentStatus::ApprovedEdited(edited_comment))) =
+ db_comment.get(&comment_id)?
+ {
+ db_comment_pending.remove(&(
+ edited_comment.topic_hash.clone(),
+ edited_comment.post_time,
+ comment_id.clone(),
+ ))?;
+ db_comment.insert(&comment_id, &(edited_comment, CommentStatus::Approved))?;
+ return ConflictableTransactionResult::<_>::Ok(Some(comment));
+ }
+ ConflictableTransactionResult::<_>::Ok(None)
+ })
+ .unwrap())
}
pub fn remove_comment(
comment_id: CommentId,
dbs: &Dbs,
) -> Result<Option<(Comment, CommentStatus)>, sled::Error> {
- if let Some((comment, edited_comment)) = dbs.comment.remove(&comment_id)? {
- match &edited_comment {
- CommentStatus::Pending => {
- dbs.comment_pending.remove(&(
- comment.topic_hash.clone(),
- comment.post_time,
- comment_id,
- ))?;
+ Ok((&dbs.comment, &dbs.comment_approved, &dbs.comment_pending)
+ .transaction(|(db_comment, db_comment_approved, db_comment_pending)| {
+ if let Some((comment, edited_comment)) = db_comment.remove(&comment_id)? {
+ match &edited_comment {
+ CommentStatus::Pending => {
+ db_comment_pending.remove(&(
+ comment.topic_hash.clone(),
+ comment.post_time,
+ comment_id.clone(),
+ ))?;
+ }
+ CommentStatus::Approved => {
+ db_comment_approved.remove(&(
+ comment.topic_hash.clone(),
+ comment.post_time,
+ comment_id.clone(),
+ ))?;
+ }
+ CommentStatus::ApprovedEdited(edited_comment) => {
+ db_comment_pending.remove(&(
+ edited_comment.topic_hash.clone(),
+ edited_comment.post_time,
+ comment_id.clone(),
+ ))?;
+ db_comment_approved.remove(&(
+ comment.topic_hash.clone(),
+ comment.post_time,
+ comment_id.clone(),
+ ))?;
+ }
+ }
+ return ConflictableTransactionResult::<_>::Ok(Some((comment, edited_comment)));
}
- CommentStatus::Approved => {
- dbs.comment_approved.remove(&(
- comment.topic_hash.clone(),
- comment.post_time,
- comment_id,
- ))?;
- }
- CommentStatus::ApprovedEdited(edited_comment) => {
- dbs.comment_pending.remove(&(
+ ConflictableTransactionResult::<_>::Ok(None)
+ })
+ .unwrap())
+}
+
+pub fn remove_edit(comment_id: CommentId, dbs: &Dbs) -> Result<Option<Comment>, sled::Error> {
+ Ok((&dbs.comment, &dbs.comment_pending)
+ .transaction(|(db_comment, db_comment_pending)| {
+ if let Some((comment, CommentStatus::ApprovedEdited(edited_comment))) =
+ db_comment.get(&comment_id)?
+ {
+ db_comment_pending.remove(&(
edited_comment.topic_hash.clone(),
edited_comment.post_time,
comment_id.clone(),
))?;
- dbs.comment_approved.remove(&(
- comment.topic_hash.clone(),
- comment.post_time,
- comment_id,
- ))?;
+ db_comment.insert(&comment_id, &(comment.clone(), CommentStatus::Approved))?;
+ return ConflictableTransactionResult::<_>::Ok(Some(comment));
}
- }
- return Ok(Some((comment, edited_comment)));
- }
- Ok(None)
-}
-
-pub fn remove_edit(comment_id: CommentId, dbs: &Dbs) -> Result<Option<Comment>, sled::Error> {
- if let Some((comment, CommentStatus::ApprovedEdited(edited_comment))) =
- dbs.comment.get(&comment_id)?
- {
- dbs.comment_pending.remove(&(
- edited_comment.topic_hash.clone(),
- edited_comment.post_time,
- comment_id.clone(),
- ))?;
- dbs.comment
- .insert(&comment_id, &(comment.clone(), CommentStatus::Approved))?;
- return Ok(Some(comment));
- }
- Ok(None)
+ ConflictableTransactionResult::<_>::Ok(None)
+ })
+ .unwrap())
}
pub fn iter_comments_by_topic<'a, V: typed_sled::KV>(