mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Merge remote-tracking branch 'origin/devel' into release-1.2
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# minimongo
|
||||
# Minimongo
|
||||
|
||||
`minimongo` is reimplementation of (almost) the entire MongoDB API, against an
|
||||
in-memory JavaScript database. It is like a MongoDB emulator that runs inside
|
||||
@@ -11,4 +11,72 @@ Minimongo is used as a temporary data cache in the standard Meteor stack, to
|
||||
learn more about mini-databases and what they can do, see [the project page on
|
||||
www.meteor.com](https://www.meteor.com/mini-databases)
|
||||
|
||||
## Internals
|
||||
|
||||
Minimongo implements the following features, mirroring the MongoDB features:
|
||||
|
||||
- Selectors
|
||||
- Modifiers
|
||||
- Fields projections
|
||||
- Querying with `sort` and `limit`
|
||||
- ObjectID generation
|
||||
- Geo-positional operator `$near` with GeoJSON parsing
|
||||
|
||||
Internally, all documents are mapped in a single JS object from `_id` to the
|
||||
document. Besides this mapping, Minimongo doesn't implement any types of
|
||||
secondary indexes.
|
||||
|
||||
Also, currently Minimongo doesn't implement any aggregation features. The full
|
||||
list of incompatible features can be found in the NOTES file.
|
||||
|
||||
Besides the MongoDB features, Minimongo implements the following for a better
|
||||
integration with the Meteor stack:
|
||||
|
||||
- `observe` and `observeChanges` APIs, notification callbacks when the result of
|
||||
a query changes
|
||||
- integration with Meteor's [Tracker](https://www.meteor.com/tracker)
|
||||
- Meteor's Publish a cursor interface `_publishCursor`, that results into an
|
||||
`observe` call
|
||||
- Meteor's interface of `pauseObservers` and `resumeObservers`, for client-side
|
||||
caches (allow latency compensation to change multiple objects at once w/o a
|
||||
flicker)
|
||||
- In addition to the previous point, `saveOriginals` and `retrieveOriginals` are
|
||||
used to revert the local changes
|
||||
- additional analysis functions for Meteor's server-side Oplog Observe Driver
|
||||
(only loaded for the server-side):
|
||||
* can this modifier change the result of this selector if the document didn't
|
||||
match before
|
||||
* can the sort order change after applying this modifier (for a given
|
||||
selector)
|
||||
* what is a combined projection for these selector, sorter and projection
|
||||
|
||||
|
||||
### saveOriginals/retrieveOriginals & pauseObserver/resumeObservers
|
||||
|
||||
This part of the implementation is very important for a smooth Optimistic UI
|
||||
experience (also called "Latency Compensation") avoiding an extra flicker.
|
||||
|
||||
Let's review the usual Optimistic UI flow:
|
||||
|
||||
- User triggers an interaction on the client
|
||||
- The simulation applies some mutations to the state locally
|
||||
- The RPC is fired to be executed on the server
|
||||
- After some time, the RPC returns with the result
|
||||
- After some more time, RPC returns an "updated" message (on DDP level), meaning
|
||||
that all the changes from RPC have persisted
|
||||
- At this point we know, that all the actual changes from the server are synced,
|
||||
we can throw away the simulated mutations (preserving the real changes from
|
||||
the server)
|
||||
|
||||
To implement the last step, Minimongo implements the following:
|
||||
|
||||
- When a simulation starts, `saveOriginals` is called, to take a snapshot of the
|
||||
state before the update. Internally, it is implemented in a more efficient
|
||||
copy-on-write style.
|
||||
- After the simulation, wait, to get all the real changes from the server.
|
||||
- When the server is done with giving us new changes, we apply all the new
|
||||
changes and throw away all the simulated changes (with `retrieveOriginals`).
|
||||
- All massive replacements happen in between `pauseObservers` and
|
||||
`resumeObservers` calls, so any user code (such as Blaze) sees the whole
|
||||
change in one tick (helps to avoid the flicker).
|
||||
|
||||
|
||||
@@ -15,12 +15,19 @@ selftest.define("parse-stack - parse stack traces without fibers", () => {
|
||||
|
||||
markBottom(() => {
|
||||
const markedErr = new Error();
|
||||
const parsedStack = parse(markedErr).outsideFiber;
|
||||
|
||||
const {
|
||||
outsideFiber,
|
||||
insideFiber
|
||||
} = parse(markedErr);
|
||||
|
||||
// Don't return an empty array
|
||||
selftest.expectEqual(insideFiber, undefined);
|
||||
|
||||
// The stack trace should only contain this one function since we marked the
|
||||
// bottom
|
||||
selftest.expectEqual(parsedStack.length, 1);
|
||||
selftest.expectEqual(_.last(parsedStack[0].file.split("/")),
|
||||
selftest.expectEqual(outsideFiber.length, 1);
|
||||
selftest.expectEqual(_.last(outsideFiber[0].file.split("/")),
|
||||
"parse-stack-test.js");
|
||||
})();
|
||||
});
|
||||
|
||||
@@ -92,7 +92,7 @@ _.extend(Job.prototype, {
|
||||
// If a nontrivial stack trace (more than just the file and line
|
||||
// we already complained about), print it.
|
||||
var where = "";
|
||||
if (frame && frame.file) {
|
||||
if (frame.file) {
|
||||
where += frame.file;
|
||||
if (frame.line) {
|
||||
where += ":" + frame.line;
|
||||
@@ -102,11 +102,11 @@ _.extend(Job.prototype, {
|
||||
}
|
||||
}
|
||||
|
||||
if (frame && ! frame.func && ! where)
|
||||
if (! frame.func && ! where)
|
||||
return; // that's a pretty lame stack frame
|
||||
|
||||
line += " at ";
|
||||
if (frame && frame.func)
|
||||
if (frame.func)
|
||||
line += frame.func + " (" + where + ")\n";
|
||||
else
|
||||
line += where + "\n";
|
||||
@@ -439,7 +439,7 @@ var error = function (message, options) {
|
||||
} = parseStack.parse(new Error());
|
||||
|
||||
// Concatenate and get rid of lines about Future and buildmessage
|
||||
info.stack = outsideFiber.concat(insideFiber).slice(2);
|
||||
info.stack = outsideFiber.concat(insideFiber || []).slice(2);
|
||||
if (typeof info.useMyCaller === 'number') {
|
||||
info.stack = info.stack.slice(info.useMyCaller);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user