Skip to content

Paginate init_certified_assets #2685

@peterpeterparker

Description

@peterpeterparker

Motivation

With thousands of assets the instruction limit is hit when certifying the assets

Claude solution

const INIT_CHUNK_SIZE: usize = 500;

// Add to your state (heap or stable, wherever survives across timer callbacks)
pub struct CertifiedAssetsInitState {
    pub in_progress: bool,
    pub heap_cursor: usize,
    pub stable_cursor: usize,
    pub asset_hashes: CertifiedAssetHashes,
}

fn init_certified_assets_impl(state: &State) {
    // Reset progress and kick off the first chunk via a 0-delay timer
    with_state_mut(|s| {
        s.certified_init = Some(CertifiedAssetsInitState {
            in_progress: true,
            heap_cursor: 0,
            stable_cursor: 0,
            asset_hashes: CertifiedAssetHashes::default(),
        });
    });

    ic_cdk_timers::set_timer(Duration::ZERO, || {
        ic_cdk::spawn(init_certified_assets_chunk());
    });
}

async fn init_certified_assets_chunk() {
    let done = with_state_mut(|state| {
        let config = &state.heap.storage.config;
        let init = state.certified_init.as_mut().unwrap();

        // --- heap assets ---
        let heap_assets: Vec<_> = state.heap.storage.assets
            .iter()
            .skip(init.heap_cursor)
            .take(INIT_CHUNK_SIZE)
            .collect();

        let heap_done = heap_assets.len() < INIT_CHUNK_SIZE;
        for (_key, asset) in &heap_assets {
            init.asset_hashes.insert(asset, config);
        }
        init.heap_cursor += heap_assets.len();

        if !heap_done {
            return false; // still more heap assets
        }

        // --- stable assets ---
        let stable_assets: Vec<_> = state.stable.assets
            .iter()
            .skip(init.stable_cursor)
            .take(INIT_CHUNK_SIZE)
            .collect();

        let stable_done = stable_assets.len() < INIT_CHUNK_SIZE;
        for entry in &stable_assets {
            init.asset_hashes.insert(&entry.value(), config);
        }
        init.stable_cursor += stable_assets.len();

        stable_done
    });

    if !done {
        // Schedule next chunk immediately
        ic_cdk_timers::set_timer(Duration::ZERO, || {
            ic_cdk::spawn(init_certified_assets_chunk());
        });
        return;
    }

    // All assets inserted — finalize
    with_state_mut(|state| {
        let init = state.certified_init.take().unwrap();
        let config = &state.heap.storage.config;

        extend_and_init_certified_assets(
            &mut { init.asset_hashes },
            config,
            &StorageState,
            &StorageCertificate,
        );
    });
}

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions