Skip to content

Commit 322f644

Browse files
committed
ref #2498 - replace yallist with custom made linked list
1 parent e27693f commit 322f644

File tree

3 files changed

+195
-17
lines changed

3 files changed

+195
-17
lines changed

packages/client/lib/client/commands-queue.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as LinkedList from 'yallist';
1+
import Queue, { QueueNode } from './queue';
22
import encodeCommand from '../RESP/encoder';
33
import { Decoder, PUSH_FLAGS, RESP_TYPES } from '../RESP/decoder';
44
import { CommandArguments, Flags, ReplyUnion, RespVersions } from '../RESP/types';
@@ -37,8 +37,8 @@ const RESP2_PUSH_FLAGS = {
3737

3838
export default class RedisCommandsQueue {
3939
private readonly _maxLength: number | null | undefined;
40-
private readonly _waitingToBeSent = new LinkedList<CommandWaitingToBeSent>();
41-
private readonly _waitingForReply = new LinkedList<CommandWaitingForReply>();
40+
private readonly _waitingToBeSent = new Queue<CommandWaitingToBeSent>();
41+
private readonly _waitingForReply = new Queue<CommandWaitingForReply>();
4242
private readonly _onShardedChannelMoved: OnShardedChannelMoved;
4343

4444
private readonly _pubSub = new PubSub();
@@ -154,30 +154,30 @@ export default class RedisCommandsQueue {
154154
}
155155

156156
return new Promise((resolve, reject) => {
157-
const node = new LinkedList.Node<CommandWaitingToBeSent>({
157+
let node: QueueNode<CommandWaitingToBeSent>;
158+
const value: CommandWaitingToBeSent = {
158159
args,
159160
chainId: options?.chainId,
160161
flags: options?.flags,
161162
resolve,
162-
reject
163-
});
163+
reject,
164+
removeAbortListener: undefined
165+
};
164166

165-
if (options?.signal) {
167+
const signal = options?.signal;
168+
if (signal) {
166169
const listener = () => {
167-
this._waitingToBeSent.removeNode(node);
168-
node.value.reject(new AbortError());
170+
this._waitingToBeSent.remove(node);
171+
value.reject(new AbortError());
169172
};
170173

171-
node.value.removeAbortListener = () => options.signal?.removeEventListener('abort', listener);
172-
173-
options.signal.addEventListener('abort', listener, { once: true });
174+
value.removeAbortListener = () => signal.removeEventListener('abort', listener);
175+
signal.addEventListener('abort', listener, { once: true });
174176
}
175177

176-
if (options?.asap) {
177-
this._waitingToBeSent.unshiftNode(node);
178-
} else {
179-
this._waitingToBeSent.pushNode(node);
180-
}
178+
node = options?.asap ?
179+
this._waitingToBeSent.unshift(value) :
180+
this._waitingToBeSent.push(value);
181181
});
182182
}
183183

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import Queue from './queue';
2+
import { equal, deepEqual } from 'assert/strict';
3+
4+
describe.only('Queue', () => {
5+
const queue = new Queue();
6+
7+
it('should start empty', () => {
8+
equal(queue.length, 0);
9+
deepEqual(Array.from(queue), []);
10+
});
11+
12+
it('shift empty', () => {
13+
equal(queue.shift(), null);
14+
equal(queue.length, 0);
15+
deepEqual(Array.from(queue), []);
16+
});
17+
18+
it('push 1', () => {
19+
queue.push(1);
20+
equal(queue.length, 1);
21+
deepEqual(Array.from(queue), [1]);
22+
});
23+
24+
it('push 2', () => {
25+
queue.push(2);
26+
equal(queue.length, 2);
27+
deepEqual(Array.from(queue), [1, 2]);
28+
});
29+
30+
it('unshift 0', () => {
31+
queue.unshift(0);
32+
equal(queue.length, 3);
33+
deepEqual(Array.from(queue), [0, 1, 2]);
34+
});
35+
36+
it('remove middle node', () => {
37+
queue.remove(queue.head.next!);
38+
equal(queue.length, 2);
39+
deepEqual(Array.from(queue), [0, 2]);
40+
});
41+
42+
it('remove head', () => {
43+
queue.remove(queue.head);
44+
equal(queue.length, 1);
45+
deepEqual(Array.from(queue), [2]);
46+
});
47+
48+
it('remove tail', () => {
49+
queue.remove(queue.tail);
50+
equal(queue.length, 0);
51+
deepEqual(Array.from(queue), []);
52+
});
53+
54+
it('unshift empty queue', () => {
55+
queue.unshift(0);
56+
equal(queue.length, 1);
57+
deepEqual(Array.from(queue), [0]);
58+
});
59+
60+
it('push 1', () => {
61+
queue.push(1);
62+
equal(queue.length, 2);
63+
deepEqual(Array.from(queue), [0, 1]);
64+
});
65+
66+
it('shift', () => {
67+
equal(queue.shift(), 0);
68+
equal(queue.length, 1);
69+
deepEqual(Array.from(queue), [1]);
70+
});
71+
72+
it('shift last element', () => {
73+
equal(queue.shift(), 1);
74+
equal(queue.length, 0);
75+
deepEqual(Array.from(queue), []);
76+
});
77+
});

packages/client/lib/client/queue.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
export interface QueueNode<T> {
2+
value: T;
3+
previous: QueueNode<T> | null;
4+
next: QueueNode<T> | null;
5+
}
6+
7+
export default class Queue<T> {
8+
#length = 0;
9+
10+
get length() {
11+
return this.#length;
12+
}
13+
14+
#head: QueueNode<T> | null = null;
15+
16+
get head() {
17+
return this.#head;
18+
}
19+
20+
#tail: QueueNode<T> | null = null;
21+
22+
get tail() {
23+
return this.#tail;
24+
}
25+
26+
push(value: T) {
27+
++this.#length;
28+
29+
if (!this.#tail) {
30+
return this.#tail = this.#head = {
31+
previous: this.#head,
32+
next: null,
33+
value
34+
};
35+
}
36+
37+
return this.#tail = this.#tail.next = {
38+
previous: this.#tail,
39+
next: null,
40+
value
41+
};
42+
}
43+
44+
unshift(value: T) {
45+
++this.#length;
46+
47+
if (!this.#head) {
48+
return this.#head = this.#tail = {
49+
previous: null,
50+
next: null,
51+
value
52+
};
53+
}
54+
55+
return this.#head = this.#head.previous = {
56+
previous: null,
57+
next: this.#head,
58+
value
59+
};
60+
}
61+
62+
shift() {
63+
if (!this.#head) return null;
64+
65+
--this.#length;
66+
const node = this.#head;
67+
if (node.next) {
68+
node.next.previous = node.previous;
69+
this.#head = node.next;
70+
node.next = null;
71+
} else {
72+
this.#head = this.#tail = null;
73+
}
74+
return node.value;
75+
}
76+
77+
remove(node: QueueNode<T>) {
78+
--this.#length;
79+
80+
if (this.#tail === node) {
81+
this.#tail = node.previous;
82+
}
83+
84+
if (this.#head === node) {
85+
this.#head = node.next;
86+
} else {
87+
node.previous!.next = node.next;
88+
node.previous = null;
89+
}
90+
91+
node.next = null;
92+
}
93+
94+
*[Symbol.iterator]() {
95+
let node = this.#head;
96+
while (node !== null) {
97+
yield node.value;
98+
node = node.next;
99+
}
100+
}
101+
}

0 commit comments

Comments
 (0)