Skip to content

Commit e8b1286

Browse files
authored
More DFGv1 cleanups and checks and Blobstore updates (#1159)
* _version -> VersionNumber
1 parent 8ae0b9b commit e8b1286

21 files changed

+350
-349
lines changed

src/DataBlobs/entities/BlobEntry.jl

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,10 @@ Base.@kwdef struct Blobentry
4141
createdTimestamp::Union{ZonedDateTime, Nothing} = nothing
4242
""" Use carefully, but necessary to support advanced usage such as time synchronization over Blob data. """
4343
lastUpdatedTimestamp::Union{ZonedDateTime, Nothing} = nothing
44-
""" Type version of this Blobentry. TBD.jl consider upgrading to `::VersionNumber`. """
45-
_version::String = string(_getDFGVersion())
44+
""" Type version of this Blobentry."""
45+
_version::VersionNumber = _getDFGVersion()
4646
end
4747

4848
StructTypes.StructType(::Type{Blobentry}) = StructTypes.UnorderedStruct()
4949
StructTypes.idproperty(::Type{Blobentry}) = :id
5050
StructTypes.omitempties(::Type{Blobentry}) = (:id,)
51-
52-
_fixtimezone(cts::NamedTuple) = ZonedDateTime(cts.utc_datetime * "+00")

src/DataBlobs/entities/BlobStores.jl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,31 @@
1+
"""
2+
AbstractBlobstore{T}
3+
4+
Abstract supertype for all blobstore implementations.
5+
6+
# Usage
7+
8+
Subtypes of `AbstractBlobstore{T}` must implement the required interface for blob storage and retrieval, such as:
9+
10+
- `add!(store, blobId, blob)`: Add a new blob to the store.
11+
- `get(store, blobId)`: Retrieve a blob by its ID.
12+
- `list(store)`: List all blob IDs in the store.
13+
14+
The parameter `T` represents the type of blobs stored (e.g., `Vector{UInt8}` or a custom `Blob` type).
15+
16+
See concrete implementations for details.
17+
18+
Design Notes
19+
- `blobId` is not considered unique across blobstores with different labels only within a single blobstore.
20+
- We cannot guarantee that `blobId` is unique across different blobstores with the same label and this is up to the end user.
21+
- Within a single blobstore `addBlob!` will fail if there is a UUID collision.
22+
- TODO: We should consider using uuid7 for `blobId`s (requires jl v1.12).
23+
- `Blobstrores`are identified by a `label::Symbol`, which allows for multiple blobstores to coexist in the same system.
24+
25+
TODO: If we want to make the `blobId`=>Blob pair immutable:
26+
- We can use the tombstone pattern to mark a blob as deleted. See FolderStore in PR#TODO.
27+
28+
Design goal: all `Blobstore`s with the same `label` can contain the same `blobId`=>`Blob` pair and the blobs should be identical since they are immutable.
29+
30+
"""
131
abstract type AbstractBlobstore{T} end

src/DataBlobs/services/BlobEntry.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ function addBlobentry!(var::VariableDFG, entry::Blobentry)
168168
return entry
169169
end
170170

171-
function addBlobentry!(dfg::AbstractDFG, vLbl::Symbol, entry::Blobentry;)
171+
function addBlobentry!(dfg::AbstractDFG, vLbl::Symbol, entry::Blobentry)
172172
return addBlobentry!(getVariable(dfg, vLbl), entry)
173173
end
174174

@@ -238,7 +238,7 @@ end
238238
"""
239239
$SIGNATURES
240240
241-
Does a blob entry (element) exist with `blobLabel`.
241+
Does a blob entry exist with `blobLabel`.
242242
"""
243243
hasBlobentry(var::AbstractDFGVariable, blobLabel::Symbol) = haskey(var.dataDict, blobLabel)
244244

src/DataBlobs/services/BlobStores.jl

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ $(METHODLIST)
1313
function getBlob end
1414

1515
"""
16-
Adds a blob to the blob store or dfg with the given entry.
16+
Adds a blob to the blob store or dfg with the blobId.
1717
1818
Related
1919
[`addBlobentry!`](@ref)
@@ -81,34 +81,11 @@ end
8181
##==============================================================================
8282
## AbstractBlobstore derived CRUD for Blob
8383
##==============================================================================
84-
#TODO looking in all the blobstores does not make sense since since there is a chance that the blobId is not unique across blobstores.
85-
# using the cached blobstore is the right way to go here.
84+
#TODO maybe we should generalize and move the cached blobstore to DFG.
8685
function getBlob(dfg::AbstractDFG, entry::Blobentry)
87-
stores = getBlobstores(dfg)
88-
storekeys = collect(keys(stores))
89-
# first check the saved blobstore and then fall back to the rest
90-
fidx = findfirst(==(entry.blobstore), storekeys)
91-
if !isnothing(fidx)
92-
skey = storekeys[fidx]
93-
popat!(storekeys, fidx)
94-
pushfirst!(storekeys, skey)
95-
end
96-
for k in storekeys
97-
store = stores[k]
98-
try
99-
blob = getBlob(store, entry)
100-
return blob
101-
catch err
102-
if !(err isa KeyError)
103-
throw(err)
104-
end
105-
end
106-
end
107-
throw(
108-
KeyError(
109-
"could not find $(entry.label), uuid $(entry.blobId) in any of the listed blobstores:\n $([s->getLabel(s) for (s,v) in stores]))",
110-
),
111-
)
86+
storeLabel = entry.blobstore
87+
store = getBlobstore(dfg, storeLabel)
88+
return getBlob(store, entry.blobId)
11289
end
11390

11491
function getBlob(store::AbstractBlobstore, entry::Blobentry)
@@ -204,19 +181,18 @@ function getBlob(store::FolderStore{T}, blobId::UUID) where {T}
204181
return read(f)
205182
end
206183
else
207-
throw(KeyError("Could not find file '$(blobfilename)'."))
184+
throw(IdNotFoundError("Blob", blobId))
208185
end
209186
end
210187

211188
function addBlob!(store::FolderStore{T}, blobId::UUID, data::T) where {T}
212189
blobfilename = joinpath(store.folder, string(store.label), string(blobId))
213190
if isfile(blobfilename)
214-
throw(KeyError("Key '$blobId' blob already exists."))
191+
throw(IdExistsError("Blob", blobId))
215192
else
216193
open(blobfilename, "w") do f
217194
return write(f, data)
218195
end
219-
# return data
220196
return blobId
221197
end
222198
end
@@ -235,11 +211,13 @@ end
235211

236212
function deleteBlob!(store::FolderStore{T}, blobId::UUID) where {T}
237213
blobfilename = joinpath(store.folder, string(store.label), string(blobId))
214+
if !isfile(blobfilename)
215+
throw(IdNotFoundError("Blob", blobId))
216+
end
238217
rm(blobfilename)
239218
return 1
240219
end
241220

242-
#hasBlob or existsBlob?
243221
function hasBlob(store::FolderStore, blobId::UUID)
244222
blobfilename = joinpath(store.folder, string(store.label), string(blobId))
245223
return isfile(blobfilename)
@@ -265,12 +243,15 @@ function InMemoryBlobstore(storeKey::Symbol = :default_inmemory_store)
265243
end
266244

267245
function getBlob(store::InMemoryBlobstore, blobId::UUID)
246+
if !haskey(store.blobs, blobId)
247+
throw(IdNotFoundError("Blob", blobId))
248+
end
268249
return store.blobs[blobId]
269250
end
270251

271252
function addBlob!(store::InMemoryBlobstore{T}, blobId::UUID, data::T) where {T}
272253
if haskey(store.blobs, blobId)
273-
error("Key '$blobId' blob already exists.")
254+
throw(IdExistsError("Blob", blobId))
274255
end
275256
store.blobs[blobId] = data
276257
return blobId
@@ -284,6 +265,9 @@ function updateBlob!(store::InMemoryBlobstore{T}, blobId::UUID, data::T) where {
284265
end
285266

286267
function deleteBlob!(store::InMemoryBlobstore, blobId::UUID)
268+
if !haskey(store.blobs, blobId)
269+
throw(IdNotFoundError("Blob", blobId))
270+
end
287271
pop!(store.blobs, blobId)
288272
return 1
289273
end
@@ -319,25 +303,28 @@ end
319303

320304
function getBlob(store::LinkStore, blobId::UUID)
321305
fname = get(store.cache, blobId, nothing)
306+
if isnothing(fname)
307+
throw(IdNotFoundError("Blob", blobId))
308+
end
322309
return read(fname)
323310
end
324311

325312
function addBlob!(store::LinkStore, entry::Blobentry, linkfile::String)
326-
return addBlob!(store, entry.blobId, nothing, linkfile::String)
313+
return addBlob!(store, entry.blobId, linkfile)
327314
end
328315

329-
function addBlob!(store::LinkStore, blobId::UUID, blob::Any, linkfile::String)
316+
function addBlob!(store::LinkStore, blobId::UUID, linkfile::String)
330317
if haskey(store.cache, blobId)
331-
error("blobId $blobId already exists in the store")
318+
throw(IdExistsError("Blob", blobId))
332319
end
333320
push!(store.cache, blobId => linkfile)
334321
open(store.csvfile, "a") do f
335322
return println(f, blobId, ",", linkfile)
336323
end
337-
return getBlob(store, blobId)
324+
return blobId
338325
end
339326

340-
function deleteBlob!(store::LinkStore, args...)
327+
function deleteBlob!(store::LinkStore)
341328
return error("deleteDataBlob(::LinkStore) not supported")
342329
end
343330

@@ -404,12 +391,15 @@ Tables.rows(store::RowBlobstore) = values(store.blobs)
404391

405392
##
406393
function getBlob(store::RowBlobstore, blobId::UUID)
394+
if !haskey(store.blobs, blobId)
395+
throw(IdNotFoundError("Blob", blobId))
396+
end
407397
return getfield(store.blobs[blobId], :blob)
408398
end
409399

410400
function addBlob!(store::RowBlobstore{T}, blobId::UUID, blob::T) where {T}
411401
if haskey(store.blobs, blobId)
412-
error("Key '$blobId' blob already exists.")
402+
throw(IdExistsError("Blob", blobId))
413403
end
414404
store.blobs[blobId] = RowBlob(blobId, blob)
415405
return blobId
@@ -423,7 +413,10 @@ function updateBlob!(store::RowBlobstore{T}, blobId::UUID, blob::T) where {T}
423413
end
424414

425415
function deleteBlob!(store::RowBlobstore, blobId::UUID)
426-
getfield(pop!(store.blobs, blobId), :blob)
416+
if !haskey(store.blobs, blobId)
417+
throw(IdNotFoundError("Blob", blobId))
418+
end
419+
pop!(store.blobs, blobId)
427420
return 1
428421
end
429422

@@ -469,3 +462,4 @@ if false
469462
Tables.rowtable(sstore)
470463
end
471464
##
465+
##

src/DataBlobs/services/HelpersDataWrapEntryBlob.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function Blobentry(
5757
timestamp::ZonedDateTime = entry.timestamp,
5858
createdTimestamp = entry.createdTimestamp,
5959
lastUpdatedTimestamp = entry.lastUpdatedTimestamp,
60-
_version::String = entry._version,
60+
_version = entry._version,
6161
)
6262
return Blobentry(;
6363
id,
@@ -267,7 +267,7 @@ function updateData!(
267267
blobstore = getLabel(blobstore),
268268
hash = string(bytes2hex(hashfunction(blob))),
269269
origin = buildSourceString(dfg, label),
270-
_version = string(_getDFGVersion()),
270+
_version = _getDFGVersion(),
271271
)
272272
mergeBlobentry!(dfg, label, newEntry)
273273
updateBlob!(blobstore, newEntry, blob)

src/Deprecated.jl

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ const InferenceType = AbstractPackedFactorObservation
2121
const PackedSamplableBelief = PackedBelief
2222

2323
export setSolverData!
24-
"""
25-
$SIGNATURES
26-
Set solver data structure stored in a variable.
27-
"""
24+
# """
25+
# $SIGNATURES
26+
# Set solver data structure stored in a variable.
27+
# """
2828
function setSolverData!(v::VariableCompute, data::VariableState, key::Symbol = :default)
2929
Base.depwarn(
3030
"setSolverData!(v::VariableCompute, data::VariableState, key::Symbol = :default) is deprecated, use mergeVariableState! instead.",
@@ -51,6 +51,104 @@ function mergeGraphVariableData!(args...)
5151
)
5252
end
5353

54+
#NOTE List types funcction do not fit verb noun and will be deprecated.
55+
# should return types
56+
57+
# """
58+
# $SIGNATURES
59+
60+
# Return `Vector{Symbol}` of all unique variable types in factor graph.
61+
# """
62+
function lsTypes(dfg::AbstractDFG)
63+
vars = getVariables(dfg)
64+
alltypes = Set{Symbol}()
65+
for v in vars
66+
varType = Symbol(typeof(getVariableType(v)))
67+
push!(alltypes, varType)
68+
end
69+
return collect(alltypes)
70+
end
71+
72+
# """
73+
# $SIGNATURES
74+
75+
# Return `::Dict{Symbol, Vector{Symbol}}` of all unique variable types with labels in a factor graph.
76+
# """
77+
function lsTypesDict(dfg::AbstractDFG)
78+
vars = getVariables(dfg)
79+
alltypes = Dict{Symbol, Vector{Symbol}}()
80+
for v in vars
81+
varType = Symbol(typeof(getVariableType(v)))
82+
d = get!(alltypes, varType, Symbol[])
83+
push!(d, v.label)
84+
end
85+
return alltypes
86+
end
87+
88+
# """
89+
# $SIGNATURES
90+
91+
# Return `Vector{Symbol}` of all unique factor types in factor graph.
92+
# """
93+
function lsfTypes(dfg::AbstractDFG)
94+
facs = getFactors(dfg)
95+
alltypes = Set{Symbol}()
96+
for f in facs
97+
facType = typeof(getFactorType(f)) |> nameof
98+
push!(alltypes, facType)
99+
end
100+
return collect(alltypes)
101+
end
102+
103+
# """
104+
# $SIGNATURES
105+
106+
# Return `::Dict{Symbol, Vector{Symbol}}` of all unique factors types with labels in a factor graph.
107+
# """
108+
function lsfTypesDict(dfg::AbstractDFG)
109+
facs = getFactors(dfg)
110+
alltypes = Dict{Symbol, Vector{Symbol}}()
111+
for f in facs
112+
facType = typeof(getFactorType(f)) |> nameof
113+
d = get!(alltypes, facType, Symbol[])
114+
push!(d, f.label)
115+
end
116+
return alltypes
117+
end
118+
119+
# solvekey is deprecated and sync!/copyto! is the better verb.
120+
#TODO replace with syncVariableStates! or similar
121+
# """
122+
# $SIGNATURES
123+
# Duplicate a `solveKey`` into a destination from a source.
124+
125+
# Notes
126+
# - Can copy between graphs, or to different solveKeys within one graph.
127+
# """
128+
function cloneSolveKey!(
129+
dest_dfg::AbstractDFG,
130+
dest::Symbol,
131+
src_dfg::AbstractDFG,
132+
src::Symbol;
133+
solvable::Int = 0,
134+
labels = intersect(ls(dest_dfg; solvable = solvable), ls(src_dfg; solvable = solvable)),
135+
verbose::Bool = false,
136+
)
137+
#
138+
for x in labels
139+
sd = deepcopy(getVariableState(getVariable(src_dfg, x), src))
140+
copytoVariableState!(dest_dfg, x, dest, sd)
141+
end
142+
143+
return nothing
144+
end
145+
146+
function cloneSolveKey!(dfg::AbstractDFG, dest::Symbol, src::Symbol; kw...)
147+
#
148+
@assert dest != src "Must copy to a different solveKey within the same graph, $dest."
149+
return cloneSolveKey!(dfg, dest, dfg, src; kw...)
150+
end
151+
54152
## ================================================================================
55153
## Deprecated in v0.27
56154
##=================================================================================

0 commit comments

Comments
 (0)