stable-structures
stable-structures copied to clipboard
Question: nested Vec, Map by stable memory are available?
I would like to store the following data in stable memory. In this example, each line is some kind of score history for each user.
let data: Vec<Vec<N>>
// N = Storable (tuple by scalar only etc)
[
[1, 2, 3, 4, 5, 6, ..],
[10, 20, ..],
[100, 200, ..],
...
]
The following will result in an error.
static DATA: std::cell::RefCell<ic_stable_structures::StableVec<Vec<u64>, MemoryType>> = std::cell::RefCell::new(
ic_stable_structures::StableVec::init(
MEMORY_MANAGER.with(|mm| mm.borrow().get(
ic_stable_structures::memory_manager::MemoryId::new(2)
))
).unwrap()
);
the trait bound `std::vec::Vec<u64>: BoundedStorable` is not satisfied
the following other types implement trait `BoundedStorable`:
I have a few thoughts. I would be grateful if you could help me figure out how to do this in one of them.
- What should the following be implemented? (I am using 0.5.5. ver) Even in this case I don't really understand how to implement BoundedStorable, I don't think max_size can be defined.
// replace Vec<u64> -> Datum in thread_local! definition
pub struct Datum(pub Vec<u64>);
impl ic_stable_structures::Storable for Datum {
fn to_bytes(&self) -> std::borrow::Cow<[u8]> { ... }
fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self { ... }
}
impl ic_stable_structures::BoundedStorable for Datum {
const MAX_SIZE: u32 = 1000;
const IS_FIXED_SIZE: bool = false;
}
- Would a higher version and Bound::UnBounded solve this problem?
pub enum Bound {
/// The type has no size bounds.
Unbounded,
/// The type has size bounds.
Bounded
Hey @ielashi Would you mind seeing the question?
Hi @linnefromice,
Currently, Vec doesn't support storing unbounded types. Support for unbounded types is currently only available in BTreeMap and in the append-only Log structure. So you'd either need to set a max_size as you mentioned or consider storing your data in a BTreeMap.
What I would suggest would depend on the size of the data you plan to store. If the amount of data you plan to store per user is small (i.e. on the order of KiBs), then you can store them in a BTreeMap (e.g. BTreeMap<UserId, Vec<N>>). If that amount is large though, I'd recommend using a composite key: BTreeMap<(UserId, u64, N), ()>. With the composite key approach, we store in the key the user ID, an index (starting from zero), and the value of the score. You can then use the range method in the BTreeMap to efficiently retrieve all the scores for a given UserId.
Thanks for the explanation. I will consider combining the compound key and BTreeMap as you have taught me. By the way, do you have any plans to support stable memory for Vec in Vec (or Map)?
With the composite key approach, we store in the key the user ID, an index (starting from zero), and the value of the score.
Why not store value in the value field of Map like BTreeMap<(UserID, u64), N>?
That also works. There is one subtle difference, but that won't matter in your example.
If N is in the key then it's also sorted, but I understand this is a property that's irrelevant here.
Closing this ticket given that the question has been answered. Feel free to open with additional questions.