@@ -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
13841343fn 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
15191486pub const CImportHandle = struct {
0 commit comments