-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reduce size of data in stable memory (#46)
- Loading branch information
Showing
13 changed files
with
264 additions
and
6 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
use crate::state; | ||
use ic_cdk::heartbeat; | ||
|
||
#[heartbeat] | ||
fn heartbeat() { | ||
state::mutate(|s| s.migrate_events(10000)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
mod heartbeat; | ||
mod init; | ||
mod post_upgrade; | ||
mod pre_upgrade; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
use crate::memory::{get_events_v2_data_memory, get_events_v2_index_memory, Memory}; | ||
use crate::model::string_to_num_map::StringToNumMap; | ||
use candid::Deserialize; | ||
use event_store_canister::{IdempotentEvent, IndexedEvent, TimestampMillis}; | ||
use ic_stable_structures::storable::Bound; | ||
use ic_stable_structures::{StableLog, Storable}; | ||
use serde::Serialize; | ||
use std::borrow::Cow; | ||
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct EventsV2 { | ||
#[serde(skip, default = "init_events")] | ||
events: StableLog<StorableEvent, Memory, Memory>, | ||
#[serde(default)] | ||
string_to_num_map: StringToNumMap, | ||
} | ||
|
||
impl EventsV2 { | ||
pub fn get(&self, start: u64, length: u64) -> Vec<IndexedEvent> { | ||
self.events | ||
.iter() | ||
.skip(start as usize) | ||
.take(length as usize) | ||
.map(|e| self.hydrate(e)) | ||
.collect() | ||
} | ||
|
||
pub fn push(&mut self, event: IdempotentEvent) { | ||
let storable = self.convert_to_storable(event, self.events.len()); | ||
|
||
self.events.append(&storable).unwrap(); | ||
} | ||
|
||
pub fn stats(&self) -> EventsStats { | ||
EventsStats { | ||
latest_event_index: self.events.len().checked_sub(1), | ||
} | ||
} | ||
|
||
pub fn len(&self) -> u64 { | ||
self.events.len() | ||
} | ||
|
||
fn convert_to_storable(&mut self, event: IdempotentEvent, index: u64) -> StorableEvent { | ||
StorableEvent { | ||
index, | ||
name: self.string_to_num_map.convert_to_num(event.name), | ||
timestamp: event.timestamp, | ||
user: event.user.map(|u| self.string_to_num_map.convert_to_num(u)), | ||
source: event | ||
.source | ||
.map(|s| self.string_to_num_map.convert_to_num(s)), | ||
payload: event.payload, | ||
} | ||
} | ||
|
||
fn hydrate(&self, event: StorableEvent) -> IndexedEvent { | ||
IndexedEvent { | ||
index: event.index, | ||
name: self | ||
.string_to_num_map | ||
.convert_to_string(event.name) | ||
.unwrap_or("unknown".to_string()), | ||
timestamp: event.timestamp, | ||
user: event | ||
.user | ||
.and_then(|u| self.string_to_num_map.convert_to_string(u)), | ||
source: event | ||
.source | ||
.and_then(|s| self.string_to_num_map.convert_to_string(s)), | ||
payload: event.payload, | ||
} | ||
} | ||
} | ||
|
||
impl Default for EventsV2 { | ||
fn default() -> Self { | ||
EventsV2 { | ||
events: init_events(), | ||
string_to_num_map: StringToNumMap::default(), | ||
} | ||
} | ||
} | ||
|
||
fn init_events() -> StableLog<StorableEvent, Memory, Memory> { | ||
StableLog::init(get_events_v2_index_memory(), get_events_v2_data_memory()).unwrap() | ||
} | ||
|
||
pub struct EventsStats { | ||
pub latest_event_index: Option<u64>, | ||
} | ||
|
||
#[derive(Serialize, Deserialize)] | ||
struct StorableEvent { | ||
#[serde(rename = "i")] | ||
index: u64, | ||
#[serde(rename = "n")] | ||
name: u32, | ||
#[serde(rename = "t")] | ||
timestamp: TimestampMillis, | ||
#[serde(rename = "u", default, skip_serializing_if = "Option::is_none")] | ||
user: Option<u32>, | ||
#[serde(rename = "s", default, skip_serializing_if = "Option::is_none")] | ||
source: Option<u32>, | ||
#[serde( | ||
rename = "p", | ||
default, | ||
skip_serializing_if = "is_empty_slice", | ||
with = "serde_bytes" | ||
)] | ||
payload: Vec<u8>, | ||
} | ||
|
||
impl Storable for StorableEvent { | ||
fn to_bytes(&self) -> Cow<[u8]> { | ||
Cow::Owned(rmp_serde::to_vec_named(&self).unwrap()) | ||
} | ||
|
||
fn from_bytes(bytes: Cow<[u8]>) -> Self { | ||
rmp_serde::from_slice(bytes.as_ref()).unwrap() | ||
} | ||
|
||
const BOUND: Bound = Bound::Unbounded; | ||
} | ||
|
||
fn is_empty_slice<T>(vec: &[T]) -> bool { | ||
vec.is_empty() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
pub mod events; | ||
pub mod events_v2; | ||
pub mod salt; | ||
mod string_to_num_map; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
use crate::memory::{ | ||
get_num_to_string_data_memory, get_num_to_string_index_memory, get_string_to_num_map_memory, | ||
Memory, | ||
}; | ||
use ic_stable_structures::{StableBTreeMap, StableLog}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Serialize, Deserialize)] | ||
pub struct StringToNumMap { | ||
#[serde(skip, default = "init_string_to_num")] | ||
string_to_num: StableBTreeMap<String, u32, Memory>, | ||
#[serde(skip, default = "init_num_to_string")] | ||
num_to_string: StableLog<String, Memory, Memory>, | ||
} | ||
|
||
impl StringToNumMap { | ||
pub fn convert_to_num(&mut self, string: String) -> u32 { | ||
if let Some(i) = self.string_to_num.get(&string) { | ||
i | ||
} else { | ||
let i = self.num_to_string.len() as u32; | ||
self.num_to_string.append(&string).unwrap(); | ||
self.string_to_num.insert(string, i); | ||
i | ||
} | ||
} | ||
|
||
pub fn convert_to_string(&self, num: u32) -> Option<String> { | ||
self.num_to_string.get(num as u64) | ||
} | ||
} | ||
|
||
impl Default for StringToNumMap { | ||
fn default() -> Self { | ||
StringToNumMap { | ||
string_to_num: init_string_to_num(), | ||
num_to_string: init_num_to_string(), | ||
} | ||
} | ||
} | ||
|
||
fn init_string_to_num() -> StableBTreeMap<String, u32, Memory> { | ||
StableBTreeMap::init(get_string_to_num_map_memory()) | ||
} | ||
|
||
fn init_num_to_string() -> StableLog<String, Memory, Memory> { | ||
StableLog::init( | ||
get_num_to_string_index_memory(), | ||
get_num_to_string_data_memory(), | ||
) | ||
.unwrap() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters