That would require the wasm64
WebAssembly extension, which, as Akhi says further up, isn’t ready for use yet. And even if it was – Orthogonal Persistence and keeping all data in the heap, while fine for immutable canisters, doesn’t really work well when you want to upgrade your canister. At least not with the programming languages we have at hand.
We need to figure this out (upgrading canisters with large Wasm heaps). I think the most exciting long-term goal is an unbounded Wasm heap. That’s the most ideal solution for developers.
I don’t want to imply anything but you just copied @lastmjs comment on this thread
And you did the same for another 11 posts on this forum.
Are you a bot?
Interesting lol
I thought folks here would appreciate this update: Two questions about canister storage - #18 by akhilesh.singhania
any news on this? can motoko delveopers make use of the increased stable storage yet?
We actually have had support for 32 bit stable storage silently avialable for a while as library ExperimentalStableMemory.mo. We didn’t advertise this to avoid people taking a dependency on it.
I’m currently revamping this to support 64-bit stable memory (about half way there). However, we’re not convinced this is a great solution for users since it essentially introduces one big global variable (a growable byte array) and has the potential to be a big footgun if used improperly, as well as getting in the way of future, more abstract uses of stable memory including maintaining stable variables in IC stable memory throughout computation, rather than copying out and in on upgrade.
Just to clarify, does that mean that Motoko stable
variables are still currently limited to holding only 4 GB worth of data? (Due to stable memory addresses still being 32-bit, i.e. 2^32 ~ 4 GB?)
Yes, and that’s unlikely to change any time soon. It would have rather big implications for our 32-bit tagged value representation.
Gotcha. Hopefully we can unify the APIs for <4 GB stable memory via stable
variables and for >4 GB ExperimentalStableStorage
at some point…
More importantly, it would require moving our (stable) heap from internal Wasm memory to external IC memory, which would have substantial performance/cycle implications. So, before the IC adopts the memory-64 and multi-memory extensions proposed for Wasm, this isn’t really practical.
Do you have a timeframe when 64bit support will be available? We have been testing the API with 32bit support and are interesting in using this feature.
Why do stable variables involve the wasm linear memory (which I’m guessing is the heap you’re referring to)? Does Motoko load every stable variable from stable memory into wasm linear memory on canister start, and store them back into stable memory on canister termination/upgrade?
Yes, Motoko temporarily serialises the heap to stable memory for upgrades (using the pre/post upgrade hooks). Keeping stable vars in stable memory would be vastly more expensive, because every variable access would involve API calls and de/serialising (arbitrarily large) data structures. And having to do GC on the stable memory.
Eventually, we would like to improve this, but that requires Wasm multi-memory support on the IC at a minimum.
I challenge that assumption (posting mostly for the record, we have discussed it elsewhere already): even a vastly more cycle expensive solution would likely serve some use cases better than what we have right now, and some possible implementations (e.g. a page-sized cache in main memory for stable memory accesses) might be less vast, and would allow us to build the system we envision now, and improve the cycle consumption later.
There are two basic requirements for an implementation of stable vars:
-
Variable access must be (amortised) constant time, not time linear in the size of the data it holds. (Otherwise, it will be a gigantic performance/cost foot gun.)
-
It must be possible to reclaim stable memory no longer used, without irrecoverable fragmentation. (Otherwise it will be a space/cost trap for long-running apps.)
It is not obvious how to implement stable vars directly in stable memory with the current API such that these requirements are satisfied.
Also, keep in mind that we cannot afford changing the implementation of stable variables often, since every old version must be supported forever, and complexity of the system roughly increases quadratically with each change (and testable correctness worsens quadratically). In practice, I think that means we’ll only have one, at most two, more shots in production. Hence I’d be super-reluctant to introduce half-hearted solutions, even if it’s just a stop-gap measure.
I don’t see how the API matters, besides for performance: You could have the compiler emit the code it would if we had multi-mem and mem64 on the Wasm level, and then replace the reads and writes with the system API calls – either very naively access for access, or a bit cleverer with page or object level caching. It would be more instruction expensive, but it would give the right semantics, and that may be good enough for plenty of services already (we don’t hear much complaint about people hitting the per-message cycle limit).
For the sake of the argument, assume we had multi-mem amd 64 bit memory, and stable memory on the Wasm and IC level: How would we implement stable vars then? It would be great having a plan and knowing how much it would take – even if we then conclude that we don’t have the dev capacity right now, or that there is no reasonable way to shim that on top of the existing System API.
We’d need to implement some form of cross-memory GC, probably a sort of generalisation of a generational GC. I don’t think that a GC over stable memory, while technically possible, is viable with the System API.
There is a small detail that a shim cannot fully emulate: with the Wasm extensions, you can read values from stable memory or copy arbitrarily large blocks inside stable memory directly. A shim would always need to reserve a “sufficiently large” scratch area in regular memory to copy out and in again, which might get in the way of a specific heap layout, especially during GC.
I don’t think that a GC over stable memory, while technically possible, is viable with the System API.
No way to tell without trying :-). The kind of incremental GCs we are pondering for the IC have pretty good page-wise locality, don’t they? We want that anyways for normal GC… and then a page-level caching fake multi-memory might not be too bad. (Not too bad for me means just a few factors slower :-))
And even then, it would be good to have at least the design ready so that we are not rushed to implement something suddenly quickly once the system does provide the features and someone has promised on Twitter that all will be good now.
Ah, right, I forgot that the multi-memory extension also brings us bulk memory operations. Anyways, I would have imagined the fake-multi-mem instrumentation to anyways need some region in regular memory to do its thing (not a problem for us, the Motoko compiler can be helpful here, similar to the fake-multi-value-simulation now). Wouldn’t a single scratch page be enough, even for lager memcopies? If not, we can simply not use big bulk memory instruction in the compiler while we only simulate the support.