1
0
mirror of https://github.com/redis/node-redis.git synced 2025-12-11 09:22:35 +03:00

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
This commit is contained in:
Vuong Ngo (Viktor)
2025-10-02 17:39:39 +07:00
committed by GitHub
parent 17fc725536
commit 73413e086c
3 changed files with 59 additions and 11 deletions

View File

@@ -6,7 +6,7 @@ import {
import { equal, deepEqual } from "assert/strict"; import { equal, deepEqual } from "assert/strict";
describe("DoublyLinkedList", () => { describe("DoublyLinkedList", () => {
const list = new DoublyLinkedList(); const list = new DoublyLinkedList<number>();
it("should start empty", () => { it("should start empty", () => {
equal(list.length, 0); equal(list.length, 0);
@@ -96,6 +96,38 @@ describe("DoublyLinkedList", () => {
} }
equal(count, 6); equal(count, 6);
}); });
it("should handle remove on empty list", () => {
list.reset();
const node = list.push(1);
list.remove(node);
equal(list.length, 0);
deepEqual(Array.from(list), []);
list.remove(node);
equal(list.length, 0);
deepEqual(Array.from(list), []);
});
it("should safely remove nodes while iterating", () => {
list.reset();
list.push(1);
list.push(2);
list.push(3);
list.push(4);
list.push(5);
const visited: number[] = [];
for (const node of list.nodes()) {
visited.push(node.value);
if (node.value % 2 === 0) {
list.remove(node);
}
}
deepEqual(visited, [1, 2, 3, 4, 5]);
equal(list.length, 3);
deepEqual(Array.from(list), [1, 3, 5]);
});
}); });
describe("SinglyLinkedList", () => { describe("SinglyLinkedList", () => {

View File

@@ -29,7 +29,7 @@ export class DoublyLinkedList<T> {
++this.#length; ++this.#length;
if (this.#tail === undefined) { if (this.#tail === undefined) {
return this.#tail = this.#head = { return this.#head = this.#tail = {
previous: this.#head, previous: this.#head,
next: undefined, next: undefined,
value value
@@ -73,7 +73,7 @@ export class DoublyLinkedList<T> {
--this.#length; --this.#length;
const node = this.#head; const node = this.#head;
if (node.next) { if (node.next) {
node.next.previous = node.previous; node.next.previous = undefined;
this.#head = node.next; this.#head = node.next;
node.next = undefined; node.next = undefined;
} else { } else {
@@ -83,19 +83,23 @@ export class DoublyLinkedList<T> {
} }
remove(node: DoublyLinkedNode<T>) { remove(node: DoublyLinkedNode<T>) {
if (this.#length === 0) return;
--this.#length; --this.#length;
if (this.#tail === node) { if (this.#tail === node) {
this.#tail = node.previous; this.#tail = node.previous;
} }
if (this.#head === node) { if (this.#head === node) {
this.#head = node.next; this.#head = node.next;
} else { } else {
node.previous!.next = node.next; if (node.previous) {
node.previous = undefined; node.previous.next = node.next;
}
if (node.next) {
node.next.previous = node.previous;
}
} }
node.previous = undefined;
node.next = undefined; node.next = undefined;
} }
@@ -115,8 +119,9 @@ export class DoublyLinkedList<T> {
*nodes() { *nodes() {
let node = this.#head; let node = this.#head;
while(node) { while(node) {
const next = node.next
yield node; yield node;
node = node.next; node = next;
} }
} }
} }

View File

@@ -928,6 +928,16 @@ class RedisSentinelInternal<
} }
} }
#handleSentinelFailure(node: RedisNode) {
const found = this.#sentinelRootNodes.findIndex(
(rootNode) => rootNode.host === node.host && rootNode.port === node.port
);
if (found !== -1) {
this.#sentinelRootNodes.splice(found, 1);
}
this.#reset();
}
async close() { async close() {
this.#destroy = true; this.#destroy = true;
@@ -1197,8 +1207,9 @@ class RedisSentinelInternal<
error: err error: err
}; };
this.emit('client-error', event); this.emit('client-error', event);
this.#reset(); this.#handleSentinelFailure(node);
}); })
.on('end', () => this.#handleSentinelFailure(node));
this.#sentinelClient = client; this.#sentinelClient = client;
this.#trace(`transform: adding sentinel client connect() to promise list`); this.#trace(`transform: adding sentinel client connect() to promise list`);