4

I have a simple mapping table in a database that associates integer keys with certain values. Once I stick the values in the table, they never go away. I'd like to use a Guava Cache so that these keys can be looked up once and then stay stored in memory. It looks likea Guava Cache will allow me to do this easily. However I need to map both ways: from key to value, and from value to key, like a BiMap.

Is there a simple way to get BiMap functionality using a Cache, or will I have to roll my own solution?

Is there a BiMap implementation that allows concurrent access, or will I have to use read-write locks if I want efficient, multi-threaded access?

Garret Wilson
  • 18,219
  • 30
  • 144
  • 272

1 Answers1

2

Is there a simple way to get BiMap functionality using a Cache, or will I have to roll my own solution?

There's Maps.synchronizedBiMap, but I don't think that it's good starting point, as adding all the Cache capabilities is probably way harder than adding the Bi to a Cache.

It's also just synchronized, not concurrent.

Is there a BiMap implementation that allows concurrent access,

AFAIK no.

or will I have to use read-write locks if I want efficient, multi-threaded access?

I guess, it depends of what part of the BiMap functionality you need. The BiMap allows you

  • to get and put in both directions
  • to preserve bijectivity either via forcePut or via put throwing an exception on conflicts

If you're sure that no conflicts may ever happen, then it's not that complicated. Maybe all you need is to piggyback two caches like I did here.


AFAIK for preserving bijectivity, you'd need locks. If writes are not too common, then you're done quickly with a single ReadWriteLock. Otherwise....

You could try to use Striped for maximum concurrency, but I'm afraid, it's too tricky as you'd need to lock a stripe depending on both the key and the value. And also on previous value in case of forcePut.


Whenever I used BiMap, I found out later either that I actually need to get something in more than two different ways (some secondary key) or that I need to get some additional information. So I converted it to two or three maps in a class like

void put(K1 k1, K2 k2, E extraInfo) {
    MyEntry<K1, K2, E> e = new MyEntry<>(k1, k2, extraInfo);
    firstMap.put(k1, e);
    secondMap.put(k2, e);
}

MyEntry<K1, K2, E> getByFirstKey(K1 k1);
MyEntry<K1, K2, E> getBySecondKey(K2 k2);

It's a bit hacky, but simple and maybe it applies to your cache as well.

maaartinus
  • 44,714
  • 32
  • 161
  • 320