Skip to content

Commit b87eeb2

Browse files
committed
perf: optimize allocation rules evaluation from O(n²) to O(n)
Replace repeated Array.filter() + Array.find() with Map-based lookup for deployment rules. - Add preprocessRules() function to create Map for O(1) rule lookups - Update isDeploymentWorthAllocatingTowards() to use pre-processed rules Map - Update evaluateDeployments() to preprocess rules once instead of per deployment - Update AllocationManager.matchingRuleExists() to use optimized lookup Performance improvement: - Before: O(n²) - filter + find for each deployment evaluation - After: O(n) - single preprocessing + O(1) lookups per deployment - Significant speedup when evaluating many deployments against many rules Fixes performance bottleneck in allocation rule evaluation where processing thousands of deployments with hundreds of rules resulted in quadratic complexity.
1 parent bea354e commit b87eeb2

File tree

2 files changed

+52
-13
lines changed

2 files changed

+52
-13
lines changed

packages/indexer-common/src/indexer-management/allocations.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import {
4747
encodeCollectIndexingRewardsData,
4848
encodePOIMetadata,
4949
} from '@graphprotocol/toolshed'
50+
import { preprocessRules } from '../subgraphs'
5051

5152
import {
5253
BigNumberish,
@@ -1791,8 +1792,15 @@ export class AllocationManager {
17911792
`SHOULD BE UNREACHABLE: No matching subgraphDeployment (${subgraphDeploymentID.ipfsHash}) found on the network`,
17921793
)
17931794
}
1794-
return isDeploymentWorthAllocatingTowards(logger, subgraphDeployment, indexingRules)
1795-
.toAllocate
1795+
const { deploymentRulesMap, globalRule } = preprocessRules(indexingRules)
1796+
1797+
return isDeploymentWorthAllocatingTowards(
1798+
logger,
1799+
subgraphDeployment,
1800+
indexingRules,
1801+
deploymentRulesMap,
1802+
globalRule,
1803+
).toAllocate
17961804
}
17971805

17981806
// Calculates the balance (GRT delta) of a single Action.

packages/indexer-common/src/subgraphs.ts

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,29 +187,60 @@ export class AllocationDecision {
187187
}
188188
}
189189

190+
export interface PreprocessedRules {
191+
deploymentRulesMap: { [key: string]: IndexingRuleAttributes }
192+
globalRule: IndexingRuleAttributes | undefined
193+
}
194+
195+
export function preprocessRules(rules: IndexingRuleAttributes[]): PreprocessedRules {
196+
let globalRule: IndexingRuleAttributes | undefined
197+
const deploymentRulesMap: { [key: string]: IndexingRuleAttributes } = {}
198+
199+
for (let i = 0; i < rules.length; i++) {
200+
const rule = rules[i]
201+
if (rule.identifier === INDEXING_RULE_GLOBAL) {
202+
globalRule = rule
203+
} else if (rule.identifierType === SubgraphIdentifierType.DEPLOYMENT) {
204+
deploymentRulesMap[rule.identifier] = rule
205+
}
206+
}
207+
208+
return { deploymentRulesMap, globalRule }
209+
}
210+
190211
export function evaluateDeployments(
191212
logger: Logger,
192213
networkDeployments: SubgraphDeployment[],
193214
rules: IndexingRuleAttributes[],
194215
): AllocationDecision[] {
195-
return networkDeployments.map((deployment) =>
196-
isDeploymentWorthAllocatingTowards(logger, deployment, rules),
197-
)
216+
const { deploymentRulesMap, globalRule } = preprocessRules(rules)
217+
const results: AllocationDecision[] = []
218+
219+
for (let i = 0; i < networkDeployments.length; i++) {
220+
const deployment = networkDeployments[i]
221+
results.push(
222+
isDeploymentWorthAllocatingTowards(
223+
logger,
224+
deployment,
225+
rules,
226+
deploymentRulesMap,
227+
globalRule,
228+
),
229+
)
230+
}
231+
232+
return results
198233
}
199234

200235
export function isDeploymentWorthAllocatingTowards(
201236
logger: Logger,
202237
deployment: SubgraphDeployment,
203238
rules: IndexingRuleAttributes[],
239+
deploymentRulesMap: { [key: string]: IndexingRuleAttributes },
240+
globalRule: IndexingRuleAttributes | undefined,
204241
): AllocationDecision {
205-
const globalRule = rules.find((rule) => rule.identifier === INDEXING_RULE_GLOBAL)
206-
const deploymentRule =
207-
rules
208-
.filter((rule) => rule.identifierType == SubgraphIdentifierType.DEPLOYMENT)
209-
.find(
210-
(rule) =>
211-
new SubgraphDeploymentID(rule.identifier).bytes32 === deployment.id.bytes32,
212-
) || globalRule
242+
// Use the pre-processed object for O(1) lookup
243+
const deploymentRule = deploymentRulesMap[deployment.id.ipfsHash] || globalRule
213244

214245
logger.trace('Evaluating whether subgraphDeployment is worth allocating towards', {
215246
deployment,

0 commit comments

Comments
 (0)