Skip to content

Improve single schema cache #7214

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

Merged
merged 43 commits into from
Mar 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
9db2063
Initial Commit
dplewis Feb 21, 2021
311ac85
fix flaky test
dplewis Feb 21, 2021
a4a1a3a
temporary set ci timeout
dplewis Feb 21, 2021
ca3884e
turn off ci check
dplewis Feb 21, 2021
b7e28cd
fix postgres tests
dplewis Feb 21, 2021
7233af6
fix tests
dplewis Feb 21, 2021
cf65542
node flaky test
dplewis Feb 21, 2021
a3ab545
remove improvements
dplewis Feb 21, 2021
f91d0c5
Update SchemaPerformance.spec.js
dplewis Feb 21, 2021
2c8cf56
fix tests
dplewis Feb 21, 2021
d49e4d4
revert ci
dplewis Feb 21, 2021
a6c692d
Create Singleton Object
dplewis Feb 21, 2021
ebf67d3
properly clear cache testing
dplewis Feb 21, 2021
5454895
Cleanup
dplewis Feb 21, 2021
3b91380
remove fit
dplewis Feb 21, 2021
415df3b
try PushController.spec
dplewis Feb 22, 2021
81a7d2a
try push test rewrite
dplewis Feb 22, 2021
231383b
try push enqueue time
dplewis Feb 22, 2021
e36bf3c
Increase test timeout
dplewis Feb 22, 2021
3871115
remove pg server creation test
dplewis Feb 23, 2021
a83ef11
xit push tests
dplewis Feb 23, 2021
07b06b8
more xit
dplewis Feb 23, 2021
d4db662
Merge branch 'master' into schema-improvement
dplewis Mar 12, 2021
bbb858e
remove skipped tests
dplewis Mar 12, 2021
ae79973
Merge branch 'master' into schema-improvement
dplewis Mar 13, 2021
da36ff7
Fix conflicts
dplewis Mar 13, 2021
f7bb165
reduce ci timeout
dplewis Mar 13, 2021
05aba62
fix push tests
dplewis Mar 13, 2021
41335b4
Revert "fix push tests"
dplewis Mar 16, 2021
9abb8c8
Merge branch 'master' into schema-improvement
dplewis Mar 16, 2021
c86c5ef
improve initialization
dplewis Mar 16, 2021
eb3d07b
fix flaky tests
dplewis Mar 16, 2021
00cce83
xit flaky test
dplewis Mar 16, 2021
fc18b5e
Update CHANGELOG.md
dplewis Mar 16, 2021
c78f8c1
enable debug logs
dplewis Mar 16, 2021
de42343
Update LogsRouter.spec.js
dplewis Mar 16, 2021
0d9af86
create initial indexes in series
dplewis Mar 16, 2021
5819692
lint
dplewis Mar 16, 2021
26ad212
horizontal scaling documentation
dplewis Mar 16, 2021
74d3d86
Update Changelog
dplewis Mar 16, 2021
feb942e
change horizontalScaling db option
dplewis Mar 16, 2021
977c6ab
Add enableSchemaHooks option
dplewis Mar 16, 2021
9cd2986
move enableSchemaHooks to databaseOptions
dplewis Mar 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ ___
## Unreleased (Master Branch)
[Full Changelog](https://github.com/parse-community/parse-server/compare/4.5.0...master)
### Breaking Changes
Leveraging database real-time hooks, schema caching has been drastically improved. These improvements allows for reduced calls to the DB, faster queries and prevention of memory leaks. A breaking change can occur if you are horizontally scaling Parse Server (multiple Parse Server instances connecting to the same DB). Set `databaseOptions: { enableSchemaHooks: true }` parameter in [Parse Server Options](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) (`enableSingleSchemaCache` and `schemaCacheTTL` have been removed). If you are horizontal scaling instances connected to MongoDB, you must use replica set clusters with WiredTiger, see [ChangeStream](https://docs.mongodb.com/manual/changeStreams/#availability)

The new schema cache uses a singleton object that is stored in-memory. In a horizontally scaled environment, if you update the schema in one instance the DB hooks will update the schema in all other instances. `databaseOptions: { enableSchemaHooks: true }` enables the DB hooks. If you have multiple server instances but `databaseOptions: { enableSchemaHooks: false }`, your schema maybe out of sync in your instances (resyncing will happen if an instance restarts). (Diamond Lewis, SebC) [#7214](https://github.com/parse-community/parse-server/issues/7214)
- Added file upload restriction. File upload is now only allowed for authenticated users by default for improved security. To allow file upload also for Anonymous Users or Public, set the `fileUpload` parameter in the [Parse Server Options](https://parseplatform.org/parse-server/api/master/ParseServerOptions.html) (dblythy, Manuel Trezza) [#7071](https://github.com/parse-community/parse-server/pull/7071)
### Notable Changes
- Added Parse Server Security Check to report weak security settings (Manuel Trezza, dblythy) [#7247](https://github.com/parse-community/parse-server/issues/7247)
Expand Down
3 changes: 2 additions & 1 deletion resources/buildConfigDefinitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ function getENVPrefix(iface) {
'PasswordPolicyOptions' : 'PARSE_SERVER_PASSWORD_POLICY_',
'FileUploadOptions' : 'PARSE_SERVER_FILE_UPLOAD_',
'SecurityOptions': 'PARSE_SERVER_SECURITY_',
'DatabaseOptions': 'PARSE_SERVER_DATABASE_'
}
if (options[iface.id.name]) {
return options[iface.id.name]
Expand Down Expand Up @@ -168,7 +169,7 @@ function parseDefaultValue(elt, value, t) {
if (type == 'NumberOrBoolean') {
literalValue = t.numericLiteral(parsers.numberOrBoolParser('')(value));
}
const literalTypes = ['Object', 'SecurityOptions', 'PagesRoute', 'IdempotencyOptions','FileUploadOptions','CustomPagesOptions', 'PagesCustomUrlsOptions', 'PagesOptions'];
const literalTypes = ['Object', 'SecurityOptions', 'PagesRoute', 'IdempotencyOptions','FileUploadOptions','CustomPagesOptions', 'PagesCustomUrlsOptions', 'PagesOptions', 'DatabaseOptions'];
if (literalTypes.includes(type)) {
const object = parsers.objectParser(value);
const props = Object.keys(object).map((key) => {
Expand Down
58 changes: 0 additions & 58 deletions spec/EnableSingleSchemaCache.spec.js

This file was deleted.

4 changes: 3 additions & 1 deletion spec/LogsRouter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ const WinstonLoggerAdapter = require('../lib/Adapters/Logger/WinstonLoggerAdapte

const loggerController = new LoggerController(new WinstonLoggerAdapter());

describe('LogsRouter', () => {
describe_only(() => {
return process.env.PARSE_SERVER_LOG_LEVEL !== 'debug';
})('LogsRouter', () => {
it('can check valid master key of request', done => {
// Make mock request
const request = {
Expand Down
31 changes: 31 additions & 0 deletions spec/MongoStorageAdapter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const fakeClient = {
describe_only_db('mongo')('MongoStorageAdapter', () => {
beforeEach(done => {
new MongoStorageAdapter({ uri: databaseURI }).deleteAllClasses().then(done, fail);
Config.get(Parse.applicationId).schemaCache.clear();
});

it('auto-escapes symbols in auth information', () => {
Expand Down Expand Up @@ -314,6 +315,8 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
await user.signUp();

const database = Config.get(Parse.applicationId).database;
await database.adapter.dropAllIndexes('_User');

const preIndexPlan = await database.find(
'_User',
{ username: 'bugs' },
Expand Down Expand Up @@ -546,5 +549,33 @@ describe_only_db('mongo')('MongoStorageAdapter', () => {
});
});
});

describe('watch _SCHEMA', () => {
it('should change', async done => {
const adapter = new MongoStorageAdapter({
uri: databaseURI,
collectionPrefix: '',
mongoOptions: { enableSchemaHooks: true },
});
await reconfigureServer({ databaseAdapter: adapter });
expect(adapter.enableSchemaHooks).toBe(true);
spyOn(adapter, '_onchange');
const schema = {
fields: {
array: { type: 'Array' },
object: { type: 'Object' },
date: { type: 'Date' },
},
};

await adapter.createClass('Stuff', schema);
const myClassSchema = await adapter.getClass('Stuff');
expect(myClassSchema).toBeDefined();
setTimeout(() => {
expect(adapter._onchange).toHaveBeenCalled();
done();
}, 5000);
});
});
}
});
4 changes: 1 addition & 3 deletions spec/ParseGraphQLController.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,7 @@ describe('ParseGraphQLController', () => {

beforeEach(async () => {
if (!parseServer) {
parseServer = await global.reconfigureServer({
schemaCacheTTL: 100,
});
parseServer = await global.reconfigureServer();
databaseController = parseServer.config.databaseController;
cacheController = parseServer.config.cacheController;

Expand Down
22 changes: 10 additions & 12 deletions spec/ParseGraphQLSchema.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ describe('ParseGraphQLSchema', () => {
const appId = 'test';

beforeEach(async () => {
parseServer = await global.reconfigureServer({
schemaCacheTTL: 100,
});
parseServer = await global.reconfigureServer();
databaseController = parseServer.config.databaseController;
parseGraphQLController = parseServer.config.parseGraphQLController;
parseGraphQLSchema = new ParseGraphQLSchema({
Expand Down Expand Up @@ -68,7 +66,7 @@ describe('ParseGraphQLSchema', () => {
const graphQLSubscriptions = parseGraphQLSchema.graphQLSubscriptions;
const newClassObject = new Parse.Object('NewClass');
await newClassObject.save();
await databaseController.schemaCache.clear();
await parseServer.config.schemaCache.clear();
await new Promise(resolve => setTimeout(resolve, 200));
await parseGraphQLSchema.load();
expect(parseClasses).not.toBe(parseGraphQLSchema.parseClasses);
Expand Down Expand Up @@ -426,14 +424,14 @@ describe('ParseGraphQLSchema', () => {
log: defaultLogger,
appId,
});
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema1 = await parseGraphQLSchema.load();
const types1 = parseGraphQLSchema.graphQLTypes;
const queries1 = parseGraphQLSchema.graphQLQueries;
const mutations1 = parseGraphQLSchema.graphQLMutations;
const user = new Parse.Object('User');
await user.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema2 = await parseGraphQLSchema.load();
const types2 = parseGraphQLSchema.graphQLTypes;
const queries2 = parseGraphQLSchema.graphQLQueries;
Expand All @@ -456,14 +454,14 @@ describe('ParseGraphQLSchema', () => {
});
const car1 = new Parse.Object('Car');
await car1.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema1 = await parseGraphQLSchema.load();
const types1 = parseGraphQLSchema.graphQLTypes;
const queries1 = parseGraphQLSchema.graphQLQueries;
const mutations1 = parseGraphQLSchema.graphQLMutations;
const car2 = new Parse.Object('car');
await car2.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema2 = await parseGraphQLSchema.load();
const types2 = parseGraphQLSchema.graphQLTypes;
const queries2 = parseGraphQLSchema.graphQLQueries;
Expand All @@ -486,13 +484,13 @@ describe('ParseGraphQLSchema', () => {
});
const car = new Parse.Object('Car');
await car.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema1 = await parseGraphQLSchema.load();
const queries1 = parseGraphQLSchema.graphQLQueries;
const mutations1 = parseGraphQLSchema.graphQLMutations;
const cars = new Parse.Object('cars');
await cars.save();
await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
const schema2 = await parseGraphQLSchema.load();
const queries2 = parseGraphQLSchema.graphQLQueries;
const mutations2 = parseGraphQLSchema.graphQLMutations;
Expand Down Expand Up @@ -532,7 +530,7 @@ describe('ParseGraphQLSchema', () => {

await data.save();

await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
await parseGraphQLSchema.load();

const queries1 = parseGraphQLSchema.graphQLQueries;
Expand Down Expand Up @@ -569,7 +567,7 @@ describe('ParseGraphQLSchema', () => {

await data.save();

await parseGraphQLSchema.databaseController.schemaCache.clear();
await parseGraphQLSchema.schemaCache.clear();
await parseGraphQLSchema.load();

const mutations = parseGraphQLSchema.graphQLMutations;
Expand Down
Loading