Constellation, Spacedust, Slingshot, UFOs: atproto crates and services for microcosm

reroll: reset all trim cursors

and cross notes for aarch64 raspi4

musl works -- gnu had some issue with the linker at runtime or something.

+13
ufos/readme.md
···
cargo clean
```
nginx forward proxy for websocket (run this on another host):
```nginx
···
cargo clean
```
+
for bonilla but 64-bit? (rp4)
+
```bash
+
cross build --release --target aarch64-unknown-linux-gnu && scp ../target/aarch64-unknown-linux-gnu/release/ufos pi@bonilla.local:ufos
+
# ^^ fails due to linker?
+
+
cross build --release --target aarch64-unknown-linux-musl && scp ../target/aarch64-unknown-linux-musl/release/ufos pi@bonilla.local:ufos
+
# seems to work
+
+
rsync -avhP ufos-bff-rl/ pi@bonilla:/mnt/ufos-db/
+
+
RUST_LOG=info ./ufos --jetstream us-west-2 --data /mnt/ufos-db/
+
```
+
nginx forward proxy for websocket (run this on another host):
```nginx
+6 -2
ufos/src/storage.rs
···
fn step_rollup(&mut self) -> StorageResult<(usize, HashSet<Nsid>)>;
-
fn trim_collection(&mut self, collection: &Nsid, limit: usize)
-
-> StorageResult<(usize, usize)>;
fn delete_account(&mut self, did: &Did) -> StorageResult<usize>;
}
···
fn step_rollup(&mut self) -> StorageResult<(usize, HashSet<Nsid>)>;
+
fn trim_collection(
+
&mut self,
+
collection: &Nsid,
+
limit: usize,
+
full_scan: bool,
+
) -> StorageResult<(usize, usize)>;
fn delete_account(&mut self, did: &Did) -> StorageResult<usize>;
}
+54 -26
ufos/src/storage_fjall.rs
···
Err(StorageError::BackgroundAlreadyStarted)
} else {
if reroll {
insert_static_neu::<NewRollupCursorKey>(&self.global, Cursor::from_start())?;
}
Ok(FjallBackground(self.clone()))
}
···
&mut self,
collection: &Nsid,
limit: usize,
) -> StorageResult<(usize, usize)> {
let mut dangling_feed_keys_cleaned = 0;
let mut records_deleted = 0;
-
let feed_trim_cursor_key =
-
TrimCollectionCursorKey::new(collection.clone()).to_db_bytes()?;
-
let trim_cursor = self
-
.global
-
.get(&feed_trim_cursor_key)?
-
.map(|value_bytes| db_complete(&value_bytes))
-
.transpose()?
-
.unwrap_or(Cursor::from_start());
-
-
let live_range =
-
NsidRecordFeedKey::from_pair(collection.clone(), trim_cursor).range_to_prefix_end()?;
let mut live_records_found = 0;
-
let mut latest_expired_feed_cursor = None;
let mut batch = self.keyspace.batch();
for (i, kv) in self.feeds.range(live_range).rev().enumerate() {
-
if i > 1_000_000 {
log::info!("stopping collection trim early: already scanned 1M elements");
break;
}
let (key_bytes, val_bytes) = kv?;
···
live_records_found += 1;
if live_records_found <= limit {
continue;
-
} else if latest_expired_feed_cursor.is_none() {
-
latest_expired_feed_cursor = Some(feed_key.cursor());
-
batch.insert(
-
&self.global,
-
&TrimCollectionCursorKey::new(collection.clone()).to_db_bytes()?,
-
&feed_key.cursor().to_db_bytes()?,
-
);
}
batch.remove(&self.feeds, key_bytes);
···
records_deleted += 1;
}
batch.commit()?;
-
log::trace!("trim_collection ({collection:?}) removed {dangling_feed_keys_cleaned} dangling feed entries and {records_deleted} records");
Ok((dangling_feed_keys_cleaned, records_deleted))
}
···
let t0 = Instant::now();
let (mut total_danglers, mut total_deleted) = (0, 0);
for collection in &dirty_nsids {
-
let (danglers, deleted) = self.0.trim_collection(collection, 512).inspect_err(|e| log::error!("trim error: {e:?}"))?;
total_danglers += danglers;
total_deleted += deleted;
if total_deleted > 1_000_000 {
···
)?;
assert_eq!(records.len(), 0);
-
write.trim_collection(&Nsid::new("a.a.a".to_string()).unwrap(), 6)?;
-
write.trim_collection(&Nsid::new("a.a.b".to_string()).unwrap(), 6)?;
-
write.trim_collection(&Nsid::new("a.a.c".to_string()).unwrap(), 6)?;
-
write.trim_collection(&Nsid::new("a.a.d".to_string()).unwrap(), 6)?;
let records = read.get_records_by_collections(
&[Nsid::new("a.a.a".to_string()).unwrap()],
···
Err(StorageError::BackgroundAlreadyStarted)
} else {
if reroll {
+
log::info!("reroll: resetting rollup cursor...");
insert_static_neu::<NewRollupCursorKey>(&self.global, Cursor::from_start())?;
+
log::info!("reroll: clearing trim cursors...");
+
let mut batch = self.keyspace.batch();
+
for kv in self
+
.global
+
.prefix(TrimCollectionCursorKey::from_prefix_to_db_bytes(
+
&Default::default(),
+
)?)
+
{
+
let (k, _) = kv?;
+
batch.remove(&self.global, k);
+
}
+
let n = batch.len();
+
batch.commit()?;
+
log::info!("reroll: cleared {n} trim cursors.");
}
Ok(FjallBackground(self.clone()))
}
···
&mut self,
collection: &Nsid,
limit: usize,
+
full_scan: bool,
) -> StorageResult<(usize, usize)> {
let mut dangling_feed_keys_cleaned = 0;
let mut records_deleted = 0;
+
let live_range = if full_scan {
+
let start = NsidRecordFeedKey::from_prefix_to_db_bytes(collection)?;
+
let end = NsidRecordFeedKey::prefix_range_end(collection)?;
+
start..end
+
} else {
+
let feed_trim_cursor_key =
+
TrimCollectionCursorKey::new(collection.clone()).to_db_bytes()?;
+
let trim_cursor = self
+
.global
+
.get(&feed_trim_cursor_key)?
+
.map(|value_bytes| db_complete(&value_bytes))
+
.transpose()?
+
.unwrap_or(Cursor::from_start());
+
NsidRecordFeedKey::from_pair(collection.clone(), trim_cursor).range_to_prefix_end()?
+
};
let mut live_records_found = 0;
+
let mut candidate_new_feed_lower_cursor = None;
+
let mut ended_early = false;
let mut batch = self.keyspace.batch();
for (i, kv) in self.feeds.range(live_range).rev().enumerate() {
+
if !full_scan && i > 1_000_000 {
log::info!("stopping collection trim early: already scanned 1M elements");
+
ended_early = true;
break;
}
let (key_bytes, val_bytes) = kv?;
···
live_records_found += 1;
if live_records_found <= limit {
continue;
+
}
+
if candidate_new_feed_lower_cursor.is_none() {
+
candidate_new_feed_lower_cursor = Some(feed_key.cursor());
}
batch.remove(&self.feeds, key_bytes);
···
records_deleted += 1;
}
+
if !ended_early {
+
if let Some(new_cursor) = candidate_new_feed_lower_cursor {
+
batch.insert(
+
&self.global,
+
&TrimCollectionCursorKey::new(collection.clone()).to_db_bytes()?,
+
&new_cursor.to_db_bytes()?,
+
);
+
}
+
}
+
batch.commit()?;
+
log::trace!("trim_collection ({collection:?}) removed {dangling_feed_keys_cleaned} dangling feed entries and {records_deleted} records (ended early? {ended_early})");
Ok((dangling_feed_keys_cleaned, records_deleted))
}
···
let t0 = Instant::now();
let (mut total_danglers, mut total_deleted) = (0, 0);
for collection in &dirty_nsids {
+
let (danglers, deleted) = self.0.trim_collection(collection, 512, false).inspect_err(|e| log::error!("trim error: {e:?}"))?;
total_danglers += danglers;
total_deleted += deleted;
if total_deleted > 1_000_000 {
···
)?;
assert_eq!(records.len(), 0);
+
write.trim_collection(&Nsid::new("a.a.a".to_string()).unwrap(), 6, false)?;
+
write.trim_collection(&Nsid::new("a.a.b".to_string()).unwrap(), 6, false)?;
+
write.trim_collection(&Nsid::new("a.a.c".to_string()).unwrap(), 6, false)?;
+
write.trim_collection(&Nsid::new("a.a.d".to_string()).unwrap(), 6, false)?;
let records = read.get_records_by_collections(
&[Nsid::new("a.a.a".to_string()).unwrap()],
+5 -4
ufos/src/storage_mem.rs
···
&mut self,
collection: &Nsid,
limit: usize,
// TODO: could add a start cursor limit to avoid iterating deleted stuff at the start (/end)
) -> StorageResult<(usize, usize)> {
let mut dangling_feed_keys_cleaned = 0;
···
)?;
assert_eq!(records.len(), 0);
-
write.trim_collection(&Nsid::new("a.a.a".to_string()).unwrap(), 6)?;
-
write.trim_collection(&Nsid::new("a.a.b".to_string()).unwrap(), 6)?;
-
write.trim_collection(&Nsid::new("a.a.c".to_string()).unwrap(), 6)?;
-
write.trim_collection(&Nsid::new("a.a.d".to_string()).unwrap(), 6)?;
let records = read.get_records_by_collections(
&[Nsid::new("a.a.a".to_string()).unwrap()],
···
&mut self,
collection: &Nsid,
limit: usize,
+
_full_scan: bool,
// TODO: could add a start cursor limit to avoid iterating deleted stuff at the start (/end)
) -> StorageResult<(usize, usize)> {
let mut dangling_feed_keys_cleaned = 0;
···
)?;
assert_eq!(records.len(), 0);
+
write.trim_collection(&Nsid::new("a.a.a".to_string()).unwrap(), 6, false)?;
+
write.trim_collection(&Nsid::new("a.a.b".to_string()).unwrap(), 6, false)?;
+
write.trim_collection(&Nsid::new("a.a.c".to_string()).unwrap(), 6, false)?;
+
write.trim_collection(&Nsid::new("a.a.d".to_string()).unwrap(), 6, false)?;
let records = read.get_records_by_collections(
&[Nsid::new("a.a.a".to_string()).unwrap()],