Phân tích cấu trúc dữ liệu nội bộ của Redis Phân tích cấu trúc dữ liệu nội bộ của Redis Trong bài viết nàysv 88, chúng ta sẽ đi sâu vào phân tích một trong những cấu trúc dữ liệu nội bộ quan trọng của Redis – Quicklist là thành phần cốt lõi mà Redis sử dụng để hỗ trợ kiểu dữ liệu list mà nó cung cấp ra bên ngoài. Đây là phần thứ năm trong loạt bài viết của chúng tôi về Redis, và nó đóng vai trò đặc biệt quan trọng trong việc hiểu cách hoạt động bên trong của Redis khi xử lý các danh sách.
Trong quá trình thảo luậnsv 88, chúng ta sẽ cùng tìm hiểu thêm về hai cấu hình Redis được đề cập rõ ràng trong phần CẤU HÌNH NÂNG CAO (ADVANCED CONFIG) của tậ conf.
list-max-ziplist-size -2
list-compress-depth 0
Trong quá trình thảo luậnđá gà trực tiếp app, chúng tôi sẽ giải thích chi tiết ý nghĩa của hai cấu hình này.
Lưu ý: Thực hiện này về quicklist dựa trên nhánh nguồn code của Redis 3.2.
Redis cung cấp kiểu dữ liệu danh sách (list) ở tầng giao tiếp phía trênsv 88, thường được sử dụng như một hàng đợi (queue). Một số thao tác mà nó hỗ trợ, chẳng hạn như: - Thêm phần tử vào cuối danh sách (LPUSH), giống như thêm một công việc vào cuối hàng đợi. - Lấy phần tử từ đầu danh sách (LPOP), tương đương với lấy ra công việc đầu tiên trong hàng đợi. - Đọc nhanh các phần tử mà không làm thay đổi danh sách (LRANGE), giúp kiểm tra trạng thái hiện tại của hàng đợi. - Kiểm tra xem danh sách có rỗng hay không (LLEN), cho phép xác định khi nào hàng đợi đã hoàn toàn được xử lý. Các tính năng này đã giúp Redis trở thành một lựa chọn linh hoạt và mạnh mẽ cho các ứng dụng cần quản lý dữ liệu theo mô hình hàng đợi.
lpush
: Chèn dữ liệu vào bên trái (tức là phần đầu danh sách).
rpop
: Xóa dữ liệu từ bên phải (tức là phần cuối danh sách).
rpush
: Chèn dữ liệu vào bên phải (tức là phần cuối danh sách).
lpop
: Xóa dữ liệu từ bên trái (tức là phần đầu danh sách).
Các hoạt động này đều có độ phức tạp thời gian O(1).
Tất nhiênkeo 88, list cũng hỗ trợ thao tác truy cập tại bất kỳ vị trí nào giữa, ví dụ:
lindex
và
linsert
đá gà trực tiếp app, nhưng chúng cần duyệt qua toàn bộ list, do đó độ phức tạp thời gian cao hơn, là O(N).
Tóm lạisv 88, một list có những đặc điểm như sau: đây là một danh sách có thể duy trì thứ tự của các phần tử (thứ tự được xác định bởi vị trí chèn), dễ dàng thêm hoặc xóa dữ liệu ở hai đầu danh sách, nhưng việc truy xuất ở giữa danh sách sẽ có độ phức tạp thời gian O(n). Điều này chẳng phải cũng là những gì mà một danh sách liên kết đôi có sao? Một danh sách liên kết đôi cho phép chúng ta thao tác linh hoạt ở cả hai đầu, và trong khi đó vẫn giữ được tính năng quản lý dữ liệu theo thứ tự. Điều này làm cho nó trở thành một lựa chọn rất hữu ích trong nhiều trường hợp lập trình.
Thực hiện nội bộ của list chính là một danh sách liên kết hai chiều. Trong phần chú thích đầ ckeo 88, quicklist được mô tả như sau:
A doubly linked list of ziplists
Nó thực sự là một danh sách liên kết hai chiềusv 88, và là một danh sách ziplist hai chiều.
Điều này có nghĩa gì?
Chúng ta đều hiểu rằngsv 88, danh sách liên kết hai chiều được tạo thành từ nhiều nút (Node). Điều này có nghĩa là mỗi nút trong quicklist đều là một ziplist. Ziplist đã được đề cập trước đây, và nó là một cấu trúc dữ liệu đặc biệt được sử dụng để lưu trữ các phần tử theo thứ tự tuần tự trong bộ nhớ. Với khả năng tối ưu hóa không gian lưu trữ và hiệu suất truy xuất, ziplist đóng vai trò quan trọng trong việc quản lý dữ liệu bên trong quicklist, cho phép hệ thống thực hiện các thao tác như chèn, xóa hoặc truy vấn một cách linh hoạt và hiệu quả. Bài trước Đã được giới thiệu trước đó.
Ziplist không chỉ là một danh sách có khả năng duy trì thứ tự các phần tử (theo thứ tự chúng được thêm vào)keo 88, mà còn là một danh sách tối ưu về mặt bộ nhớ (các phần tử nằm liền kề nhau trong bộ nhớ). Ví dụ, một quicklist gồm 3 nút, và mỗi nút ziplist lại chứa 4 phần tử, thì về mặt biểu hiện bên ngoài, danh sách này sẽ chứa tổng cộng 12 phần tử. Điều thú vị là khi bạn thao tác với quicklist này, nó sẽ hoạt động như thể tất cả các phần tử đã được nối thành một chuỗi duy nhất, tạo ra hiệu suất tốt hơn trong việc quản lý và truy xuất dữ liệu.
Tại sao cấu trúc của quicklist lại được thiết kế theo cách này? Nếu tóm tắt lạikeo 88, đó có lẽ là sự đánh đổi giữa không gian và thời gian: Trong thế giới lập trình, mọi thứ đều cần cân nhắc kỹ lưỡng giữa hiệu quả về bộ nhớ (không gian) và tốc độ xử lý (thời gian). Với quicklist, việc tối ưu hóa này giúp hệ thống có thể truy xuất dữ liệu nhanh chóng mà vẫn đảm bảo không tiêu tốn quá nhiều tài nguyên. Khi bạn duyệt qua danh sách, các phần tử được sắp xếp một cách thông minh để giảm thiểu thời gian tìm kiếm và tăng khả năng phản hồi tức thì cho người dùng. Với sự kết hợp khéo léo giữa hai yếu tố này, quicklist trở thành công cụ hữu ích trong việc tối ưu hóa hiệu suất tổng thể của ứng dụng hoặc hệ thống mà nó phục vụ.
Do đókeo 88, kết hợp các ưu điểm của danh sách liên kết hai chiều và ziplist, quicklist đã ra đời.
Tuy nhiênđá gà trực tiếp app, điều này cũng đặt ra một vấn đề mới: Liệu số lượng phần tử trong ziplist của một nút quicklist nên là bao nhiêu thì hợp lý? Ví dụ, khi lưu trữ 12 mục dữ liệu, ta có thể chọn cấu hình quicklist với 3 nút, mỗi nút chứa 4 phần tử ziplist; hoặc cũng có thể chia thành 6 nút, mỗi nút chỉ chứa 2 phần tử ziplist. Vậy, cách nào sẽ tối ưu hơn về hiệu suất và không gian sử dụng? Đây thực sự là một thách thức cần được cân nhắc kỹ lưỡng.
Đây lại là một bài toán khó cần tìm điểm cân bằng. Chúng ta chỉ phân tích một chút về hiệu quả lưu trữ:
Rõ ràngsv 88, một nút quicklist cần duy trì độ dài của ziplist ở mức hợp lý. Nhưng chính xác bao nhiêu là hợp lý thì có thể phụ thuộc vào ngữ cảnh sử dụng cụ thể. Thực tế, Redis cung cấp một tham số cấu hình để giúp người dùng điều chỉnh điều này. Tham số này được gọi là **list-compress-depth** trong tệp cấu hình Redis. Nó cho phép bạn thiết lập số lượng nút quicklist ở đầu và cuối danh sách mà không áp dụng nén. Điều này giúp tối ưu hóa hiệu suất khi truy xuất dữ liệu ở các vị trí gần phần đầu hoặc phần cuối của danh sách. Ví dụ, nếu bạn thường xuyên thực hiện các thao tác thêm/xóa tại hai đầu danh sách, việc tăng giá trị của tham số này sẽ giảm thiểu thời gian giải nén và cải thiện tốc độ xử lý. Tuy nhiên, hãy cân nhắc kỹ lưỡng khi đặt giá trị cho tham số này. Nếu giá trị quá lớn, bộ nhớ có thể bị lãng phí do nhiều nút quicklist chưa được nén. Ngược lại, nếu giá trị quá nhỏ, hiệu quả nén có thể không cao, dẫn đến sự gia tăng đáng kể kích thước bộ nhớ sử dụng. Vì vậy, tùy thuộc vào nhu cầu ứng dụng và đặc thù của dữ liệu, bạn nên thử nghiệm với các giá trị khác nhau để tìm ra sự cân bằng tốt nhất giữa hiệu suất và tài nguyên hệ thống.
list-max-ziplist-size
sv 88, để người dùng có thể điều chỉnh theo tình huống cụ thể của mình.
list-max-ziplist-size -2
Hãy giải thích chi tiết ý nghĩa của tham số này. Nó có thể nhận giá trị dương hoặc âm.
Khi giá trị được đặt thành dươngsv 88, nó sẽ giới hạn độ dài của ziplist trên mỗi nút quicklist dựa trên số lượng mục dữ liệu. Ví dụ, khi tham số này được cấu hình thành 5, có nghĩa là mỗi nút quicklist chỉ có thể chứa tối đa 5 mục trong ziplist của nó. Ngoài ra, việc điều chỉnh tham số này giúp tối ưu hóa bộ nhớ và cải thiện hiệu suất xử lý dữ liệu. Khi giá trị được đặt thấp, hệ thống sẽ sử dụng ít bộ nhớ hơn nhưng có thể dẫn đến tăng số lượng nút cần quản lý. Ngược lại, nếu giá trị quá cao, mặc dù giảm được số lượng nút nhưng có thể làm tăng thời gian truy xuất dữ liệu. Vì vậy, việc chọn giá trị phù hợp cho tham số này là rất quan trọng trong việc duy trì hiệu quả hoạt động tổng thể của hệ thống.
Khi đặt giá trị âmsv 88, điều này có nghĩa là giới hạn độ dài của ziplist trong mỗi nút quicklist dựa trên số lượng byte đã sử dụng. Ở chế độ này, giá trị chỉ có thể nằm trong khoảng từ -1 đến -5, và ý nghĩa của từng giá trị như sau:
Ngoài rađá gà trực tiếp app, mục tiêu của list không chỉ đơn thuần là để lưu trữ các dữ liệu mà còn hướng đến việc quản lý danh sách dữ liệu dài một cách hiệu quả. Ví dụ như trong hướng dẫn trên trang web chính thức của Redis, họ đã đưa ra một bài học cụ thể về cách sử dụng list để lưu trữ và xử lý khối lượng thông tin lớn một cách nhanh chóng và gọn gàng. Hãy tưởng tượng bạn đang điều hành một nền tảng truyền thông xã hội với hàng triệu bài đăng mỗi ngày, list sẽ trở thành công cụ hoàn hảo giúp bạn tổ chức tất cả dữ liệu này theo thứ tự thời gian thực, cho phép bạn truy xuất hoặc thêm bớt dữ liệu một cách dễ dàng mà không gặp bất kỳ vấn đề nào liên quan đến hiệu suất. Writing a simple Twitter clone with PHP and Redis keo 88, tức là sử dụng list để lưu trữ dữ liệu timeline giố
Khi danh sách trở nên dàikeo 88, dữ liệu ở hai đầu danh sách thường có xu hướng được truy cập nhiều hơn so với các phần ở giữa. Việc truy cập vào giữa danh sách không chỉ ít tần suất hơn mà còn có thể làm giảm hiệu suất tổng thể. Nếu ứng dụng của bạn gặp phải đặc điểm này, thì danh sách (list) sẽ cung cấp một tùy chọn để nén các nút dữ liệu ở giữa, từ đó giúp tiết kiệm thêm không gian bộ nhớ. Trong Redis, có một số tham số cấu hình có thể điều chỉnh để tối ưu hóa hành vi này. Điều thú vị là việc nén dữ liệu ở giữa danh sách không chỉ ảnh hưởng đến hiệu suất bộ nhớ mà còn có thể cải thiện tốc độ phản hồi trong trường hợp bạn cần xử lý một lượng lớn dữ liệu. Tuy nhiên, để đạt được hiệu quả tối đa, người dùng cần hiểu rõ cấu trúc dữ liệu mình đang làm việc và lựa chọn cách tối ưu phù hợp nhất. Tham số cấu hình của Redis cho phép bạn linh hoạt điều chỉnh mức độ nén dựa trên nhu cầu cụ thể của ứng dụng. Điều này thực sự hữu ích khi bạn phải đối mặt với những bài toán liên quan đến lưu trữ và xử lý dữ liệu lớn trong hệ thống Redis.
list-compress-depth
Là để hoàn thành việc thiết lập này.
list-compress-depth 0
Tham số này cho biết số lượng nút ở hai đầu của quicklist mà không bị nén. Lưu ý: Số lượng nút này đề cập đến các nút trong danh sách liên kết hai chiều của quicklistđá gà trực tiếp app, chứ không phải số lượng mục dữ liệ Thực tế, khi một nút quicklist được nén, toàn bộ ziplist trên nút đó sẽ bị nén hoàn toàn. Trong ngữ cảnh hoạt động của quicklist, việc duy trì một số lượng nhất định các nút không bị nén ở hai đầu có thể giúp tối ưu hóa hiệu suất truy xuất dữ liệu. Điều này đặc biệt quan trọng khi thực hiện các thao tác đọc hoặc ghi dữ liệu liên tục mà không làm gián đoạn chuỗi xử lý thông qua các nút đã được nén trước đó.
Tham số
list-compress-depth
Ý nghĩa giá trị của nó như sau:
Do 0 là một giá trị đặc biệtsv 88, có thể dễ dàng nhận thấy rằng nút đầu tiên và nút cuối cùng của quicklist luôn không bị nén lại. Điều này giúp việc truy xuất dữ liệu ở hai đầu danh sách trở nên nhanh chóng và hiệu quả hơn.
Thuật toán nén bên trong các nút quicklist của Redis sử dụng LZF —— một thuật toán nén không mất dữ liệu.
Định nghĩa cấu trúc dữ liệu quicklist có thể tìm thấ h:
typedef
struct
quicklistNode
{
struct
quicklistNode
*
prev
;
struct
quicklistNode
*
next
;
unsigned
char
*
zl
;
unsigned
int
sz
;
/* ziplist size in bytes */
unsigned
int
count
:
16
;
/* count of items in ziplist */
unsigned
int
encoding
:
2
;
/* RAW==1 or LZF==2 */
unsigned
int
container
:
2
;
/* NONE==1 or ZIPLIST==2 */
unsigned
int
recompress
:
1
;
/* was this node previous compressed? */
unsigned
int
attempted_compress
:
1
;
/* node can't compress; too small */
unsigned
int
extra
:
10
;
/* more bits to steal for future usage */
}
quicklistNode
;
typedef
struct
quicklistLZF
{
unsigned
int
sz
;
/* LZF size in bytes*/
char
compressed
[];
}
quicklistLZF
;
typedef
struct
quicklist
{
quicklistNode
*
head
;
quicklistNode
*
tail
;
unsigned
long
count
;
/* total count of all entries in all ziplists */
unsigned
int
len
;
/* number of quicklistNodes */
int
fill
:
16
;
/* fill factor for individual nodes */
unsigned
int
compress
:
16
;
/* depth of end nodes not to compress;0=off */
}
quicklist
;
Cấu trúc quicklistNode đại diện cho một nút trong quicklistkeo 88, với các trường dữ liệu bên dưới có ý nghĩa như sau:
zlbytes
,
zltail
,
zllen
,
zlend
Khi làm việc với từng mục dữ liệuđá gà trực tiếp app, cần lưu ý rằng: nếu ziplist đã được nén, giá trị của "sz" vẫn sẽ là kích thước ban đầu của ziplist trước khi bị nén. Điều này có nghĩa là ngay cả khi dữ liệu đã trải qua quá trình nén, thông số "sz" vẫn phản ánh kích thước gốc của nó, không phải kích thước sau khi nén.Cấu trúc quicklistLZF biểu diễn một ziplist đã được nén. Trong đó:
Cấu trúc thực sự đại diện cho quicklist là struct cùng tên quicklist:
list-max-ziplist-size
Giá trị tham số.
list-compress-depth
Giá trị tham số.
Hình ảnh phía trên là một ví dụ về cấu trúc củ Đối với ví dụ trong hìnhkeo 88, các thông số được thiết lập cho ziplist và độ sâu nén của nút như sau:
list-max-ziplist-size 3
list-compress-depth 2
Những điểm cần chú ý trong ví dụ này là:
push
và
pop
Một trạng thái sau khi thực hiện.
Bây giờ chúng ta hãy cùng nhau tính toán sơ bộ xem việc sử dụng 16 bit cho trường count trong cấu trúc quicklistNode có đủ không. Trong lập trìnhsv 88, việc chọn kích thước phù hợp cho các trường dữ liệu rất quan trọng. QuicklistNode là một phần quan trọng của cơ chế quản lý danh sách liên kết, nơi mà count sẽ dùng để đếm số lượng phần tử trong node đó. Nếu count chỉ được cấp phát 16 bit (tức là tối đa 2^16 giá trị), thì nó có thể chứa tối đa 65,535 giá trị. Chúng ta cần xem xét quy mô dữ liệu thực tế mà quicklistNode đang xử lý. Ví dụ như nếu mỗi node lưu trữ một chuỗi ký tự hoặc các cấu trúc phức tạp, có thể cần nhiều hơn 16 bit để biểu diễn số lượng phần tử. Tuy nhiên, nếu dữ liệu đơn giản và có giới hạn trong khoảng nhỏ, 16 bit có thể hoàn toàn ổn thỏa. Tóm lại, việc xác định xem liệu 16 bit có đủ hay không phụ thuộc vào yêu cầu cụ thể của ứng dụng và cách mà quicklistNode được triển khai. Chúng ta cần đánh giá kỹ lưỡng trước khi đưa ra quyết định cuối cùng.
Chúng ta đã biết rằng kích thước ziplist bị giới hạn bởi
list-max-ziplist-size
Tham số. Có hai trường hợp dựa trên giá trị dương và âm:
list-max-ziplist-size
Các tham số được lưu trữ trong trường fill của cấu trú Vì trường fill có kích thước 16 bitsv 88, nên các giá trị mà nó có thể biểu diễn đều có thể được biểu thị bằng 16 bit. Điều này cho phép quicklist quản lý dữ liệu một cách hiệu quả trong phạm vi giới hạn bởi giá trị tối đa của một số 16 bit.
prevrawlen
đá gà trực tiếp app, trường hợp trường byte
data
(
len
Hợp nhất làm một; xem thêm
data
Bây giờ bước vào giai đoạn phân tích mã nguồn.
Bài trước
Vì vậykeo 88, số lượng mục dữ liệu trong ziplist sẽ không vượt quá 32K, và việc sử dụng 16bit để biểu diễn là đủ. Điều này có nghĩa là mỗi phần tử trong danh sách có thể được quản lý một cách hiệu quả mà không cần đến bộ nhớ lớn hơn, giúp tối ưu hóa không gian lưu trữ một cách đáng kể.Trên thực tếsv 88, trong cách triển khai hiện tại của quicklist, kích thước của ziplist còn bị giới hạn bởi một số yếu tố khác, do đó sẽ không bao giờ đạt đến giá trị tối đa mà chúng ta đang phân tích ở đây. Điều này có nghĩa là, ngay cả khi lý thuyết cho phép một giới hạn cao nhất, các điều kiện thực tế sẽ luôn giữ kích thước ziplist ở mức nhỏ hơn nhiều so với con số lý thuyết này.
Tạo quicklist
lệnh để chèn dữ liệu lần đầu tiên vào một list chưa tồn tạikeo 88, Redis sẽ gọi
lpush
Hoặc
rpush
giao diện để tạo một quicklist rỗng.
quicklistCreate
Mã nguồn cho thấyđá gà trực tiếp app, quicklist là một danh sách liên kết hai chiều không có nút trống dư (tất cả
quicklist
*
quicklistCreate
(
void
)
{
struct
quicklist
*
quicklist
;
quicklist
=
zmalloc
(
sizeof
(
*
quicklist
));
quicklist
->
head
=
quicklist
->
tail
=
NULL
;
quicklist
->
len
=
0
;
quicklist
->
count
=
0
;
quicklist
->
compress
=
0
;
quicklist
->
fill
=
-
2
;
return
quicklist
;
}
Trong nhiều cuốn sách giới thiệu về cấu trúc dữ liệusv 88, khi triển khai danh sách liên kết hai chiều, người ta thường thêm một nút đầu trống làm đặc biệt, chủ yếu là để thuận tiện cho các thao tác chèn và xóa. Xuất phát từ điều này, ta có thể thấy rằng: Việc thêm nút đầu trống này không chỉ giúp giảm thiểu sự phức tạp trong việc quản lý vị trí của các nút khác mà còn tạo ra một điểm cố định, giúp lập trình viên dễ dàng kiểm soát chuỗi liên kết mà không cần phải lo lắng về các trường hợp viền bỉ như việc kiểm tra xem danh sách có rỗng hay không trước khi thực hiện các thao tác. Với nút đầu trống, mọi hoạt động trên danh sách liên kết trở nên mượt mà hơn, chẳng hạn như việc thêm một phần tử vào đầu danh sách hoặc loại bỏ một phần tử ở giữa đều trở nên dễ dàng và trực quan hơn bao giờ hết. Thêm nữa, việc sử dụng nút đầu trống cũng góp phần làm rõ ràng hơn về mặt logic đối với các cấu trúc phức tạp, đồng thời giảm thiểu các lỗi tiềm ẩn trong quá trình viết mã. Điều này đặc biệt hữu ích khi xử lý các tập dữ liệu lớn hoặc khi chương trình yêu cầu độ tin cậy cao. Nhờ đó, việc bảo trì và mở rộng mã nguồn sau này cũng trở nên đơn giản hơn rất nhiều.
quicklistCreate
Được khởi tạo thành NULL).
head
và
tail
Hoạt động push của quicklist
Dù chèn dữ liệu vào đầu hay cuốikeo 88, đều bao gồm hai trường hợp:
quicklistPush
Nếu kích thước ziplist trên nút đầu tiên (hoặc cuối cùng) không vượt quá giới hạn (tức
void
quicklistPush
(
quicklist
*
quicklist
,
void
*
value
,
const
size_t
sz
,
int
where
)
{
if
(
where
==
QUICKLIST_HEAD
)
{
quicklistPushHead
(
quicklist
,
value
,
sz
);
}
else
if
(
where
==
QUICKLIST_TAIL
)
{
quicklistPushTail
(
quicklist
,
value
,
sz
);
}
}
/* Add new entry to head node of quicklist.
*
* Returns 0 if used existing head.
* Returns 1 if new head created. */
int
quicklistPushHead
(
quicklist
*
quicklist
,
void
*
value
,
size_t
sz
)
{
quicklistNode
*
orig_head
=
quicklist
->
head
;
if
(
likely
(
_quicklistNodeAllowInsert
(
quicklist
->
head
,
quicklist
->
fill
,
sz
)))
{
quicklist
->
head
->
zl
=
ziplistPush
(
quicklist
->
head
->
zl
,
value
,
sz
,
ZIPLIST_HEAD
);
quicklistNodeUpdateSz
(
quicklist
->
head
);
}
else
{
quicklistNode
*
node
=
quicklistCreateNode
();
node
->
zl
=
ziplistPush
(
ziplistNew
(),
value
,
sz
,
ZIPLIST_HEAD
);
quicklistNodeUpdateSz
(
node
);
_quicklistInsertNodeBefore
(
quicklist
,
quicklist
->
head
,
node
);
}
quicklist
->
count
++
;
quicklist
->
head
->
count
++
;
return
(
orig_head
!=
quicklist
->
head
);
}
/* Add new entry to tail node of quicklist.
*
* Returns 0 if used existing tail.
* Returns 1 if new tail created. */
int
quicklistPushTail
(
quicklist
*
quicklist
,
void
*
value
,
size_t
sz
)
{
quicklistNode
*
orig_tail
=
quicklist
->
tail
;
if
(
likely
(
_quicklistNodeAllowInsert
(
quicklist
->
tail
,
quicklist
->
fill
,
sz
)))
{
quicklist
->
tail
->
zl
=
ziplistPush
(
quicklist
->
tail
->
zl
,
value
,
sz
,
ZIPLIST_TAIL
);
quicklistNodeUpdateSz
(
quicklist
->
tail
);
}
else
{
quicklistNode
*
node
=
quicklistCreateNode
();
node
->
zl
=
ziplistPush
(
ziplistNew
(),
value
,
sz
,
ZIPLIST_TAIL
);
quicklistNodeUpdateSz
(
node
);
_quicklistInsertNodeAfter
(
quicklist
,
quicklist
->
tail
,
node
);
}
quicklist
->
count
++
;
quicklist
->
tail
->
count
++
;
return
(
orig_tail
!=
quicklist
->
tail
);
}
Trả về 1)sv 88, thì dữ liệu mới sẽ được chèn trực tiếp vào ziplist (gọi
_quicklistNodeAllowInsert
Thiết lập. Cách thực hiện khá phức tạpsv 88, chúng tôi sẽ không đi sâu vào đây.
ziplistPush
)。
_quicklistInsertNodeAfter
)。
Nếu
_quicklistInsertNodeAfter
Các hoạt động khác của quicklist
list-compress-depth
Hoạt động pop của quicklist được thực hiện bằng cách gọi
Các thao tác của quicklist khá nhiều và chi tiết thực hiện cũng tương đối phức tạpđá gà trực tiếp app, do đó việc phân tích mã nguồn chi tiết sẽ không được đề cập ở đây. Thay vào đó, chúng ta sẽ giới thiệu sơ lược về một số chức năng quan trọng.
Được sử dụng để thiết lập tham số cấu hình kích thước ziplist (
quicklistPopCustom
Nếu kích thước ziplist trên nút đầu tiên (hoặc cuối cùng) không vượt quá giới hạn (tức
quicklistPopCustom
Quá trình này cơ bản ngược lại so với quicklistPush: đầu tiênkeo 88, bạn cần xóa mục dữ liệu tương ứng từ ziplist của nút đầu hoặc cuối. Nếu sau khi xóa mà ziplist trở nên trống rỗng, thì nút đầu hoặc cuối cũng cần được xóa đi. Sau khi thực hiện việc xóa, có khả năng các nút bên trong sẽ cần được giải nén lại để duy trì tính nhất quán trong cấu trúc. Quy trình này đòi hỏi sự cẩn trọng để đảm bảo không làm hỏng bất kỳ phần nào khác của danh sách.
quicklist không chỉ thực hiện chèn từ đầu hoặc cuốisv 88, mà còn thực hiện chèn từ bất kỳ vị trí được chỉ định nào.
quicklistInsertAfter
và
quicklistInsertBefore
Bạn có thể chèn thêm các mục dữ liệu ngay sau hoặc ngay trước vị trí được chỉ định. Việc thực hiện thao tác chèn dữ liệu vào bất kỳ vị trí nào trong danh sách không hề đơn giảnđá gà trực tiếp app, nó đòi hỏi nhiều nhánh logic khác nhau để xử lý từng trường hợp cụ thể. Một số trường hợp phức tạp hơn, đặc biệt khi vị trí cần chèn nằm ở giữa danh sách hoặc gần cuối cấu trúc dữ liệu, điều này yêu cầu hệ thống phải điều chỉnh và cập nhật hàng loạt liên kết để đảm bảo tính toàn vẹn của toàn bộ dữ liệu.
quicklistSetOptions
Được sử dụng để thiết lập tham số cấu hình kích thước ziplist (
list-max-ziplist-size
list-compress-depth
Mã code khá đơn giảnđá gà trực tiếp app, chỉ cần gán các giá trị tương ứng lần lượt cho trường fill và trường compress trong cấu trú Đây là phần việc không quá phức tạp, nhưng đòi hỏi sự cẩn thận để đảm bảo rằng các giá trị được gán đúng vào đúng vị trí mà chúng thuộc về trong cấu trúc này.
Trong bài viết tiếp theođá gà trực tiếp app, chúng ta sẽ cùng tìm hiểu về cấu trúc dữ liệu skiplist và cách nó hỗ trợ cho kiểu dữ liệ Đây là một chủ đề thú vị mà bạn không nên bỏ lỡ, hãy đón chờ nhé!