mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
Moving updated-at timestamps to unique millisecond times (#17489)
To allow the ability to have guaranteed-unique cursors, we make two important updates: * Add new updated_at_ms and created_at_ms columns that are in millisecond precision * Guarantee uniqueness -- if multiple items are inserted at the same millisecond, bump the new one by one millisecond until it becomes unique This lets us use single-number cursors for forwards and backwards paging through resultsets and guarantee that the cursor is a fixed point to do (timestamp > cursor) and get new items only. This updated implementation is backwards-compatible since multiple appservers can be running and won't handle the previous method well.
This commit is contained in:
committed by
GitHub
Unverified
parent
61fe23159e
commit
4f2fc3e3fa
@@ -1,6 +1,5 @@
|
||||
use anyhow::Result;
|
||||
use chrono::DateTime;
|
||||
use chrono::Timelike;
|
||||
use chrono::Utc;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::openai_models::ReasoningEffort;
|
||||
@@ -300,7 +299,7 @@ impl ThreadMetadata {
|
||||
}
|
||||
|
||||
fn canonicalize_datetime(dt: DateTime<Utc>) -> DateTime<Utc> {
|
||||
dt.with_nanosecond(0).unwrap_or(dt)
|
||||
epoch_millis_to_datetime(datetime_to_epoch_millis(dt)).unwrap_or(dt)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -389,8 +388,8 @@ impl TryFrom<ThreadRow> for ThreadMetadata {
|
||||
Ok(Self {
|
||||
id: ThreadId::try_from(id)?,
|
||||
rollout_path: PathBuf::from(rollout_path),
|
||||
created_at: epoch_seconds_to_datetime(created_at)?,
|
||||
updated_at: epoch_seconds_to_datetime(updated_at)?,
|
||||
created_at: epoch_millis_to_datetime(created_at)?,
|
||||
updated_at: epoch_millis_to_datetime(updated_at)?,
|
||||
source,
|
||||
agent_nickname,
|
||||
agent_role,
|
||||
@@ -423,13 +422,30 @@ pub(crate) fn anchor_from_item(item: &ThreadMetadata, sort_key: SortKey) -> Opti
|
||||
Some(Anchor { ts, id })
|
||||
}
|
||||
|
||||
pub(crate) fn datetime_to_epoch_millis(dt: DateTime<Utc>) -> i64 {
|
||||
dt.timestamp_millis()
|
||||
}
|
||||
|
||||
pub(crate) fn datetime_to_epoch_seconds(dt: DateTime<Utc>) -> i64 {
|
||||
dt.timestamp()
|
||||
}
|
||||
|
||||
pub(crate) fn epoch_seconds_to_datetime(secs: i64) -> Result<DateTime<Utc>> {
|
||||
DateTime::<Utc>::from_timestamp(secs, 0)
|
||||
.ok_or_else(|| anyhow::anyhow!("invalid unix timestamp: {secs}"))
|
||||
pub(crate) fn epoch_millis_to_datetime(value: i64) -> Result<DateTime<Utc>> {
|
||||
// Values older than 2020 if interpreted as milliseconds are legacy second-precision rows.
|
||||
// Convert them in memory so old state DBs keep ordering correctly after new writes use ms.
|
||||
const MIN_EPOCH_MILLIS: i64 = 1_577_836_800_000;
|
||||
let millis = if value < MIN_EPOCH_MILLIS {
|
||||
value.saturating_mul(1000)
|
||||
} else {
|
||||
value
|
||||
};
|
||||
DateTime::<Utc>::from_timestamp_millis(millis)
|
||||
.ok_or_else(|| anyhow::anyhow!("invalid unix timestamp millis: {value}"))
|
||||
}
|
||||
|
||||
pub(crate) fn epoch_seconds_to_datetime(value: i64) -> Result<DateTime<Utc>> {
|
||||
DateTime::<Utc>::from_timestamp(value, 0)
|
||||
.ok_or_else(|| anyhow::anyhow!("invalid unix timestamp seconds: {value}"))
|
||||
}
|
||||
|
||||
/// Statistics about a backfill operation.
|
||||
|
||||
Reference in New Issue
Block a user