update schema.graphql with denormalized schema#132
update schema.graphql with denormalized schema#132mariobassem wants to merge 5 commits intomasterfrom
Conversation
Signed-off-by: mariobassem <mariobassem12@gmail.com>
Signed-off-by: mariobassem <mariobassem12@gmail.com>
Signed-off-by: mariobassem <mariobassem12@gmail.com>
Signed-off-by: mariobassem <mariobassem12@gmail.com>
Signed-off-by: mariobassem <mariobassem12@gmail.com>
| await db.query(`CREATE TABLE "contract_resources" ("id" character varying NOT NULL, "hru" numeric NOT NULL, "sru" numeric NOT NULL, "cru" numeric NOT NULL, "mru" numeric NOT NULL, "contract_id" character varying, CONSTRAINT "PK_557de19994fcca90916e8c6582f" PRIMARY KEY ("id"))`) | ||
| await db.query(`ALTER TABLE "contract_resources" ADD CONSTRAINT "FK_621238dffde9099b2233650235d" FOREIGN KEY ("contract_id") REFERENCES "node_contract"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`) | ||
| } | ||
| } |
There was a problem hiding this comment.
Thanks, Mario, for all the good work!
-
Since this PR is about performance, have we conducted any tests or benchmarks to demonstrate the effectiveness of the performance improvements made here?
I would like to see some numbers before and after the changes for the queries that were used in production. This will help us understand the impact of the changes and whether they are worth implementing. -
Also, I was wondering if there are any other parts of the system that use this database directly besides gridproxy. If so, it might be helpful to include a note in the PR description about what will be affected by this change.
| ip.contractId = null | ||
| const farm = await ctx.store.get(Farm, { where: { farmID: ip.farm.farmID } }) | ||
| if (farm) { | ||
| farm.freeIps += 1 |
There was a problem hiding this comment.
I would like to understand the motivation behind updating the counters for free and total IPs in multiple places within the code instead of relying on the database count function. I’m afraid we are sacrificing consistency for small or premature performance optimization.
In my opinion, this approach may be more error-prone, and we can end up with incorrect counters in the database.
If we really can't just use db count function, we can consider using an indexed view to maintain the IP counters.
There was a problem hiding this comment.
it's pretty common, i think, that a farms is filtered by how many public ips it has, and currently, farm queries in gridproxy counts all farm ips, and counts all farm ips that don't have a contract id (this is done per farm). and since the processor actually process's the events that manipulate ips, i thought it would be more efficient to have the ip counts pre-calculated.
i don't really see how this is error-prone, can you explain?
| if (!savedNode) return | ||
| savedNode.freeMRU += savedContract.usedMRU || BigInt(0) | ||
| savedNode.freeSRU += savedContract.usedSRU || BigInt(0) | ||
| savedNode.freeHRU += savedContract.usedHRU || BigInt(0) |
There was a problem hiding this comment.
I keep seeing this pattern in the code where we first read the data in memory, modify it, and then write it back to the database. I’m not an expert on TypeORM, but in general, I think there are better ways to update a field or a few fields in one query. Doing so in multiple queries is less efficient and susceptible to overwrite problems (not atomic).
I never used typeORM but doing a quick search and checking repository API, I believe its safer to use .update() or .increment() and .decrement().
Another alternative is doing so using QueryBuilder.
| savedContract.state = ContractState.Deleted | ||
|
|
||
| await ctx.store.save<RentContract>(savedContract) | ||
| await ctx.store.save<Contract>(savedContract) |
There was a problem hiding this comment.
as the previous comment, can we do so in one query?
| if (savedNode) { | ||
| savedNode.dedicated = savedNode.extraFee !== null | ||
| savedNode.rentedBy = null | ||
| await ctx.store.save<Node>(savedNode) |
There was a problem hiding this comment.
as the previous comment, can we do so in one query?
| savedNode.freeHRU += (savedContract.usedHRU || BigInt(0)) - usedResources.used.hru | ||
| savedNode.freeSRU += (savedContract.usedSRU || BigInt(0)) - usedResources.used.sru | ||
|
|
||
| await ctx.store.save<Node>(savedNode) |
There was a problem hiding this comment.
As previous comment, should be safer to use .increment() or .decrement(). check here
|
|
||
| newFarm.publicIPs?.push(newIP) | ||
|
|
||
| newFarm.totalIps += 1 |
There was a problem hiding this comment.
This could be more error-prone, and susceptible to overwrite problems (not atomic).
As explained before, i would suggest relay on db count function whenever we need such info, or consider using an indexed view for IPs counters.
| const savedIP = await ctx.store.get(PublicIp, { where: { ip: ip.ip.toString() }, relations: { farm: true } }) | ||
| // ip is already there in storage, don't save it again | ||
|
|
||
| savedFarm.totalIps += 1 |
There was a problem hiding this comment.
As previous comment
Also, do we need to increment totalIps here?
| savedNode.dedicated = savedNode.extraFee !== null | ||
| await ctx.store.save<Node>(savedNode) | ||
| if (savedContract.nodeID) { | ||
| const savedNode = await ctx.store.get(Node, { where: { nodeID: savedContract.nodeID }, relations: { location: true, interfaces: true } }) |
There was a problem hiding this comment.
Do we need to load these relations?
| import { allowedNodeEnvironmentFlags } from "process"; | ||
|
|
||
| const ZOSUsedSRU = 107374182400; | ||
| const ZOSMinUsedMemory = 2147483648; |
There was a problem hiding this comment.
What are these numbers and where it came from?
Please add a code comment explaining these magic numbers.
| let savedPublicIPs: PublicIp[] = await ctx.store.find(PublicIp, { where: { contractId: contractID }, relations: { farm: true } }) | ||
| Promise.all(savedPublicIPs.map(async (ip) => { | ||
| ip.contractId = null | ||
| const farm = await ctx.store.get(Farm, { where: { farmID: ip.farm.farmID } }) |
There was a problem hiding this comment.
I'm not sure, but do we need to read Farm instance again? can we use ip.farm directly instead?
Description:
this pr tries to denormalize schema generated by the processor
Changes
Related issues: