Skip to content

Commit

Permalink
Synchronize document + transaction methods
Browse files Browse the repository at this point in the history
A few methods added to Document and TransactionImpl were missing the
synchronized keyword which is necessary to ensure the pointers which they
resptectively manage are exclusive.
  • Loading branch information
alexjg committed Jan 11, 2024
1 parent 55cf7c6 commit d92e28a
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 31 deletions.
50 changes: 33 additions & 17 deletions lib/src/main/java/org/automerge/Document.java
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ public class Document implements Read {
// If a transaction is in progress we must forward all calls to the transaction.
// In rust code the transaction holds a mutable reference to the document, so
// any
// calls to the document whilst the transaction exists would be undefined
// behaviour.
// calls to the document whilst the transaction exists would be unsafe
private Optional<AutomergeSys.TransactionPointer> transactionPtr;

/** Create a new document with a random actor ID */
Expand Down Expand Up @@ -336,47 +335,47 @@ public synchronized Optional<AmValue> get(ObjectId obj, int key) {
}
}

public Optional<AmValue> get(ObjectId obj, String key, ChangeHash[] heads) {
public synchronized Optional<AmValue> get(ObjectId obj, String key, ChangeHash[] heads) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.getAtInMapInTx(this.transactionPtr.get(), obj, key, heads);
} else {
return AutomergeSys.getAtInMapInDoc(this.pointer.get(), obj, key, heads);
}
}

public Optional<AmValue> get(ObjectId obj, int idx, ChangeHash[] heads) {
public synchronized Optional<AmValue> get(ObjectId obj, int idx, ChangeHash[] heads) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.getAtInListInTx(this.transactionPtr.get(), obj, idx, heads);
} else {
return AutomergeSys.getAtInListInDoc(this.pointer.get(), obj, idx, heads);
}
}

public Optional<Conflicts> getAll(ObjectId obj, String key) {
public synchronized Optional<Conflicts> getAll(ObjectId obj, String key) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.getAllInMapInTx(this.transactionPtr.get(), obj, key);
} else {
return AutomergeSys.getAllInMapInDoc(this.pointer.get(), obj, key);
}
}

public Optional<Conflicts> getAll(ObjectId obj, int idx) {
public synchronized Optional<Conflicts> getAll(ObjectId obj, int idx) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.getAllInListInTx(this.transactionPtr.get(), obj, idx);
} else {
return AutomergeSys.getAllInListInDoc(this.pointer.get(), obj, idx);
}
}

public Optional<Conflicts> getAll(ObjectId obj, String key, ChangeHash[] heads) {
public synchronized Optional<Conflicts> getAll(ObjectId obj, String key, ChangeHash[] heads) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.getAllAtInMapInTx(this.transactionPtr.get(), obj, key, heads);
} else {
return AutomergeSys.getAllAtInMapInDoc(this.pointer.get(), obj, key, heads);
}
}

public Optional<Conflicts> getAll(ObjectId obj, int idx, ChangeHash[] heads) {
public synchronized Optional<Conflicts> getAll(ObjectId obj, int idx, ChangeHash[] heads) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.getAllAtInListInTx(this.transactionPtr.get(), obj, idx, heads);
} else {
Expand Down Expand Up @@ -657,7 +656,7 @@ protected synchronized void receiveSyncMessageLogPatches(AutomergeSys.SyncStateP
* @return The patches required to transform the state at `before` to the state
* at `after`
*/
public List<Patch> diff(ChangeHash[] before, ChangeHash[] after) {
public synchronized List<Patch> diff(ChangeHash[] before, ChangeHash[] after) {
return AutomergeSys.diff(this.pointer.get(), before, after);
}

Expand All @@ -680,22 +679,39 @@ public synchronized HashMap<String, AmValue> getMarksAtIndex(ObjectId obj, int i
}

@Override
public Cursor makeCursor(ObjectId obj, long index) {
return AutomergeSys.makeCursorInDoc(this.pointer.get(), obj, index, Optional.empty());
public synchronized Cursor makeCursor(ObjectId obj, long index) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.makeCursorInTx(this.transactionPtr.get(), obj, index, Optional.empty());
} else {
return AutomergeSys.makeCursorInDoc(this.pointer.get(), obj, index, Optional.empty());
}
}

@Override
public Cursor makeCursor(ObjectId obj, long index, ChangeHash[] heads) {
return AutomergeSys.makeCursorInDoc(this.pointer.get(), obj, index, Optional.of(heads));
public synchronized Cursor makeCursor(ObjectId obj, long index, ChangeHash[] heads) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.makeCursorInTx(this.transactionPtr.get(), obj, index, Optional.of(heads));
} else {
return AutomergeSys.makeCursorInDoc(this.pointer.get(), obj, index, Optional.of(heads));
}
}

@Override
public long lookupCursorIndex(ObjectId obj, Cursor cursor) {
return AutomergeSys.lookupCursorIndexInDoc(this.pointer.get(), obj, cursor, Optional.empty());
public synchronized long lookupCursorIndex(ObjectId obj, Cursor cursor) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.lookupCursorIndexInTx(this.transactionPtr.get(), obj, cursor, Optional.empty());
} else {
return AutomergeSys.lookupCursorIndexInDoc(this.pointer.get(), obj, cursor, Optional.empty());
}

}

@Override
public long lookupCursorIndex(ObjectId obj, Cursor cursor, ChangeHash[] heads) {
return AutomergeSys.lookupCursorIndexInDoc(this.pointer.get(), obj, cursor, Optional.of(heads));
public synchronized long lookupCursorIndex(ObjectId obj, Cursor cursor, ChangeHash[] heads) {
if (this.transactionPtr.isPresent()) {
return AutomergeSys.lookupCursorIndexInTx(this.transactionPtr.get(), obj, cursor, Optional.of(heads));
} else {
return AutomergeSys.lookupCursorIndexInDoc(this.pointer.get(), obj, cursor, Optional.of(heads));
}
}
}
34 changes: 20 additions & 14 deletions lib/src/main/java/org/automerge/TransactionImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -280,47 +280,53 @@ public synchronized void mark(ObjectId obj, long start, long end, String markNam
}

@Override
public void mark(ObjectId obj, long start, long end, String markName, String value, ExpandMark expand) {
public synchronized void mark(ObjectId obj, long start, long end, String markName, String value,
ExpandMark expand) {
AutomergeSys.markString(this.pointer.get(), obj, markName, start, end, value, expand);
}

@Override
public void mark(ObjectId obj, long start, long end, String markName, long value, ExpandMark expand) {
public synchronized void mark(ObjectId obj, long start, long end, String markName, long value, ExpandMark expand) {
AutomergeSys.markInt(this.pointer.get(), obj, markName, start, end, value, expand);
}

@Override
public void markUint(ObjectId obj, long start, long end, String markName, long value, ExpandMark expand) {
public synchronized void markUint(ObjectId obj, long start, long end, String markName, long value,
ExpandMark expand) {
AutomergeSys.markUint(this.pointer.get(), obj, markName, start, end, value, expand);
}

@Override
public void mark(ObjectId obj, long start, long end, String markName, double value, ExpandMark expand) {
public synchronized void mark(ObjectId obj, long start, long end, String markName, double value,
ExpandMark expand) {
AutomergeSys.markDouble(this.pointer.get(), obj, markName, start, end, value, expand);
}

@Override
public void mark(ObjectId obj, long start, long end, String markName, byte[] value, ExpandMark expand) {
public synchronized void mark(ObjectId obj, long start, long end, String markName, byte[] value,
ExpandMark expand) {
AutomergeSys.markBytes(this.pointer.get(), obj, markName, start, end, value, expand);
}

@Override
public void mark(ObjectId obj, long start, long end, String markName, Counter value, ExpandMark expand) {
public synchronized void mark(ObjectId obj, long start, long end, String markName, Counter value,
ExpandMark expand) {
AutomergeSys.markCounter(this.pointer.get(), obj, markName, start, end, value.getValue(), expand);
}

@Override
public void mark(ObjectId obj, long start, long end, String markName, Date value, ExpandMark expand) {
public synchronized void mark(ObjectId obj, long start, long end, String markName, Date value, ExpandMark expand) {
AutomergeSys.markDate(this.pointer.get(), obj, markName, start, end, value, expand);
}

@Override
public void mark(ObjectId obj, long start, long end, String markName, boolean value, ExpandMark expand) {
public synchronized void mark(ObjectId obj, long start, long end, String markName, boolean value,
ExpandMark expand) {
AutomergeSys.markBool(this.pointer.get(), obj, markName, start, end, value, expand);
}

@Override
public void markNull(ObjectId obj, long start, long end, String markName, ExpandMark expand) {
public synchronized void markNull(ObjectId obj, long start, long end, String markName, ExpandMark expand) {
AutomergeSys.markNull(this.pointer.get(), obj, markName, start, end, expand);
}

Expand All @@ -336,7 +342,7 @@ public synchronized List<Mark> marks(ObjectId obj, ChangeHash[] heads) {
return AutomergeSys.getMarksInTx(this.pointer.get(), obj, Optional.of(heads));
}

public void close() {
public synchronized void close() {
if (this.pointer.isPresent()) {
this.rollback();
}
Expand All @@ -353,22 +359,22 @@ public synchronized HashMap<String, AmValue> getMarksAtIndex(ObjectId obj, int i
}

@Override
public Cursor makeCursor(ObjectId obj, long index) {
public synchronized Cursor makeCursor(ObjectId obj, long index) {
return AutomergeSys.makeCursorInTx(this.pointer.get(), obj, index, Optional.empty());
}

@Override
public Cursor makeCursor(ObjectId obj, long index, ChangeHash[] heads) {
public synchronized Cursor makeCursor(ObjectId obj, long index, ChangeHash[] heads) {
return AutomergeSys.makeCursorInTx(this.pointer.get(), obj, index, Optional.of(heads));
}

@Override
public long lookupCursorIndex(ObjectId obj, Cursor cursor) {
public synchronized long lookupCursorIndex(ObjectId obj, Cursor cursor) {
return AutomergeSys.lookupCursorIndexInTx(this.pointer.get(), obj, cursor, Optional.empty());
}

@Override
public long lookupCursorIndex(ObjectId obj, Cursor cursor, ChangeHash[] heads) {
public synchronized long lookupCursorIndex(ObjectId obj, Cursor cursor, ChangeHash[] heads) {
return AutomergeSys.lookupCursorIndexInTx(this.pointer.get(), obj, cursor, Optional.of(heads));
}

Expand Down

0 comments on commit d92e28a

Please sign in to comment.