#
Troubleshooting Coding and Queries
This guide covers common issues and performance tips when working with custom code and queries in Curiosity Workspace.
#
Deadlocking
Deadlocks occur when two concurrent operations wait for each other to release a lock, causing both to freeze.
#
Common Causes
- Inconsistent Locking Order:
- Thread A locks Node 1, then tries to lock Node 2.
- Thread B locks Node 2, then tries to lock Node 1.
- Long-held Locks: Holding a lock while performing long network requests or heavy computation increases the window for conflicts.
#
Solutions
Consistent Ordering: If you need to lock multiple nodes, always sort them by their UID before acquiring locks.
// CORRECT: Consistent order prevents deadlocks var uidsToLock = new[] { uidA, uidB }.OrderBy(u => u).ToList(); // Lock in this order// WRONG: Locking in arbitrary order await Graph.GetOrAddLockedAsync(uidA); // ... some work ... await Graph.GetOrAddLockedAsync(uidB); // Risk of deadlock if another thread locked B then ALock Late, Commit Early: Acquire locks immediately before you need to modify data, and call
CommitAsyncas soon as the modification is done.Avoid Expensive Operations Inside Locks: Do not perform network requests or heavy calculations while holding a lock.
// WRONG var node = await Graph.GetOrAddLockedAsync(uid); var data = await CallSlowExternalApi(); // Slow! Blocks other threads needing 'node' node.UpdateProperty("data", data); await Graph.CommitAsync(node); // CORRECT var data = await CallSlowExternalApi(); // Do slow work first var node = await Graph.GetOrAddLockedAsync(uid); // Lock briefly node.UpdateProperty("data", data); await Graph.CommitAsync(node);
#
Uncommitted Nodes
One of the most common errors is forgetting to commit a locked node.
var node = await Graph.GetOrAddLockedAsync(uid);
node.UpdateProperty("status", "processing");
// ... exception thrown here ...
// Commit is never reached! Node remains locked forever (until restart).
await Graph.CommitAsync(node);
Fix: Use try/finally or ensure code paths are safe. If an endpoint finishes and a node is still locked, the system will eventually detect it, abandon the changes, and throw an exception to warn you, but this causes instability.
#
Performance Optimization
Curiosity's GraphDB is an in-memory graph database, but understanding its performance characteristics is crucial for writing efficient code.
#
Edge Traversal is Fast
Relationships are stored as direct memory pointers. Operations like Out(), IsRelatedTo(), and SortByConnectivity() are extremely fast because they traverse these pointers without deserializing data.
#
Property Access can be Slower
Reading a property value (e.g., node.GetString("name")) involves deserializing the node's content blob. While fast, doing this for millions of nodes in a loop is significantly slower than edge traversal.
Implication:
- Avoid
Where(n => n.GetString("status") == "Active")if possible. This forces the engine to load and deserialize every node to check the property. - Instead, use
WhereString("status", "Active"). This uses internal indexes to filter UIDs before loading the content.
#
Indexing
- Exact Match: Use
StartWhereStringorWhereStringto leverage hash indexes for exact value lookups. - Full Text: Use
StartSearchfor fuzzy matching or relevance-based search. This uses the inverted index.
#
Large Result Sets
If a query returns thousands of nodes:
- Don't use
ToList()immediately if you don't need all data in memory. - Do use
AsEnumerableAsync()to stream results. - Do use
Take()andSkip()for pagination.