I've got something like, ```object FileCache { ...
# getting-started
y
I've got something like,
Copy code
object FileCache {
    private val contentOf: MutableMap<Path, String>
    // ...
}
which is shared and has a function to read file contents, which given a
Path
would serve the data from
contentOf
if it's already there, or otherwise open the file, read the content to the map, then serve that. some questions about the design: 1. is there a problem with serving `String`s? should I be giving out
StringReader
or something like that? (if so, why?) 2. am I correct that it's enough to lock the object (
synchronized(this)
) only when mutating
contentOf
(so only when initializing it with file content if it's not already in the map), and that I can do
contentOf.get(...)
without locks? 3. any glaring problems with this design? it seems pretty naive. I will also note that I don't expect files to be very large here, nor do I expect the map to have a very large number of entries
s
1. If you want to cache the contents of the file then keeping a
String
is the right thing to do. A
Reader
just provides a way to read from the file, so caching the
Reader
wouldn't help to reduce the number of reads. 2. No, you would still need to lock on all accesses. With a regular mutable map, the data structure is not in a consistent state during mutations, and you might get incorrect behavior or exceptions if you try to call
get
while a write is in progress. If you're on Java, there are some built-in solutions for problems like this, e.g.
Collections.synchronizedMap
which locks the map during all accesses, and
ConcurrentMap
which locks parts of the map while still allowing some concurrent access. With both you can also use methods like
Map.computeIfAbsent
, which is a good way to do a "get or put" without introducing races.
1
👍 1
j
1. It depends on what type of file/content you're returning, and more specifically if the clients of your cache will always read the whole file or not. Also, if you cache the whole thing in memory anyway, there is no point in doing anything fancy and strings are fine. If you changed this and only cached what is actually read by clients, things would get much more complicated. 2. It's not enough. You need to protect get access too 3. Do you actually need a cache?
👍 1
e
3. all modern OSes have a file or buffer cache, which can manage shrinking under memory pressure and so on better than a map inside your application can
👍 2
c
If you really want to use caching here (as mentioned by other users, you possibly do not need it), I have a multiplatform library that does this with expiration policies: https://opensavvy.gitlab.io/pedestal/api-docs/cache/index.html
👍 1