Skip to content

Commit

Permalink
Node bridge memory cleanup (#208)
Browse files Browse the repository at this point in the history
# Goal
The goal of this PR is to implement an automated memory cleanup
mechanism that might help free the memory in cases that the uses forget
to manually free it.

Closes #128
  • Loading branch information
aramikm authored Aug 12, 2024
1 parent af2fa63 commit 451043b
Show file tree
Hide file tree
Showing 6 changed files with 687 additions and 17 deletions.
15 changes: 14 additions & 1 deletion bridge/node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const includePending: boolean = true;

const connections: DsnpGraphEdge[] = graph.getConnectionsForUserGraph(dsnpUserId, schemaId, includePending);

// Free the graph state
// It is important to free the graph state from memory
graph.freeGraphState();

```
Expand Down Expand Up @@ -178,6 +178,7 @@ The SDK provides various type definitions that can be used with the Graph class

const updates = graph.exportUpdates();

// It is important to free the graph state from memory
graph.freeGraphState();

```
Expand All @@ -204,6 +205,7 @@ The SDK provides various type definitions that can be used with the Graph class

const updates = graph.exportUpdates();

// It is important to free the graph state from memory
graph.freeGraphState();

```
Expand Down Expand Up @@ -236,6 +238,7 @@ The SDK provides various type definitions that can be used with the Graph class

const deserialized_keys = Graph.deserializeDsnpKeys(dsnp_keys);

// It is important to free the graph state from memory
graph.freeGraphState();

```
Expand Down Expand Up @@ -275,6 +278,7 @@ The SDK provides various type definitions that can be used with the Graph class

const exported_updates = graph.exportUpdates();

// It is important to free the graph state from memory
graph.freeGraphState();

```
Expand Down Expand Up @@ -340,4 +344,13 @@ The SDK provides various type definitions that can be used with the Graph class

const applied = graph.applyActions(actions);

// It is important to free the graph state from memory
graph.freeGraphState();

```
### Memory management
Creating any `Graph` instance allocates some memory which should be released manually by calling `graph.freeGraphState()` at the end of
graph operations.

Even though we have implemented `FinalizationRegistry`, based on the [documentations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry#avoid_where_possible) it is not a reliable
way of releasing memory and the best practice is still manual release.
21 changes: 19 additions & 2 deletions bridge/node/js/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,28 @@ import {
import { EnvironmentInterface } from "./models/environment";

export class Graph {
/// while there is no guarantee that this will free the allocated resources, and we should always manually
/// call freeGraphState for cleanup, having FinalizationRegistry might help in some cases that we forgot.
static #finalizerInstance: FinalizationRegistry<number>;

/// The handle to the native graph state
private handle: number;
private readonly handle: number;

constructor(environment: EnvironmentInterface) {
this.handle = graphsdkModule.initializeGraphState(environment);
if (!Graph.#finalizerInstance) {
Graph.#finalizerInstance = new FinalizationRegistry<number>(
(handle: number) => {
try {
graphsdkModule.freeGraphState(handle);
} catch {
// nothing to do here
}
},
);
}
const my_handle = graphsdkModule.initializeGraphState(environment);
Graph.#finalizerInstance.register(this, my_handle);
this.handle = my_handle;
}

getGraphHandle(): number {
Expand Down
19 changes: 11 additions & 8 deletions bridge/node/node-example-client/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Graph, EnvironmentInterface, Action, DsnpKeys, EnvironmentType, ConnectAction, Connection, ConnectionType, PrivacyType } from "@dsnp/graph-sdk";

const environment: EnvironmentInterface = {environmentType: EnvironmentType.Mainnet};
const graph = new Graph(environment);
function interactWithGraph() {
const environment: EnvironmentInterface = {environmentType: EnvironmentType.Mainnet};
const graph= new Graph(environment);

async function interactWithGraph() {
let public_follow_graph_schema_id = await graph.getSchemaIdFromConfig(environment, ConnectionType.Follow, PrivacyType.Public);
let public_follow_graph_schema_id = graph.getSchemaIdFromConfig(environment, ConnectionType.Follow, PrivacyType.Public);

let connect_action: ConnectAction = {
type: "Connect",
Expand All @@ -23,14 +23,17 @@ async function interactWithGraph() {
let actions = [] as Action[];
actions.push(connect_action);

let applied = await graph.applyActions(actions);
let applied = graph.applyActions(actions);
console.log(applied);

let connections_including_pending = await graph.getConnectionsForUserGraph("1", public_follow_graph_schema_id, true);
let connections_including_pending = graph.getConnectionsForUserGraph("1", public_follow_graph_schema_id, true);
console.log(connections_including_pending);

let exported = await graph.exportUpdates();
let exported = graph.exportUpdates();
console.log(exported);

// always clean up the allocated memory in the end
graph.freeGraphState();
}

interactWithGraph();
Loading

0 comments on commit 451043b

Please sign in to comment.