[Fix] client state synchronization, shared data
This commit is contained in:
parent
21a31862c8
commit
516c395706
9 changed files with 163 additions and 78 deletions
|
|
@ -450,6 +450,10 @@ fn purge_database_rows(user_id: i64) -> Result<(), crate::storage_error::Storage
|
|||
"DELETE FROM client_sync_state WHERE user_id = ?1",
|
||||
params![user_id],
|
||||
)?;
|
||||
tx.execute(
|
||||
"DELETE FROM client_device_sync_state WHERE user_id = ?1",
|
||||
params![user_id],
|
||||
)?;
|
||||
tx.execute(
|
||||
"DELETE FROM client_message_deliveries WHERE user_id = ?1",
|
||||
params![user_id],
|
||||
|
|
|
|||
|
|
@ -41,11 +41,12 @@ pub fn acknowledge_sync_delivery(
|
|||
/* Acknowledge a state-sync response and delete only its recorded visible messages atomically. */
|
||||
pub fn acknowledge_client_state(
|
||||
user_id: i64,
|
||||
device_id: &str,
|
||||
session_id: i64,
|
||||
version: i64,
|
||||
cache_schema_version: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
if user_id <= 0 || session_id <= 0 || version < 0 {
|
||||
if user_id <= 0 || device_id.is_empty() || session_id <= 0 || version < 0 {
|
||||
return Err(StorageError::Other("invalid sync acknowledgement".into()));
|
||||
}
|
||||
db::with_immediate_transaction(|tx| {
|
||||
|
|
@ -70,7 +71,7 @@ pub fn acknowledge_client_state(
|
|||
})?
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
};
|
||||
tx.execute("INSERT INTO client_sync_state (user_id, session_id, acknowledged_version, cache_schema_version, updated_at) VALUES (?1, ?2, ?3, ?4, ?5) ON CONFLICT(user_id, session_id) DO UPDATE SET acknowledged_version = MAX(acknowledged_version, excluded.acknowledged_version), cache_schema_version = excluded.cache_schema_version, updated_at = excluded.updated_at", params![user_id, session_id, version, cache_schema_version, sync::now_millis()])?;
|
||||
tx.execute("INSERT INTO client_device_sync_state (user_id, device_id, acknowledged_version, cache_schema_version, updated_at) VALUES (?1, ?2, ?3, ?4, ?5) ON CONFLICT(user_id, device_id) DO UPDATE SET acknowledged_version = MAX(acknowledged_version, excluded.acknowledged_version), cache_schema_version = excluded.cache_schema_version, updated_at = excluded.updated_at", params![user_id, device_id, version, cache_schema_version, sync::now_millis()])?;
|
||||
if message_storage_policy::get_in_tx(tx, user_id)?.history_mode
|
||||
== message_storage_policy::MessageHistoryMode::DeleteAfterClientDelivery
|
||||
{
|
||||
|
|
|
|||
|
|
@ -887,6 +887,22 @@ fn run_migrations_on_connection(conn: &Connection) -> Result<(), StorageError> {
|
|||
conn.pragma_update(None, "user_version", 25)?;
|
||||
}
|
||||
|
||||
if current_version < 26 {
|
||||
conn.execute_batch(
|
||||
r#"
|
||||
CREATE TABLE IF NOT EXISTS client_device_sync_state (
|
||||
user_id INTEGER NOT NULL,
|
||||
device_id TEXT NOT NULL,
|
||||
acknowledged_version INTEGER NOT NULL,
|
||||
cache_schema_version INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
PRIMARY KEY (user_id, device_id)
|
||||
);
|
||||
"#,
|
||||
)?;
|
||||
conn.pragma_update(None, "user_version", 26)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -956,7 +972,7 @@ mod tests {
|
|||
run_migrations_on_connection(&conn)?;
|
||||
|
||||
let version: i64 = conn.pragma_query_value(None, "user_version", |row| row.get(0))?;
|
||||
assert_eq!(version, 25);
|
||||
assert_eq!(version, 26);
|
||||
for column in ["height", "reply_to", "edited_count", "deleted_by_external"] {
|
||||
let mut statement =
|
||||
conn.prepare("SELECT 1 FROM pragma_table_info('messages') WHERE name = ?1")?;
|
||||
|
|
@ -975,11 +991,12 @@ mod tests {
|
|||
run_migrations_on_connection(&conn)?;
|
||||
run_migrations_on_connection(&conn)?;
|
||||
let version: i64 = conn.pragma_query_value(None, "user_version", |row| row.get(0))?;
|
||||
assert_eq!(version, 25);
|
||||
assert_eq!(version, 26);
|
||||
for table in [
|
||||
"sync_heads",
|
||||
"sync_events",
|
||||
"client_sync_state",
|
||||
"client_device_sync_state",
|
||||
"user_residency",
|
||||
"relay_replay",
|
||||
"pending_relays",
|
||||
|
|
@ -1021,7 +1038,7 @@ mod tests {
|
|||
run_migrations_on_connection(&conn)?;
|
||||
|
||||
let version: i64 = conn.pragma_query_value(None, "user_version", |row| row.get(0))?;
|
||||
assert_eq!(version, 25);
|
||||
assert_eq!(version, 26);
|
||||
for column in [
|
||||
"id",
|
||||
"user_id",
|
||||
|
|
@ -1116,7 +1133,7 @@ mod tests {
|
|||
)?;
|
||||
let version: i64 = conn.pragma_query_value(None, "user_version", |row| row.get(0))?;
|
||||
assert_eq!(preserved, "remote_committed");
|
||||
assert_eq!(version, 25);
|
||||
assert_eq!(version, 26);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,23 +114,23 @@ pub fn head(user_id: i64) -> Result<i64, StorageError> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn has_session(user_id: i64, session_id: i64) -> Result<bool, StorageError> {
|
||||
pub fn has_device(user_id: i64, device_id: &str) -> Result<bool, StorageError> {
|
||||
db::with_db(|conn| {
|
||||
Ok(conn
|
||||
.query_row(
|
||||
"SELECT 1 FROM client_sync_state WHERE user_id = ?1 AND session_id = ?2",
|
||||
params![user_id, session_id],
|
||||
"SELECT 1 FROM client_device_sync_state WHERE user_id = ?1 AND device_id = ?2",
|
||||
params![user_id, device_id],
|
||||
|_| Ok(()),
|
||||
)
|
||||
.is_ok())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn acknowledged_version(user_id: i64, session_id: i64) -> Result<Option<i64>, StorageError> {
|
||||
pub fn acknowledged_version(user_id: i64, device_id: &str) -> Result<Option<i64>, StorageError> {
|
||||
db::with_db(|conn| {
|
||||
conn.query_row(
|
||||
"SELECT acknowledged_version FROM client_sync_state WHERE user_id = ?1 AND session_id = ?2",
|
||||
params![user_id, session_id],
|
||||
"SELECT acknowledged_version FROM client_device_sync_state WHERE user_id = ?1 AND device_id = ?2",
|
||||
params![user_id, device_id],
|
||||
|row| row.get(0),
|
||||
)
|
||||
.optional()
|
||||
|
|
@ -138,33 +138,6 @@ pub fn acknowledged_version(user_id: i64, session_id: i64) -> Result<Option<i64>
|
|||
})
|
||||
}
|
||||
|
||||
pub fn acknowledge(
|
||||
user_id: i64,
|
||||
session_id: i64,
|
||||
version: i64,
|
||||
cache_schema_version: i64,
|
||||
) -> Result<(), StorageError> {
|
||||
if user_id <= 0 || session_id <= 0 || version < 0 {
|
||||
return Err(StorageError::Other("invalid sync acknowledgement".into()));
|
||||
}
|
||||
db::with_db(|conn| {
|
||||
let head = conn
|
||||
.query_row(
|
||||
"SELECT version FROM sync_heads WHERE user_id = ?1",
|
||||
[user_id],
|
||||
|r| r.get(0),
|
||||
)
|
||||
.unwrap_or(0);
|
||||
if version > head {
|
||||
return Err(StorageError::Other(
|
||||
"acknowledgement is ahead of head".into(),
|
||||
));
|
||||
}
|
||||
conn.execute("INSERT INTO client_sync_state (user_id, session_id, acknowledged_version, cache_schema_version, updated_at) VALUES (?1, ?2, ?3, ?4, ?5) ON CONFLICT(user_id, session_id) DO UPDATE SET acknowledged_version = MAX(acknowledged_version, excluded.acknowledged_version), cache_schema_version = excluded.cache_schema_version, updated_at = excluded.updated_at", params![user_id, session_id, version, cache_schema_version, now_millis()])?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/* Retain deltas until every non-stale client has acknowledged them. */
|
||||
pub fn compact_user_sync_state(user_id: i64) -> Result<SyncCompactionResult, StorageError> {
|
||||
if user_id <= 0 {
|
||||
|
|
@ -173,15 +146,15 @@ pub fn compact_user_sync_state(user_id: i64) -> Result<SyncCompactionResult, Sto
|
|||
let stale_before = now_millis().saturating_sub(STALE_CLIENT_SYNC_STATE_MS);
|
||||
db::with_immediate_transaction(|tx| {
|
||||
tx.execute(
|
||||
"DELETE FROM client_message_deliveries WHERE user_id = ?1 AND session_id IN (SELECT session_id FROM client_sync_state WHERE user_id = ?1 AND updated_at < ?2)",
|
||||
"DELETE FROM client_message_deliveries WHERE user_id = ?1 AND created_at < ?2",
|
||||
params![user_id, stale_before],
|
||||
)?;
|
||||
let removed_stale_clients = tx.execute(
|
||||
"DELETE FROM client_sync_state WHERE user_id = ?1 AND updated_at < ?2",
|
||||
"DELETE FROM client_device_sync_state WHERE user_id = ?1 AND updated_at < ?2",
|
||||
params![user_id, stale_before],
|
||||
)?;
|
||||
let minimum_acknowledged: Option<i64> = tx.query_row(
|
||||
"SELECT MIN(acknowledged_version) FROM client_sync_state WHERE user_id = ?1",
|
||||
"SELECT MIN(acknowledged_version) FROM client_device_sync_state WHERE user_id = ?1",
|
||||
[user_id],
|
||||
|row| row.get(0),
|
||||
)?;
|
||||
|
|
|
|||
Loading…
Reference in a new issue