diff --git a/apps/language_server/lib/language_server/build.ex b/apps/language_server/lib/language_server/build.ex index 041fcae8e..3f2e1cb52 100644 --- a/apps/language_server/lib/language_server/build.ex +++ b/apps/language_server/lib/language_server/build.ex @@ -140,7 +140,6 @@ defmodule ElixirLS.LanguageServer.Build do end) if Keyword.get(opts, :compile?) do - Tracer.save() Logger.info("Compile took #{div(us, 1000)} milliseconds") else Logger.info("Mix project load took #{div(us, 1000)} milliseconds") diff --git a/apps/language_server/lib/language_server/providers/workspace_symbols.ex b/apps/language_server/lib/language_server/providers/workspace_symbols.ex index 78a0761e2..cecafa102 100644 --- a/apps/language_server/lib/language_server/providers/workspace_symbols.ex +++ b/apps/language_server/lib/language_server/providers/workspace_symbols.ex @@ -67,8 +67,8 @@ defmodule ElixirLS.LanguageServer.Providers.WorkspaceSymbols do GenServer.start_link(__MODULE__, :ok, opts |> Keyword.put_new(:name, __MODULE__)) end - def notify_settings_stored() do - GenServer.cast(__MODULE__, :notify_settings_stored) + def notify_settings_stored(project_dir) do + GenServer.cast(__MODULE__, {:notify_settings_stored, project_dir}) end def notify_build_complete(server \\ __MODULE__) do @@ -150,9 +150,7 @@ defmodule ElixirLS.LanguageServer.Providers.WorkspaceSymbols do end @impl GenServer - def handle_cast(:notify_settings_stored, state) do - project_dir = :persistent_term.get(:language_server_project_dir) - + def handle_cast({:notify_settings_stored, project_dir}, state) do # as of LSP 3.17 only one tag is defined and clients are required to silently ignore unknown tags # so there's no need to pass the list tag_support = diff --git a/apps/language_server/lib/language_server/server.ex b/apps/language_server/lib/language_server/server.ex index 58d751bd6..3dd567c47 100644 --- a/apps/language_server/lib/language_server/server.ex +++ b/apps/language_server/lib/language_server/server.ex @@ -1865,9 +1865,8 @@ defmodule ElixirLS.LanguageServer.Server do state = create_gitignore(state) if state.mix_project? do - :persistent_term.put(:language_server_project_dir, state.project_dir) - WorkspaceSymbols.notify_settings_stored() - Tracer.notify_settings_stored() + WorkspaceSymbols.notify_settings_stored(state.project_dir) + Tracer.notify_settings_stored(state.project_dir) end JsonRpc.telemetry( diff --git a/apps/language_server/lib/language_server/tracer.ex b/apps/language_server/lib/language_server/tracer.ex index dbc8602b4..89a2dabbc 100644 --- a/apps/language_server/lib/language_server/tracer.ex +++ b/apps/language_server/lib/language_server/tracer.ex @@ -20,12 +20,8 @@ defmodule ElixirLS.LanguageServer.Tracer do GenServer.start_link(__MODULE__, args, name: __MODULE__) end - def notify_settings_stored() do - GenServer.cast(__MODULE__, :notify_settings_stored) - end - - def save() do - GenServer.cast(__MODULE__, :save) + def notify_settings_stored(project_dir) do + GenServer.cast(__MODULE__, {:notify_settings_stored, project_dir}) end defp get_project_dir() do @@ -57,19 +53,7 @@ defmodule ElixirLS.LanguageServer.Tracer do ]) end - project_dir = :persistent_term.get(:language_server_project_dir, nil) - state = %{project_dir: project_dir} - - if project_dir != nil do - {us, _} = - :timer.tc(fn -> - for table <- @tables do - init_table(table, project_dir) - end - end) - - Logger.info("Loaded DETS databases in #{div(us, 1000)}ms") - end + state = %{project_dir: nil} {:ok, state} end @@ -80,26 +64,12 @@ defmodule ElixirLS.LanguageServer.Tracer do end @impl true - def handle_cast(:notify_settings_stored, state) do - project_dir = :persistent_term.get(:language_server_project_dir) - maybe_close_tables(state) - + def handle_cast({:notify_settings_stored, project_dir}, state) do for table <- @tables do table_name = table_name(table) :ets.delete_all_objects(table_name) end - if project_dir != nil do - {us, _} = - :timer.tc(fn -> - for table <- @tables do - init_table(table, project_dir) - end - end) - - Logger.info("Loaded DETS databases in #{div(us, 1000)}ms") - end - {:noreply, %{state | project_dir: project_dir}} end @@ -113,22 +83,8 @@ defmodule ElixirLS.LanguageServer.Tracer do {:noreply, state} end - def handle_cast(:save, %{project_dir: project_dir} = state) do - for table <- @tables do - table_name = table_name(table) - - sync(table_name) - end - - write_manifest(project_dir) - - {:noreply, state} - end - @impl true def terminate(reason, state) do - maybe_close_tables(state) - case reason do :normal -> :ok @@ -168,112 +124,6 @@ defmodule ElixirLS.LanguageServer.Tracer do end end - defp maybe_close_tables(%{project_dir: nil}), do: :ok - - defp maybe_close_tables(_state) do - for table <- @tables do - close_table(table) - end - - :ok - end - - defp dets_path(project_dir, table) do - Path.join([project_dir, ".elixir_ls", "#{table}.dets"]) - end - - def init_table(table, project_dir) do - table_name = table_name(table) - path = dets_path(project_dir, table) - - opts = [file: path |> String.to_charlist(), auto_save: 60_000, repair: true] - - :ok = path |> Path.dirname() |> File.mkdir_p() - - case :dets.open_file(table_name, opts) do - {:ok, _} -> - :ok - - {:error, {:needs_repair, _} = reason} -> - Logger.warning("Unable to open DETS #{path}: #{inspect(reason)}") - File.rm_rf!(path) - - {:ok, _} = :dets.open_file(table_name, opts) - - {:error, {:repair_failed, _} = reason} -> - Logger.warning("Unable to open DETS #{path}: #{inspect(reason)}") - File.rm_rf!(path) - - {:ok, _} = :dets.open_file(table_name, opts) - - {:error, {:cannot_repair, _} = reason} -> - Logger.warning("Unable to open DETS #{path}: #{inspect(reason)}") - File.rm_rf!(path) - - {:ok, _} = :dets.open_file(table_name, opts) - - {:error, {:not_a_dets_file, _} = reason} -> - Logger.warning("Unable to open DETS #{path}: #{inspect(reason)}") - File.rm_rf!(path) - - {:ok, _} = :dets.open_file(table_name, opts) - - {:error, {:format_8_no_longer_supported, _} = reason} -> - Logger.warning("Unable to open DETS #{path}: #{inspect(reason)}") - File.rm_rf!(path) - - {:ok, _} = :dets.open_file(table_name, opts) - end - - case :dets.to_ets(table_name, table_name) do - ^table_name -> - :ok - - {:error, reason} -> - Logger.warning("Unable to read DETS #{path}: #{inspect(reason)}") - File.rm_rf!(path) - - {:ok, _} = :dets.open_file(table_name, opts) - ^table_name = :dets.to_ets(table_name, table_name) - end - catch - kind, payload -> - {payload, stacktrace} = Exception.blame(kind, payload, __STACKTRACE__) - error_msg = Exception.format(kind, payload, stacktrace) - - Logger.error( - "Unable to init tracer table #{table} in directory #{project_dir}: #{error_msg}" - ) - - JsonRpc.show_message( - :error, - "Unable to init tracer tables in #{project_dir}" - ) - - JsonRpc.telemetry( - "lsp_server_error", - %{ - "elixir_ls.lsp_process" => inspect(__MODULE__), - "elixir_ls.lsp_server_error" => error_msg - }, - %{} - ) - - unless :persistent_term.get(:language_server_test_mode, false) do - Process.sleep(2000) - System.halt(1) - else - IO.warn("Unable to init tracer table #{table} in directory #{project_dir}: #{error_msg}") - end - end - - def close_table(table) do - table_name = table_name(table) - sync(table_name) - - :ok = :dets.close(table_name) - end - defp modules_by_file_matchspec(file, return) do [ {{:"$1", :"$2"}, @@ -434,11 +284,6 @@ defmodule ElixirLS.LanguageServer.Tracer do end end - defp sync(table_name) do - :ok = :dets.from_ets(table_name, table_name) - :ok = :dets.sync(table_name) - end - defp in_project_sources?(path) do project_dir = get_project_dir() @@ -486,37 +331,4 @@ defmodule ElixirLS.LanguageServer.Tracer do :ets.safe_fixtable(table, false) end end - - defp manifest_path(project_dir) do - Path.join([project_dir, ".elixir_ls", "tracer_db.manifest"]) - end - - def write_manifest(project_dir) do - path = manifest_path(project_dir) - File.rm_rf!(path) - - File.write!(path, "#{@version}", [:write]) - end - - def read_manifest(project_dir) do - with {:ok, text} <- File.read(manifest_path(project_dir)), - {version, ""} <- Integer.parse(text) do - version - else - other -> - IO.warn("Manifest: #{inspect(other)}") - nil - end - end - - def manifest_version_current?(project_dir) do - read_manifest(project_dir) == @version - end - - def clean_dets(project_dir) do - for path <- - Path.join([SourceFile.Path.escape_for_wildcard(project_dir), ".elixir_ls/*.dets"]) - |> Path.wildcard(), - do: File.rm_rf!(path) - end end diff --git a/apps/language_server/test/providers/references_test.exs b/apps/language_server/test/providers/references_test.exs index 398d6a131..5c0642866 100644 --- a/apps/language_server/test/providers/references_test.exs +++ b/apps/language_server/test/providers/references_test.exs @@ -10,11 +10,10 @@ defmodule ElixirLS.LanguageServer.Providers.ReferencesTest do require ElixirLS.Test.TextLoc setup_all context do - File.rm_rf!(FixtureHelpers.get_path(".elixir_ls/calls.dets")) {:ok, pid} = Tracer.start_link([]) project_path = FixtureHelpers.get_path("") - :persistent_term.put(:language_server_project_dir, project_path) - Tracer.notify_settings_stored() + + Tracer.notify_settings_stored(project_path) compiler_options = Code.compiler_options() Build.set_compiler_options(ignore_module_conflict: true) diff --git a/apps/language_server/test/tracer_test.exs b/apps/language_server/test/tracer_test.exs index 0543d0e00..1b02f3171 100644 --- a/apps/language_server/test/tracer_test.exs +++ b/apps/language_server/test/tracer_test.exs @@ -4,9 +4,6 @@ defmodule ElixirLS.LanguageServer.TracerTest do alias ElixirLS.LanguageServer.Test.FixtureHelpers setup context do - File.rm_rf!(FixtureHelpers.get_path(".elixir_ls/tracer_db.manifest")) - File.rm_rf!(FixtureHelpers.get_path(".elixir_ls/calls.dets")) - File.rm_rf!(FixtureHelpers.get_path(".elixir_ls/modules.dets")) {:ok, _pid} = start_supervised(Tracer) {:ok, context} @@ -14,35 +11,16 @@ defmodule ElixirLS.LanguageServer.TracerTest do test "set project dir" do project_path = FixtureHelpers.get_path("") - :persistent_term.put(:language_server_project_dir, project_path) - Tracer.notify_settings_stored() + Tracer.notify_settings_stored(project_path) assert GenServer.call(Tracer, :get_project_dir) == project_path end - test "saves DETS" do - project_path = FixtureHelpers.get_path("") - :persistent_term.put(:language_server_project_dir, project_path) - Tracer.notify_settings_stored() - - Tracer.save() - GenServer.call(Tracer, :get_project_dir) - - assert File.exists?(FixtureHelpers.get_path(".elixir_ls/calls.dets")) - assert File.exists?(FixtureHelpers.get_path(".elixir_ls/modules.dets")) - end - - test "skips save if project dir not set" do - Tracer.save() - GenServer.call(Tracer, :get_project_dir) - end - describe "call trace" do setup context do project_path = FixtureHelpers.get_path("") - :persistent_term.put(:language_server_project_dir, project_path) - Tracer.notify_settings_stored() + Tracer.notify_settings_stored(project_path) GenServer.call(Tracer, :get_project_dir) {:ok, context} @@ -153,18 +131,4 @@ defmodule ElixirLS.LanguageServer.TracerTest do assert [] == sorted_calls() end end - - describe "manifest" do - test "return nil when not found" do - project_path = FixtureHelpers.get_path("") - assert nil == Tracer.read_manifest(project_path) - end - - test "reads manifest" do - project_path = FixtureHelpers.get_path("") - Tracer.write_manifest(project_path) - - assert 3 == Tracer.read_manifest(project_path) - end - end end