Chi tiết về Kết cấu Dữ liệu Bên trong Redis
cấu trúc dữ liệu
Khía cạnh đầu tiên99win club, từ góc độ người sử dụng. Ví dụ:
Khía cạnh này cũng là giao diện gọi API mà Redis cung cấp ra bên ngoài.
Khía cạnh thứ haiđá gà trực tiếp app, từ góc độ triển khai nội bộ, thuộc về phần thực hiện ở tầng thấp hơn. Ví dụ:
Cấu trúc dữ liệu http://redis.io/topics/data-types-intro Bài viết này sẽ tập trung vào việc thảo luận về khía cạnh thứ hai99win club, đó là cách Redis triển khai các cấu trúc dữ liệu bên trong ở cấp độ thứ hai, cũng như mối quan hệ giữa các cấu trúc dữ liệu ở hai cấp độ này: Redis làm thế nào để xây dựng các cấu trúc dữ liệu cao cấp hơn ở cấp độ đầu tiên bằng cách kết hợp các thành phần cơ bản từ cấp độ thứ hai. Ngoài ra, việc hiểu rõ cách hoạt động của các cấu trúc dữ liệu cơ bản tại cấp độ thứ hai sẽ giúp chúng ta có cái nhìn sâu sắc hơn về hiệu suất và khả năng xử lý dữ liệu của Redis. Redis sử dụng một loạt các công cụ như danh sách liên kết đôi, cây cân bằng, hoặc chuỗi phân tán để tạo nên các tính năng phức tạp mà người dùng thường xuyên sử dụng, chẳng hạn như chuỗi (string), danh sách (list), tập hợp (set), hoặc bảng băm (hash). Mỗi loại dữ liệu trong Redis đều được xây dựng dựa trên các yếu tố cơ bản như mảng, cây nhị phân, hoặc chuỗi, và được tùy chỉnh để phù hợp với yêu cầu cụ thể của từng trường hợp sử dụng. Điều này không chỉ giúp tối ưu hóa hiệu quả lưu trữ mà còn đảm bảo rằng Redis có thể xử lý hàng tỷ giao dịch mỗi giây một cách nhanh chóng và ổn định.
Khi thảo luận về việc triển khai nội bộ của bất kỳ hệ thống nàođá gà trực tiếp app, chúng ta cần trước tiên xác định rõ các nguyên tắc thiết kế của nó. Điều này giúp chúng ta hiểu sâu hơn về ý định thực sự đằng sau việc tại sao hệ thống lại được thiết kế theo cách đó. Trong phần tiếp theo của bài viết này, chúng tôi sẽ tập trung vào một số điểm chính sau đây: Trước hết, việc hiểu rõ bản chất của các nguyên tắc thiết kế không chỉ giúp chúng ta đánh giá cao tầm quan trọng của từng yếu tố mà còn cung cấp cái nhìn toàn diện về cách mà hệ thống hoạt động hiệu quả. Thứ hai, khi phân tích kỹ lưỡng những gì đã được thực hiện, chúng ta có thể khám phá ra những điểm mạnh và điểm yếu tiềm ẩn trong cơ chế vận hành của hệ thống. Cuối cùng, chúng tôi sẽ cố gắng đưa ra một số nhận định về cách cải tiến có thể áp dụng nhằm tối ưu hóa hiệu suất tổng thể. Chúng tôi hy vọng rằng qua việc đi sâu vào phân tích này, độc giả sẽ có được cái nhìn mới mẻ và sâu sắc hơn về hệ thống đang được thảo luận.
Chi tiết về Kết cấu Dữ liệu Nội bộ của Redis
Dict là một cấu trúc dữ liệu được thiết kế để duy trì mối quan hệ ánh xạ giữa key và value99WIN, tương tự như Map hoặc dictionary trong nhiều ngôn ngữ lập trình khác. Trong Redis, tất cả các mối quan hệ ánh xạ từ key đến value trong một database đều được duy trì thông qua một dict. Tuy nhiên, đây chỉ là một trong những ứng dụng của dict trong Redis mà thôi. Có rất nhiều nơi khác mà dict được sử dụng trong hệ thống này. Ví dụ, khi một hash trong Redis có số lượng field lớn, dict sẽ được dùng để lưu trữ chúng. Thêm vào đó, Redis thường kết hợp sử dụng dict cùng với skiplist để quản lý một tập hợp đã sắp xếp (sorted set). Những chi tiết này, chúng ta sẽ tìm hiểu kỹ hơn ở các bài viết sau. Còn trong bài viết hiện tại, chúng ta sẽ tập trung phân tích cách thức triển khai của dict. Trước tiên, cần hiểu rằng dict trong Redis không chỉ đơn thuần là một công cụ để ánh xạ key-value mà còn đóng vai trò quan trọng trong việc tối ưu hóa hiệu suất của hệ thống. Với cơ chế hashing thông minh, dict giúp giảm thiểu thời gian truy xuất dữ liệu và tăng cường khả năng mở rộng cho các yêu cầu phức tạp. Điều này đặc biệt hữu ích khi xử lý các trường hợp như yêu cầu tìm kiếm, thêm hoặc xóa dữ liệu nhanh chó Đặc biệt, dict trong Redis cũng được thiết kế để hỗ trợ khả năng tự động điều chỉnh kích thước bộ nhớ khi cần thiết. Khi số lượng phần tử trong dict vượt quá giới hạn tối đa, nó sẽ tự động tăng kích thước bộ nhớ để đảm bảo hiệu suất hoạt động ổn định. Đây là một tính năng quan trọng giúp Redis duy trì hiệu quả cao trong mọi tình huống vận hành. Như vậy, dù chỉ là một thành phần nhỏ trong hệ thống Redis, dict vẫn giữ vai trò then chốt trong việc tạo nên sự linh hoạt và hiệu quả trong việc quản lý dữ liệu. Chúng ta sẽ tiếp tục khám phá sâu hơn về cách hoạt động chi tiết của dict trong các phần tiếp theo của bài viết.
Dict về cơ bản được thiết kế để giải quyết các vấn đề tìm kiếm (searching) trong lĩnh vực thuật toán. Thông thường99WIN, các phương pháp giải quyết vấn đề tìm kiếm có thể chia thành hai nhóm lớn: một là dựa trên các cây cân bằng (balanced tree), và hai là dựa trên bảng băm (hash table). Các Map hoặc dictionary mà chúng ta sử dụng hàng ngày chủ yếu đều được xây dựng dựa trên bảng băm. Trong trường hợp không yêu cầu dữ liệu phải được sắp xếp theo thứ tự và có thể duy trì xác suất xung đột giá trị băm ở mức thấp, hiệu suất tìm kiếm dựa trên bảng băm có thể đạt được mức độ hiệu quả rất cao, gần như O(1), đồng thời cách thực hiện cũng khá đơn giản và trực quan.
thời gian phản hồi nhanh
Tiếp theo sẽ đưa ra chi tiết giới thiệu.
Để thực hiện việc tái phân tán hash theo cách tăng dần (incremental rehashing)đá gà trực tiếp app, cấu trúc dữ liệu của dict bao gồm hai bảng hash. Trong quá trình tái phân tán, dữ liệu sẽ được di chuyển từ bảng hash đầu tiên sang bảng hash thứ hai một cách từ từ và hiệu quả. Bên cạnh đó, việc sử dụng hai bảng hash này không chỉ giúp quá trình tái phân dữ liệu trở nên mượt mà hơn mà còn đảm bảo rằng các hoạt động đọc/ghi vẫn có thể diễn ra bình thường trong khi hệ thống đang xử lý việc phân phối lại dữ liệu. Điều này làm cho dict trở nên linh hoạt và ổn định hơn trong nhiều tình huống thực tế.
Định nghĩa mã nguồn C của dict như sau (trích từ tệp dict.h của mã nguồn Redis):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
typedef
struct
dictEntry
{
void
*
key
;
union
{
void
*
val
;
uint64_t
u64
;
int64_t
s64
;
double
d
;
}
v
;
struct
dictEntry
*
next
;
}
dictEntry
;
typedef
struct
dictType
{
unsigned
int
(
*
hashFunction
)(
const
void
*
key
);
void
*
(
*
keyDup
)(
void
*
privdata
,
const
void
*
key
);
void
*
(
*
valDup
)(
void
*
privdata
,
const
void
*
obj
);
int
(
*
keyCompare
)(
void
*
privdata
,
const
void
*
key1
,
const
void
*
key2
);
void
(
*
keyDestructor
)(
void
*
privdata
,
void
*
key
);
void
(
*
valDestructor
)(
void
*
privdata
,
void
*
obj
);
}
dictType
;
/* This is our hash table structure. Every dictionary has two of this as we
* implement incremental rehashing99WIN, for the old to the new table. */
typedef
struct
dictht
{
dictEntry
**
table
;
unsigned
long
size
;
unsigned
long
sizemask
;
unsigned
long
used
;
}
dictht
;
typedef
struct
dict
{
dictType
*
type
;
void
*
privdata
;
dictht
ht
[
2
];
long
rehashidx
;
/* rehashing not in progress if rehashidx == -1 */
int
iterators
;
/* number of iterators currently running */
}
dict
;
Để có thể hiểu rõ hơn về định nghĩa cấu trúc dữ liệu của dictđá gà trực tiếp app, chúng ta sẽ biểu diễn nó bằng một sơ đồ cấu trúc. Dưới đây là hình ảnh.
Dựa trên mã nguồn và sơ đồ cấu trúc được cung cấp ở trênđá gà trực tiếp app, ta có thể dễ dàng nhận ra cấu trúc của từ điển (dict). Một dict bao gồm các thành phần sau đây: Trước hết, mỗi dict luôn bắt đầu bằng dấu ngoặc nhọn `{}` để xác định phạm vi của nó. Tiếp theo, mỗi thành phần bên trong dict sẽ là một cặp "key-value", tức là một cặp giá trị duy nhất được phân tách bởi dấu hai chấm `:`. Các cặp này sẽ được phân cách nhau bằng dấu phẩy `,`, tạo nên sự mạch lạc và rõ ràng trong cấu trúc. Ví dụ, một dict đơn giản có thể trông như thế này: ``` { "name": "John", "age": 30, "is_student": False } ``` Trong đó: - `"name"` là key và `"John"` là value tương ứng. - `"age"` là key và `30` là value. - `"is_student"` là key và `False` (giá trị logic) là value. Thêm vào đó, dict hỗ trợ nhiều loại dữ liệu khác nhau làm giá trị, bao gồm chuỗi, số, boolean, danh sách (list), hoặc thậm chí là các dict lồng nhau. Điều này khiến cho dict trở thành công cụ mạnh mẽ và linh hoạt trong việc lưu trữ và truy xuất thông tin.
Trong cấu trúc dictType99WIN, có chứa một số con trỏ đến hàm, cho phép người gọi của dict tùy chỉnh các thao tác liên quan đến key và value. Các thao tác này bao gồm: - Tạo và quản lý việc thêm hoặc xóa key-value. - So sánh hai key để xác định thứ tự hoặc tính chất bằng nhau. - Hash hóa key để tạo mã định danh duy nhất. - Sắp xếp và tìm kiếm key trong trường hợp cần thiết. - Xử lý các lỗi hoặc tình huống bất thường khi thực hiện thao tác trên dict. Tính linh hoạt này giúp dictType trở nên mạnh mẽ và phù hợp với nhiều ứng dụng khác nhau trong hệ thống.
Con trỏ dữ liệu riêng tư (privdata) là một tham chiếu được truyền lại cho người gọi khi một số chức năng của dictType được thực hiện. Trong quá trình xử lýđá gà trực tiếp app, con trỏ này đóng vai trò quan trọng trong việc lưu trữ hoặc quản lý các thông tin đặc thù mà mỗi lần gọi có thể cần đến, từ đó giúp tăng tính linh hoạt và hiệu quả cho hoạt động của hệ thống.
Cần xem xét kỹ hơn cấu trúc dictht. Nó định nghĩa cấu trúc của bảng băm99WIN, bao gồm các thành phần sau:
Trong cấu trúc dictEntry99WIN, bao gồm các thành phần k, v và con trỏ next để trỏ đến phần tử tiếp theo trong danh sách liên kết. Biến k là một con trỏ void, điều này cho phép nó có thể trỏ đến bất kỳ kiểu dữ liệu nào. Còn v là một union (liên hợp), khi giá trị của nó là uint64_t, int64_t hoặc double thì không cần thêm bộ nhớ lưu trữ bổ sung, điều này giúp giảm thiểu mảnh vụn bộ nhớ. Tất nhiên, v cũng có thể là một con trỏ void để lưu trữ bất kỳ loại dữ liệu nào. Cấu trúc dictEntry không chỉ đơn giản là một công cụ lưu trữ mà còn mang tính linh hoạt cao. Với khả năng tối ưu hóa bộ nhớ thông qua union, nó đảm bảo hiệu suất tốt hơn trong việc quản lý tài nguyên hệ thống. Đồng thời, việc sử dụng con trỏ void làm tham số k và v cho phép nó tương thích với hầu hết các loại dữ liệu hiện có, từ đó mở rộng phạm vi ứng dụng của dictEntry trong các hệ thống phức tạp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
dict
*
dictCreate
(
dictType
*
type
,
void
*
privDataPtr
)
{
dict
*
d
=
zmalloc
(
sizeof
(
*
d
));
_dictInit
(
d
,
type
,
privDataPtr
);
return
d
;
}
int
_dictInit
(
dict
*
d
,
dictType
*
type
,
void
*
privDataPtr
)
{
_dictReset
(
&
d
->
ht
[
0
]);
_dictReset
(
&
d
->
ht
[
1
]);
d
->
type
=
type
;
d
->
privdata
=
privDataPtr
;
d
->
rehashidx
=
-
1
;
d
->
iterators
=
0
;
return
DICT_OK
;
}
static
void
_dictReset
(
dictht
*
ht
)
{
ht
->
table
=
NULL
;
ht
->
size
=
0
;
ht
->
sizemask
=
0
;
ht
->
used
=
0
;
}
Hàm dictCreate sẽ cấp phát bộ nhớ cho cấu trúc dữ liệu dict và gán giá trị ban đầu cho các biến liên quan. Trong đó99WIN, hai bảng băm ht[0] và ht[1] ban đầu chưa được cấp phát không gian, cả hai con trỏ table đều được đặt thành NULL. Điều này có nghĩa là việc phân bổ thực tế chỉ xảy ra khi dữ liệu đầu tiên được chèn vào. Khi đó, hệ thống mới bắt đầu thiết lập và quản lý không gian lưu trữ theo yêu cầu của các phần tử sắp tới.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#define dictIsRehashing(d) ((d)->rehashidx != -1)
dictEntry
*
dictFind
(
dict
*
d
,
const
void
*
key
)
{
dictEntry
*
he
;
unsigned
int
h
,
idx
,
table
;
if
(
d
->
ht
[
0
].
used
+
d
->
ht
[
1
].
used
==
0
)
return
NULL
;
/* dict is empty */
if
(
dictIsRehashing
(
d
))
_dictRehashStep
(
d
);
h
=
dictHashKey
(
d
,
key
);
for
(
table
=
0
;
table
<=
1
;
table
++
)
{
idx
=
h
&
d
->
ht
[
table
].
sizemask
;
he
=
d
->
ht
[
table
].
table
[
idx
];
while
(
he
)
{
if
(
key
==
he
->
key
||
dictCompareKeys
(
d
,
key
,
he
->
key
))
return
he
;
he
=
he
->
next
;
}
if
(
!
dictIsRehashing
(
d
))
return
NULL
;
}
return
NULL
;
}
Mã nguồn của dictFind trên đây99WIN, dựa trên việc dict hiện tại có đang tiến hành băm lại hay không, lần lượt thực hiện các bước sau:
Chúng ta cần xem xét kỹ hơn cách thực hiện của _dictRehashStep99WIN, tiến trình băm lại từng bước.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
static
void
_dictRehashStep
(
dict
*
d
)
{
if
(
d
->
iterators
==
0
)
dictRehash
(
d
,
1
);
}
int
dictRehash
(
dict
*
d
,
int
n
)
{
int
empty_visits
=
n
*
10
;
/* Max number of empty buckets to visit. */
if
(
!
dictIsRehashing
(
d
))
return
0
;
while
(
n
--
&&
d
->
ht
[
0
].
used
!=
0
)
{
dictEntry
*
de
,
*
nextde
;
/* Note that rehashidx can't overflow as we are sure there are more
* elements because ht[0].used != 0 */
assert
(
d
->
ht
[
0
].
size
>
(
unsigned
long
)
d
->
rehashidx
);
while
(
d
->
ht
[
0
].
table
[
d
->
rehashidx
]
==
NULL
)
{
d
->
rehashidx
++
;
if
(
--
empty_visits
==
0
)
return
1
;
}
de
=
d
->
ht
[
0
].
table
[
d
->
rehashidx
];
/* Move all the keys in this bucket from the old to the new hash HT */
while
(
de
)
{
unsigned
int
h
;
nextde
=
de
->
next
;
/* Get the index in the new hash table */
h
=
dictHashKey
(
d
,
de
->
key
)
&
d
->
ht
[
1
].
sizemask
;
de
->
next
=
d
->
ht
[
1
].
table
[
h
];
d
->
ht
[
1
].
table
[
h
]
=
de
;
d
->
ht
[
0
].
used
--
;
d
->
ht
[
1
].
used
++
;
de
=
nextde
;
}
d
->
ht
[
0
].
table
[
d
->
rehashidx
]
=
NULL
;
d
->
rehashidx
++
;
}
/* Check if we already rehashed the whole table... */
if
(
d
->
ht
[
0
].
used
==
0
)
{
zfree
(
d
->
ht
[
0
].
table
);
d
->
ht
[
0
]
=
d
->
ht
[
1
];
_dictReset
(
&
d
->
ht
[
1
]);
d
->
rehashidx
=
-
1
;
return
0
;
}
/* More to rehash... */
return
1
;
}
Trong mỗi lần thực hiện dictRehash99WIN, ít nhất n bước của quá trình tái phân tán sẽ được tiến hành (trừ khi toàn bộ quá trình tái phân phối kết thúc trước khi đạt đến n bước). Tại mỗi bước, một bucket cụ thể từ danh sách dictEntry nằm trong mảng ht[0] sẽ được di chuyển sang mảng ht[1]. Vị trí mới của các dictEntry này trên mảng ht[1] sẽ được tính toán lại dựa trên giá trị sizemask của mảng ht[1]. Biến rehashidx giữ track của vị trí bucket chưa được di chuyển (còn đang chờ xử lý) trong mảng ht[0].
Khi dictRehash được thực hiện và bucket mà rehashidx đang chỉ tới hoàn toàn trống (không có dictEntry nào)99WIN, điều đó có nghĩa là không có dữ liệu nào cần được di chuyển ở thời điểm này. Tại thời điểm này, hệ thống sẽ cố gắng tìm kiếm trong mảng ht[0].table để tìm vị trí tiếp theo chứa dữ liệu. Nó sẽ lần lượt kiểm tra các bucket tiếp theo cho đến khi tìm thấy một bucket có dữ liệu. Tuy nhiên, nếu nó không thể tìm thấy bất kỳ bucket nào chứa dữ liệu sau khi thực hiện tối đa n * 10 bước, quá trình tái phân tán hash (rehash) tạm thời sẽ bị dừng lại để tránh lãng phí tài nguyên.
Cuối cùng99win club, khi tất cả dữ liệu trên ht[0] đã được di chuyển hoàn toàn sang ht[1] (tức là d->ht[0].used == 0), quá trình tái phân tán hash sẽ kết thúc. Lúc này, ht[0] sẽ nhận toàn bộ nội dung từ ht[1], trong khi ht[1] sẽ được làm trống lại về trạng thái ban đầu, sẵn sàng cho các hoạt động tiếp theo.
Dựa trên phân tích về quá trình tái-hashing được đề cập ở trên99WIN, chúng ta có thể dễ dàng nhận ra rằng hình ảnh cấu trúc dict được trình bày trong phần trước của bài viết chính là tình huống khi rehashidx = 2. Hai bucket đầu tiên (ht[0].table[0] và ht[0].table[1]) đã được di chuyển hoàn toàn sang ht[1]. Bên cạnh đó, có thể thấy rằng việc tái-hashing đang diễn ra một cách có hệ thống, đảm bảo rằng các giá trị trong hash table cũ (ht[0]) được sắp xếp lại một cách hợp lý vào bảng mới (ht[1]). Điều này cho phép duy trì hiệu quả hoạt động của thuật toán trong suốt quá trình xử lý dữ liệu lớn hoặc khi cần mở rộng kích thước củ
dictAdd chèn cặp mới key và value99WIN, nếu key đã tồn tại thì sẽ thất bại.
Hàm dictReplace cũng thêm vào một cặp khóa và giá trị99win club, nhưng khi khóa đã tồn tại, nó sẽ cập nhật giá trị tương ứng. Điều này giúp đảm bảo rằng từ điển luôn chứa thông tin mới nhất mà không cần phải xóa hoặc thao tác phức tạp khác.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
int
dictAdd
(
dict
*
d
,
void
*
key
,
void
*
val
)
{
dictEntry
*
entry
=
dictAddRaw
(
d
,
key
);
if
(
!
entry
)
return
DICT_ERR
;
dictSetVal
(
d
,
entry
,
val
);
return
DICT_OK
;
}
dictEntry
*
dictAddRaw
(
dict
*
d
,
void
*
key
)
{
int
index
;
dictEntry
*
entry
;
dictht
*
ht
;
if
(
dictIsRehashing
(
d
))
_dictRehashStep
(
d
);
/* Get the index of the new elementđá gà trực tiếp app, or -1 if
* the element already exists. */
if
((
index
=
_dictKeyIndex
(
d
,
key
))
==
-
1
)
return
NULL
;
/* Allocate the memory and store the new entry.
* Insert the element in top99WIN, with the assumption that in a database
* system it is more likely that recently added entries are accessed
* more frequently. */
ht
=
dictIsRehashing
(
d
)
?
&
d
->
ht
[
1
]
:
&
d
->
ht
[
0
];
entry
=
zmalloc
(
sizeof
(
*
entry
));
entry
->
next
=
ht
->
table
[
index
];
ht
->
table
[
index
]
=
entry
;
ht
->
used
++
;
/* Set the hash entry fields. */
dictSetKey
(
d
,
entry
,
key
);
return
entry
;
}
static
int
_dictKeyIndex
(
dict
*
d
,
const
void
*
key
)
{
unsigned
int
h
,
idx
,
table
;
dictEntry
*
he
;
/* Expand the hash table if needed */
if
(
_dictExpandIfNeeded
(
d
)
==
DICT_ERR
)
return
-
1
;
/* Compute the key hash value */
h
=
dictHashKey
(
d
,
key
);
for
(
table
=
0
;
table
<=
1
;
table
++
)
{
idx
=
h
&
d
->
ht
[
table
].
sizemask
;
/* Search if this slot does not already contain the given key */
he
=
d
->
ht
[
table
].
table
[
idx
];
while
(
he
)
{
if
(
key
==
he
->
key
||
dictCompareKeys
(
d
,
key
,
he
->
key
))
return
-
1
;
he
=
he
->
next
;
}
if
(
!
dictIsRehashing
(
d
))
break
;
}
return
idx
;
}
Đây là mã nguồn quan trọng của dictAdd. Chúng ta cần lưu ý các điểm chính sau:
dictReplace được xây dựng dựa trên dictAddđá gà trực tiếp app, như sau:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int
dictReplace
(
dict
*
d
,
void
*
key
,
void
*
val
)
{
dictEntry
*
entry
,
auxentry
;
/* Try to add the element. If the key
* does not exists dictAdd will suceed. */
if
(
dictAdd
(
d
,
key
,
val
)
==
DICT_OK
)
return
1
;
/* It already exists99WIN, get the entry */
entry
=
dictFind
(
d
,
key
);
/* Set the new value and free the old one. Note that it is important
* to do that in this order99WIN, as the value may just be exactly the same
* as the previous one. In this context, think to reference counting,
* you want to increment (set), and then decrement (free), and not the
* reverse. */
auxentry
=
*
entry
;
dictSetVal
(
d
,
entry
,
val
);
dictFreeVal
(
d
,
&
auxentry
);
return
0
;
}
Trong trường hợp key đã tồn tạiđá gà trực tiếp app, dictReplace sẽ gọi đồng thời cả dictAdd và dictFind, điều này thực chất giống như thực hiện hai lần quá trình tìm kiếm. Tại đây, mã nguồn của Redis chưa được tối ưu hóa một cách hiệu quả. Điều này có thể dẫn đến việc tiêu tốn thêm tài nguyên và làm chậm tốc độ xử lý khi số lượng phần tử trong từ điển tăng lên. Một giải pháp tối ưu hơn có thể là chỉ sử dụng dictFind để kiểm tra sự tồn tại của key và thực hiện hành động phù hợp thay vì chạy thêm dictAdd không cần thiết. Điều này không chỉ giúp giảm bớt gánh nặng cho hệ thống mà còn cải thiện hiệu suất tổng thể của Redis.
Mã nguồn của dictDelete ở đây bị bỏ quađá gà trực tiếp app, vui lòng tham khả c. Cần chú ý một chút là:
Việc triển khai của dict tương đối đơn giản99win club, bài viết này sẽ dừng lại ở đây. Ở bài viết tiếp theo, chúng ta sẽ tìm hiểu về việc triển khai chuỗi động trong Redis - sds, hãy cùng đón chờ nhé.