Time to live (Enterprise)
Time-to-live allows a user to tag vertices and edges with an expiration time. Once a vertex has expired, the vertex and all its associated edges will be deleted.
The TTL
label and ttl
property are reserved names for TTL. See Tagging objects for more info.
Time-to-live is implemented as a background job that periodically gets executed. This is a best effort solution; meaning that even if an object expires, that does not mean it gets deleted right away, but eventually, once the background job gets executed.
Usage
In order to use the feature the user needs to:
Once that is done, a background job will periodically delete expired vertices, its associated edges and expired edges.
What is indexed
Time-to-live uses a label TTL
and property ttl
to tag vertices. A label+property value index is used to speed up query execution.
Edges are tagged using only the ttl
property and are scanned using the global edge property index.
Executed query
Time-to-live is implemented as a background job that execute the following queries:
MATCH (n:TTL) WHERE n.ttl < $now WITH n LIMIT $batch DETACH DELETE n;
MATCH ()-[e]->() WHERE e.ttl < $now WITH e LIMIT $batch DELETE e;
The query DETACH DELETEs all vertices and DELETEs edges that have expired at this point in time. The query is batched to limit the serialization errors and lost work that the error might cause.
Since time-to-live is implemented as a query like any other, the user might get serialization errors. This can happen if the user is modifying an expired vertex or edge. The chance of serialization errors can be minimized by limiting the duration of write transactions. In addition, the user can disable TTL before starting an important write transaction and re-enable it after commit. See configuration.
Configuration
Time to live is by default disabled. To enable it, run:
ENABLE TTL [EVERY "period"] [AT "time"];
- period: a string literal defining the period of execution. Format: “NdNhNmNs”
- time: a specific time at which the first ttl job will get executed. Format: “24:59:59”
NOTE: If period is omitted while time is not, the default period value will be 1 day
Time is converted between local and system time using the database defined timezone.
Examples demonstrating TTL setup:
# Run TTL every dat at 14:30 (will run immediately once if started after 14:30)
ENABLE TTL AT "14:30:00";
# Run TTL every 2nd day at 4:00 (will run immediately once if started after 4:00)
ENABLE TTL EVERY "2d" AT "04:00:00";
# Run TTL every 3 hours, starting from 19:45 today (will run immediately once if started after 19:45)
ENABLE TTL EVERY "3h" AT "19:45:00";
The time-to-live job can be stopped and re-enabled via:
STOP TTL;
ENABLE TTL;
NOTE: Once stopped, ttl can be re-enabled with the old configuration or a new one.
To stop and drop any index created, run:
DISABLE TTL;
NOTE: Once disabled, ttl has to be re-enabled with a new configuration.
Tagging objects
In order to tag a vertex for expiration, the user needs to add the TTL
label and ttl
property.
Edges are tagged with only the ttl
property. This allows the user to use TTL on any edge type.
ttl
property defines when the vertex has expired as a number of microseconds since POSIX epoch.
POSIX epoch defined as starting from 1st of January 1970. Negative values define time before, while positive numbers the time since.
The user can simply input the number or can use builtin Memgraph functions to define the expiration time.
Define arbitrary time since epoch when creating an object:
CREATE (:TTL{ttl:123});
CREATE ()-[e:E{ttl:123}]->();
Mark an already existing object with an arbitrary time since epoch:
MATCH (n) SET n:TTL, n.ttl=123;
MATCH ()-[e]->() SET e.ttl=123;
Set object expiration to time at creation:
CREATE (:TTL{ttl:timestamp()});
CREATE ()-[e:A{ttl:timestamp()}]->();
Update object’s expiration to now:
MATCH (n) SET n:TTL, n.ttl=timestamp();
MATCH ()-[e]->() SET e.ttl=timestamp();
Create an object that will expire 11 hours and 25 minutes after creation:
CREATE(:TTL{ttl:timestamp() + timestamp(duration({hour:11, minute:25}))});
CREATE ()-[e:B{ttl:timestamp() + timestamp(duration({hour:11, minute:25}))}]->();
Update object’s expiration to 11 hours and 25 minutes from now:
MATCH (n) SET n:TTL, n.ttl=timestamp() + timestamp(duration({hour:11, minute:25}));
MATCH ()-[e]->() SET e.ttl=timestamp() + timestamp(duration({hour:11, minute:25}));
Create object that will expire on July 15th 2024 at 14:15:
CREATE (:TTL{ttl:timestamp(LocalDateTime("2024-07-15T14:15:00"))});
CREATE ()-[e:C{ttl:timestamp(LocalDateTime("2024-07-15T14:15:00"))}]->();
Update object’s so it expires on July 15th 2024 at 14:15:
MATCH (n) SET n:TTL, n.ttl=timestamp(LocalDateTime("2024-07-15T14:15:00"));
MATCH ()-[e]->() SET e.ttl=timestamp(LocalDateTime("2024-07-15T14:15:00"));
Authorization
Time-to-live configuration queries require permissions:
- CONFIG
- INDEX
- MATCH
- DELETE
Compatibility
List of features and their supported status:
Feature | Support |
---|---|
Multitenancy | yes |
Durability | yes |
Storage modes | yes (all) |
Replication | yes |
Concurrent transactions | yes |
Fine-grained access control | no |
Multitenancy
Time-to-live configuration is tenant based; meaning that the feature will need to be enabled and configured manually for each tenant.
Replication
Time-to-live background job will be execute only on MAIN and the changes will be replicated. While the TTL effect is replicated, the configuration is not. TTL needs to be configured manually on every instance that can become MAIN. If an instance is a REPLICA, the TTL background job will be paused until the instance becomes MAIN.