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

feat: Add back the addToBeginning to the PoolManagers #558

Merged
merged 1 commit into from
Oct 1, 2021
Merged
Changes from all commits
Commits
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
157 changes: 88 additions & 69 deletions src/requestPool/RequestPoolManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,57 @@ type AdditionalDetails = {
thumbnail: { [key: number]: [] }
prefetch: { [key: number]: [] }
}

class RequestPoolManager {
// priority is fixed for interaction and thumbnail to be 0, however,
// the priority of prefetch can be configured and it can have priorities other
// than 0 (highest priority)

// TODO: Some of this stuff shouldn't be public but it's easier right now
private requestPool: RequestPool;
private awake: boolean;
private numRequests: { interaction: number, thumbnail: number, prefetch: number };
public maxNumRequests: { interaction: number, thumbnail: number, prefetch: number };
private numRequests: {
interaction: number;
thumbnail: number;
prefetch: number;
};
public maxNumRequests: {
interaction: number;
thumbnail: number;
prefetch: number;
};
public grabDelay: number;
private timeoutHandle: number;

constructor() {
this.requestPool = {
interaction: { 0: [] },
thumbnail: { 0: [] },
prefetch: { 0: [] },
}
};

this.awake = false;
this.grabDelay = 5;
this.numRequests = {

this.numRequests = {
interaction: 0,
thumbnail: 0,
prefetch: 0,
};

this.maxNumRequests = {
interaction: 6,
thumbnail: 6,
prefetch: 5,
}
};
}

destroy() {
if (this.timeoutHandle) {
window.clearTimeout(this.timeoutHandle)
window.clearTimeout(this.timeoutHandle);
}
}

/**
* Adds the requests to the pool of requests.
*
Expand All @@ -75,30 +83,37 @@ type AdditionalDetails = {
requestFn: () => Promise<void>,
type: string,
additionalDetails: Record<string, unknown>,
priority = 0
priority = 0,
addToBeginning = false
): void {
// Describe the request
const requestDetails: RequestDetailsInterface = {
requestFn,
type,
additionalDetails,
}
};

// Check if the priority group exists on the request type
if (this.requestPool[type][priority] === undefined) {
this.requestPool[type][priority] = []
this.requestPool[type][priority] = [];
}

// Adding the request to the correct priority group of the request type
this.requestPool[type][priority].push(requestDetails)

if (addToBeginning) {
// Add it to the beginning of the stack
this.requestPool[type][priority].unshift(requestDetails);
} else {
// Add it to the end of the stack
this.requestPool[type][priority].push(requestDetails);
}

// Wake up
if (!this.awake) {
this.awake = true
this.startGrabbing()
this.awake = true;
this.startGrabbing();
}
}

/**
* Filter the requestPoolManager's pool of request based on the result of
* provided filter function. The provided filter function needs to return false or true
Expand All @@ -110,17 +125,17 @@ type AdditionalDetails = {
filterFunction: (requestDetails: RequestDetailsInterface) => boolean
): void {
Object.keys(this.requestPool).forEach((type: string) => {
const requestType = this.requestPool[type]
const requestType = this.requestPool[type];
Object.keys(requestType).forEach((priority) => {
requestType[priority] = requestType[priority].filter(
(requestDetails: RequestDetailsInterface) => {
return filterFunction(requestDetails)
return filterFunction(requestDetails);
}
)
})
})
);
});
});
}

/**
* Clears the requests specific to the provided type. For instance, the
* pool of requests of type 'interaction' can be cleared via this function.
Expand All @@ -131,110 +146,114 @@ type AdditionalDetails = {
*/
clearRequestStack(type: string): void {
if (!this.requestPool[type]) {
throw new Error(`No category for the type ${type} found`)
throw new Error(`No category for the type ${type} found`);
}
this.requestPool[type] = { 0: [] }
this.requestPool[type] = { 0: [] };
}

sendRequest({ requestFn, type }: RequestDetailsInterface) {
// Increment the number of current requests of this type
this.numRequests[type]++
this.awake = true
this.numRequests[type]++;
this.awake = true;

requestFn().finally(() => {
this.numRequests[type]--
this.startAgain()
})
this.numRequests[type]--;

this.startAgain();
});
}

startGrabbing(): void {
// Begin by grabbing X images

// TODO: This is the reason things aren't going as fast as expected
// const maxSimultaneousRequests = getMaxSimultaneousRequests()
// this.maxNumRequests = {
// interaction: Math.max(maxSimultaneousRequests, 1),
// thumbnail: Math.max(maxSimultaneousRequests - 2, 1),
// prefetch: Math.max(maxSimultaneousRequests - 1, 1),
// }

const maxRequests =
this.maxNumRequests.interaction + this.maxNumRequests.thumbnail + this.maxNumRequests.prefetch
this.maxNumRequests.interaction +
this.maxNumRequests.thumbnail +
this.maxNumRequests.prefetch;
const currentRequests =
this.numRequests.interaction + this.numRequests.thumbnail + this.numRequests.prefetch
const requestsToSend = maxRequests - currentRequests
this.numRequests.interaction +
this.numRequests.thumbnail +
this.numRequests.prefetch;
const requestsToSend = maxRequests - currentRequests;
for (let i = 0; i < requestsToSend; i++) {
const requestDetails = this.getNextRequest()
const requestDetails = this.getNextRequest();
if (requestDetails === false) {
break;
} else if (requestDetails) {
this.sendRequest(requestDetails)
this.sendRequest(requestDetails);
}
}
}

startAgain(): void {
if (!this.awake) {
return
return;
}

if (this.grabDelay) {
this.timeoutHandle = window.setTimeout(() => {
this.startGrabbing()
}, this.grabDelay)
this.startGrabbing();
}, this.grabDelay);
} else {
this.startGrabbing()
this.startGrabbing();
}
}

getSortedPriorityGroups(type: string): Array<number> {
const priorities = Object.keys(this.requestPool[type])
.map(Number)
.filter((priority) => this.requestPool[type][priority].length)
.sort()
return priorities
.sort();
return priorities;
}

getNextRequest(): RequestDetailsInterface | false {
const interactionPriorities = this.getSortedPriorityGroups('interaction')
const interactionPriorities = this.getSortedPriorityGroups('interaction');
for (const priority of interactionPriorities) {
if (
this.requestPool.interaction[priority].length &&
this.numRequests.interaction < this.maxNumRequests.interaction
) {
return this.requestPool.interaction[priority].shift()
return this.requestPool.interaction[priority].shift();
}
}
const thumbnailPriorities = this.getSortedPriorityGroups('thumbnail')
const thumbnailPriorities = this.getSortedPriorityGroups('thumbnail');
for (const priority of thumbnailPriorities) {
if (
this.requestPool.thumbnail[priority].length &&
this.numRequests.thumbnail < this.maxNumRequests.thumbnail
) {
return this.requestPool.thumbnail[priority].shift()
return this.requestPool.thumbnail[priority].shift();
}
}
const prefetchPriorities = this.getSortedPriorityGroups('prefetch')
const prefetchPriorities = this.getSortedPriorityGroups('prefetch');
for (const priority of prefetchPriorities) {
if (
this.requestPool.prefetch[priority].length &&
this.numRequests.prefetch < this.maxNumRequests.prefetch
) {
return this.requestPool.prefetch[priority].shift()
return this.requestPool.prefetch[priority].shift();
}
}

if (
!interactionPriorities.length &&
!thumbnailPriorities.length &&
!prefetchPriorities.length
) {
this.awake = false
this.awake = false;
}
return false
return false;
}

/**
* Returns the request pool containing different categories, their priority and
* the added request details.
Expand All @@ -243,7 +262,7 @@ type AdditionalDetails = {
* @category requestPool
*/
getRequestPool(): RequestPool {
return this.requestPool
return this.requestPool;
}
}

Expand Down