Key Level TTL for Hazelcast Map replace function

94 Views Asked by At

I have a requirement where I need to set a key level TTL for my hazelcast Imap backed by an external store. Now we use replace(object, object, object) a way of optimistic locking to update the value in the map.

I am using EntryStore implantation for the external store so that the value is MetadataAware.

What can I do to send TTL along with the value to Hazelcast and EntryStore implementations?

Hazelcast version: 5.2.4

I have two options but confused about both -

  1. use Imap.setTTL Not sure if this triggers MapStore methods though.

  2. Use MetadataAwareValue in the replace call I have my serious doiubts about the feasibility of this.

1

There are 1 best solutions below

0
Orçun Çolak On

Assume that you have an EntryStore like this

EntryStore<String, MyRecord> {
  private static final Logger LOGGER = LoggerFactory.getLogger(EntryStoreTest.class);

  @Override
  public void store(String key, MetadataAwareValue<MyRecord> value) {
    LOGGER.info("store is called with expiration time {}", 
    value.getExpirationTime());
    ...
  }
  ...
}

If you call

 map.put(KEY, value, 5, TimeUnit.SECONDS);

You are going to see that the expiration time is passed to EntryStore. You will see a log like this

store is called with expiration time 1695713821941

When you replace you need to call IMap#setTtl as below

 map.replace(KEY, value, newvalue);
 map.setTtl(KEY, 5, TimeUnit.SECONDS);

Then you will see two logs as below

store is called with expiration time 9223372036854775807
store is called with expiration time 1695713821982

The first log is for the replace call. Because replace does not allow a TTL to be passed.
The second log is for the setTtl call. Now you will have your expiration time again

Note : Setting Ttl on the map entry does not trigger EntryStore. Add a listener to your IMap

IMap<String, MyRecord> map = ...

EntryAdapter<String, MyRecord> stringMyRecordEntryAdapter = new EntryAdapter<>() {
  @Override
  public void entryExpired(EntryEvent<String, MyRecord> event) {
    LOGGER.info("entryExpired {} {}", event.getOldValue(), event.getValue());
  }
};

map.addEntryListener(stringMyRecordEntryAdapter, true);

You will see that entry expires but EntryStore#delete is not triggered. I am not sure why it behaves like this though. Probably EntryStore expiration logic is left to implementor