Map and Buckets Example -> Query method possible?

I am looking at the “Map and Buckets” example (GitHub / Forum) but, cannot figure a way to implement a performant getter method.

The actor’s get is not defined as query because, I guess, the Bucket get has to return an async value.

Map (main canister):

 public func get(k : Key) : async ?Value {
    switch (buckets[k % n]) {
      case null null;
      case (?bucket) await bucket.get(k);
    };
  };

Bucket (“sub canister”):

public func get(k : Key) : async ?Value {
    assert((k % n) == i);
    map.get(k);
  };

I tried to remove the async in a playground but, get following error.

shared query function must have syntactic return type 'async ’

Is there a way to provide query functions with the “Map and Buckets” (“canister and sub-canisters”) pattern?

Queries can (in fact, must) have async results. The reason that get is not a query is that query methods cannot call other canister methods (like bucket) at the moment. This is a current limitation of the IC. Until the IC is extended with support for cross-canister queries, you have to use regular update methods if they need to make secondary calls.

This would be neat!

Gotcha, thx for the answer.

If you run some performance metrics it would be interesting to see if two queries are faster than one update. If so you could query the map for the bucket principal and then query the bucket directly.

1 Like

That’s the path I gonna try to follow.

I am careful about the subject because in my early version of our proof of concept I did not implement the query:sweat_smile:. It had for effect that requests (GET) took up to 10sec. I did changed these to query and now it tops 100ms (:partying_face:) but, I don’t have yet tried out this “map and buckets” pattern.

For the curious, without query (9937ms for a get):

Capture d’écran 2021-08-06 à 07.27.27

With query (132ms for a get):

Capture d’écran 2021-08-09 à 07.43.03

3 Likes