Удалите все записи из таблицы ets, имеющие метку даты старше 10 секунд - PullRequest
0 голосов
/ 19 декабря 2018

У меня есть таблица ets set в приложении эликсира.Мне нужно очистить записи, у которых их поле updated_at старше 10 секунд.Есть ли способ установить срок действия или сделать это вручную без перебора всех записей?Я сопоставляю записи на основе временных отметок, превышающих указанное время.

пример записи:

key: key_1
record: %{id: key_1, updated_at: ~N[2018-12-19 10:08:47.803075]}

пока у меня есть этот код

def clean_stale(previous_key) do
  if previous_key == :"$end_of_table" do
    :ok
  else
    device = get(previous_key)
    next_key = :ets.next(__MODULE__, previous_key)
    if NaiveDateTime.diff(NaiveDateTime.utc_now, device.last_recorded_at) > 10 do
      remove(device.id)
    end
    clean_stale(next_key)
  end
end

1 Ответ

0 голосов
/ 19 декабря 2018

Если вы храните «обновленное в» время как целое число, а не как NaiveDateTime структуру, вы можете использовать спецификацию соответствия.

Например, чтобы получить текущее время в виде количества секундначиная с эпохи Unix:

> DateTime.to_unix(DateTime.utc_now())
1545215338

Вы можете сделать что-то вроде этого:

iex(3)> :ets.new(:foo, [:public, :named_table])
:foo
iex(4)> :ets.insert(:foo, {:key1, DateTime.to_unix(DateTime.utc_now())})
true
iex(5)> :ets.insert(:foo, {:key2, DateTime.to_unix(DateTime.utc_now())})
true
iex(6)> :ets.tab2list(:foo)
[key2: 1545215144, key1: 1545215140]
iex(7)> :ets.select_delete(:foo, [{{:_, :"$1"}, [{:<, :"$1", 1545215144}], [true]}])
1
iex(8)> :ets.tab2list(:foo)
[key2: 1545215144]

При вызове ets:select_delete/2 я передаю соответствие спецификации .Он состоит из трех частей:

  • С {:_, :"$1"} я выполняю сопоставление записей в таблице.В этом примере у меня есть кортеж с двумя элементами.Я игнорирую ключ с помощью :_ и назначаю метку времени переменной соответствия с :"$1".
  • С помощью [{:<, :"$1", 1545215144}] я указываю, что я хочу сопоставлять записи только с меткой времени до этого времени.В вашем случае вы бы рассчитали время в десяти секундах в прошлом и поместили бы это значение здесь.
  • С [true] я указываю, что хочу вернуть true для соответствующих записей, что в случаеselect_delete означает «удалить эту запись».

Поэтому после вызова select_delete в таблице останется только вторая запись.


Если временная метка находится внутрикарту, вы можете использовать map_get, чтобы получить к ней доступ и сравнить ее:

:ets.select_delete(:foo, [{{:_, :"$1"},
                           [{:<, {:map_get, :updated_at, :"$1"}, 1545215339}],
                           [true]}])

или (в Erlang / OTP 18.0 и более поздних версиях) сопоставить значение карты:

:ets.select_delete(:foo, [{{:_, #{updated_at: :"$1"}},
                           [{:<, :"$1", 1545215339}],
                           [true]}])
...