Skip to content

Commit

Permalink
fixing mismatched assumptions about documents being created automatic…
Browse files Browse the repository at this point in the history
…ally vs reporting they don't exist
  • Loading branch information
heckj committed Jul 3, 2024
1 parent 5a3e5ae commit 503038e
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,13 @@ final class Repo_TwoClient_WebsocketIntegrationTests: XCTestCase {
// now establish a new connection, representing a second peer, looking for the data
let (repoB, websocketB) = try await newConnectedRepoWithStorageAdapter()

// await repoB.setLogLevel(.repo, to: .tracing)
// await repoB.setLogLevel(.storage, to: .tracing)
// await repoB.setLogLevel(.storage, to: .tracing)
// await repoB.setLogLevel(.resolver, to: .tracing)

let handle = try await repoB.find(id: documentIdForTest)

let historyFromFoundDoc = handle.doc.getHistory()
XCTAssertEqual(historyFromCreatedDoc, historyFromFoundDoc)

Expand Down Expand Up @@ -210,8 +216,14 @@ final class Repo_TwoClient_WebsocketIntegrationTests: XCTestCase {
expectation(
description: "Document handle from repo 'B' receives a change when the document handle from Repo 'A' is updated"
)

// little hack to make this a single notification, the API complains if you call it twice...
var fulfilled = false
let a = handle.doc.objectWillChange.receive(on: DispatchQueue.main).sink { _ in
documentChangePublisherExpectation.fulfill()
if fulfilled != true {
documentChangePublisherExpectation.fulfill()
fulfilled = true
}
}
XCTAssertNotNil(a)
// This is loosely the equivalent of the code provided in the issue, but without the prepend
Expand Down
18 changes: 18 additions & 0 deletions Sources/AutomergeRepo/Repo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -629,9 +629,11 @@ public final class Repo {
let handle: InternalDocHandle
if let knownHandle = handles[id] {
handle = knownHandle
// make handle as local to indicate it is already known in memory and wasn't created externally
handle.remote = false
docHandlePublisher.send(handle.snapshot())
} else {
// mark handle as remote to indicate we don't have this locally
let newHandle = InternalDocHandle(id: id, isNew: false)
handles[id] = newHandle
docHandlePublisher.send(newHandle.snapshot())
Expand Down Expand Up @@ -845,6 +847,9 @@ public final class Repo {
case .loading:
// Do we have the document
if let docFromHandle = handle.doc {
if loglevel.canTrace() {
Logger.resolver.trace("RESOLVE: :: \(id) has a document in memory")
}
// We have the document - so being in loading means "try to save this to
// a storage provider, if one exists", then hand it back as good.
if let storage {
Expand All @@ -866,7 +871,13 @@ public final class Repo {
// TODO: if we're allowed and prolific in gossip, notify any connected
// peers there's a new document before jumping to the 'ready' state
handle.state = .ready
if loglevel.canTrace() {
Logger.resolver.trace("RESOLVE: :: \(id) -> [\(String(describing: handle.state))]")
}
docHandlePublisher.send(handle.snapshot())
if loglevel.canTrace() {
Logger.resolver.trace("RESOLVE: :: continuing to resolve")
}
return try await resolveDocHandle(id: id)
} else {
// We don't have the underlying Automerge document, so attempt
Expand All @@ -876,6 +887,13 @@ public final class Repo {
if let doc = try await loadFromStorage(id: id) {
handle.doc = doc
handle.state = .ready
if loglevel.canTrace() {
Logger.resolver.trace("RESOLVE: :: loaded \(id) from storage provider")
Logger.resolver.trace("RESOLVE: :: \(id) -> [\(String(describing: handle.state))]")
}
if loglevel.canTrace() {
Logger.resolver.trace("RESOLVE: :: continuing to resolve")
}
docHandlePublisher.send(handle.snapshot())
return try await resolveDocHandle(id: id)
} else {
Expand Down
11 changes: 8 additions & 3 deletions Sources/AutomergeRepo/Storage/DocumentStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ final class DocumentStorage {
try await _storage.remove(id: id)
}

/// Returns an existing, or creates a new, document for the document Id you provide.
/// Returns an existing document, or nil, for the document Id you provide.
///
/// The method throws errors from the underlying storage system or Document errors if the
/// loaded data was corrupt or incorrect.
///
/// - Parameter id: The document Id
/// - Returns: An automerge document.
public func loadDoc(id: DocumentId) async throws -> Document {
/// - Returns: An automerge document or nil if the storage provider doesn't have a record of the document Id.
public func loadDoc(id: DocumentId) async throws -> Document? {
var combined: Data
let storageChunks = try await _storage.loadRange(id: id, prefix: chunkNamespace)
if chunks[id] == nil {
Expand All @@ -72,6 +72,11 @@ final class DocumentStorage {
combined = baseData
storedDocSize[id] = baseData.count
} else {
// no full document is available to be loaded by id, so if there were no storage chunks available
// either, return nil to indicate we don't know about this document
if storageChunks.isEmpty {
return nil
}
// loading only incremental saves available, the base document doesn't exist in storage
combined = Data()
storedDocSize[id] = 0
Expand Down

0 comments on commit 503038e

Please sign in to comment.