Skip to content

Commit 73413e0

Browse files
authored
fix: resolve doubly linked list push issue (#3085)
* fix redis sentinel failover * fix: resolve doubly linked list push issue * fix semicolon syntax * correctly set the removed node ref * fix linked list node iterator * revert push logic and refactor remove logic * add linked list tests
1 parent 17fc725 commit 73413e0

File tree

3 files changed

+59
-11
lines changed

3 files changed

+59
-11
lines changed

packages/client/lib/client/linked-list.spec.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
import { equal, deepEqual } from "assert/strict";
77

88
describe("DoublyLinkedList", () => {
9-
const list = new DoublyLinkedList();
9+
const list = new DoublyLinkedList<number>();
1010

1111
it("should start empty", () => {
1212
equal(list.length, 0);
@@ -96,6 +96,38 @@ describe("DoublyLinkedList", () => {
9696
}
9797
equal(count, 6);
9898
});
99+
100+
it("should handle remove on empty list", () => {
101+
list.reset();
102+
const node = list.push(1);
103+
list.remove(node);
104+
equal(list.length, 0);
105+
deepEqual(Array.from(list), []);
106+
list.remove(node);
107+
equal(list.length, 0);
108+
deepEqual(Array.from(list), []);
109+
});
110+
111+
112+
it("should safely remove nodes while iterating", () => {
113+
list.reset();
114+
list.push(1);
115+
list.push(2);
116+
list.push(3);
117+
list.push(4);
118+
list.push(5);
119+
120+
const visited: number[] = [];
121+
for (const node of list.nodes()) {
122+
visited.push(node.value);
123+
if (node.value % 2 === 0) {
124+
list.remove(node);
125+
}
126+
}
127+
deepEqual(visited, [1, 2, 3, 4, 5]);
128+
equal(list.length, 3);
129+
deepEqual(Array.from(list), [1, 3, 5]);
130+
});
99131
});
100132

101133
describe("SinglyLinkedList", () => {

packages/client/lib/client/linked-list.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class DoublyLinkedList<T> {
2929
++this.#length;
3030

3131
if (this.#tail === undefined) {
32-
return this.#tail = this.#head = {
32+
return this.#head = this.#tail = {
3333
previous: this.#head,
3434
next: undefined,
3535
value
@@ -73,7 +73,7 @@ export class DoublyLinkedList<T> {
7373
--this.#length;
7474
const node = this.#head;
7575
if (node.next) {
76-
node.next.previous = node.previous;
76+
node.next.previous = undefined;
7777
this.#head = node.next;
7878
node.next = undefined;
7979
} else {
@@ -83,19 +83,23 @@ export class DoublyLinkedList<T> {
8383
}
8484

8585
remove(node: DoublyLinkedNode<T>) {
86+
if (this.#length === 0) return;
8687
--this.#length;
8788

8889
if (this.#tail === node) {
8990
this.#tail = node.previous;
90-
}
91-
91+
}
9292
if (this.#head === node) {
9393
this.#head = node.next;
9494
} else {
95-
node.previous!.next = node.next;
96-
node.previous = undefined;
95+
if (node.previous) {
96+
node.previous.next = node.next;
97+
}
98+
if (node.next) {
99+
node.next.previous = node.previous;
100+
}
97101
}
98-
102+
node.previous = undefined;
99103
node.next = undefined;
100104
}
101105

@@ -115,8 +119,9 @@ export class DoublyLinkedList<T> {
115119
*nodes() {
116120
let node = this.#head;
117121
while(node) {
122+
const next = node.next
118123
yield node;
119-
node = node.next;
124+
node = next;
120125
}
121126
}
122127
}

packages/client/lib/sentinel/index.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,16 @@ class RedisSentinelInternal<
928928
}
929929
}
930930

931+
#handleSentinelFailure(node: RedisNode) {
932+
const found = this.#sentinelRootNodes.findIndex(
933+
(rootNode) => rootNode.host === node.host && rootNode.port === node.port
934+
);
935+
if (found !== -1) {
936+
this.#sentinelRootNodes.splice(found, 1);
937+
}
938+
this.#reset();
939+
}
940+
931941
async close() {
932942
this.#destroy = true;
933943

@@ -1197,8 +1207,9 @@ class RedisSentinelInternal<
11971207
error: err
11981208
};
11991209
this.emit('client-error', event);
1200-
this.#reset();
1201-
});
1210+
this.#handleSentinelFailure(node);
1211+
})
1212+
.on('end', () => this.#handleSentinelFailure(node));
12021213
this.#sentinelClient = client;
12031214

12041215
this.#trace(`transform: adding sentinel client connect() to promise list`);

0 commit comments

Comments
 (0)