Skip to content

Commit 4d2837b

Browse files
savhappysolnic
andauthored
Refactor span storage (#817)
* initial refactor with ETS for span storage * add genserver back * Fix updating root spans in ets * remove comment --------- Co-authored-by: Peter Solnica <[email protected]>
1 parent 52fb607 commit 4d2837b

File tree

3 files changed

+40
-49
lines changed

3 files changed

+40
-49
lines changed

lib/sentry/application.ex

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ defmodule Sentry.Application do
1010
config = Config.validate!()
1111
:ok = Config.persist(config)
1212

13-
# Setup ETS tables for span storage
14-
Sentry.Opentelemetry.SpanStorage.setup()
15-
1613
http_client = Keyword.fetch!(config, :client)
1714

1815
maybe_http_client_spec =
@@ -30,6 +27,7 @@ defmodule Sentry.Application do
3027
Sentry.Sources,
3128
Sentry.Dedupe,
3229
Sentry.ClientReport.Sender,
30+
Sentry.Opentelemetry.SpanStorage,
3331
{Sentry.Integrations.CheckInIDMappings,
3432
[
3533
max_expected_check_in_time:
Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,79 @@
11
defmodule Sentry.Opentelemetry.SpanStorage do
22
@moduledoc false
3+
use GenServer
34

4-
@root_spans_table :sentry_root_spans
5-
@child_spans_table :sentry_child_spans
5+
@table :span_storage
66

7-
def setup do
8-
case :ets.whereis(@root_spans_table) do
9-
:undefined ->
10-
:ets.new(@root_spans_table, [:set, :public, :named_table])
7+
@spec start_link(keyword()) :: GenServer.on_start()
8+
def start_link(opts \\ []) do
9+
name = Keyword.get(opts, :name, __MODULE__)
10+
GenServer.start_link(__MODULE__, nil, name: name)
11+
end
1112

12-
_ ->
13-
:ok
14-
end
13+
@impl true
14+
def init(nil) do
15+
_table =
16+
if :ets.whereis(@table) == :undefined do
17+
:ets.new(@table, [:named_table, :public, :bag])
18+
end
1519

16-
case :ets.whereis(@child_spans_table) do
17-
:undefined ->
18-
:ets.new(@child_spans_table, [:bag, :public, :named_table])
20+
{:ok, :no_state}
21+
end
1922

20-
_ ->
21-
:ok
23+
def store_span(span_data) when span_data.parent_span_id == nil do
24+
case :ets.lookup(@table, {:root_span, span_data.span_id}) do
25+
[] -> :ets.insert(@table, {{:root_span, span_data.span_id}, span_data})
26+
_ -> :ok
2227
end
23-
24-
:ok
2528
end
2629

2730
def store_span(span_data) do
28-
if span_data.parent_span_id == nil do
29-
:ets.insert(@root_spans_table, {span_data.span_id, span_data})
30-
else
31-
:ets.insert(@child_spans_table, {span_data.parent_span_id, span_data})
32-
end
33-
34-
:ok
31+
_ = :ets.insert(@table, {span_data.parent_span_id, span_data})
3532
end
3633

3734
def get_root_span(span_id) do
38-
case :ets.lookup(@root_spans_table, span_id) do
39-
[{^span_id, span}] -> span
35+
case :ets.lookup(@table, {:root_span, span_id}) do
36+
[{{:root_span, ^span_id}, span}] -> span
4037
[] -> nil
4138
end
4239
end
4340

4441
def get_child_spans(parent_span_id) do
45-
:ets.lookup(@child_spans_table, parent_span_id)
42+
:ets.lookup(@table, parent_span_id)
4643
|> Enum.map(fn {_parent_id, span} -> span end)
4744
end
4845

4946
def update_span(span_data) do
5047
if span_data.parent_span_id == nil do
51-
:ets.insert(@root_spans_table, {span_data.span_id, span_data})
48+
case :ets.lookup(@table, {:root_span, span_data.span_id}) do
49+
[] ->
50+
:ets.insert(@table, {{:root_span, span_data.span_id}, span_data})
51+
52+
_ ->
53+
:ets.delete(@table, {:root_span, span_data.span_id})
54+
:ets.insert(@table, {{:root_span, span_data.span_id}, span_data})
55+
end
5256
else
53-
existing_spans = :ets.lookup(@child_spans_table, span_data.parent_span_id)
54-
55-
:ets.delete(@child_spans_table, span_data.parent_span_id)
57+
existing_spans = :ets.lookup(@table, span_data.parent_span_id)
5658

5759
Enum.each(existing_spans, fn {parent_id, span} ->
58-
if span.span_id != span_data.span_id do
59-
:ets.insert(@child_spans_table, {parent_id, span})
60+
if span.span_id == span_data.span_id do
61+
:ets.delete_object(@table, {parent_id, span})
62+
:ets.insert(@table, {span_data.parent_span_id, span_data})
6063
end
6164
end)
62-
63-
:ets.insert(@child_spans_table, {span_data.parent_span_id, span_data})
6465
end
6566

6667
:ok
6768
end
6869

6970
def remove_span(span_id) do
70-
:ets.delete(@root_spans_table, span_id)
71+
:ets.delete(@table, {:root_span, span_id})
7172
:ok
7273
end
7374

7475
def remove_child_spans(parent_span_id) do
75-
:ets.delete(@child_spans_table, parent_span_id)
76+
:ets.delete(@table, parent_span_id)
7677
:ok
7778
end
7879
end

test/sentry/opentelemetry/span_processor_test.exs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,10 @@ defmodule Sentry.Opentelemetry.SpanProcessorTest do
66
alias Sentry.Opentelemetry.SpanStorage
77

88
setup do
9-
# Create tables
10-
SpanStorage.setup()
11-
129
on_exit(fn ->
1310
# Only try to clean up tables if they exist
14-
if :ets.whereis(:sentry_root_spans) != :undefined do
15-
:ets.delete_all_objects(:sentry_root_spans)
16-
end
17-
18-
if :ets.whereis(:sentry_child_spans) != :undefined do
19-
:ets.delete_all_objects(:sentry_child_spans)
11+
if :ets.whereis(:span_storage) != :undefined do
12+
:ets.delete_all_objects(:span_storage)
2013
end
2114
end)
2215

@@ -71,7 +64,6 @@ defmodule Sentry.Opentelemetry.SpanProcessorTest do
7164
TestEndpoint.instrumented_function()
7265

7366
assert [%Sentry.Transaction{} = transaction] = Sentry.Test.pop_sentry_transactions()
74-
7567
assert_valid_iso8601(transaction.timestamp)
7668
assert_valid_iso8601(transaction.start_timestamp)
7769
assert transaction.timestamp > transaction.start_timestamp

0 commit comments

Comments
 (0)