Skip to content

asMap() compute and the Weigher #513

@boschb

Description

@boschb

Hi Ben,

Using Caffeine 2.8.5 currently.

I'm trying to utilize the 'compute' varients (specifically computeIfPresent()) of the concurrent map from asMap() such that it will update the weight for the Weigher based eviction. I'm writing tests to see the functionality, but it's hard to know if Eviction is working correctly when things are updated in this way. Here is one strange behavior that I found already:

  @Test
  public void asMap_computeEvictionIssue() {
    LoadingCache<Long, Integer> cache =
        Caffeine.newBuilder()
            .maximumWeight(3)
            .<Long, Integer>weigher((k, v) -> v)
            .recordStats()
            .executor(MoreExecutors.directExecutor())
            .build(key -> 1);

    assertThat(cache.get(1L)).isNotNull();
    assertThat(cache.get(2L)).isNotNull();
    assertThat(cache.get(3L)).isNotNull();
    assertThat(cache.stats().evictionWeight()).isEqualTo(0); // nothing evicted yet

    // Real Test
    cache
        .asMap()
        .computeIfPresent(1L, (id, integer) -> 2); // Update id-1 with weight 2
    assertThat(cache.stats().evictionWeight()).isEqualTo(2); // the just computed is gone!
    assertThat(cache.getIfPresent(1L)).isEqualTo(2); // FIXME: isNull() currently!!
  }

  @Test
  public void putEvictionIssue() {
    LoadingCache<Long, Integer> cache =
        Caffeine.newBuilder()
            .maximumWeight(3)
            .<Long, Integer>weigher((k, v) -> v)
            .recordStats()
            .executor(MoreExecutors.directExecutor())
            .build(key -> 1);

    assertThat(cache.get(1L)).isNotNull();
    assertThat(cache.get(2L)).isNotNull();
    assertThat(cache.get(3L)).isNotNull();
    assertThat(cache.stats().evictionWeight()).isEqualTo(0); // nothing evicted yet

    // Real Test
    cache.put(1L, 2); // Update id-1 with weight 2
    assertThat(cache.stats().evictionWeight()).isEqualTo(2); // the just put is gone!
    assertThat(cache.getIfPresent(1L)).isEqualTo(2); // FIXME: isNull() currently!!
  }

Essentially I want to re-weigh a value and it appears the safest way to do that is to to update the value with a new value. Ideally in a compute() context, but I suppose I could settle for PUT in this case and just accept the race condition. Put appears none better however.

Any pointers on getting this update to values and weight correct?

Also I noticed that calling cleanUp() allows eviction to happen when utilizing compute() changes, but I have no idea how heavy a hammer this is? Does cleanUp() internally re-compute all weights?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions