Skip to content

Commit 5a9dfca

Browse files
author
Oliver Rumbelow
authored
Merge pull request #35 from holidayextras/deadlocks
Prevent ghost rows in the database
2 parents 5c57c9d + 1d6dc7a commit 5a9dfca

File tree

3 files changed

+29
-15
lines changed

3 files changed

+29
-15
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
- 2016-07-11 - v1.2.5
2+
- 2016-07-11 - Fixing bug when concurrently updating the same resource id
13
- 2016-07-04 - v1.2.4
24
- 2016-07-04 - Use stricter MySQL transaction isolation READ_COMMITTED
35
- 2016-07-01 - v1.2.3

lib/sqlHandler.js

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,12 @@ SqlStore.prototype.populate = function(callback) {
8080
self.baseModel.sync().asCallback(cb);
8181
},
8282
function(cb) {
83-
async.each(self.relationArray, function(model, ecb) {
83+
async.eachSeries(self.relationArray, function(model, ecb) {
8484
model.sync().asCallback(ecb);
8585
}, cb);
8686
},
8787
function(cb) {
88-
async.each(self.resourceConfig.examples, function(exampleJson, ecb) {
88+
async.eachSeries(self.resourceConfig.examples, function(exampleJson, ecb) {
8989
var validation = Joi.validate(exampleJson, self.resourceConfig.attributes);
9090
if (validation.error) return ecb(validation.error);
9191
self.create({ request: { type: self.resourceConfig.resource } }, validation.value, ecb);
@@ -225,6 +225,15 @@ SqlStore.prototype._fixObject = function(json) {
225225

226226
SqlStore.prototype._errorHandler = function(e, callback) {
227227
// console.log(e, e.stack);
228+
if (e.message.match(/^ER_LOCK_DEADLOCK/)) {
229+
return callback({
230+
status: "500",
231+
code: "EMODIFIED",
232+
title: "Resource Just Changed",
233+
detail: "The resource you tried to mutate was modified by another request. Your request has been aborted."
234+
});
235+
}
236+
228237
return callback({
229238
status: "500",
230239
code: "EUNKNOWN",
@@ -321,7 +330,7 @@ SqlStore.prototype._dealWithTransaction = function(done, callback) {
321330
});
322331
};
323332
var rollback = function(e) {
324-
debug("Err", e);
333+
debug("Err", transaction.name, e);
325334
var a = function() {
326335
if (e instanceof Error) return self._errorHandler(e, done);
327336
return done(e);
@@ -338,9 +347,12 @@ SqlStore.prototype._dealWithTransaction = function(done, callback) {
338347
};
339348

340349
SqlStore.prototype._clearAndSetMany = function(relationModel, prop, theResource, keyName, ucKeyName, t, taskCallback) {
341-
async.map(theResource[keyName] || [], function(deadRow, acallback) {
342-
deadRow.destroy(t).asCallback(acallback);
343-
}, function(deleteError) {
350+
var whereClause = { };
351+
whereClause[theResource.type + "Id"] = theResource.id;
352+
relationModel.destroy({
353+
where: whereClause,
354+
transaction: t.transaction
355+
}).asCallback(function(deleteError) {
344356
if (deleteError) return taskCallback(deleteError);
345357

346358
async.map(prop, function(item, acallback) {
@@ -354,7 +366,12 @@ SqlStore.prototype._clearAndSetMany = function(relationModel, prop, theResource,
354366
};
355367

356368
SqlStore.prototype._clearAndSetOne = function(relationModel, prop, theResource, keyName, ucKeyName, t, taskCallback) {
357-
var next = function(deleteError) {
369+
var whereClause = { };
370+
whereClause[theResource.type + "Id"] = theResource.id;
371+
relationModel.destroy({
372+
where: whereClause,
373+
transaction: t.transaction
374+
}).asCallback(function(deleteError) {
358375
if (deleteError) return taskCallback(deleteError);
359376
if (!prop) {
360377
theResource["set" + ucKeyName](null, t).asCallback(taskCallback);
@@ -365,12 +382,7 @@ SqlStore.prototype._clearAndSetOne = function(relationModel, prop, theResource,
365382
theResource["set" + ucKeyName](newRelationModel, t).asCallback(taskCallback);
366383
});
367384
}
368-
}
369-
if (theResource[keyName]) {
370-
theResource[keyName].destroy(t).asCallback(next);
371-
} else {
372-
next();
373-
}
385+
});
374386
};
375387

376388
SqlStore.prototype._clearAndSetRelationTables = function(theResource, partialResource, t, callback) {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jsonapi-store-relationaldb",
3-
"version": "1.2.4",
3+
"version": "1.2.5",
44
"description": "Relational data store for jsonapi-server.",
55
"keywords": [
66
"json:api",
@@ -35,7 +35,7 @@
3535
"blanket": "1.1.9",
3636
"coveralls": "^2.11.9",
3737
"eslint": "^2.11.0",
38-
"jsonapi-server": "^1.15.0",
38+
"jsonapi-server": "^1.15.4",
3939
"mocha": "^2.5.3",
4040
"mocha-lcov-reporter": "^1.2.0",
4141
"mocha-performance": "^0.1.1",

0 commit comments

Comments
 (0)