Skip to content
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

Refactor/kvao flush to deleteAll #1214

Merged
merged 1 commit into from
Jan 10, 2017
Merged

Refactor/kvao flush to deleteAll #1214

merged 1 commit into from
Jan 10, 2017

Conversation

superkhau
Copy link
Contributor

@superkhau superkhau commented Jan 6, 2017

Aggregate pull request for refactoring kvao.flush to kvao.deleteAll. Implementation consists of 3 parts:

  • delete
  • deleteAll
  • Fall back deleteAll

@superkhau superkhau self-assigned this Jan 6, 2017
@superkhau superkhau requested a review from bajtos January 6, 2017 02:42
@superkhau superkhau added this to the Sprint 26 milestone Jan 6, 2017
@superkhau superkhau force-pushed the refactor/kvao-flush branch 4 times, most recently from 5e1615d to b998dd4 Compare January 6, 2017 04:28
@superkhau superkhau changed the title Refactor/kvao flush Refactor/kvao flush to deleteAll Jan 6, 2017
@superkhau superkhau force-pushed the refactor/kvao-flush branch 3 times, most recently from ad9c691 to 6c3d63b Compare January 6, 2017 07:39
@superkhau
Copy link
Contributor Author

superkhau commented Jan 6, 2017

@rmg I think something is wrong with CI, PTAL. Could be NPM though because I see npm ERR! 404 no such package available : inherits in the logs, could be something wrong with internal registry.

@superkhau
Copy link
Contributor Author

@slnode test please

if (typeof connector.deleteAll === 'function') {
connector.deleteAll(this.modelName, options, callback);
} else if (typeof connector.delete === 'function') {
console.warn('falling back to unoptimized `deleteAll`');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will print a ton of warnings in a real app. Please use debug instead.

connector.deleteAll(this.modelName, options, callback);
} else if (typeof connector.delete === 'function') {
console.warn('falling back to unoptimized `deleteAll`');
let it = connector.iterateKeys(this.modelName, {});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should pass options instead of {} as the second arg.

} else if (typeof connector.delete === 'function') {
console.warn('falling back to unoptimized `deleteAll`');
let it = connector.iterateKeys(this.modelName, {});
asyncIterators.toArray(it, function(err, keys) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have 100k keys in your store, this will create an array of 100k, which seems like a huge waste of memory to me.

Is there a reason against iterating the async-iterator directly? See how .keys() is implemented in lib/kvao/keys.js.

This is what I am thinking about:

  var iter = connector.iterateKeys(this.modelName, {});
  var keys = [];
  iter.next(onNextKey);

  function onNextKey(err, key) {
    if (err) return callback(err);
    if (key === undefined) return callback();
    connector.delete(self.modelName, key, options, onDeleted);
  }

  function onDeleted(err) {
    if (err) return callback(err);
    iter.next(onNextKey);
  }

Also since the code is more that a couple of lines, please move it to an new internal method, e.g. iterateAndDelete.

}, callback);
});
} else {
console.warn('connector does not support `deleteAll`');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should return an Error with statusCode=501.

assert(typeof key === 'string' && key, 'key must be a non-empty string');

callback = callback || utils.createPromiseCallback();
this.getConnector().delete(this.modelName, key, options, callback);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check that the connector provides delete method and report a descriptive 501 error otherwise.

"eslint": "^3.11.1",
"eslint-config-loopback": "^6.0.0",
"mocha": "^2.1.0",
"should": "^8.0.2"
},
"dependencies": {
"async": "~1.0.0",
"async-iterators": "^0.2.2",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not depend on pre-1.0 versions in production. We are already implementing our own iteration in keys, I think we should do the same in the fall-back version of deleteAll (see my earlier comment for details).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simply moved this from a devDep to a dep. It's actually not needed as a full on dep anymore with your suggested changes for deleteAll, so removing this as it's unused now.


if (excludeFromConnector) {
// `delete connector.deleteAll` doesn't work
dataSource.connector[excludeFromConnector] = undefined;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the way how we force a datasource to use fall-back (unoptimized) methods.

See memory connector tests for the correct solution: https://github.com/strongloop/loopback-datasource-juggler/blob/66c54a96467b39609fec07f41b6d8018c5fc3819/test/memory.test.js#L887-L906.

The idea is to run the shared test suite twice for the built-in kv-memory connector. Once we run against the "full" connector, the second time we delete optimized functions from the connector instance after the datasource was created.

Th change in this file should be reverted.

const should = require('should');

module.exports = function(dataSourceFactory, connectorCapabilities) {
// override injected data source factory
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See my comment above, the decision fallback vs regular deleteAll is made by the connector. There is no point to test how connectors implementing optimized deleteAll are handling the fall-back variant, because the fall-back variant will be never invoked.

This whole file should be deleted and test/kv-memory.test.js should be modified to run the shared test suite twice.

return helpers.givenKeys(CacheItem, ['key1', 'key2'])
.then(() => helpers.givenKeys(AnotherModel, ['key3', 'key4']))
.then(() => CacheItem.deleteAll())
.then(() => CacheItem.keys())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I commented in your earlier pull request, there is no need to verify that CacheItem.deleteAll deletes CacaheItem keys - that has been already verified by the previous test.

@rmg
Copy link
Contributor

rmg commented Jan 6, 2017

@slnode test please

@cgole cgole removed the #review label Jan 7, 2017
@superkhau superkhau force-pushed the refactor/kvao-flush branch 3 times, most recently from 0faeed3 to 52877bf Compare January 7, 2017 02:17
Copy link
Member

@bajtos bajtos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good, see few minor comments below. No need for further review, unless you feel so.

debug('falling back to unoptimized `deleteAll`');
iterateAndDelete(this.modelName, connector, options, callback);
} else {
debug('connector does not support `deleteAll`');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is not entirely correct. How about Connector does not support deleting key/values. (Also notice the error message is a proper sentence, starting with a capital letter and ending with a dot. I don't mind the missing dot, but I believe we are starting error messages with a capital letter in other places.)

} else {
debug('connector does not support `deleteAll`');
process.nextTick(function() {
var err = new Error('connector does not support `deleteAll`');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, new Error('Connector does not support deleting key/values').

(Feel free to use a different wording for "key/values", just stay consistent in the error message and the debug log.)

return callback.promise;
};

function iterateAndDelete(modelName, connector, options, callback) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: I would personally change the order of arguments from (modelName, connector,...) to (connector, modelName, ...), Start with the thing that's changing the least (connector remains the same for the lifetime of a datasource), follow with things that change more often.

if (typeof connector.delete === 'function') {
connector.delete(this.modelName, key, options, callback);
} else {
debug('connector does not support `delete`');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it may be better to use the same message I proposed for "deleteAll" above, i.e. Connector does not support deleting key/values.

} else {
debug('connector does not support `delete`');
process.nextTick(function() {
var err = new Error('connector does not support `delete`');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

- Rename `flush` to `deleteAll`
- Add `delete`
- Detect `delete/deleteAll` before running downstream test suites
- Fall back to unoptimized `deleteAll` when connector does not support
  `deleteAll` but supports `delete`
- Return 501 for connectors not supporting `delete` or `deleteAll`
@superkhau
Copy link
Contributor Author

@slnode test please

@superkhau
Copy link
Contributor Author

@slnode test please

@superkhau
Copy link
Contributor Author

Created follow up issue for long term Oracle fail at loopbackio/loopback-connector-oracle#99. Merging as everything else is green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants