@@ -154,36 +154,40 @@ class GridstoreStorage {
154154 calculatedFileContentHash = args [ 2 ] ;
155155 }
156156
157+ const finalizeCallback = ( ) => {
158+ if ( returned ) {
159+ // might be already finished if retrying after delay
160+ return ;
161+ }
162+
163+ returned = true ;
164+ if ( calculatedFileContentHash ) {
165+ this . updateFileWithContentHashMetadata ( args , hash , calculatedFileContentHash , callback ) ;
166+ return ;
167+ }
168+
169+ callback ( ...args ) ;
170+ } ;
171+
157172 if ( storeLock ) {
158173 log . silly ( 'GridStore' , '[%s] UNLOCK lock=%s status=%s' , instance , lockId , storeLock . success ? 'locked' : 'empty' ) ;
174+
159175 if ( storeLock . success ) {
160- this . lock . releaseLock ( storeLock , ( ) => {
161- if ( returned ) {
162- // might be already finished if retrying after delay
163- return ;
164- }
165- if ( calculatedFileContentHash ) {
166- // locked upload, new file
167- this . updateFileWithContentHashMetadata ( args , hash , calculatedFileContentHash , callback ) ;
168- return ; // return from attachmentCallback. Top level callback will be ran after hash update
169- }
170- } ) ;
171- // unset variable to prevent double releasing
172- storeLock = false ;
173- return ;
176+ // lock acquired
177+ this . lock . releaseLock ( storeLock , finalizeCallback ) ;
174178 }
179+
180+ if ( ! storeLock . success ) {
181+ // lock was not acquired
182+ finalizeCallback ( ) ;
183+ }
184+
185+ // unset variable to prevent double releasing
175186 storeLock = false ;
176- }
177- if ( returned ) {
178- // might be already finished if retrying after delay
179187 return ;
180188 }
181- if ( calculatedFileContentHash ) {
182- // no lock upload, new file
183- this . updateFileWithContentHashMetadata ( args , hash , calculatedFileContentHash , callback ) ;
184- return ; // return from attachmentCallback. Top level callback will be ran after hash update
185- }
186- callback ( ...args ) ;
189+
190+ finalizeCallback ( ) ;
187191 } ;
188192
189193 let tryCount = 0 ;
@@ -245,7 +249,6 @@ class GridstoreStorage {
245249 if ( returned ) {
246250 return ;
247251 }
248- returned = true ;
249252 return attachmentCallback ( err ) ;
250253 }
251254
@@ -266,56 +269,56 @@ class GridstoreStorage {
266269 if ( returned ) {
267270 return ;
268271 }
269- if ( err . code === 11000 ) {
270- // most probably a race condition, try again
271- if ( tryCount ++ < 5 ) {
272- if ( / \. c h u n k s / . test ( err . message ) ) {
273- // Partial chunks detected. Might be because of:
274- // * another process is inserting the same attachment and thus no "files" entry yet (should not happened though due to locking)
275- // * previously deleted attachment that has not been properly removed
276-
277- // Load data for an existing chunk to see the age of it
278- return this . gridfs . collection ( this . bucketName + '.chunks' ) . findOne (
279- {
280- files_id : hash
281- } ,
282- {
283- projection : {
284- _id : true
285- }
286- } ,
287- ( err , data ) => {
288- if ( err ) {
289- // whatever
290- return setTimeout ( tryStore , 100 + 200 * Math . random ( ) ) ;
291- }
292-
293- if ( ! data || ! data . _id ) {
294- // try again, no chunks found
295- return setTimeout ( tryStore , 10 ) ;
296- }
272+ // most probably a race condition, try again
273+ if ( tryCount ++ < 5 ) {
274+ if ( / \. c h u n k s / . test ( err . message ) ) {
275+ // Partial chunks detected. Might be because of:
276+ // * another process is inserting the same attachment and thus no "files" entry yet (should not happened though due to locking)
277+ // * previously deleted attachment that has not been properly removed
278+
279+ // Load data for an existing chunk to see the age of it
280+ return this . gridfs . collection ( this . bucketName + '.chunks' ) . findOne (
281+ {
282+ files_id : hash
283+ } ,
284+ {
285+ projection : {
286+ _id : true
287+ }
288+ } ,
289+ ( err , data ) => {
290+ if ( err ) {
291+ // whatever
292+ return setTimeout ( tryStore , 100 + 200 * Math . random ( ) ) ;
293+ }
297294
298- // Check how old is the previous chunk
299- let timestamp = data . _id . getTimestamp ( ) ;
300- if ( timestamp && typeof timestamp . getTime === 'function' && timestamp . getTime ( ) >= Date . now ( ) - 5 * 60 * 1000 ) {
301- // chunk is newer than 5 minutes, assume race condition and try again after a while
302- return setTimeout ( tryStore , 300 + 200 * Math . random ( ) ) ;
303- }
295+ if ( ! data || ! data . _id ) {
296+ // try again, no chunks found
297+ return setTimeout ( tryStore , 10 ) ;
298+ }
304299
305- // partial chunks for a probably deleted message detected, try to clean up
306- setTimeout ( ( ) => {
307- if ( returned ) {
308- return ;
309- }
310- this . cleanupGarbage ( id , tryStore ) ;
311- } , 100 + 200 * Math . random ( ) ) ;
300+ // Check how old is the previous chunk
301+ let timestamp = data . _id . getTimestamp ( ) ;
302+ if ( timestamp && typeof timestamp . getTime === 'function' && timestamp . getTime ( ) >= Date . now ( ) - 5 * 60 * 1000 ) {
303+ // chunk is newer than 5 minutes, assume race condition and try again after a while
304+ return setTimeout ( tryStore , 300 + 200 * Math . random ( ) ) ;
312305 }
313- ) ;
314- }
306+
307+ // partial chunks for a probably deleted message detected, try to clean up
308+ setTimeout ( ( ) => {
309+ if ( returned ) {
310+ return ;
311+ }
312+ this . cleanupGarbage ( id , tryStore ) ;
313+ } , 100 + 200 * Math . random ( ) ) ;
314+ }
315+ ) ;
316+ } else {
315317 return setTimeout ( tryStore , 10 ) ;
316318 }
319+ } else {
320+ attachmentCallback ( err ) ;
317321 }
318- attachmentCallback ( err ) ;
319322 } ) ;
320323
321324 store . once ( 'finish' , ( ) => attachmentCallback ( null , id , fileHashCalculator . hash ) ) ;
0 commit comments