mirror of
https://github.com/nodemailer/wildduck.git
synced 2024-12-27 02:10:52 +08:00
fix condition where message was not inserted if a partially stored attachment already existed
This commit is contained in:
parent
29c7311fbf
commit
f117a6f6d9
2 changed files with 33 additions and 6 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -4,6 +4,7 @@ npm-debug.log
|
|||
.npmrc
|
||||
config/production.*
|
||||
config/development.*
|
||||
package-lock.json*
|
||||
|
||||
emails/*
|
||||
!emails/README.md
|
||||
|
|
|
@ -35,9 +35,7 @@ class GridstoreStorage {
|
|||
|
||||
create(attachment, hash, callback) {
|
||||
hash = Buffer.from(hash, 'hex');
|
||||
|
||||
let returned = false;
|
||||
let retried = false;
|
||||
|
||||
let id = hash;
|
||||
let metadata = {
|
||||
|
@ -52,6 +50,7 @@ class GridstoreStorage {
|
|||
}
|
||||
});
|
||||
|
||||
let tryCount = 0;
|
||||
let tryStore = () => {
|
||||
this.gridfs.collection(this.bucketName + '.files').findOneAndUpdate({
|
||||
_id: hash
|
||||
|
@ -84,8 +83,11 @@ class GridstoreStorage {
|
|||
}
|
||||
if (err.code === 11000) {
|
||||
// most probably a race condition, try again
|
||||
if (!retried) {
|
||||
retried = true;
|
||||
if (tryCount++ < 5) {
|
||||
if (/attachments\.chunks /.test(err.message)) {
|
||||
// partial chunks for a probably deleted message detected, try to clean up
|
||||
return setTimeout(() => this.cleanupGarbage(id, tryStore), 100 + 200 * Math.random());
|
||||
}
|
||||
return setTimeout(tryStore, 10);
|
||||
}
|
||||
}
|
||||
|
@ -205,8 +207,8 @@ class GridstoreStorage {
|
|||
// make sure that we do not delete a message that is already re-used
|
||||
'metadata.c': 0,
|
||||
'metadata.m': 0
|
||||
}, (err, result) => {
|
||||
if (err || !result.deletedCount) {
|
||||
}, err => {
|
||||
if (err) {
|
||||
return processNext();
|
||||
}
|
||||
|
||||
|
@ -227,6 +229,30 @@ class GridstoreStorage {
|
|||
|
||||
processNext();
|
||||
}
|
||||
|
||||
cleanupGarbage(id, next) {
|
||||
this.gridfs.collection('attachments.files').findOne({
|
||||
_id: id
|
||||
}, (err, file) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
if (file) {
|
||||
// attachment entry exists, do nothing
|
||||
return next(null, false);
|
||||
}
|
||||
|
||||
// orphaned attachment, delete data chunks
|
||||
this.gridfs.collection('attachments.chunks').deleteMany({
|
||||
files_id: id
|
||||
}, (err, info) => {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
next(null, info.deletedCount);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GridstoreStorage;
|
||||
|
|
Loading…
Reference in a new issue