-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Segmentation Fault with Projection API #37
Comments
I'll take a look this afternoon! JD
|
Currently, we restrict relationships to use foreign keys. There is no foreign key called fk_id1. There should be a better error message. I'll create a test case for this. How should the foreign key fk_id1 be defined? |
Apologies! I omitted that from my original post. We have a foreign key constraint called "fk_id" that makes "id1" on the associations table a foreign key that references "id" on the objects table. |
I don't see the segfault, but I do (without the foreign key) see this error message: { [Error: I also have a hunch that PARTITION BY KEY may cause a problem, so I'd suggest removing PARTITION BY KEY from both tables, getting the app to work, and then putting it back and testing again. (The issue here is just that the partition key and the primary key in NDB are usually interchangable, but we don't currently have tests for cases where they are not, just because effectively testing it requires a larger cluster than we have in our usual dev environments). |
Right that's the error I get when I put the incorrect foreign key as well. Again sorry for omitting that from the original post. I'm curious to see what happens for you when you make "id1" on the associations table a foreign key that references the "id" column on the objects table. In the mean time I'll try and remove the partition and see if that changes things. Thanks! |
John, Your hunch was right and the partitions were the root cause of my issue. Removing them and switching the connection properties from ndb to mysql made everything work perfectly! As soon as I re-added the partition i got the following error:
|
Ok. We will add a test case that includes partition by key. |
Hi David, Two questions here!
|
Okay so in order: Craig, I removed the partition on the table with the foreign key (keeping the one on referencing table) and it still gave me issues. After I removed the referencing table's partitioning it worked again. John here are my current show create tables (without partitioning on id_company):
node: ../impl/src/ndb/NdbRecordObject.cpp:76: NdbRecordObject::NdbRecordObject(const Record_, ColumnHandlerSet_, const Arguments&): Assertion `nblobs == record->getNoOfBlobColumns()' failed. |
Awesome thanks! Should I close this issue then? |
It looks to me like the example code hangs after fetching the result. You can call session.close() at the end of a session, and jones.closeAllOpenSessionFactories() at the end of the script, to disconnect from the database and allow the session to close. If everything here is resolved you are welcome to close the issue, and I'll keep working on 38. |
Hi John, I changed my openSession function block to be jones.openSession(connectionProperties).then(
function(session) {
return session.find(objectProjection, {id: 1});
}).
then(console.log, console.trace).
then(jones.closeAllOpenSessionFactories).
then(process.exit, console.trace); and with ndb as the connection property I'm getting issue 38. With 'mysql' I'm getting the
|
Here's a bit about the specific problem in #38. When you create a column of type JSON in MySQL, you don't have a chance to specify a maximum length for the column. So the basic type of a JSON column is actually BLOB, and the JSON content is stored using MySQL's wl#8132 binary encoding for JSON. Unfortunately, support for BLOB columns is limited in some ways, and one of the limits in NDB is that the push-down-join interface (which we call "SPJ", for Select/Project/Join) does not support them. Because jones-ndb uses SPJ to support the join query on Objects and Associations, it cannot both execute the join and fetch the BLOB (or JSON) columns in a single operation. There are many possible work-arounds. Here are a few that come to mind:
|
Hey John, Thank you for looking into this for me. I tried to do the third work-around by omitting the JSON columns from the addfields() function, but I'm still getting the same error with the assertion failing. Do I need to get the latest version from Github to make that work-around work? Thanks |
No, I don't think you need to update. I expect you to be able to run the join if the mappings & projections do not include the JSON columns. But I also see that it's not working as expected, so I'll look into it. |
I'm going to look into the mysql bug issue reported above: /api_tests/mysql-js/node_modules/mysql/lib/protocol/Parser.js:78 |
There are a some tricky parts to getting the "load the JSON fields later" workaround right. You have to set mapAllColumns=false on the TableMappings to really exclude the JSON columns; you have to have a "do-nothing" constructor like Object() {} because session.find calls your constructor with no arguments and does not allow you to clobber any of the data that was just read; and you should do the Projection find and the batch load within one transaction so that they see a consistent view of the data. Later this morning when I get a chance I will work up a code example for you showing all of this together. |
I think it would be better if the adapter would "load the JSON fields later". For queries, once the values are loaded, the adapter can internally execute a second operation with the JSON fields that exceed the inline size. |
Yes, I definitely agree with that. |
Sounds good John, I will wait for your example before I proceed. Thank you guys for all the work you've been putting in to help us out! |
"use strict";
//require("unified_debug").level_debug();
var jones = require("./database-jones");
var connectionProperties = new jones.ConnectionProperties("ndb");
connectionProperties.database = 'graph';
/* A no-op constructor for object and association that have key fields only.
session.find() will call these constructors with no arguments.
The "Basic" constructor has only key fields mapped.
*/
function BasicObject() {}
function BasicAssociation() {}
/* The "Full" constructor has a default mapping with all fields mapped.
We will call the constructor with a key-only object.
Then we can use load() to load the non-key fields from the database.
*/
function FullAssociation(basicAssociation) {
if(basicAssociation) {
this.id_company = basicAssociation.id_company;
this.id1 = basicAssociation.id1;
this.atype = basicAssociation.atype;
this.id2 = basicAssociation.id2;
}
}
function FullObject(basicObject) {
if(basicObject) {
this.id = basicObject.id;
this.id_company = basicObject.id_company;
this.assoc = [];
if(Array.isArray(basicObject.assoc)) {
basicObject.assoc.forEach(function(basicAssoc, n) {
this.assoc[n] = new FullAssociation(basicAssoc);
}, this);
}
}
}
/* Mappings for the "basic" objects have key fields only */
var objectMapping = new jones.TableMapping("objects");
objectMapping.mapAllColumns = false; // important so there are no BLOBs!
objectMapping.mapField("id");
objectMapping.mapField("id_company");
objectMapping.mapOneToMany({
fieldName: "assoc",
target: BasicAssociation,
targetField: "obj_assoc"
});
objectMapping.applyToClass(BasicObject);
var associationMapping = new jones.TableMapping("associations");
associationMapping.mapAllColumns = false;
associationMapping.mapField("id_company");
associationMapping.mapField("id1");
associationMapping.mapField("atype");
associationMapping.mapField("id2");
associationMapping.mapManyToOne({
fieldName: "obj_assoc",
target: BasicObject,
foreignKey: "fk_id1"
});
associationMapping.applyToClass(BasicAssociation);
/* Projections: */
var associationProject = new jones.Projection(BasicAssociation)
.addFields("id_company", "id1", "atype", "id2");
var objectProjection = new jones.Projection(BasicObject)
.addFields("id", "id_company").addRelationship("assoc", associationProject);
/* Apply a default mapping to the "full" classes */
new jones.TableMapping("objects").applyToClass(FullObject);
new jones.TableMapping("associations").applyToClass(FullAssociation);
/* Here we go: */
var session, batch, fullObject;
jones.openSession(connectionProperties).then(function(_session) {
session = _session;
/* Start a transaction so that the projection read and the batch read
have a single consistent view of the database */
session.currentTransaction().begin();
return session.find(objectProjection, {id: 1});
}).then(function(result) {
console.log("Intermediate result:", result);
/* Build a FullObject from the result, and, in a batch, load the object
and all its associations
*/
fullObject = new FullObject(result);
batch = session.createBatch();
batch.load(fullObject); // load the parent
fullObject.assoc.forEach(function(assoc) {
batch.load(assoc);
});
return batch.execute();
}).then(function() {
console.log("Full result:");
console.log(fullObject); /* success */
}, function(error) {
console.trace(error); /* failure of any step up to this point */
}).then(function() {
/* Close the transaction */
if(session) {
console.log("Closing transaction.");
return session.currentTransaction().commit();
}
}).then(function() {
jones.closeAllOpenSessionFactories();
}); |
That's great thank you so much John! I will use this example and hopefully build off this to meet our needs. Should I close this issue or are you guys still looking into some related bugs? |
This patch will fix the bug: It would fail on using any table defined with PARTITION BY KEY. |
Looks like all issues related to this are resolved. |
Hey guys,
I believe I have set everything up correctly, but the only response I'm getting from the console when I run the script is "Segmentation fault". Here are the versions I'm running:
Software Versioning
mysql-js: up-to-date as of August 5th, 2016
node version: v0.12.2
MySQL Cluster version: 7.5.3
MySql Cluster Table Set-up
CREATE TABLE 'graph'.'objects' ( 'id_company' INT NOT NULL COMMENT '', 'id' BIGINT(20) NOT NULL COMMENT '', 'otype' VARCHAR(45) NOT NULL COMMENT '', 'data' JSON, 'data2' JSON, PRIMARY KEY ('id_company','id', 'otype') COMMENT '') ENGINE=NDBCLUSTER PARTITION BY KEY(id_company);
CREATE TABLE 'graph'.'associations' ( 'id_company' INT NOT NULL COMMENT '', 'id1' BIGINT(20) NOT NULL COMMENT '', 'atype' BIGINT(20) NOT NULL COMMENT '', 'id2' BIGINT(20) NOT NULL COMMENT '', 'time' DATETIME NULL DEFAULT NOW() COMMENT '', 'data' JSON , PRIMARY KEY ('id_company', 'id1', 'atype', 'id2') COMMENT '') ENGINE=NDBCLUSTER PARTITION BY KEY(id_company);
Objects has a one-to-many relationship with associations.
App.js Code
The text was updated successfully, but these errors were encountered: