@@ -89,6 +89,28 @@ export class Mongo {
8989 * @param {object } store - A game state to persist.
9090 */
9191 async set ( id , state ) {
92+ // Don't set a value if the cache has a more recent version.
93+ // This can occur due a race condition.
94+ //
95+ // For example:
96+ //
97+ // A --sync--> server | DB => 0 --+
98+ // |
99+ // A <--sync-- server | DB => 0 --+
100+ //
101+ // B --sync--> server | DB => 0 ----+
102+ // |
103+ // A --move--> server | DB <= 1 --+ |
104+ // | |
105+ // A <--sync-- server | DB => 1 --+ |
106+ // |
107+ // B <--sync-- server | DB => 0 ----+
108+ //
109+ const cacheValue = this . cache . get ( id ) ;
110+ if ( cacheValue && cacheValue . _stateID >= state . _stateID ) {
111+ return ;
112+ }
113+
92114 this . cache . set ( id , state ) ;
93115
94116 const col = this . db . collection ( id ) ;
@@ -105,9 +127,9 @@ export class Mongo {
105127 * if no game is found with this id.
106128 */
107129 async get ( id ) {
108- const item = this . cache . get ( id ) ;
109- if ( item !== undefined ) {
110- return item ;
130+ let cacheValue = this . cache . get ( id ) ;
131+ if ( cacheValue !== undefined ) {
132+ return cacheValue ;
111133 }
112134
113135 const col = this . db . collection ( id ) ;
@@ -117,7 +139,27 @@ export class Mongo {
117139 . limit ( 1 )
118140 . toArray ( ) ;
119141
120- this . cache . set ( id , docs [ 0 ] ) ;
142+ let oldStateID = 0 ;
143+ cacheValue = this . cache . get ( id ) ;
144+ /* istanbul ignore next line */
145+ if ( cacheValue !== undefined ) {
146+ /* istanbul ignore next line */
147+ oldStateID = cacheValue . _stateID ;
148+ }
149+
150+ let newStateID = - 1 ;
151+ if ( docs . length > 0 ) {
152+ newStateID = docs [ 0 ] . _stateID ;
153+ }
154+
155+ // Update the cache, but only if the read
156+ // value is newer than the value already in it.
157+ // A race condition might overwrite the
158+ // cache with an older value, so we need this.
159+ if ( newStateID >= oldStateID ) {
160+ this . cache . set ( id , docs [ 0 ] ) ;
161+ }
162+
121163 return docs [ 0 ] ;
122164 }
123165
@@ -127,8 +169,8 @@ export class Mongo {
127169 * @returns {boolean } - True if a game with this id exists.
128170 */
129171 async has ( id ) {
130- const item = this . cache . get ( id ) ;
131- if ( item !== undefined ) {
172+ const cacheValue = this . cache . get ( id ) ;
173+ if ( cacheValue !== undefined ) {
132174 return true ;
133175 }
134176
0 commit comments