Удалите все записи из таблицы ets, имеющие метку даты старше 10 секунд
У меня есть ets
накрывать на стол в приложении эликсир. Мне нужно очистить записи, у которых их поле 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 ответ
Если вы храните "обновлено в" время как целое число, а не как NaiveDateTime
struct, вы можете использовать соответствие спецификации.
Например, чтобы получить текущее время в виде количества секунд с начала эпохи 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]}])