Packages
ferricstore
0.11.4
0.11.14
0.11.12
0.11.11
0.11.10
0.11.9
0.11.8
0.11.7
0.11.6
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.3
0.10.2
0.10.1
0.10.0
0.9.1
0.9.0
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.0
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.2.0
0.1.0
FerricFlow durable workflows and queues with native-protocol storage, Raft durability, and Bitcask persistence.
Current section
Files
Jump to
Current section
Files
lib/ferricstore/flow/info_count_read.ex
defmodule Ferricstore.Flow.InfoCountRead do
@moduledoc false
alias Ferricstore.CommandTime
alias Ferricstore.Flow.IndexZSet
alias Ferricstore.Flow.InfoCounts
alias Ferricstore.Flow.LMDB
alias Ferricstore.Flow.LMDBMirror
alias Ferricstore.Flow.LMDBWriter
alias Ferricstore.Store.Router
@default_terminal_lmdb_sweep_limit 10_000
def zset_count_many(_ctx, []), do: {:ok, []}
def zset_count_many(ctx, keys) do
case Router.flow_index_count_all_many(ctx, keys) do
{:ok, counts} -> InfoCounts.validate_counts(keys, counts)
:unavailable -> zcard_many_fallback(ctx, keys)
end
end
def terminal_lmdb_counts(
_ctx,
_state_keys,
_partition_key,
false,
_consistent?,
_terminal_states
),
do: {:ok, %{}}
def terminal_lmdb_counts(ctx, state_keys, partition_key, true, consistent?, terminal_states) do
terminal_keys = InfoCounts.terminal_keys(state_keys, terminal_states)
case terminal_keys do
[] ->
{:ok, %{}}
[first_key | _] ->
with :ok <- maybe_flush_lmdb_for_index(ctx, first_key, partition_key, consistent?),
:ok <- LMDBMirror.require_healthy(ctx, first_key, partition_key) do
now_ms = CommandTime.now_ms()
sweep_limit = terminal_lmdb_sweep_limit()
ctx
|> lmdb_paths_for_index(first_key, partition_key)
|> Enum.reduce_while({:ok, Map.new(terminal_keys, &{&1, 0})}, fn path, {:ok, acc} ->
with {:ok, counts} <- LMDB.terminal_counts(path, terminal_keys),
{:ok, counts} <- InfoCounts.validate_counts(terminal_keys, counts),
{:ok, counts} <-
maybe_sweep_terminal_lmdb_counts(
path,
terminal_keys,
counts,
now_ms,
sweep_limit
),
{:ok, merged} <- InfoCounts.merge_terminal_counts(acc, terminal_keys, counts) do
{:cont, {:ok, merged}}
else
{:error, _reason} = error -> {:halt, error}
end
end)
end
end
end
defp zcard_many_fallback(ctx, keys) do
Enum.reduce_while(keys, {:ok, []}, fn key, {:ok, acc} ->
case IndexZSet.card(ctx, key) do
{:ok, count} -> {:cont, {:ok, [count | acc]}}
{:error, _reason} = error -> {:halt, error}
end
end)
|> case do
{:ok, counts} -> InfoCounts.validate_counts(keys, Enum.reverse(counts))
{:error, _reason} = error -> error
end
end
defp maybe_flush_lmdb_for_index(_ctx, _index_key, _partition_key, false), do: :ok
defp maybe_flush_lmdb_for_index(ctx, index_key, partition_key, true) do
case partition_key do
nil ->
LMDBWriter.flush_all(ctx.name, ctx.shard_count)
partition_key when is_binary(partition_key) ->
shard_index = Router.shard_for(ctx, index_key)
LMDBWriter.flush(ctx.name, shard_index)
end
end
defp maybe_sweep_terminal_lmdb_counts(path, terminal_keys, counts, now_ms, sweep_limit) do
if Enum.any?(counts, &(&1 > 0)) do
with {:ok, _swept} <- LMDB.sweep_expired_terminal(path, now_ms, sweep_limit) do
LMDB.terminal_counts(path, terminal_keys)
end
else
{:ok, counts}
end
end
defp lmdb_paths_for_index(ctx, _index_key, nil) do
LMDBMirror.paths_for_index(ctx, nil, nil)
end
defp lmdb_paths_for_index(ctx, index_key, partition_key) when is_binary(partition_key) do
LMDBMirror.paths_for_index(ctx, index_key, partition_key)
end
@doc false
def terminal_lmdb_sweep_limit do
case Application.get_env(
:ferricstore,
:flow_lmdb_terminal_sweep_limit,
@default_terminal_lmdb_sweep_limit
) do
value when is_integer(value) and value > 0 -> value
_invalid -> @default_terminal_lmdb_sweep_limit
end
end
end