Skip to content

Commit ae7ad39

Browse files
committed
some document store refactoring
No more log entry per opened document.
1 parent 61cb222 commit ae7ad39

File tree

2 files changed

+83
-115
lines changed

2 files changed

+83
-115
lines changed

src/DocumentStore.zig

Lines changed: 80 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ pub const Handle = struct {
259259
done,
260260
};
261261

262-
/// takes ownership of `uri` and `text`
262+
/// Takes ownership of `text` on success.
263263
fn init(
264264
allocator: std.mem.Allocator,
265265
uri: Uri,
@@ -680,11 +680,6 @@ pub fn getOrLoadHandle(store: *DocumentStore, uri: Uri) ?*Handle {
680680

681681
const file_contents = store.readUri(uri) orelse return null;
682682
return store.createAndStoreDocument(uri, file_contents, false) catch |err| {
683-
store.lock.lock();
684-
defer store.lock.unlock();
685-
686-
_ = store.currently_loading_uris.swapRemove(uri);
687-
688683
log.err("failed to store document '{s}': {}", .{ uri, err });
689684
return null;
690685
};
@@ -1345,99 +1340,81 @@ fn uriInImports(
13451340
/// invalidates any pointers into `DocumentStore.build_files`
13461341
/// takes ownership of the `text` passed in.
13471342
/// **Thread safe** takes an exclusive lock
1348-
fn createDocument(self: *DocumentStore, uri: Uri, text: [:0]const u8, lsp_synced: bool) error{OutOfMemory}!Handle {
1349-
const tracy_zone = tracy.trace(@src());
1350-
defer tracy_zone.end();
1351-
1352-
const duped_uri = try self.allocator.dupe(u8, uri);
1353-
errdefer self.allocator.free(duped_uri);
1354-
1355-
var handle: Handle = try .init(self.allocator, duped_uri, text, lsp_synced);
1356-
errdefer handle.deinit();
1357-
1358-
if (!supports_build_system) {
1359-
// nothing to do
1360-
} else if (isBuildFile(handle.uri) and !isInStd(handle.uri)) {
1361-
_ = self.getOrLoadBuildFile(handle.uri);
1362-
} else if (!isBuiltinFile(handle.uri) and !isInStd(handle.uri)) blk: {
1363-
const potential_build_files = self.collectPotentialBuildFiles(uri) catch {
1364-
log.err("failed to collect potential build files of '{s}'", .{handle.uri});
1365-
break :blk;
1366-
};
1367-
errdefer self.allocator.free(potential_build_files);
1368-
1369-
var has_been_checked: std.DynamicBitSetUnmanaged = try .initEmpty(self.allocator, potential_build_files.len);
1370-
errdefer has_been_checked.deinit(self.allocator);
1371-
1372-
handle.impl.associated_build_file = .{ .unresolved = .{
1373-
.has_been_checked = has_been_checked,
1374-
.potential_build_files = potential_build_files,
1375-
} };
1376-
}
1377-
1378-
return handle;
1379-
}
1380-
1381-
/// takes ownership of the `text` passed in.
1382-
/// invalidates any pointers into `DocumentStore.build_files`
1383-
/// **Thread safe** takes an exclusive lock
13841343
fn createAndStoreDocument(
13851344
self: *DocumentStore,
13861345
uri: Uri,
13871346
text: [:0]const u8,
13881347
lsp_synced: bool,
13891348
) error{OutOfMemory}!*Handle {
1390-
// TODO: Move pointer creation out.
1391-
const handle = handle: {
1392-
errdefer self.allocator.free(text);
1349+
const tracy_zone = tracy.trace(@src());
1350+
defer tracy_zone.end();
13931351

1394-
const handle: *Handle = try self.allocator.create(Handle);
1395-
errdefer self.allocator.destroy(handle);
1352+
const gop = gop: {
1353+
var new_handle: Handle = try .init(self.allocator, uri, text, lsp_synced);
13961354

1397-
handle.* = try self.createDocument(uri, text, lsp_synced);
1398-
break :handle handle;
1399-
};
1400-
errdefer {
1401-
self.allocator.free(handle.uri);
1402-
handle.deinit();
1403-
self.allocator.destroy(handle);
1404-
}
1405-
1406-
// TODO: Maybe split this out?
1407-
const old_handle_optional = blk: {
14081355
self.lock.lock();
14091356
defer self.lock.unlock();
14101357

1411-
const gop = try self.handles.getOrPut(self.allocator, handle.uri);
1412-
const old_handle_optional = if (gop.found_existing) old_handle_optional: {
1413-
gop.key_ptr.* = handle.uri;
1414-
break :old_handle_optional gop.value_ptr.*;
1415-
} else null;
1416-
gop.value_ptr.* = handle;
1358+
errdefer self.allocator.free(text);
1359+
1360+
const gop = try self.handles.getOrPut(self.allocator, uri);
1361+
errdefer if (!gop.found_existing) std.debug.assert(self.handles.swapRemove(uri));
1362+
1363+
if (gop.found_existing) {
1364+
new_handle.uri = gop.key_ptr.*;
1365+
new_handle.impl.associated_build_file = gop.value_ptr.*.impl.associated_build_file;
1366+
gop.value_ptr.*.impl.associated_build_file = .none;
1367+
1368+
gop.value_ptr.*.deinit();
1369+
gop.value_ptr.*.* = new_handle;
1370+
} else {
1371+
gop.value_ptr.* = try self.allocator.create(Handle);
1372+
errdefer self.allocator.destroy(gop.value_ptr.*);
1373+
1374+
gop.key_ptr.* = try self.allocator.dupe(u8, uri);
1375+
errdefer self.allocator.free(gop.key_ptr.*);
1376+
1377+
new_handle.uri = gop.key_ptr.*;
1378+
gop.value_ptr.*.* = new_handle;
1379+
// The `associated_build_file` field is not yet set.
1380+
}
1381+
errdefer comptime unreachable; // would double free `text` on error
14171382

14181383
if (self.currently_loading_uris.swapRemove(uri)) {
14191384
self.wait_for_currently_loading_uri.broadcast();
14201385
}
14211386

1422-
break :blk old_handle_optional;
1387+
break :gop gop;
14231388
};
1389+
const handle = gop.value_ptr.*;
14241390

1425-
if (old_handle_optional) |old_handle| {
1426-
self.allocator.free(old_handle.uri);
1427-
old_handle.deinit();
1428-
self.allocator.destroy(old_handle);
1429-
}
1391+
if (gop.found_existing or !supports_build_system or isInStd(uri)) {
1392+
// nothing to do
1393+
} else if (isBuildFile(uri)) {
1394+
_ = self.getOrLoadBuildFile(uri);
1395+
} else blk: {
1396+
const potential_build_files = self.collectPotentialBuildFiles(uri) catch {
1397+
log.err("failed to collect potential build files of '{s}'", .{handle.uri});
1398+
break :blk;
1399+
};
1400+
errdefer self.allocator.free(potential_build_files);
14301401

1431-
if (isBuildFile(handle.uri)) {
1432-
log.debug("Opened document '{s}' (build file)", .{handle.uri});
1433-
} else {
1434-
log.debug("Opened document '{s}'", .{handle.uri});
1402+
var has_been_checked: std.DynamicBitSetUnmanaged = try .initEmpty(self.allocator, potential_build_files.len);
1403+
errdefer has_been_checked.deinit(self.allocator);
1404+
1405+
handle.impl.lock.lock();
1406+
defer handle.impl.lock.unlock();
1407+
1408+
handle.impl.associated_build_file = .{ .unresolved = .{
1409+
.has_been_checked = has_been_checked,
1410+
.potential_build_files = potential_build_files,
1411+
} };
14351412
}
14361413

14371414
return handle;
14381415
}
14391416

1440-
pub fn loadDirectoryRecursive(store: *DocumentStore, directory_uri: Uri) !void {
1417+
pub fn loadDirectoryRecursive(store: *DocumentStore, directory_uri: Uri) !usize {
14411418
const workspace_path = try URI.parse(store.allocator, directory_uri);
14421419
defer store.allocator.free(workspace_path);
14431420

@@ -1447,50 +1424,33 @@ pub fn loadDirectoryRecursive(store: *DocumentStore, directory_uri: Uri) !void {
14471424
var walker = try workspace_dir.walk(store.allocator);
14481425
defer walker.deinit();
14491426

1450-
var uris: std.ArrayListUnmanaged([]const u8) = .empty;
1451-
defer uris.deinit(store.allocator);
1427+
var not_currently_loading_uris: std.ArrayListUnmanaged(Uri) = .empty;
1428+
defer {
1429+
for (not_currently_loading_uris.items) |uri| store.allocator.free(uri);
1430+
not_currently_loading_uris.deinit(store.allocator);
1431+
}
1432+
1433+
var file_count: usize = 0;
14521434

14531435
{
1454-
errdefer {
1455-
for (uris.items) |uri| {
1456-
store.allocator.free(uri);
1457-
}
1458-
}
1459-
14601436
while (try walker.next()) |entry| {
14611437
if (std.mem.indexOf(u8, entry.path, std.fs.path.sep_str ++ ".zig-cache" ++ std.fs.path.sep_str) != null) continue;
14621438
if (std.mem.startsWith(u8, entry.path, ".zig-cache" ++ std.fs.path.sep_str)) continue;
14631439
if (!std.mem.eql(u8, std.fs.path.extension(entry.basename), ".zig")) continue;
14641440

1465-
const uri = try std.fs.path.join(store.allocator, &.{ workspace_path, entry.path });
1466-
defer store.allocator.free(uri);
1441+
file_count += 1;
14671442

1468-
_ = try uris.append(store.allocator, try URI.fromPath(store.allocator, uri));
1469-
}
1470-
}
1443+
const path = try std.fs.path.join(store.allocator, &.{ workspace_path, entry.path });
1444+
defer store.allocator.free(path);
14711445

1472-
try store.loadManyUrisAtOnce(uris.items);
1473-
}
1446+
try not_currently_loading_uris.ensureUnusedCapacity(store.allocator, 1);
14741447

1475-
/// **Thread safe**
1476-
/// Takes ownership of uris
1477-
fn loadManyUrisAtOnce(store: *DocumentStore, uris: []const Uri) !void {
1478-
var not_currently_loading_uris: std.ArrayListUnmanaged(Uri) =
1479-
try .initCapacity(store.allocator, uris.len);
1480-
defer {
1481-
not_currently_loading_uris.deinit(store.allocator);
1482-
}
1483-
errdefer {
1484-
for (not_currently_loading_uris.items) |duped_import_uri| {
1485-
store.allocator.free(duped_import_uri);
1486-
}
1487-
}
1448+
const uri = try URI.fromPath(store.allocator, path);
1449+
errdefer comptime unreachable;
14881450

1489-
{
1490-
store.lock.lockShared();
1491-
defer store.lock.unlockShared();
1451+
store.lock.lockShared();
1452+
defer store.lock.unlockShared();
14921453

1493-
for (uris) |uri| {
14941454
if (!store.handles.contains(uri) and
14951455
!store.currently_loading_uris.contains(uri))
14961456
{
@@ -1504,16 +1464,23 @@ fn loadManyUrisAtOnce(store: *DocumentStore, uris: []const Uri) !void {
15041464
const S = struct {
15051465
fn getOrLoadHandleVoid(s: *DocumentStore, uri: Uri) void {
15061466
_ = s.getOrLoadHandle(uri);
1507-
defer s.allocator.free(uri);
1467+
s.allocator.free(uri);
15081468
}
15091469
};
15101470

1511-
for (not_currently_loading_uris.items) |uri| {
1512-
store.thread_pool.spawn(S.getOrLoadHandleVoid, .{ store, uri }) catch {
1513-
defer store.allocator.free(uri);
1514-
_ = store.getOrLoadHandle(uri);
1515-
};
1471+
if (builtin.single_threaded) {
1472+
while (not_currently_loading_uris.pop()) |uri| {
1473+
S.getOrLoadHandleVoid(store, uri);
1474+
}
1475+
} else {
1476+
var wait_group: std.Thread.WaitGroup = .{};
1477+
while (not_currently_loading_uris.pop()) |uri| {
1478+
store.thread_pool.spawnWg(&wait_group, S.getOrLoadHandleVoid, .{ store, uri });
1479+
}
1480+
store.thread_pool.waitAndWork(&wait_group);
15161481
}
1482+
1483+
return file_count;
15171484
}
15181485

15191486
pub const CImportHandle = struct {

src/Server.zig

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,6 @@ const Workspace = struct {
890890
fn addWorkspace(server: *Server, uri: types.URI) error{OutOfMemory}!void {
891891
try server.workspaces.ensureUnusedCapacity(server.allocator, 1);
892892
server.workspaces.appendAssumeCapacity(try Workspace.init(server, uri));
893-
log.info("added Workspace Folder: {s}", .{uri});
894893

895894
if (BuildOnSaveSupport.isSupportedComptime() and
896895
// Don't initialize build on save until initialization finished.
@@ -904,13 +903,15 @@ fn addWorkspace(server: *Server, uri: types.URI) error{OutOfMemory}!void {
904903
});
905904
}
906905

907-
server.document_store.loadDirectoryRecursive(uri) catch |err| switch (err) {
906+
const file_count = server.document_store.loadDirectoryRecursive(uri) catch |err| switch (err) {
908907
error.UnsupportedScheme => return,
909908
else => {
910909
log.err("failed to load files in workspace '{s}': {}", .{ uri, err });
911910
return;
912911
},
913912
};
913+
914+
log.info("added Workspace Folder: {s} ({d} files)", .{ uri, file_count });
914915
}
915916

916917
fn removeWorkspace(server: *Server, uri: types.URI) void {

0 commit comments

Comments
 (0)