Skip to content
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

Improve PartialECChangeUnifier to handle very large changeset #7607

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

khanaffan
Copy link
Contributor

@khanaffan khanaffan commented Jan 24, 2025

Fixes: #7553

This API is beta.

PartialECChangeUnifier use in memory cache that resulted OOM error when processing very large changeset.

Solution is to use SQLite TEMP db to unify changes across multiple tables

original POC done by @mattbjordan

@khanaffan khanaffan requested a review from a team as a code owner January 24, 2025 20:56
// table name should be unique in case two PartialECChangeUnifiers are made
this._db.withPreparedSqliteStatement(`CREATE TABLE [temp].[${this._cacheTable}] ([key] text primary key, [value] text)`, (stmt) => {
if (DbResult.BE_SQLITE_DONE !== stmt.step()) {
// throw new Error(db.nativeDb.getLastError());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove commented out line

private dropTempTable(): void {
this._db.withPreparedSqliteStatement(`DROP TABLE IF EXISTS [temp].[${this._cacheTable}]`, (stmt) => {
if (DbResult.BE_SQLITE_DONE !== stmt.step()) {
// throw new Error(db.nativeDb.getLastError());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove commented out line

stmt.bindString(1, key);
stmt.bindString(2, JSON.stringify(shallowCopy));
stmt.step();

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove empty line

const key = PartialECChangeUnifier.buildKey(rhs, db);
const lhs = this._cache.get(key);
const key = this.buildKey(rhs);
const lhs = this.getInstance(key); // get from temp db instead
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment is probably not needed anymore

Comment on lines +517 to +518
}
private static replaceBase64WithUint8Array(row: any): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline between methods

Suggested change
}
private static replaceBase64WithUint8Array(row: any): void {
}
private static replaceBase64WithUint8Array(row: any): void {

Comment on lines +559 to +560
}
private dropTempTable(): void {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline between methods

Suggested change
}
private dropTempTable(): void {
}
private dropTempTable(): void {

Comment on lines +567 to 568
}
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline between methods

Suggested change
}
/**
}
/**

Comment on lines 619 to +620
}
private *getInstances(): IterableIterator<ChangedECInstance> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline between methods

Suggested change
}
private *getInstances(): IterableIterator<ChangedECInstance> {
}
private *getInstances(): IterableIterator<ChangedECInstance> {

Comment on lines +628 to 629
}
/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline between methods

Suggested change
}
/**
}
/**

private _readonly = false;
public constructor(private _db: AnyDb) {
this.createTempTable();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about turning using a temp table into an option? Because this method should be quite a bit slower than the old method of just keeping the values in a map in RAM.

Maybe just a boolean parameter, then the question is which should be the default? Only stupidly large iModels/Changesets will have this issue - but those aren't THAT uncommon or unexpected. It'd be nice if we could automatically make an educated guess for which method to use based on the size of the iModel and changes - but is that feasible here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Handle PartialECChangeUnifier Changes On-Disk
2 participants