Skip to content

Commit

Permalink
fix: post-merge fixes and test cleaning
Browse files Browse the repository at this point in the history
  • Loading branch information
JanLewDev committed Sep 12, 2024
1 parent 7d75a7f commit 53c8753
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 140 deletions.
2 changes: 1 addition & 1 deletion packages/crdt/src/cros/AddWinsSet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class AddWinsSet<T> implements CRO {
}

// in this case is an array of length 2 and there are only two possible operations
resolveConflicts(vertices: Vertex<T>[]): ResolveConflictsType {
resolveConflicts(vertices: Vertex[]): ResolveConflictsType {
if (
vertices[0].operation.type !== vertices[1].operation.type &&
vertices[0].operation.value === vertices[1].operation.value
Expand Down
6 changes: 3 additions & 3 deletions packages/crdt/src/cros/PseudoRandomWinsSet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function compute_hash(s: string): number {
An arbitrary number of concurrent operations can be reduced to a single operation.
The winning operation is chosen using a pseudo-random number generator.
*/
export class PseudoRandomWinsSet<T> implements CRO<T> {
export class PseudoRandomWinsSet<T> implements CRO {
operations: string[] = ["add", "remove"];
state: Map<T, boolean>;
semanticsType = SemanticsType.multiVertex;
Expand Down Expand Up @@ -61,7 +61,7 @@ export class PseudoRandomWinsSet<T> implements CRO<T> {
.map(([value, _]) => value);
}

resolveConflicts(vertices: Vertex<T>[]): ResolveConflictsType {
resolveConflicts(vertices: Vertex[]): ResolveConflictsType {
vertices.sort((a, b) => (a.hash < b.hash ? -1 : 1));
const seed: string = vertices.map((vertex) => vertex.hash).join("");
const rnd = new Smush32(compute_hash(seed));
Expand All @@ -72,7 +72,7 @@ export class PseudoRandomWinsSet<T> implements CRO<T> {
}

// merged at HG level and called as a callback
mergeCallback(operations: Operation<T>[]): void {
mergeCallback(operations: Operation[]): void {
this.state = new Map<T, boolean>();
for (const op of operations) {
switch (op.type) {
Expand Down
2 changes: 1 addition & 1 deletion packages/node/src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const VERSION = "0.1.1-3";
export const VERSION = "0.1.1";
79 changes: 26 additions & 53 deletions packages/object/src/hashgraph/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import * as crypto from "node:crypto";
import { linearizeMultiVertex } from "../linearize/multi-vertexSemantics.js";
import { linearizePairWise } from "../linearize/pair-wiseSemantics.js";
import { BitSet } from "./bitset.js";

export type Hash = string;
Expand All @@ -14,8 +16,20 @@ export enum ActionType {
DropRight = 1,
Nop = 2,
Swap = 3,
Reduce = 4,
}

export enum SemanticsType {
pairWise = 0,
multiVertex = 1,
}

// In the case of multi-vertex semantics, we are returning an array of vertices (their hashes) to be reduced.
export type ResolveConflictsType = {
action: ActionType;
vertices?: Hash[];
};

export interface Vertex {
hash: Hash;
nodeId: string;
Expand All @@ -27,7 +41,8 @@ export interface Vertex {

export class HashGraph {
nodeId: string;
resolveConflicts: (vertices: Vertex[]) => ActionType;
resolveConflicts: (vertices: Vertex[]) => ResolveConflictsType;
semanticsType: SemanticsType;

vertices: Map<Hash, Vertex> = new Map();
frontier: Hash[] = [];
Expand All @@ -45,10 +60,12 @@ export class HashGraph {

constructor(
nodeId: string,
resolveConflicts: (vertices: Vertex[]) => ActionType,
resolveConflicts: (vertices: Vertex[]) => ResolveConflictsType,
semanticsType: SemanticsType,
) {
this.nodeId = nodeId;
this.resolveConflicts = resolveConflicts;
this.semanticsType = semanticsType;

// Create and add the NOP root vertex
const rootVertex: Vertex = {
Expand Down Expand Up @@ -182,58 +199,14 @@ export class HashGraph {
}

linearizeOperations(): Operation[] {
const order = this.topologicalSort(true);
const result: Operation[] = [];
let i = 0;

while (i < order.length) {
const anchor = order[i];
let j = i + 1;
let shouldIncrementI = true;

while (j < order.length) {
const moving = order[j];

if (!this.areCausallyRelatedUsingBitsets(anchor, moving)) {
const v1 = this.vertices.get(anchor);
const v2 = this.vertices.get(moving);
let action: ActionType;
if (!v1 || !v2) {
action = ActionType.Nop;
} else {
action = this.resolveConflicts([v1, v2]);
}

switch (action) {
case ActionType.DropLeft:
order.splice(i, 1);
j = order.length; // Break out of inner loop
shouldIncrementI = false;
continue; // Continue outer loop without incrementing i
case ActionType.DropRight:
order.splice(j, 1);
continue; // Continue with the same j
case ActionType.Swap:
[order[i], order[j]] = [order[j], order[i]];
j = order.length; // Break out of inner loop
break;
case ActionType.Nop:
j++;
break;
}
} else {
j++;
}
}

if (shouldIncrementI) {
const op = this.vertices.get(order[i])?.operation;
if (op && op.value !== null) result.push(op);
i++;
}
switch (this.semanticsType) {
case SemanticsType.pairWise:
return linearizePairWise(this);
case SemanticsType.multiVertex:
return linearizeMultiVertex(this);
default:
return [];
}

return result;
}

// Amortised time complexity: O(1), Amortised space complexity: O(1)
Expand Down
18 changes: 7 additions & 11 deletions packages/object/src/linearize/multi-vertexSemantics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import {
type HashGraph,
type Operation,
type Vertex,
} from "../hashgraph.js";
} from "../hashgraph/index.js";

export function linearizeMultiVertex<T>(
hashGraph: HashGraph<T>,
): Operation<T>[] {
let order = hashGraph.topologicalSort();
export function linearizeMultiVertex(hashGraph: HashGraph): Operation[] {
let order = hashGraph.topologicalSort(true);
const indices: Map<Hash, number> = new Map();
const result: Operation<T>[] = [];
const result: Operation[] = [];
let i = 0;

while (i < order.length) {
Expand All @@ -22,7 +20,7 @@ export function linearizeMultiVertex<T>(
while (j < order.length) {
const moving = order[j];

if (!hashGraph.areCausallyRelated(anchor, moving)) {
if (!hashGraph.areCausallyRelatedUsingBitsets(anchor, moving)) {
const concurrentOps: Hash[] = [];
concurrentOps.push(anchor);
indices.set(anchor, i);
Expand All @@ -32,7 +30,7 @@ export function linearizeMultiVertex<T>(
for (; k < order.length; k++) {
let add = true;
for (const hash of concurrentOps) {
if (hashGraph.areCausallyRelated(hash, order[k])) {
if (hashGraph.areCausallyRelatedUsingBitsets(hash, order[k])) {
add = false;
break;
}
Expand All @@ -43,9 +41,7 @@ export function linearizeMultiVertex<T>(
}
}
const resolved = hashGraph.resolveConflicts(
concurrentOps.map(
(hash) => hashGraph.vertices.get(hash) as Vertex<T>,
),
concurrentOps.map((hash) => hashGraph.vertices.get(hash) as Vertex),
);

switch (resolved.action) {
Expand Down
14 changes: 9 additions & 5 deletions packages/object/src/linearize/pair-wiseSemantics.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { ActionType, type HashGraph, type Operation } from "../hashgraph.js";
import {
ActionType,
type HashGraph,
type Operation,
} from "../hashgraph/index.js";

export function linearizePairWise<T>(hashGraph: HashGraph<T>): Operation<T>[] {
const order = hashGraph.topologicalSort();
const result: Operation<T>[] = [];
export function linearizePairWise(hashGraph: HashGraph): Operation[] {
const order = hashGraph.topologicalSort(true);
const result: Operation[] = [];
let i = 0;

while (i < order.length) {
Expand All @@ -13,7 +17,7 @@ export function linearizePairWise<T>(hashGraph: HashGraph<T>): Operation<T>[] {
while (j < order.length) {
const moving = order[j];

if (!hashGraph.areCausallyRelated(anchor, moving)) {
if (!hashGraph.areCausallyRelatedUsingBitsets(anchor, moving)) {
const v1 = hashGraph.vertices.get(anchor);
const v2 = hashGraph.vertices.get(moving);
let action: ActionType;
Expand Down
Loading

0 comments on commit 53c8753

Please sign in to comment.