mirror of
https://github.com/floor-licker/polyfill-rs.git
synced 2026-07-27 20:47:46 +00:00
docs: clarify websocket snapshot ordering
This commit is contained in:
@@ -78,6 +78,8 @@ Run the WS hot-path benchmark locally with `cargo bench --bench ws_hot_path`.
|
||||
|
||||
**Parsing paths:** `polyfill-rs` keeps two parsing layers on purpose. The allocation-sensitive WS `book` path uses `WsBookUpdateProcessor` in `src/ws_hot_path.rs`, which walks a reusable `simd-json` tape and applies fixed-point book levels directly. The generic stream parser in `src/decode.rs` is an ergonomic compatibility path: it parses through `serde_json::Value` so it can tolerate batches, unknown event types, and mixed message shapes. Likewise, several generic numeric/decimal deserializers in `src/decode.rs` accept string-or-number API fields through `serde_json::Value`; they are not the zero-allocation hot path.
|
||||
|
||||
**WebSocket snapshot ordering:** Polymarket `book` messages expose a millisecond `timestamp` and optional `hash`, but no monotonic server sequence/version. The book applier treats newer timestamps as newer, rejects older timestamps, suppresses exact same-timestamp/same-hash duplicates, and accepts same-timestamp/different-hash snapshots in websocket arrival order. The hash distinguishes duplicate vs distinct state; it is not a logical ordering key.
|
||||
|
||||
**Key Performance Optimizations:**
|
||||
|
||||
The 21.4% performance improvement comes from HTTP/2 tuning with 512KB stream windows optimized for 469KB payloads, explicit Polymarket request headers, SIMD-backed parsing where the client uses the typed fast-response helper for large REST market responses, and opt-in connection prewarming/keep-alive support.
|
||||
|
||||
+6
-3
@@ -601,9 +601,10 @@ impl OrderBook {
|
||||
return Err(PolyfillError::validation("Token ID mismatch"));
|
||||
}
|
||||
|
||||
// Use the exchange-provided timestamp as the monotonic snapshot marker.
|
||||
// If the feed emits two snapshots in the same millisecond, a different hash is treated as
|
||||
// a distinct newer state. Equal timestamp without a hash is considered duplicate/stale.
|
||||
// Use the exchange-provided timestamp as the primary snapshot marker. The WS `book`
|
||||
// message does not expose a monotonic server sequence/version, so same-millisecond
|
||||
// snapshots with different hashes are ordered by websocket arrival order. The hash
|
||||
// distinguishes duplicate vs distinct state; it is not a logical ordering key.
|
||||
// Snapshot timestamps are intentionally separate from legacy delta sequence numbers.
|
||||
if !self.should_apply_snapshot(update.timestamp, update.hash.as_deref()) {
|
||||
return Ok(());
|
||||
@@ -725,6 +726,8 @@ impl OrderBook {
|
||||
|
||||
#[inline]
|
||||
fn should_apply_snapshot(&self, timestamp: u64, hash: Option<&str>) -> bool {
|
||||
// Without a server sequence/version, equal-timestamp distinct hashes can only be ordered
|
||||
// by arrival. Older timestamps are always stale; exact same timestamp/hash is duplicate.
|
||||
if timestamp > self.last_snapshot_timestamp_ms {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -976,16 +976,26 @@ pub enum StreamMessage {
|
||||
}
|
||||
|
||||
/// Orderbook update message (full snapshot or delta).
|
||||
///
|
||||
/// WebSocket `book` messages expose a millisecond timestamp and optional book hash, but no
|
||||
/// monotonic server sequence/version. Same-timestamp messages with different hashes are therefore
|
||||
/// ordered by websocket arrival order by the book applier; the hash is a duplicate/state
|
||||
/// discriminator, not a logical ordering key.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BookUpdate {
|
||||
pub asset_id: String,
|
||||
pub market: String,
|
||||
/// Exchange-provided snapshot timestamp in milliseconds.
|
||||
#[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
|
||||
pub timestamp: u64,
|
||||
#[serde(deserialize_with = "crate::decode::deserializers::vec_from_null")]
|
||||
pub bids: Vec<OrderSummary>,
|
||||
#[serde(deserialize_with = "crate::decode::deserializers::vec_from_null")]
|
||||
pub asks: Vec<OrderSummary>,
|
||||
/// Exchange-provided snapshot hash.
|
||||
///
|
||||
/// Used to suppress exact duplicate same-timestamp snapshots and to allow distinct
|
||||
/// same-timestamp states. It does not encode ordering.
|
||||
#[serde(default)]
|
||||
pub hash: Option<String>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user