Skip to content

Commit 9a1a1b4

Browse files
committed
fix dict copy performance
1 parent 58c688f commit 9a1a1b4

1 file changed

Lines changed: 54 additions & 13 deletions

File tree

contracts/TopShotIPFSResolver.cdc

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,23 @@ access(all) contract TopShotIPFSResolver {
33
access(all) event CIDSet(setID: UInt32, playID: UInt32, subeditionID: UInt32, mediaType: String, cid: String)
44
access(all) event GatewayUpdated(gateway: String)
55

6-
// Number of buckets to split CID entries across
76
access(all) let numBuckets: UInt64
87

9-
// Sharded storage: bucket index -> composite key -> { mediaType: CID }
10-
// Let's us store 32 * 100k = 32M CID entries
11-
access(contract) let shards: {UInt64: {String: {String: String}}}
8+
// Each shard is a resource stored at its own path so writes
9+
// borrow a reference and mutate in place — no dict copy.
10+
access(all) resource Shard {
11+
access(all) let entries: {String: {String: String}}
12+
13+
init() {
14+
self.entries = {}
15+
}
16+
17+
access(contract) fun setCID(key: String, mediaType: String, cid: String) {
18+
var inner = self.entries[key] ?? {}
19+
inner[mediaType] = cid
20+
self.entries[key] = inner
21+
}
22+
}
1223

1324
// IPFS gateway base URL (e.g., "https://ipfs.dapperlabs.com/ipfs/")
1425
access(all) var gateway: String
@@ -19,25 +30,56 @@ access(all) contract TopShotIPFSResolver {
1930
access(all) fun setCID(setID: UInt32, playID: UInt32, subeditionID: UInt32, mediaType: String, cid: String) {
2031
let key = TopShotIPFSResolver.buildKey(setID: setID, playID: playID, subeditionID: subeditionID)
2132
let bucket = TopShotIPFSResolver.getBucket(setID: setID, playID: playID, subeditionID: subeditionID)
22-
var shard = TopShotIPFSResolver.shards[bucket] ?? {}
23-
var inner = shard[key] ?? {}
24-
inner[mediaType] = cid
25-
shard[key] = inner
26-
TopShotIPFSResolver.shards[bucket] = shard
33+
let shard = TopShotIPFSResolver.borrowShard(bucket)
34+
shard.setCID(key: key, mediaType: mediaType, cid: cid)
2735
emit CIDSet(setID: setID, playID: playID, subeditionID: subeditionID, mediaType: mediaType, cid: cid)
2836
}
2937

3038
access(all) fun setGateway(gateway: String) {
3139
TopShotIPFSResolver.gateway = gateway
3240
emit GatewayUpdated(gateway: gateway)
3341
}
42+
43+
access(all) fun clearAllCIDs() {
44+
var i: UInt64 = 0
45+
while i < TopShotIPFSResolver.numBuckets {
46+
let path = TopShotIPFSResolver.shardPath(i)
47+
if let existing <- TopShotIPFSResolver.account.storage.load<@Shard>(from: path) {
48+
destroy existing
49+
}
50+
i = i + 1
51+
}
52+
}
3453
}
3554

3655
access(all) view fun getCIDs(setID: UInt32, playID: UInt32, subeditionID: UInt32): {String: String}? {
3756
let key = self.buildKey(setID: setID, playID: playID, subeditionID: subeditionID)
3857
let bucket = self.getBucket(setID: setID, playID: playID, subeditionID: subeditionID)
39-
let shard = self.shards[bucket] ?? {}
40-
return shard[key]
58+
let path = self.shardPath(bucket)
59+
if let shard = self.account.storage.borrow<&Shard>(from: path) {
60+
if let entry = shard.entries[key] {
61+
// Return a copy, not a reference
62+
let result: {String: String} = {}
63+
for mediaType in entry.keys {
64+
result[mediaType] = entry[mediaType]
65+
}
66+
return result
67+
}
68+
}
69+
return nil
70+
}
71+
72+
access(contract) fun borrowShard(_ bucket: UInt64): &Shard {
73+
let path = self.shardPath(bucket)
74+
if let shard = self.account.storage.borrow<&Shard>(from: path) {
75+
return shard
76+
}
77+
self.account.storage.save(<- create Shard(), to: path)
78+
return self.account.storage.borrow<&Shard>(from: path)!
79+
}
80+
81+
access(all) view fun shardPath(_ bucket: UInt64): StoragePath {
82+
return StoragePath(identifier: "TopShotIPFSShard_".concat(bucket.toString()))!
4183
}
4284

4385
access(all) view fun getBucket(setID: UInt32, playID: UInt32, subeditionID: UInt32): UInt64 {
@@ -53,8 +95,7 @@ access(all) contract TopShotIPFSResolver {
5395
}
5496

5597
init() {
56-
self.numBuckets = 32
57-
self.shards = {}
98+
self.numBuckets = 31
5899
self.gateway = "https://ipfs.dapperlabs.com/ipfs/"
59100
self.AdminStoragePath = /storage/TopShotIPFSResolverAdmin
60101
self.account.storage.save<@Admin>(<- create Admin(), to: self.AdminStoragePath)

0 commit comments

Comments
 (0)