-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
update schema.graphql with denormalized schema #132
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: mariobassem <[email protected]>
Signed-off-by: mariobassem <[email protected]>
Signed-off-by: mariobassem <[email protected]>
Signed-off-by: mariobassem <[email protected]>
Signed-off-by: mariobassem <[email protected]>
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
.
|
||
if (!savedContract) return | ||
|
||
savedContract.state = ContractState.Deleted | ||
|
||
await ctx.store.save<RentContract>(savedContract) | ||
await ctx.store.save<Contract>(savedContract) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As previous comment, should be safer to use .increment()
or .decrement()
. check here
@@ -70,10 +72,14 @@ export async function farmStored( | |||
newIP.farm = newFarm | |||
|
|||
newFarm.publicIPs?.push(newIP) | |||
|
|||
newFarm.totalIps += 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
if (ip.ip.toString().indexOf('\x00') >= 0) { | ||
return | ||
} | ||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to load these relations?
@@ -15,6 +15,9 @@ import { Ctx } from '../processor' | |||
import assert from "assert"; | |||
import { allowedNodeEnvironmentFlags } from "process"; | |||
|
|||
const ZOSUsedSRU = 107374182400; | |||
const ZOSMinUsedMemory = 2147483648; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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: