Skip to content

Commit 5db3801

Browse files
committed
Use createAndStoreDocument more often
1 parent 7e20e38 commit 5db3801

File tree

2 files changed

+72
-75
lines changed

2 files changed

+72
-75
lines changed

src/DocumentStore.zig

Lines changed: 68 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ pub const Handle = struct {
234234
/// `true` if the document has been directly opened by the client i.e. with `textDocument/didOpen`
235235
/// `false` indicates the document only exists because it is a dependency of another document
236236
/// or has been closed with `textDocument/didClose` and is awaiting cleanup through `garbageCollection`
237-
open: bool = false,
237+
lsp_synced: bool = false,
238238
/// true if a thread has acquired the permission to compute the `DocumentScope`
239239
/// all other threads will wait until the given thread has computed the `DocumentScope` before reading it.
240240
has_document_scope_lock: bool = false,
@@ -520,16 +520,16 @@ pub const Handle = struct {
520520
return @bitCast(self.impl.status.load(.acquire));
521521
}
522522

523-
pub fn isOpen(self: *const Handle) bool {
524-
return self.getStatus().open;
523+
pub fn isLspSynced(self: *const Handle) bool {
524+
return self.getStatus().lsp_synced;
525525
}
526526

527527
/// returns the previous value
528-
fn setOpen(self: *Handle, open: bool) bool {
529-
if (open) {
530-
return self.impl.status.bitSet(@offsetOf(Handle.Status, "open"), .release) == 1;
528+
fn setLspSynced(self: *Handle, lsp_synced: bool) bool {
529+
if (lsp_synced) {
530+
return self.impl.status.bitSet(@offsetOf(Handle.Status, "lsp_synced"), .release) == 1;
531531
} else {
532-
return self.impl.status.bitReset(@offsetOf(Handle.Status, "open"), .release) == 1;
532+
return self.impl.status.bitReset(@offsetOf(Handle.Status, "lsp_synced"), .release) == 1;
533533
}
534534
}
535535

@@ -558,7 +558,7 @@ pub const Handle = struct {
558558
defer tracy_zone.end();
559559

560560
const new_status: Handle.Status = .{
561-
.open = self.getStatus().open,
561+
.lsp_synced = self.isLspSynced(),
562562
};
563563

564564
const new_tree = try parseTree(self.impl.allocator, new_text, self.tree.mode);
@@ -759,7 +759,7 @@ pub fn getOrLoadHandle(store: *DocumentStore, uri: Uri) ?*Handle {
759759
}
760760

761761
const file_contents = store.readUri(uri) orelse return null;
762-
return store.createAndStoreDocument(uri, file_contents) catch |err| {
762+
return store.createAndStoreDocument(uri, file_contents, false) catch |err| {
763763
log.err("failed to store document '{s}': {}", .{ uri, err });
764764
return null;
765765
};
@@ -839,40 +839,17 @@ fn getOrLoadBuildFile(self: *DocumentStore, uri: Uri) ?*BuildFile {
839839

840840
/// **Not thread safe**
841841
/// Assumes that no other thread is currently accessing the given document
842-
pub fn openDocument(self: *DocumentStore, uri: Uri, text: []const u8) error{OutOfMemory}!void {
842+
pub fn openLspSyncedDocument(self: *DocumentStore, uri: Uri, text: []const u8) error{OutOfMemory}!void {
843843
const tracy_zone = tracy.trace(@src());
844844
defer tracy_zone.end();
845845

846-
const handle_ptr: *Handle = try self.allocator.create(Handle);
847-
errdefer self.allocator.destroy(handle_ptr);
848-
849846
const duped_text = try self.allocator.dupeZ(u8, text);
850-
handle_ptr.* = try self.createDocument(uri, duped_text, true);
851-
errdefer handle_ptr.deinit();
852-
853-
const gop = try self.handles.getOrPut(self.allocator, handle_ptr.uri);
854-
if (gop.found_existing) {
855-
if (gop.value_ptr.*.isOpen()) {
856-
log.warn("Document already open: {s}", .{uri});
857-
}
858-
std.mem.swap([]const u8, &gop.value_ptr.*.uri, &handle_ptr.uri);
859-
gop.value_ptr.*.deinit();
860-
self.allocator.destroy(gop.value_ptr.*);
861-
}
862-
gop.value_ptr.* = handle_ptr;
863-
864-
try self.loadDependencies(handle_ptr.import_uris.items);
865-
866-
if (isBuildFile(uri)) {
867-
log.debug("Opened document '{s}' (build file)", .{uri});
868-
} else {
869-
log.debug("Opened document '{s}'", .{uri});
870-
}
847+
_ = try self.createAndStoreDocument(uri, duped_text, true);
871848
}
872849

873850
/// **Thread safe** takes a shared lock, takes an exclusive lock (with `tryLock`)
874851
/// Assumes that no other thread is currently accessing the given document
875-
pub fn closeDocument(self: *DocumentStore, uri: Uri) void {
852+
pub fn closeLspSyncedDocument(self: *DocumentStore, uri: Uri) void {
876853
const tracy_zone = tracy.trace(@src());
877854
defer tracy_zone.end();
878855

@@ -886,7 +863,7 @@ pub fn closeDocument(self: *DocumentStore, uri: Uri) void {
886863
};
887864
// instead of destroying the handle here we just mark it not open
888865
// and let it be destroy by the garbage collection code
889-
if (!handle.setOpen(false)) {
866+
if (!handle.setLspSynced(false)) {
890867
log.warn("Document already closed: {s}", .{uri});
891868
}
892869
}
@@ -906,12 +883,12 @@ pub fn closeDocument(self: *DocumentStore, uri: Uri) void {
906883
///
907884
/// **Thread safe** takes a shared lock when called on different documents
908885
/// **Not thread safe** when called on the same document
909-
pub fn refreshDocument(self: *DocumentStore, uri: Uri, new_text: [:0]const u8) !void {
886+
pub fn refreshLspSyncedDocument(self: *DocumentStore, uri: Uri, new_text: [:0]const u8) !void {
910887
const tracy_zone = tracy.trace(@src());
911888
defer tracy_zone.end();
912889

913890
const handle = self.getHandle(uri).?;
914-
if (!handle.getStatus().open) {
891+
if (!handle.isLspSynced()) {
915892
log.warn("Document modified without being opened: {s}", .{uri});
916893
}
917894
try handle.setSource(new_text);
@@ -920,26 +897,20 @@ pub fn refreshDocument(self: *DocumentStore, uri: Uri, new_text: [:0]const u8) !
920897
try self.loadDependencies(handle.import_uris.items);
921898
}
922899

923-
/// Removes a document from the store, unless said document is currently open and
900+
/// Refreshes a document from the file system, unless said document is currently open and
924901
/// has been synchronized via `textDocument/didOpen`.
925902
/// **Thread safe** takes an exclusive lock when called on different documents
926903
/// **Not thread safe** when called on the same document
927904
pub fn refreshDocumentFromFileSystem(self: *DocumentStore, uri: Uri) !bool {
928-
{
929-
const handle = self.getHandle(uri) orelse return false;
930-
if (handle.getStatus().open) return false;
905+
if (self.getHandle(uri)) |handle| {
906+
if (handle.isLspSynced()) {
907+
return false;
908+
}
931909
}
932910

933-
{
934-
self.lock.lock();
935-
defer self.lock.unlock();
936-
937-
const kv = self.handles.fetchSwapRemove(uri) orelse return false;
938-
log.debug("Closing document {s}", .{kv.key});
939-
kv.value.deinit();
940-
self.allocator.destroy(kv.value);
941-
return true;
942-
}
911+
const file_contents = self.readUri(uri) orelse return false;
912+
_ = try self.createAndStoreDocument(uri, file_contents, false);
913+
return true;
943914
}
944915

945916
/// Invalidates a build files.
@@ -1122,7 +1093,7 @@ fn garbageCollectionImports(self: *DocumentStore) error{OutOfMemory}!void {
11221093
var queue: std.ArrayListUnmanaged(Uri) = .empty;
11231094

11241095
for (self.handles.values(), 0..) |handle, handle_index| {
1125-
if (!handle.getStatus().open) continue;
1096+
if (!handle.getStatus().lsp_synced) continue;
11261097
reachable.set(handle_index);
11271098

11281099
try self.collectDependenciesInternal(arena.allocator(), handle, &queue, false);
@@ -1536,14 +1507,14 @@ fn uriInImports(
15361507
/// invalidates any pointers into `DocumentStore.build_files`
15371508
/// takes ownership of the `text` passed in.
15381509
/// **Thread safe** takes an exclusive lock
1539-
fn createDocument(self: *DocumentStore, uri: Uri, text: [:0]const u8, open: bool) error{OutOfMemory}!Handle {
1510+
fn createDocument(self: *DocumentStore, uri: Uri, text: [:0]const u8, lsp_synced: bool) error{OutOfMemory}!Handle {
15401511
const tracy_zone = tracy.trace(@src());
15411512
defer tracy_zone.end();
15421513

15431514
var handle: Handle = try .init(self.allocator, uri, text);
15441515
errdefer handle.deinit();
15451516

1546-
_ = handle.setOpen(open);
1517+
_ = handle.setLspSynced(lsp_synced);
15471518

15481519
if (!supports_build_system) {
15491520
// nothing to do
@@ -1574,35 +1545,61 @@ fn createDocument(self: *DocumentStore, uri: Uri, text: [:0]const u8, open: bool
15741545
/// takes ownership of the `text` passed in.
15751546
/// invalidates any pointers into `DocumentStore.build_files`
15761547
/// **Thread safe** takes an exclusive lock
1577-
fn createAndStoreDocument(self: *DocumentStore, uri: Uri, text: [:0]const u8) error{OutOfMemory}!*Handle {
1578-
const handle_ptr: *Handle = try self.allocator.create(Handle);
1579-
errdefer self.allocator.destroy(handle_ptr);
1548+
fn createAndStoreDocument(
1549+
self: *DocumentStore,
1550+
uri: Uri,
1551+
text: [:0]const u8,
1552+
lsp_synced: bool,
1553+
) error{OutOfMemory}!*Handle {
1554+
const handle = handle: {
1555+
errdefer self.allocator.free(text);
15801556

1581-
handle_ptr.* = try self.createDocument(uri, text, false);
1582-
errdefer handle_ptr.deinit();
1557+
const handle: *Handle = try self.allocator.create(Handle);
1558+
errdefer self.allocator.destroy(handle);
15831559

1584-
const gop = blk: {
1560+
handle.* = try self.createDocument(uri, text, lsp_synced);
1561+
break :handle handle;
1562+
};
1563+
errdefer {
1564+
handle.deinit();
1565+
self.allocator.destroy(handle);
1566+
}
1567+
1568+
const old_handle_optional = blk: {
15851569
self.lock.lock();
15861570
defer self.lock.unlock();
15871571

1588-
const gop = try self.handles.getOrPutValue(self.allocator, handle_ptr.uri, handle_ptr);
1589-
std.debug.assert(!gop.found_existing);
1572+
const gop = try self.handles.getOrPut(self.allocator, handle.uri);
1573+
const old_handle_optional = if (gop.found_existing) old_handle_optional: {
1574+
gop.key_ptr.* = handle.uri;
1575+
break :old_handle_optional gop.value_ptr.*;
1576+
} else null;
1577+
gop.value_ptr.* = handle;
15901578

1591-
std.debug.assert(self.currently_loading_uris.swapRemove(uri));
1592-
self.wait_for_currently_loading_uri.broadcast();
1579+
if (self.currently_loading_uris.swapRemove(uri)) {
1580+
self.wait_for_currently_loading_uri.broadcast();
1581+
}
15931582

1594-
break :blk gop;
1583+
break :blk old_handle_optional;
15951584
};
15961585

1597-
try self.loadDependencies(handle_ptr.import_uris.items);
1586+
if (old_handle_optional) |old_handle| {
1587+
if (old_handle.isLspSynced()) {
1588+
log.warn("Document already open: {s}", .{uri});
1589+
}
1590+
old_handle.deinit();
1591+
self.allocator.destroy(old_handle);
1592+
}
1593+
1594+
try self.loadDependencies(handle.import_uris.items);
15981595

1599-
if (isBuildFile(gop.value_ptr.*.uri)) {
1600-
log.debug("Opened document '{s}' (build file)", .{gop.value_ptr.*.uri});
1596+
if (isBuildFile(handle.uri)) {
1597+
log.debug("Opened document '{s}' (build file)", .{handle.uri});
16011598
} else {
1602-
log.debug("Opened document '{s}'", .{gop.value_ptr.*.uri});
1599+
log.debug("Opened document '{s}'", .{handle.uri});
16031600
}
16041601

1605-
return gop.value_ptr.*;
1602+
return handle;
16061603
}
16071604

16081605
fn loadDependencies(store: *DocumentStore, import_uris: []const []const u8) !void {

src/Server.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ pub fn updateConfiguration(
10941094
if (server.status == .initialized) {
10951095
if (new_zig_exe_path and server.client_capabilities.supports_publish_diagnostics) {
10961096
for (server.document_store.handles.values()) |handle| {
1097-
if (!handle.isOpen()) continue;
1097+
if (!handle.isLspSynced()) continue;
10981098
try server.pushJob(.{ .generate_diagnostics = try server.allocator.dupe(u8, handle.uri) });
10991099
}
11001100
}
@@ -1546,7 +1546,7 @@ fn openDocumentHandler(server: *Server, _: std.mem.Allocator, notification: type
15461546
return error.InternalError;
15471547
}
15481548

1549-
try server.document_store.openDocument(notification.textDocument.uri, notification.textDocument.text);
1549+
try server.document_store.openLspSyncedDocument(notification.textDocument.uri, notification.textDocument.text);
15501550

15511551
if (server.client_capabilities.supports_publish_diagnostics) {
15521552
try server.pushJob(.{
@@ -1569,7 +1569,7 @@ fn changeDocumentHandler(server: *Server, _: std.mem.Allocator, notification: ty
15691569
return error.InternalError;
15701570
}
15711571

1572-
try server.document_store.refreshDocument(handle.uri, new_text);
1572+
try server.document_store.refreshLspSyncedDocument(handle.uri, new_text);
15731573

15741574
if (server.client_capabilities.supports_publish_diagnostics) {
15751575
try server.pushJob(.{
@@ -1611,7 +1611,7 @@ fn saveDocumentHandler(server: *Server, arena: std.mem.Allocator, notification:
16111611
}
16121612

16131613
fn closeDocumentHandler(server: *Server, _: std.mem.Allocator, notification: types.DidCloseTextDocumentParams) error{}!void {
1614-
server.document_store.closeDocument(notification.textDocument.uri);
1614+
server.document_store.closeLspSyncedDocument(notification.textDocument.uri);
16151615

16161616
if (server.client_capabilities.supports_publish_diagnostics) {
16171617
// clear diagnostics on closed file

0 commit comments

Comments
 (0)