Skip to content

Commit

Permalink
create new canisters on demand; deploy stored wasm
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyan-dfinity committed Oct 21, 2024
1 parent e41aeb7 commit 2e6fb7a
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 30 deletions.
17 changes: 12 additions & 5 deletions service/pool/Main.mo
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
};
};
case (#reuse info) {
let no_uninstall = Option.get(params.no_uninstall, false);
let cid = { canister_id = info.id };
let status = await IC.canister_status cid;
let topUpCycles : Nat = if (status.cycles < params.cycles_per_canister) {
Expand All @@ -119,7 +118,12 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
Cycles.add<system> topUpCycles;
await IC.deposit_cycles cid;
};
if (not no_uninstall and Option.isSome(status.module_hash)) {
let need_uninstall = switch ((params.stored_module_hash, status.module_hash)) {
case ((null, ?_)) { true };
case ((_, null)) { false };
case (?stored, ?current) { stored != current };
};
if (need_uninstall) {
await* pool_uninstall_code(cid.canister_id);
};
switch (status.status) {
Expand All @@ -130,7 +134,7 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
};
stats := Logs.updateStats(stats, #getId topUpCycles);
statsByOrigin.addCanister(origin);
let mode = if (no_uninstall) { #reinstall } else { #install };
let mode = if (need_uninstall) { #install } else { #reinstall };
(info, mode);
};
case (#outOfCapacity time) {
Expand Down Expand Up @@ -192,6 +196,9 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
if (not Principal.isController(caller)) {
throw Error.reject "Only called by controller";
};
if (Option.isSome(params.stored_module_hash) and Option.isSome(args)) {
throw Error.reject "args should be null when stored_module_hash is set";
};
let origin = { origin = "admin"; tags = [] };
let (info, mode) = switch (opt_info) {
case null { await* getExpiredCanisterInfo(origin) };
Expand Down Expand Up @@ -358,7 +365,7 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
};

func updateTimer<system>(info: Types.CanisterInfo) {
if (Option.get(params.no_uninstall, false)) {
if (Option.isSome(params.stored_module_hash)) {
return;
};
func job() : async () {
Expand Down Expand Up @@ -436,7 +443,7 @@ shared (creator) actor class Self(opt_params : ?Types.InitParams) = this {
throw Error.reject "only called by controllers";
};
for (info in pool.getAllCanisters()) {
if (not Option.get(params.no_uninstall, false)) {
if (Option.isNull(params.stored_module_hash)) {
await* pool_uninstall_code(info.id);
};
ignore pool.retire info;
Expand Down
56 changes: 31 additions & 25 deletions service/pool/Types.mo
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ module {
canister_time_to_live: Nat;
nonce_time_to_live: Nat;
max_family_tree_size: Nat;
// Used for asset canister. If set to true, will not use timer to kill expired canisters, and will not uninstall code when fetching an expired canister.
no_uninstall: ?Bool;
// Used for installing asset canister. If set, will not use timer to kill expired canisters, and will not uninstall code when fetching an expired canister (unless the module hash changed).
stored_module_hash: ?Blob;
wasm_utils_principal: ?Text;
};
public let defaultParams : InitParams = {
Expand All @@ -30,7 +30,7 @@ module {
canister_time_to_live = 1200_000_000_000;
nonce_time_to_live = 300_000_000_000;
max_family_tree_size = 5;
no_uninstall = null;
stored_module_hash = null;
wasm_utils_principal = ?"ozk6r-tyaaa-aaaab-qab4a-cai";
};
public type InstallArgs = {
Expand Down Expand Up @@ -90,29 +90,35 @@ module {
len -= 1;
};
public func getExpiredCanisterId() : NewId {
if (len < size) {
// increment len here to prevent race condition
len += 1;
#newId
} else {
switch (tree.entries().next()) {
case null { assert false; loop(); };
case (?info) {
let now = Time.now();
let elapsed : Nat = Int.abs(now) - Int.abs(info.timestamp);
if (elapsed >= ttl) {
// Lazily cleanup pool state before reusing canister
tree.remove info;
let newInfo = { timestamp = now; id = info.id; };
tree.insert newInfo;
metadata.put(newInfo.id, (newInfo.timestamp, false));
deleteFamilyNode(newInfo.id);
#reuse newInfo
} else {
#outOfCapacity(ttl - elapsed)
}
switch (tree.entries().next()) {
case null {
if (len < size) {
len += 1;
#newId
} else {
Debug.trap "No canister in the pool"
};
};
};
case (?info) {
let now = Time.now();
let elapsed : Nat = Int.abs(now) - Int.abs(info.timestamp);
if (elapsed >= ttl) {
// Lazily cleanup pool state before reusing canister
tree.remove info;
let newInfo = { timestamp = now; id = info.id; };
tree.insert newInfo;
metadata.put(newInfo.id, (newInfo.timestamp, false));
deleteFamilyNode(newInfo.id);
#reuse newInfo
} else {
if (len < size) {
len += 1;
#newId
} else {
#outOfCapacity(ttl - elapsed)
}
}
};
};
};
public func removeCanister(info: CanisterInfo) {
Expand Down

0 comments on commit 2e6fb7a

Please sign in to comment.