changed
CHANGELOG.md
|
@@ -4,6 4,29 @@ All notable changes to this project will be documented in this file.
|
4
4
|
|
5
5
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
## [v2.5.2](https://github.com/cabol/nebulex/tree/v2.5.2) (2023-07-14)
|
8
|
|
9
|
[Full Changelog](https://github.com/cabol/nebulex/compare/v2.5.1...v2.5.2)
|
10
|
|
11
|
**Closed issues:**
|
12
|
|
13
|
- Replicated adapter syncing during rolling deployment.
|
14
|
[#209](https://github.com/cabol/nebulex/issues/209)
|
15
|
- Ambiguity regarding ttl and `gc_interval` relation.
|
16
|
[#208](https://github.com/cabol/nebulex/issues/208)
|
17
|
- Seeing Nebulex.RPCError during deployments with partitioned adapter.
|
18
|
[#206](https://github.com/cabol/nebulex/issues/206)
|
19
|
- Random `:erpc`, `:timeout` with partitioned get.
|
20
|
[#202](https://github.com/cabol/nebulex/issues/202)
|
21
|
- Processes reading from cache blocked by generational gc process.
|
22
|
[#197](https://github.com/cabol/nebulex/issues/197)
|
23
|
|
24
|
**Merged pull requests:**
|
25
|
|
26
|
- Delay flushing ets table to avoid blocking processes using it.
|
27
|
[#210](https://github.com/cabol/nebulex/pull/210)
|
28
|
([szajbus](https://github.com/szajbus))
|
29
|
|
7
30
|
## [v2.5.1](https://github.com/cabol/nebulex/tree/v2.5.1) (2023-05-27)
|
8
31
|
|
9
32
|
[Full Changelog](https://github.com/cabol/nebulex/compare/v2.5.0...v2.5.1)
|
changed
hex_metadata.config
|
@@ -59,4 59,4 @@
|
59
59
|
{<<"optional">>,true},
|
60
60
|
{<<"repository">>,<<"hexpm">>},
|
61
61
|
{<<"requirement">>,<<"~> 0.4 or ~> 1.0">>}]]}.
|
62
|
- {<<"version">>,<<"2.5.1">>}.
|
62
|
{<<"version">>,<<"2.5.2">>}.
|
changed
lib/nebulex/adapters/local.ex
|
@@ -87,6 87,10 @@ defmodule Nebulex.Adapters.Local do
|
87
87
|
the timeout used when the cache starts and there are few entries or the
|
88
88
|
consumed memory is near to `0`. Defaults to `600_000` (10 minutes).
|
89
89
|
|
90
|
* `:gc_flush_delay` - If it is set, an integer > 0 is expected defining the
|
91
|
delay in milliseconds before objects from the oldest generation are
|
92
|
flushed. Defaults to `10_000` (10 seconds).
|
93
|
|
90
94
|
## Usage
|
91
95
|
|
92
96
|
`Nebulex.Cache` is the wrapper around the cache. We can define a
|
changed
lib/nebulex/adapters/local/generation.ex
|
@@ -10,6 10,16 @@ defmodule Nebulex.Adapters.Local.Generation do
|
10
10
|
(triggered by `:gc_interval` timeout), a new cache generation is created
|
11
11
|
and the oldest one is deleted.
|
12
12
|
|
13
|
The deletion of the oldest generation happens in two steps. First, the
|
14
|
underlying ets table is flushed to release space and only marked for deletion
|
15
|
as there may still be processes referencing it. The actual deletion of the
|
16
|
ets table happens at next GC run.
|
17
|
|
18
|
However, flushing is a blocking operation, once started, processes wanting
|
19
|
to access the table will need to wait until it finishes. To circumvent this,
|
20
|
flushing can be delayed by configuring `:gc_flush_delay` to allow time for
|
21
|
these processes to finish their work without being accidentally blocked.
|
22
|
|
13
23
|
The only way to create new generations is through this module (this server
|
14
24
|
is the metadata owner) calling `new/2` function. When a Cache is created,
|
15
25
|
a generational garbage collector is attached to it automatically,
|
|
@@ -46,6 56,10 @@ defmodule Nebulex.Adapters.Local.Generation do
|
46
56
|
the timeout used when the cache starts and there are few entries or the
|
47
57
|
consumed memory is near to `0`. Defaults to `600_000` (10 minutes).
|
48
58
|
|
59
|
* `:gc_flush_delay` - If it is set, an integer > 0 is expected defining the
|
60
|
delay in milliseconds before objects from the oldest generation are
|
61
|
flushed. Defaults to `10_000` (10 seconds).
|
62
|
|
49
63
|
"""
|
50
64
|
|
51
65
|
# State
|
|
@@ -64,7 78,8 @@ defmodule Nebulex.Adapters.Local.Generation do
|
64
78
|
:allocated_memory,
|
65
79
|
:gc_cleanup_min_timeout,
|
66
80
|
:gc_cleanup_max_timeout,
|
67
|
- :gc_cleanup_ref
|
81
|
:gc_cleanup_ref,
|
82
|
:gc_flush_delay
|
68
83
|
]
|
69
84
|
|
70
85
|
use GenServer
|
|
@@ -279,7 294,8 @@ defmodule Nebulex.Adapters.Local.Generation do
|
279
294
|
gc_cleanup_min_timeout:
|
280
295
|
get_option(opts, :gc_cleanup_min_timeout, "an integer > 0", pos_integer, 10_000),
|
281
296
|
gc_cleanup_max_timeout:
|
282
|
- get_option(opts, :gc_cleanup_max_timeout, "an integer > 0", pos_integer, 600_000)
|
297
|
get_option(opts, :gc_cleanup_max_timeout, "an integer > 0", pos_integer, 600_000),
|
298
|
gc_flush_delay: get_option(opts, :gc_flush_delay, "an integer > 0", pos_integer, 10_000)
|
283
299
|
})
|
284
300
|
end
|
285
301
|
|
|
@@ -384,6 400,20 @@ defmodule Nebulex.Adapters.Local.Generation do
|
384
400
|
{:noreply, state}
|
385
401
|
end
|
386
402
|
|
403
|
def handle_info(
|
404
|
:flush_older_gen,
|
405
|
%__MODULE__{
|
406
|
meta_tab: meta_tab,
|
407
|
backend: backend
|
408
|
} = state
|
409
|
) do
|
410
|
if deprecated = Metadata.get(meta_tab, :deprecated) do
|
411
|
true = backend.delete_all_objects(deprecated)
|
412
|
end
|
413
|
|
414
|
{:noreply, state}
|
415
|
end
|
416
|
|
387
417
|
defp check_size(%__MODULE__{max_size: max_size} = state) when not is_nil(max_size) do
|
388
418
|
maybe_cleanup(:size, state)
|
389
419
|
end
|
|
@@ -454,7 484,8 @@ defmodule Nebulex.Adapters.Local.Generation do
|
454
484
|
meta_tab: meta_tab,
|
455
485
|
backend: backend,
|
456
486
|
backend_opts: backend_opts,
|
457
|
- stats_counter: stats_counter
|
487
|
stats_counter: stats_counter,
|
488
|
gc_flush_delay: gc_flush_delay
|
458
489
|
}) do
|
459
490
|
# Create new generation
|
460
491
|
gen_tab = Backend.new(backend, meta_tab, backend_opts)
|
|
@@ -472,7 503,7 @@ defmodule Nebulex.Adapters.Local.Generation do
|
472
503
|
# - Delete previously stored deprecated generation
|
473
504
|
# - Flush the older generation
|
474
505
|
# - Deprecate it (mark it for deletion)
|
475
|
- :ok = process_older_gen(meta_tab, backend, older)
|
506
|
:ok = process_older_gen(meta_tab, backend, older, gc_flush_delay)
|
476
507
|
|
477
508
|
[newer] ->
|
478
509
|
# Update generations
|
|
@@ -489,14 520,14 @@ defmodule Nebulex.Adapters.Local.Generation do
|
489
520
|
# Hence, the idea is to keep it alive till a new generation is pushed, but
|
490
521
|
# flushing its data before so that we release memory space. By the time a new
|
491
522
|
# generation is pushed, then it is safe to delete it completely.
|
492
|
- defp process_older_gen(meta_tab, backend, older) do
|
523
|
defp process_older_gen(meta_tab, backend, older, gc_flush_delay) do
|
493
524
|
if deprecated = Metadata.get(meta_tab, :deprecated) do
|
494
525
|
# Delete deprecated generation if it does exist
|
495
526
|
_ = Backend.delete(backend, meta_tab, deprecated)
|
496
527
|
end
|
497
528
|
|
498
529
|
# Flush older generation to release space so it can be marked for deletion
|
499
|
- true = backend.delete_all_objects(older)
|
530
|
Process.send_after(self(), :flush_older_gen, gc_flush_delay)
|
500
531
|
|
501
532
|
# Keep alive older generation reference into the metadata
|
502
533
|
Metadata.put(meta_tab, :deprecated, older)
|
changed
mix.exs
|
@@ -2,7 2,7 @@ defmodule Nebulex.MixProject do
|
2
2
|
use Mix.Project
|
3
3
|
|
4
4
|
@source_url "https://github.com/cabol/nebulex"
|
5
|
- @version "2.5.1"
|
5
|
@version "2.5.2"
|
6
6
|
|
7
7
|
def project do
|
8
8
|
[
|