Batch mget requests on dashboard load and cache field_stat results (#10274)

Backports PR #10081

**Commit 1:**
defer loading visualization saved objects so they can be loaded in a single _mget

* Original sha: 5c1344e6a4
* Authored by nreese <reese.nathan@gmail.com> on 2017-01-24T23:41:05Z

**Commit 2:**
Merge branch 'defer' of https://github.com/nreese/kibana into nreese-defer

* Original sha: 96af3ea647
* Authored by Stacey Gammon <gammon@elastic.co> on 2017-01-26T13:44:55Z

**Commit 3:**
Don't request field stats more than once for the same index pattern

* Original sha: 9a02e5b349
* Authored by Stacey Gammon <gammon@elastic.co> on 2017-01-26T15:57:34Z

**Commit 4:**
[ui/courier] batch fetch requests for all searches and docs

* Original sha: 20d55fe602
* Authored by spalger <spalger@users.noreply.github.com> on 2017-02-06T22:13:23Z

**Commit 5:**
[ui/courier] remove remaining mentions of req.isFetchRequested()

* Original sha: f5bd5ca0f3
* Authored by spalger <spalger@users.noreply.github.com> on 2017-02-08T21:22:32Z

**Commit 6:**
[courier/fetch/request] remove unneceessary !!

* Original sha: eb5446d89a
* Authored by spalger <spalger@users.noreply.github.com> on 2017-02-09T20:48:48Z
This commit is contained in:
jasper 2017-02-09 16:07:20 -05:00 committed by Court Ewing
parent e1d7f16c24
commit daddd3f05f
3 changed files with 58 additions and 13 deletions

View file

@ -8,23 +8,32 @@ import ReqStatusProvider from './req_status';
export default function fetchService(Private, Promise) {
const requestQueue = Private(RequestQueueProvider);
const fetchThese = Private(FetchTheseProvider);
const immediatelyFetchThese = Private(FetchTheseProvider);
const callResponseHandlers = Private(CallResponseHandlersProvider);
const INCOMPLETE = Private(ReqStatusProvider).INCOMPLETE;
function fetchQueued(strategy) {
const requests = requestQueue.getStartable(strategy);
if (!requests.length) return Promise.resolve();
else return fetchThese(requests);
}
const debouncedFetchThese = _.debounce(() => {
const requests = requestQueue.get().filter(req => req.isFetchRequestedAndPending());
immediatelyFetchThese(requests);
}, {
wait: 10,
maxWait: 50
});
this.fetchQueued = fetchQueued;
const fetchTheseSoon = (requests) => {
requests.forEach(req => req._setFetchRequested());
debouncedFetchThese();
return Promise.all(requests.map(req => req.defer.promise));
};
this.fetchQueued = (strategy) => {
return fetchTheseSoon(requestQueue.getStartable(strategy));
};
function fetchASource(source, strategy) {
const defer = Promise.defer();
fetchThese([
fetchTheseSoon([
source._createRequest(defer)
]);
@ -50,7 +59,7 @@ export default function fetchService(Private, Promise) {
* @param {array} reqs - the requests to fetch
* @async
*/
this.these = fetchThese;
this.these = fetchTheseSoon;
/**
* Send responses to a list of requests, used when requests

View file

@ -15,12 +15,42 @@ export default function AbstractReqProvider(Private, Promise) {
this.source = source;
this.defer = defer || Promise.defer();
this._whenAbortedHandlers = [];
requestQueue.push(this);
}
/**
* Called by the loopers to find requests that should be sent to the
* fetch() module. When a module is sent to fetch() it's _fetchRequested flag
* is set, and this consults that flag so requests are not send to fetch()
* multiple times.
*
* @return {Boolean}
*/
canStart() {
return Boolean(!this.stopped && !this.source._fetchDisabled);
return !this._fetchRequested && !this.stopped && !this.source._fetchDisabled;
}
/**
* Used to find requests that were previously sent to the fetch() module but
* have not been started yet, so they can be started.
*
* @return {Boolean}
*/
isFetchRequestedAndPending() {
return this._fetchRequested && !this.started;
}
/**
* Called by the fetch() module when this request has been sent to
* be fetched. At that point the request is somewhere between `ready-to-start`
* and `started`. The fetch module then waits a short period of time to
* allow requests to build up in the request queue, and then immediately
* fetches all requests that return true from `isFetchRequestedAndPending()`
*
* @return {undefined}
*/
_setFetchRequested() {
this._fetchRequested = true;
}
start() {

View file

@ -15,6 +15,8 @@ export default function FetchStrategyForSearch(Private, Promise, timefilter, kbn
* @return {Promise} - a promise that is fulfilled by the request body
*/
reqsFetchParamsToBody: function (reqsFetchParams) {
const indexToListMapping = {};
return Promise.map(reqsFetchParams, function (fetchParams) {
return Promise.resolve(fetchParams.index)
.then(function (indexList) {
@ -23,7 +25,11 @@ export default function FetchStrategyForSearch(Private, Promise, timefilter, kbn
}
const timeBounds = timefilter.getBounds();
return indexList.toIndexList(timeBounds.min, timeBounds.max);
if (!indexToListMapping[indexList.id]) {
indexToListMapping[indexList.id] = indexList.toIndexList(timeBounds.min, timeBounds.max);
}
return indexToListMapping[indexList.id];
})
.then(function (indexList) {
let body = fetchParams.body || {};