6
As part of a test I was asked to develop an application to manage high Scores in environments with high competition. This application should not persist on disk or use libraries and frameworks external. Basically the requirements say that:
- Optimizing memory and CPU usage is critical
- the service will receive a stellar number of requests simultaneous
- for the http part we should use the class Httpserver.
The application is basically a set of Rest services for the user:
- log in (you must return a token and keep the user authenticated for 10 minutes)
- post a high score to a certain level
- get a list of high Scores to a certain level (in order)
The system should only return 15 high Scores for each level, the high Scores are unique for each pair User / Level (ie for phase x the user y should only own one high score).
Considering the functional and non-functional requirements I thought of the following data structure to store high Scores (with minimum retention):
// Mapa que liga um nivel a uma lista ordenada de High Scores
private static final Map<Integer, ConcurrentSkipListSet<HighScore>> scores =
new ConcurrentHashMap<>();
// Conjunto de usuários autenticados
private static final Set<AuthToken> authorized =
Collections.newSetFromMap(new ConcurrentHashMap<AuthToken, Boolean>());
While this data structure seems efficient in reducing retention I don’t know how much it ends up wasting memory internally.
In the same way, the ConcurrentSkipListSet
allow orderly insertion in log(n)
and make the implementation of the method that returns high Scores trivial.
On the other hand, to limit the Set
to the top 15 high Scores by level (to avoid memory wastage and crashes), I did a real gymnastics including the use of Atomicinteger to count the amount of high Scores by level (the method size
of ConcurrentSkipListSet
is costly) and the need to synchronize multiple points with Locks.
In short, I’m not convinced that I’m using the most efficient strategy to solve the problem and I’m not used to thinking at such a low level...
In the "real" world would solve this problem in a trivial way with the use of a container Jetty, a Servlet for logging in and storing authentication in the session and probably a database Embedded like the H2. Unfortunately I’m not allowed to wear any of that.
In this way, how would you approach a problem of this kind given the constraints technology artificials? What data structures would you use (or develop your own?)? My strategy is "good enough" for the problem or I traveled in solution?
P.S. That problem submitted to Code Review looks a lot like what I’m solving (and the solution was similar to mine too).
I suppose it’s outside its scope a case where the same user submits a high score minor that another submitted previously, right? (even because it would not make sense...) Similarly, a submitted score cannot be removed, right? (I wonder if you can even safely rule out the 16th forward result)
– mgibsonbr
@mgibsonbr, exactly. A single score per user / level (the largest) and there is no front to delete a high-score. We can safely rule out results beyond the fifteenth.
– Anthony Accioly