Skip to content

Commit

Permalink
optimize get for all other cache types
Browse files Browse the repository at this point in the history
  • Loading branch information
Th3-M4jor committed Aug 10, 2024
1 parent 2563f25 commit db8474f
Show file tree
Hide file tree
Showing 14 changed files with 121 additions and 51 deletions.
20 changes: 8 additions & 12 deletions lib/nostrum/cache/guild_cache.ex
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,14 @@ defmodule Nostrum.Cache.GuildCache do
Returns `{:error, :not_found}` if no result was found.
"""
@spec get(Guild.id()) :: {:ok, Guild.t()} | {:error, :not_found}
@spec get(Guild.id(), module()) :: {:ok, Guild.t()} | {:error, :not_found}
def get(guild_id, cache \\ @configured_cache) do
handle = :nostrum_guild_cache_qlc.get(guild_id, cache)

wrap_qlc(cache, fn ->
case :qlc.eval(handle) do
[guild] -> {:ok, guild}
[] -> {:error, :not_found}
end
end)
end
@callback get(Guild.id()) :: {:ok, Guild.t()} | {:error, :not_found}

@doc """
Retrieves a single `Nostrum.Struct.Guild` from the cache via its `id`.
Returns `{:error, :not_found}` if no result was found.
"""
defdelegate get(guild_id), to: @configured_cache

# Functions called from nostrum.

Expand Down
11 changes: 11 additions & 0 deletions lib/nostrum/cache/guild_cache/ets.ex
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ defmodule Nostrum.Cache.GuildCache.ETS do
def tabname, do: @table_name

# IMPLEMENTATION

@doc "Get a guild from the cache."
@impl GuildCache
@spec get(Guild.id()) :: {:ok, Guild.t()} | {:error, :not_found}
def get(guild_id) do
case :ets.lookup(@table_name, guild_id) do
[{_id, guild}] -> {:ok, guild}
[] -> {:error, :not_found}
end
end

@doc "Create the given guild in the cache."
@impl GuildCache
@spec create(map()) :: Guild.t()
Expand Down
12 changes: 12 additions & 0 deletions lib/nostrum/cache/guild_cache/mnesia.ex
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ if Code.ensure_loaded?(:mnesia) do
:ok
end

@impl GuildCache
@doc "get a guild from the cache."
@spec get(Guild.id()) :: {:ok, Guild.t()} | {:error, :not_found}
def get(guild_id) do
:mnesia.activity(:sync_transaction, fn ->
case :mnesia.read(@table_name, guild_id) do
[{_tag, _id, guild}] -> {:ok, guild}
[] -> {:error, :not_found}
end
end)
end

# Used by dispatch

@impl GuildCache
Expand Down
3 changes: 3 additions & 0 deletions lib/nostrum/cache/guild_cache/noop.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ defmodule Nostrum.Cache.GuildCache.NoOp do
Supervisor.init([], strategy: :one_for_one)
end

@impl GuildCache
def get(_guild_id), do: {:error, :not_found}

@impl GuildCache
def create(payload), do: Guild.to_struct(payload)

Expand Down
22 changes: 7 additions & 15 deletions lib/nostrum/cache/member_cache.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ defmodule Nostrum.Cache.MemberCache do

@configured_cache Nostrum.Cache.Base.get_cache_module(:members, @default_cache_implementation)

@doc """
Retrieve a member from the cache by guild and user ID.
"""
@callback get(Guild.id(), Member.user_id()) :: {:ok, Member.t()} | {:error, atom()}

@doc """
Add the member for the given guild from upstream data.
Expand Down Expand Up @@ -116,7 +121,7 @@ defmodule Nostrum.Cache.MemberCache do
@spec get_with_user(Guild.id(), Member.user_id(), module()) ::
{Member.t(), User.t() | nil} | nil
def get_with_user(guild_id, member_id, cache \\ @configured_cache) do
case get(guild_id, member_id, cache) do
case cache.get(guild_id, member_id) do
{:ok, member} ->
case UserCache.get(member_id) do
{:ok, user} ->
Expand Down Expand Up @@ -152,20 +157,7 @@ defmodule Nostrum.Cache.MemberCache do
Get a single member on the given guild ID.
"""
@spec get(Guild.id(), Member.user_id()) :: {:ok, Member.t()} | {:error, atom()}
@spec get(Guild.id(), Member.user_id(), module()) :: {:ok, Member.t()} | {:error, atom()}
def get(guild_id, user_id, cache \\ @configured_cache) do
handle = :nostrum_member_cache_qlc.lookup(guild_id, user_id, cache)

wrap_qlc(cache, fn ->
case :qlc.e(handle) do
[result] ->
{:ok, result}

[] ->
{:error, :not_found}
end
end)
end
defdelegate get(guild_id, member_id), to: @configured_cache

@doc """
Fold (reduce) over members for the given guild ID.
Expand Down
13 changes: 13 additions & 0 deletions lib/nostrum/cache/member_cache/ets.ex
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ defmodule Nostrum.Cache.MemberCache.ETS do

# Used by dispatch

@impl MemberCache
@doc "Retrieve the member for the given guild and user in the cache."
@spec get(Guild.id(), Member.user_id()) :: {:ok, Member.t()} | {:error, any()}
def get(guild_id, user_id) do
case :ets.lookup(@table_name, {guild_id, user_id}) do
[{_, member}] ->
{:ok, member}

[] ->
{:error, :member_not_found}
end
end

@doc "Add the given member to the given guild in the cache."
@impl MemberCache
@spec create(Guild.id(), map()) :: Member.t()
Expand Down
14 changes: 14 additions & 0 deletions lib/nostrum/cache/member_cache/mnesia.ex
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ if Code.ensure_loaded?(:mnesia) do

# Used by dispatch

@impl MemberCache
@doc "Retrieve the member for the given guild and user in the cache."
@spec get(Guild.id(), Member.user_id()) :: {:ok, Member.t()} | {:error, any()}
def get(guild_id, user_id) do
key = {guild_id, user_id}

:mnesia.activity(:sync_transaction, fn ->
case :mnesia.read(@table_name, key) do
[{_tag, _key, _guild_id, _user_id, member}] -> {:ok, member}
[] -> {:error, :member_not_found}
end
end)
end

@impl MemberCache
@doc "Add the given member to the given guild in the cache."
@spec create(Guild.id(), map()) :: Member.t()
Expand Down
3 changes: 3 additions & 0 deletions lib/nostrum/cache/member_cache/noop.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ defmodule Nostrum.Cache.MemberCache.NoOp do
Supervisor.init([], strategy: :one_for_one)
end

@impl MemberCache
def get(_guild_id, _user_id), do: {:error, :member_not_found}

@impl MemberCache
def create(_guild_id, payload), do: Util.cast(payload, {:struct, Member})

Expand Down
18 changes: 5 additions & 13 deletions lib/nostrum/cache/presence_cache.ex
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,10 @@ defmodule Nostrum.Cache.PresenceCache do
end
```
"""
@spec get(Guild.id(), User.id()) :: {:ok, presence()} | {:error, :presence_not_found}
@spec get(Guild.id(), User.id(), module()) :: {:ok, presence()} | {:error, :presence_not_found}
def get(guild_id, user_id, cache \\ @configured_cache) do
handle = :nostrum_presence_cache_qlc.get(guild_id, user_id, cache)

wrap_qlc(cache, fn ->
case :qlc.eval(handle) do
[presence] -> {:ok, presence}
[] -> {:error, :not_found}
end
end)
end
@spec get(Guild.id(), User.id()) :: {:ok, presence()} | {:error, any()}
defdelegate get(guild_id, user_id), to: @configured_cache

@callback get(Guild.id(), User.id()) :: {:ok, presence()} | {:error, any()}

@doc """
Create a presence in the cache.
Expand Down Expand Up @@ -154,7 +146,7 @@ defmodule Nostrum.Cache.PresenceCache do
def get!(guild_id, user_id, cache \\ @configured_cache)
when is_snowflake(user_id) and is_snowflake(guild_id) do
guild_id
|> get(user_id, cache)
|> get(user_id)
|> Util.bangify_find({guild_id, user_id}, cache)
end

Expand Down
12 changes: 12 additions & 0 deletions lib/nostrum/cache/presence_cache/ets.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ defmodule Nostrum.Cache.PresenceCache.ETS do
@table_name :nostrum_presences

alias Nostrum.Struct.Guild
alias Nostrum.Struct.User

use Supervisor

@doc "Start the supervisor."
Expand All @@ -34,6 +36,16 @@ defmodule Nostrum.Cache.PresenceCache.ETS do
Supervisor.init([], strategy: :one_for_one)
end

@impl PresenceCache
@doc "Retrieve a presence from the cache."
@spec get(Guild.id(), User.id()) :: {:ok, PresenceCache.presence()} | {:error, any}
def get(guild_id, user_id) do
case :ets.lookup(@table_name, {guild_id, user_id}) do
[{_, presence}] -> {:ok, presence}
[] -> {:error, :presence_not_found}
end
end

@impl PresenceCache
@doc "Add the given presence data to the cache."
@spec create(map) :: :ok
Expand Down
15 changes: 15 additions & 0 deletions lib/nostrum/cache/presence_cache/mnesia.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ if Code.ensure_loaded?(:mnesia) do
@behaviour Nostrum.Cache.PresenceCache

alias Nostrum.Cache.PresenceCache

alias Nostrum.Struct.Guild
alias Nostrum.Struct.User

use Supervisor

@doc "Retrieve the table name used by the cache."
Expand Down Expand Up @@ -46,6 +49,18 @@ if Code.ensure_loaded?(:mnesia) do
Supervisor.init([], strategy: :one_for_one)
end

@impl PresenceCache
@doc "Retrieve a presence from the cache."
@spec get(Guild.id(), User.id()) :: {:ok, PresenceCache.presence()} | {:error, any}
def get(guild_id, user_id) do
:mnesia.activity(:sync_transaction, fn ->
case :mnesia.read(@table_name, {guild_id, user_id}) do
[{_tag, _key, presence}] -> {:ok, presence}
[] -> {:error, :presence_not_found}
end
end)
end

@impl PresenceCache
@doc "Add the given presence to the cache."
@spec create(map()) :: :ok
Expand Down
7 changes: 7 additions & 0 deletions lib/nostrum/cache/presence_cache/noop.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ defmodule Nostrum.Cache.PresenceCache.NoOp do
@behaviour Nostrum.Cache.PresenceCache

alias Nostrum.Cache.PresenceCache

alias Nostrum.Struct.Guild
alias Nostrum.Struct.User

use Supervisor

@doc "Start the supervisor."
Expand All @@ -22,6 +25,10 @@ defmodule Nostrum.Cache.PresenceCache.NoOp do
Supervisor.init([], strategy: :one_for_one)
end

@impl PresenceCache
@spec get(Guild.id(), User.id()) :: {:ok, map()} | {:error, any()}
def get(_guild_id, _user_id), do: {:error, :presence_not_found}

@impl PresenceCache
@spec create(map) :: :ok
def create(_presence), do: :ok
Expand Down
12 changes: 6 additions & 6 deletions test/nostrum/cache/guild_cache_meta_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ defmodule Nostrum.Cache.GuildCacheMetaTest do
created = @cache.channel_create(@test_guild.id, @test_channel)
expected = Channel.to_struct(@test_channel)
assert ^expected = created
{:ok, cached} = GuildCache.get(@test_guild.id, @cache)
{:ok, cached} = @cache.get(@test_guild.id)
channels = %{expected.id => expected}
assert ^channels = cached.channels

Expand Down Expand Up @@ -128,7 +128,7 @@ defmodule Nostrum.Cache.GuildCacheMetaTest do
assert ^expected_return = @cache.role_create(@test_guild.id, @test_role)

assert {:ok, %Guild{roles: %{^role_id => ^expected_role_struct}}} =
GuildCache.get(@test_guild.id, @cache)
@cache.get(@test_guild.id)

# role_update/2
updated_payload = Map.put(@test_role, :name, "Higher Sharders")
Expand All @@ -139,7 +139,7 @@ defmodule Nostrum.Cache.GuildCacheMetaTest do

# role_delete/2
{_guild_id, ^new_role} = @cache.role_delete(@test_guild.id, @test_role.id)
{:ok, guild} = GuildCache.get(@test_guild.id, @cache)
{:ok, guild} = @cache.get(@test_guild.id)
assert guild.roles == %{}
end
end
Expand All @@ -152,11 +152,11 @@ defmodule Nostrum.Cache.GuildCacheMetaTest do
end

test "member count operations" do
assert {:ok, %{member_count: 0}} = GuildCache.get(@test_guild.id, @cache)
assert {:ok, %{member_count: 0}} = @cache.get(@test_guild.id)
assert @cache.member_count_up(@test_guild.id)
assert {:ok, %{member_count: 1}} = GuildCache.get(@test_guild.id, @cache)
assert {:ok, %{member_count: 1}} = @cache.get(@test_guild.id)
assert @cache.member_count_down(@test_guild.id)
assert {:ok, %{member_count: 0}} = GuildCache.get(@test_guild.id, @cache)
assert {:ok, %{member_count: 0}} = @cache.get(@test_guild.id)
end

test "member count operations for uncached guild" do
Expand Down
10 changes: 5 additions & 5 deletions test/nostrum/cache/presence_cache_meta_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ defmodule Nostrum.Cache.PresenceCacheMetaTest do

describe "empty cache" do
test "lookup of nonexistent user" do
assert {:error, :not_found} =
PresenceCache.get(@test_guild_id, @test_presence.user.id + 1, @cache)
assert {:error, :presence_not_found} =
@cache.get(@test_guild_id, @test_presence.user.id + 1)
end

test "create, update, delete" do
Expand All @@ -71,7 +71,7 @@ defmodule Nostrum.Cache.PresenceCacheMetaTest do
assert :noop = @cache.update(@test_presence)

assert {:ok, ^test_presence} =
PresenceCache.get(@test_guild_id, test_presence.user.id, @cache)
@cache.get(@test_guild_id, test_presence.user.id)

updated_presence = Map.put(@test_presence, :status, :offline)

Expand All @@ -87,8 +87,8 @@ defmodule Nostrum.Cache.PresenceCacheMetaTest do
user_2_presence = %{status: :offline, user: %{id: user_2_id}}
presences = [user_1_presence, user_2_presence]
assert :ok = @cache.bulk_create(guild_id, presences)
assert {:ok, ^user_1_presence} = PresenceCache.get(guild_id, user_1_id, @cache)
assert {:ok, ^user_2_presence} = PresenceCache.get(guild_id, user_2_id, @cache)
assert {:ok, ^user_1_presence} = @cache.get(guild_id, user_1_id)
assert {:ok, ^user_2_presence} = @cache.get(guild_id, user_2_id)
end

test "bulk_create/2 with empty presences" do
Expand Down

0 comments on commit db8474f

Please sign in to comment.