A callback processing method and system for Redis asynchronous sending
By designing redundant high-bit bits in the client array and connection object pointer, combined with pattern flags and generation numbers, the overhead of searching and traversing and the problem of wild pointers in Redis asynchronous callback processing are solved, realizing efficient and secure asynchronous callbacks in mixed connection scenarios.
Patent Information
- Authority / Receiving Office
- CN · China
- Patent Type
- Applications(China)
- Current Assignee / Owner
- CHINA UNICOM INTERNET OF THINGS CO LTD
- Filing Date
- 2026-05-22
- Publication Date
- 2026-06-19
Smart Images

Figure CN122240040A_ABST
Abstract
Description
Technical Field
[0001] This invention belongs to the field of computer storage technology, and in particular relates to a callback processing method and system for asynchronous sending to Redis. Background Technology
[0002] After Redis introduced a kernel-level asynchronous sending mechanism, asynchronous completion events need to be efficiently matched with client connection objects to execute callback processing. Existing solutions primarily use file descriptors combined with hash table lookups to obtain connection objects. In scenarios with millions of long-lived connections, each asynchronous completion event requires a hash lookup operation, and the lookup overhead significantly offsets the performance improvements brought by asynchronous sending. Another known solution is to directly store the connection object pointer in the asynchronous request, allowing access to the connection object without lookup during callbacks. However, this solution has significant drawbacks in scenarios with frequent establishment and closure of short connections: when a short connection is closed, all associated pointers must be traversed and marked as invalid in the in-transit asynchronous request queue; otherwise, released or reused connection memory may be accessed incorrectly, leading to the risk of dangling pointers. Furthermore, the traversal operation itself incurs considerable performance overhead in scenarios with tens of thousands of short connection closures per second. In addition, while generating independent nested callback functions for each connection avoids lookups and traversals, the cost of frequently generating and releasing such functions is drastically amplified in short-connection scenarios, and it is highly dependent on specific compilation environments, lacking versatility and adaptability.
[0003] Therefore, in mixed deployment scenarios where Redis simultaneously handles a large number of long connections and high-frequency short connections, existing asynchronous callback matching schemes cannot achieve a balance between eliminating lookup overhead, avoiding traversal overhead, and eliminating the risk of dangling pointers, and it is also difficult to maintain consistent performance under different compilation environments. Summary of the Invention
[0004] This disclosure provides a callback processing method and system for asynchronous Redis sending, which can always complete the safe matching of asynchronous callbacks with low and stable computational cost when facing a mixed load of a large number of long connections and high frequency of short connections.
[0005] This application discloses a callback handling method for asynchronous sending to Redis, including: Retrieve user data corresponding to the asynchronous send completion event. The user data includes a mode flag, a generation number, and content information. The mode flag is used to indicate whether the connection is a long connection or a short connection. The generation number is a count value read from the slot corresponding to the file descriptor of the connection in the client array when the connection is established. The client array is an array in the Redis server with file descriptors as indices and the slots are not released when the connection is closed. The content information is a pointer to the connection object or a file descriptor stored according to the connection type. Based on the pattern marker and the generation number, the connection indicated by the content information is validated. After successful validation, a send completion callback is executed through the connection object indicated by the content information. Specifically, if the pattern marker indicates a long connection, the connection object is directly obtained from the content information, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the validation passes. If the pattern marker indicates a short connection, the client array is indexed based on the file descriptor in the content information, the connection object pointer for the corresponding slot is obtained, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the validation passes.
[0006] Optionally, before obtaining the user data corresponding to the asynchronous send completion event, the method further includes: The mode flag is set according to the type of connection associated with the data to be sent; Read the connection object pointer and the generation number from the slot corresponding to the file descriptor of the connection in the client array, and combine the read connection object pointer or the file descriptor as content information with the mode tag and the generation number to form the user data according to the type of the connection; Submit the asynchronous send request carrying the user data to the asynchronous queue.
[0007] Optionally, the generation number in the user data is stored in the high-order part of the user data, and the file descriptor is stored in the low-order part; The step of indexing the client array based on the file descriptor in the content information, obtaining the connection object pointer for the corresponding slot, and comparing the generation number in the user data with the current generation number stored in the high-order bits of the obtained connection object pointer further includes: Extract the file descriptor from the low-order part of the user data, access the corresponding slot of the client array using the extracted file descriptor as an index, and obtain the connection object pointer stored in the slot; Extract the current generation number from the high-order bits of the obtained connection object pointer and compare it with the generation number stored in the high-order bits of the user data.
[0008] Optionally, when the mode flag indicates that the connection is a long connection and the content information is a thunk function pointer, the step of executing the send completion callback process through the connection object indicated by the content information further includes: The thunk function pointed to by the thunk function pointer is executed. When the thunk function is executed, the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer to the embedded connection object in the thunk function. If they match, a callback process is executed.
[0009] Optionally, the method further includes: When the connection is closed, the connection object pointers in the client array corresponding to the file descriptor of the connection are cleared, and the generation number of the slot is incremented. The generation number carried in the submitted and en route asynchronous send requests remains unchanged.
[0010] Optionally, the generation number is stored in the high-order bits of the connection object pointer, wherein the high-order bits of the connection object pointer are the high 16 bits of a 64-bit address, the generation number occupies 15 bits of the high 16 bits, and the generation number is written into the high-order bits of the pointer when the connection is established.
[0011] Optionally, when establishing a connection, depending on whether the compilation environment supports nested functions, a thunk callback method or a direct pointer reference method can be selected for the long connection, and the mode flag and content information can be set accordingly.
[0012] Optionally, setting the mode flag according to the type of connection associated with the data to be sent further includes: If the connection is a master-slave replication connection, a cluster bus connection, or a connection that has been configured with Transmission Control Protocol keep-alive and whose lifespan exceeds a preset duration, then the mode flag is set to a long connection flag. Otherwise, the pattern marker is set to a short connection marker.
[0013] Optionally, the generation number in the client array is initialized to zero when the service starts and incremented each time a connection is closed, and the incremented generation number is written to the high bit of the pointer of the newly allocated connection object.
[0014] A second aspect of this disclosure provides a callback processing system for asynchronous Redis sending, comprising: The event acquisition unit is used to acquire user data corresponding to the asynchronous sending completion event. The user data includes a mode flag, a generation number, and content information. The mode flag is used to indicate whether the connection is a long connection or a short connection. The generation number is a count value read from the slot corresponding to the file descriptor of the connection in the client array when the connection is established. The client array is an array in the Redis server with file descriptors as the index and the slots are not released when the connection is closed. The content information is a pointer to the connection object or a file descriptor stored according to the connection type. The verification unit is used to verify the validity of the connection indicated by the content information based on the pattern marker and the generation number. If the pattern marker indicates that the connection is a long connection, the connection object is directly obtained from the content information, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the verification passes. If the pattern marker indicates that the connection is a short connection, the client array is indexed according to the file descriptor in the content information, the connection object pointer of the corresponding slot is obtained, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the verification passes. The callback execution unit is used to execute the send completion callback process through the connection object indicated by the content information after the verification is passed.
[0015] As described above, the technical solution leverages the inherent characteristic of Redis server-side client arrays, where file descriptors are used as indices and slots are not released after connection closure. Combined with the zero-cost storage space provided by the high-order redundant bits of the connection object pointer, user data consisting of a pattern flag, generation number, and content information is carried in asynchronous requests. The pattern flag distinguishes between long and short connections, the generation number is taken from the count value in the corresponding file descriptor slot, and the content information is a connection object pointer or callback function pointer for long connections and a file descriptor for short connections. When the asynchronous completion event is triggered, the pattern flag is checked. For long connections, the connection object is directly retrieved from the content information and compared with the generation number. For short connections, the connection object is retrieved from the client array using the file descriptor index in the content information and compared with the generation number. If they match, the callback is executed. When the connection is closed, only the generation number of the corresponding slot is incremented, without traversing any ongoing asynchronous requests. Therefore, the generation number that enables verification is bound to the connection pointer in a way that does not require additional storage overhead. This provides a direct access path for long connections without lookup and a lightweight index access path for short connections. At the same time, the incremental characteristic of the generation number makes old requests after closure automatically invalidate during callbacks. This achieves efficient and secure callback processing in all scenarios, so that when facing a mixed load of millions of long connections and hundreds of thousands of short connections, it can always complete the secure matching of asynchronous callbacks with low and stable computational cost. Attached Figure Description
[0016] To more clearly illustrate the technical solutions in the embodiments of this disclosure or the prior art, the drawings used in the description of the embodiments or the prior art will be briefly introduced below. Obviously, the drawings described below are some embodiments of this application. For those skilled in the art, other drawings can be obtained based on these drawings without creative effort.
[0017] Figure 1This is a flowchart of a callback processing method for asynchronous sending to Redis, as described in an embodiment of this disclosure. Figure 2 This is a flowchart illustrating the process before obtaining the user data corresponding to the asynchronous sending completion event in a callback processing method for asynchronous sending to Redis, as described in one embodiment of this disclosure. Figure 3 This is a flowchart illustrating a callback processing method for asynchronous Redis sending in this embodiment of the present disclosure, which involves indexing the client array based on the file descriptor in the content information, obtaining the connection object pointer for the corresponding slot, and comparing the generation number in the user data with the current generation number stored in the high-order bits of the obtained connection object pointer. Figure 4 This is a schematic diagram of a callback processing system for asynchronous Redis sending in an embodiment of this disclosure. Detailed Implementation
[0018] In the following description, specific details such as particular system architectures and techniques are set forth for illustrative purposes and not limiting, in order to provide a thorough understanding of the embodiments of this disclosure. However, those skilled in the art will understand that this application may be implemented in other embodiments without such specific details. In other instances, detailed descriptions of well-known systems, apparatuses, circuits, and methods have been omitted so as not to obscure the description of this application with unnecessary detail.
[0019] This application discloses a callback handling method for asynchronous sending to Redis, such as... Figure 1 As shown, it includes: Step S100: Obtain the user data corresponding to the asynchronous send completion event. The user data includes a mode flag, a generation number, and content information. The mode flag is used to indicate whether the connection is a long connection or a short connection. The generation number is a count value read from the slot corresponding to the file descriptor of the connection in the client array when the connection is established. The client array is an array in the Redis server with file descriptors as the index and the slots are not released when the connection is closed. The content information is a pointer to the connection object or a file descriptor stored according to the connection type. Step S200: Based on the pattern marker and the generation number, perform a validity check on the connection indicated by the content information. After the check passes, execute the send completion callback process through the connection object indicated by the content information. If the pattern marker indicates that the connection is a long connection, the connection object is directly obtained from the content information, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the check passes. If the pattern marker indicates that the connection is a short connection, the connection object pointer of the corresponding slot is obtained from the file descriptor index client array in the content information, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the check passes.
[0020] This application provides a callback handling method for asynchronous Redis sending. When the asynchronous sending completion event occurs, the retrieved user data already carries the pattern flag and generation number. This directly utilizes the permanent nature of client array slots and the zero-cost storage characteristic of the generation number in the high-order bits of the pointer, allowing the information required for verification to be attached to the event without loss or additional overhead when submitting the asynchronous request, eliminating the need for any form of global lookup during the callback phase. During the validity verification process, branch judgment based on the pattern flag separates the processing paths for long connections and short connections: for long connections, the content information directly provides the connection object pointer or function pointer, and the connection validity can be confirmed without array indexing and lookup by comparing the generation number, completely eliminating the matching overhead of long connection callbacks; for short connections, the connection object pointer is obtained by directly indexing the client array through the file descriptor in the content information and the generation number is compared, requiring only one array reference operation, avoiding the linear time consumption required to traverse the in-transit request. Meanwhile, since closing a connection only involves constant-time operations such as clearing the pointer and incrementing the generation number, without modifying the asynchronous queue, all old requests in transit are silently discarded during the callback verification phase because their generation numbers do not match the incremented current generation number. This eliminates access to dangling pointers to released or reused connection memory while avoiding traversal overhead. These technical features are interconnected at runtime, forming a lightweight verification closed loop from request submission to callback processing. This ensures that the overall solution consistently achieves safe matching of asynchronous callbacks with low and stable computational cost when facing mixed loads of millions of long connections and hundreds of thousands of short connections.
[0021] It is particularly noteworthy that the embodiments disclosed herein simultaneously address the problems of high lookup overhead, large traversal overhead, dangling pointer risk, and insufficient versatility in existing technologies. Specifically, the permanent existence of client array slots ensures that operations indexing connection objects via file descriptors will not result in out-of-bounds access, providing a foundation for lightweight indexing of short connections; the high-bit redundancy of 64-bit pointers allows the generation number to be bound to the connection object pointer without additional storage overhead, providing a basis for connection validity verification; the long-short connection classification strategy allows long connections to use direct access for low lookup overhead, while short connections can use index access to avoid pointer invalidation; the incrementing characteristic of the generation number eliminates the need to traverse in-transit requests when closing a connection, automatically invalidating all old requests simply by incrementing the generation number. These technical features work together to achieve efficient and secure asynchronous callback processing in hybrid deployment scenarios.
[0022] The embodiments of this disclosure will now be described in detail.
[0023] In step S100, the user data corresponding to the asynchronous send completion event is obtained. The user data includes a mode flag, a generation number, and content information. The mode flag is used to indicate whether the connection is a long connection or a short connection. The generation number is a count value read from the slot corresponding to the file descriptor of the connection in the client array when the connection is established. The client array is an array in the Redis server with file descriptors as the index and the slots are not released when the connection is closed. The content information is a pointer to the connection object or a file descriptor stored according to the connection type.
[0024] In this embodiment, the method described above is used to handle the callback matching process after asynchronous sending is completed in the Redis server. The asynchronous sending completion event refers to the notification event returned by the kernel to the Redis server after completing data sending. User data is custom data submitted to the kernel along with the asynchronous sending request. The kernel returns this user data unchanged to the Redis server when returning the completion event. User data consists of three parts: a pattern flag, a generation number, and content information. The pattern flag is an identifier used to indicate whether the connection corresponding to the asynchronous sending request is a long connection or a short connection. The generation number is a count value read from the slot corresponding to the file descriptor of the connection in the client array when the connection is established, used to identify the lifecycle of the connection. The client array is an array in the Redis server used to store all client connection objects. This array uses file descriptors as indices. When a connection is closed, only the connection object pointer in the corresponding slot is cleared; the slot itself is not released. Therefore, the slots in this array are permanently stored. The content information is stored differently depending on the type of connection. For long connections, the content information stores a pointer to the connection object; for short connections, the content information stores the file descriptor of the connection.
[0025] In an alternative embodiment, such as Figure 2 As shown, before obtaining the user data corresponding to the asynchronous send completion event, the method also includes: Step S010: Set the mode flag according to the type of connection associated with the data to be sent; Step S020: Read the connection object pointer and generation number from the slot corresponding to the file descriptor of the connection in the client array, and according to the connection type, use the retrieved connection object pointer or file descriptor as content information, and combine it with the mode tag and generation number to form user data; Step S030: Submit the asynchronous sending request carrying user data to the asynchronous queue.
[0026] In this embodiment, the above steps are performed when an asynchronous send request is submitted, and are used to construct user data and submit the asynchronous send request. The data to be sent is the data that the Redis server needs to send to the client, and this data is associated with a specific client connection. After completing command processing, the Redis server generates corresponding response data and adds the response data to the connection's send buffer. When there is data to be sent in the send buffer, the Redis server determines whether asynchronous sending can be used. If so, the above steps are executed to construct user data and submit the asynchronous send request.
[0027] First, a mode flag needs to be set according to the connection type. The connection type is determined when the connection is established or dynamically adjusted based on the connection's behavior during operation. If the connection is a long-lived connection, the mode flag is set to the identifier corresponding to long-lived connections; if the connection is a short-lived connection, the mode flag is set to the identifier corresponding to short-lived connections. The value of the mode flag can be defined according to actual needs, for example, using 1 to represent a long-lived connection and 0 to represent a short-lived connection.
[0028] Optionally, setting the pattern flag, depending on the type of connection associated with the data to be sent, further includes: If the connection is a master-slave replication connection, a cluster bus connection, or a connection with Transmission Control Protocol keep-alive configured and whose lifespan exceeds the preset duration, then the mode flag is set to a long connection flag; otherwise, the mode flag is set to a short connection flag.
[0029] In this embodiment, the connection type is categorized based on its purpose and lifecycle. Different types of connections have different traffic characteristics and lifecycles, thus requiring different callback methods. Master-slave replication connections are used between Redis master and slave nodes for data replication. These connections are typically long-lived and are not frequently closed and established. The traffic of master-slave replication connections is usually continuous, requiring the transfer of large amounts of data; therefore, using a long-lived connection mode can achieve lower callback overhead and improve replication performance.
[0030] Cluster bus connections are communication connections used between nodes in a Redis cluster. These connections are also long-lived. Cluster bus connections are used to transmit cluster status information, forward commands, migrate data, and handle relatively stable traffic. Therefore, using long-lived connections can improve the cluster's communication efficiency.
[0031] Connections configured with Transmission Control Protocol (TCP) keep-alive and whose lifespan exceeds a preset duration are typically long-lived connections between clients and servers, such as connections to backend management systems or real-time monitoring systems. Clients on these connections periodically send keep-alive packets to maintain the connection's activity. The preset duration can be set according to actual business needs, such as 3 seconds, 5 seconds, or 10 seconds. If the connection's lifespan exceeds the preset duration, it indicates that the connection is long-lived and suitable for a long-connection mode.
[0032] Besides the connection types mentioned above, other connections are typically short-lived, such as API access connections for regular users. These connections have a short lifespan and are usually closed after completing one or a few requests. Traffic on short connections is often bursty, with connections being established and closed very frequently. Using a long-lived connection model would frequently generate and release thunk functions, increasing system overhead. Therefore, short connections are suitable for the short-connection model to avoid pointer invalidation issues and the overhead of frequently generating thunk functions.
[0033] For example, the preset duration is set to 3 seconds. When a connection is established, it is first determined whether the connection is a master-slave replication connection or a cluster bus connection. If so, the mode flag is set to a long connection flag. If not, it is determined whether the connection has the Transmission Control Protocol (TCP) keep-alive option set. If so, a timer is started to track the connection's lifetime. When the connection's lifetime exceeds 3 seconds, the mode flag is switched from a short connection flag to a long connection flag. If the connection's lifetime does not exceed 3 seconds, the short connection flag is maintained. If the connection does not have the TCP keep-alive option set, the mode flag is directly set to a short connection flag.
[0034] Those skilled in the art will understand that the way connection types are classified can be adjusted according to actual business needs. For example, connection types can be classified based on information such as the client's IP address, port number, and username. Alternatively, connection types can be dynamically adjusted based on connection traffic characteristics, such as requests per second and data transfer volume.
[0035] Next, the connection object pointer and generation number are read from the slot corresponding to the file descriptor of the connection in the client array. The connection object pointer is a pointer to the connection object corresponding to the connection, which stores all the state information of the connection, including the send buffer, receive buffer, connection state, protocol version, etc. The generation number is the current count value of the slot, used to identify the lifecycle of the connection in that slot. Depending on the connection type, either the connection object pointer or the file descriptor is chosen as the content information. For long-lived connections, the connection object pointer is chosen as the content information because long-lived connections have a longer lifecycle, and the connection object is not easily released. For short-lived connections, the file descriptor is chosen as the content information because short-lived connections have a shorter lifecycle, and the connection object may be released; using a file descriptor avoids the problem of dangling pointers. The mode flag, generation number, and content information are combined to form the user data.
[0036] Next, the asynchronous send request carrying the user data is submitted to the asynchronous queue. The asynchronous queue stores pending asynchronous send requests; the kernel retrieves requests from this queue and executes the send operation. The asynchronous queue can be implemented using an asynchronous I / O mechanism provided by the kernel, such as io_uring. Once the kernel completes the send operation, it generates an asynchronous send completion event and returns the user data to the Redis server. The Redis server listens for the asynchronous send completion event in its event loop and executes callback processing when the event is triggered.
[0037] For example, when the connection associated with the data to be sent is a long-lived connection, the mode flag is first set to 1. Then, the connection object pointer and generation number are read from the slot corresponding to the file descriptor of that connection in the client array. The connection object pointer is used as content information and combined with the mode flag and generation number to form user data. An asynchronous send request carrying this user data is submitted to an asynchronous queue. When the kernel completes the send, the returned completion event will carry this user data. The Redis server can then find the corresponding connection object based on this user data and execute the callback processing.
[0038] When the connection associated with the data to be sent is a short connection, the mode flag is first set to 0. Then, the connection object pointer and generation number are read from the slot corresponding to the file descriptor of that connection in the client array. The file descriptor is used as content information and combined with the mode flag and generation number to form user data. An asynchronous send request carrying this user data is submitted to the asynchronous queue. When the kernel completes the send, the returned completion event will carry this user data. The Redis server can use the file descriptor index in the user data to find the corresponding connection object in the client array and execute the callback processing.
[0039] It's important to note that the asynchronous send request is submitted within the Redis main thread, thus eliminating the need for additional synchronization mechanisms. After submitting the asynchronous send request, the Redis main thread can continue processing other events without waiting for the send operation to complete. This approach improves the main thread's processing efficiency and reduces blocking time.
[0040] In step S200, the validity of the connection indicated by the content information is verified according to the mode tag and the generation number. After the verification is passed, the send completion callback process is executed through the connection object indicated by the content information. If the mode tag indicates that the connection is a long connection, the connection object is directly obtained from the content information, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the verification is passed. If the mode tag indicates that the connection is a short connection, the connection object pointer of the corresponding slot is obtained according to the file descriptor index client array in the content information, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the verification is passed.
[0041] It's important to note that the Redis server employs a single-threaded event-driven model, where all network events, command processing, and callback operations are executed within the same main thread. This model avoids the synchronization overhead between multiple threads, but it also requires that no operation should block the main thread for an excessively long time. The asynchronous sending mechanism was introduced to decouple network sending operations from the main thread and delegate them to the kernel for asynchronous execution, thereby improving the main thread's processing efficiency. However, after asynchronous sending is complete, the completion event needs to be matched with the corresponding connection object to execute subsequent callback processing. The efficiency of this matching process directly impacts the overall system performance.
[0042] In the embodiments of this disclosure, after obtaining user data, the connection validity needs to be verified based on the pattern tag and generation number. The purpose of the validity verification is to confirm that the connection corresponding to the asynchronous transmission request still exists and has not been closed or reused. If the verification fails, it means that the connection has been closed and may have been reused as a new connection. In this case, there is no need to execute callback processing, and the completion event can be discarded directly. If the verification passes, it means that the connection is still valid. In this case, the transmission completion callback processing can be executed through the connection object indicated by the content information. The transmission completion callback processing typically includes operations such as updating the transmission status of the connection, reclaiming the transmission buffer, advancing the subsequent transmission process, and handling the connection closing logic.
[0043] For example, when the pattern flag indicates that the connection is a long-lived connection, since long-lived connections have a long lifespan, the connection object is usually not released during the asynchronous request processing. Therefore, the pointer to the connection object can be directly obtained from the content information. To ensure that the connection object is still the original connection, the generation number in the user data needs to be compared with the current generation number stored in the high bits of the pointer to the obtained connection object. If they match, it means that the connection object has not been closed or reused, and the verification passes; if they do not match, it means that the connection has been closed and may have been reused as a new connection, and the verification fails. This verification method does not require any lookup operations, only one bitwise operation and one integer comparison, resulting in extremely low overhead.
[0044] When the pattern flag indicates a short connection, the connection object may be released during asynchronous request processing due to the short lifespan of short connections. Therefore, a pointer to the connection object cannot be directly stored, otherwise a dangling pointer problem will occur. In this case, the content information stores the file descriptor of the connection. By indexing the client array through this file descriptor, the pointer to the connection object in the corresponding slot can be obtained. Similarly, to ensure that the connection object is still the original connection, the generation number in the user data needs to be compared with the current generation number stored in the high-order bits of the pointer to the obtained connection object. If they match, it means that the connection object has not been closed or reused, and the verification passes; if they do not match, it means that the connection has been closed and may have been reused as a new connection, and the verification fails. This verification method only requires one array index operation, one bitwise operation, and one integer comparison, which is far less expensive than hash table lookup operations.
[0045] Those skilled in the art will understand that the permanent slot feature of the client array is an inherent design feature of the Redis server. Redis uses file descriptors as unique identifiers for connections, and file descriptors are consecutive integers allocated by the kernel. Using an array as the data structure for storing connection objects enables access with O(1) time complexity, which is crucial for high-performance network services. O(1) time is also known as constant time, meaning that the execution time remains constant regardless of the data volume. When a connection is closed, Redis only clears the pointer to the connection object in the corresponding slot, without releasing the slot itself, because new connections may subsequently use the same file descriptor. This design ensures that the size of the client array only grows with the increase in the number of connections, and does not shrink when a connection is closed, thus avoiding frequent memory allocation and deallocation operations.
[0046] In an optional embodiment, the generation number in the user data is stored in the high-order part of the user data, and the file descriptor is stored in the low-order part, such as... Figure 3As shown, the process of indexing the client array based on the file descriptor in the content information, obtaining the connection object pointer for the corresponding slot, and comparing the generation number in the user data with the current generation number stored in the high-order bits of the obtained connection object pointer further includes: Step S211: Extract the file descriptor from the low-order part of the user data, use the extracted file descriptor as an index to access the corresponding slot in the client array, and obtain the connection object pointer stored in the slot; Step S221: Extract the current generation number from the high-order bits of the obtained connection object pointer and compare it with the generation number stored in the high-order bits of the user data.
[0047] In this embodiment, the user data is a 64-bit integer with a carefully designed bit layout to achieve information carrying without additional storage overhead. The generation number is stored in the high-order bits of the user data, and the file descriptor is stored in the low-order bits. Specifically, the high 16 bits of the 64-bit user data are used to store the mode marker and the generation number, with the highest bit used to store the mode marker and the next 15 bits used to store the generation number; the low 48 bits are used to store content information. For short connections, the low 48 bits store the file descriptor; for long connections, the low 48 bits store the connection object pointer or the thunk function pointer.
[0048] It's important to note that in a 64-bit system, the user-space virtual address uses only the lower 48 bits; the higher 16 bits are a signature extension and are not used for actual addressing. This is because current 64-bit processors typically implement only a 48-bit virtual address space, sufficient to support 256TB of memory addressing, which is adequate for most applications. The higher 16 bits are used to extend the virtual address to 64 bits. When the 47th bit of the virtual address is 0, all of the higher 16 bits are 0; when the 47th bit is 1, all of the higher 16 bits are 1. Therefore, storing the mode flag and generation number in the higher 16 bits does not affect the correctness of pointers or file descriptors stored in the lower 48 bits. This bit-field layout allows user data to carry all necessary information in a single 64-bit integer without requiring additional memory allocation, reducing memory overhead and access latency.
[0049] When the mode flag indicates a short connection, the file descriptor needs to be extracted from the lower-order bits of the user data. Since the file descriptor is stored in the lower 48 bits, its value can be extracted using bitmasking. For example, performing a bitwise AND operation on the user data using the bitmask 0x0000ffffffffffff can yield the lower 48 bits of the file descriptor. Using the extracted file descriptor as an index, the corresponding slot in the client array is accessed to obtain the connection object pointer stored in that slot. Then, the current generation number is extracted from the higher-order bits of the obtained connection object pointer and compared with the generation number stored in the higher-order bits of the user data. If they match, the verification passes; otherwise, the verification fails.
[0050] For example, assume the user data value is 0x0003000000000800, where the high 16 bits are 0x0003 and the low 48 bits are 0x000000000800. The mode flag is the highest bit, i.e., 0, indicating that the connection is a short connection. The generation number is the low 15 bits of the high 16 bits, i.e., 0x0003. The file descriptor is the low 48 bits, i.e., 0x800, corresponding to a decimal value of 2048. A bitwise AND operation is performed on the user data using the bitmask 0x0000ffffffffffff to obtain file descriptor 2048. The client array is accessed using index 2048 to retrieve the connection object pointer in the corresponding slot. Assuming the value of the connection object pointer is 0x000355555579c000, a bitwise AND operation is performed on the connection object pointer using the bitmask 0xffff000000000000, and then right-shifted by 48 bits to obtain the current generation number 0x0003. Comparing the generation number 0x0003 in the user data with the current generation number 0x0003, they match, therefore the verification passes.
[0051] Those skilled in the art will understand that the design of the bit field layout can be adjusted according to actual needs. For example, if more modes need to be supported, the number of bits for the mode marker can be increased; if a longer generation number is needed, the number of bits for the generation number can be increased. However, it should be noted that adjusting the bit field layout must not affect the correctness of the pointers or file descriptors stored in the lower 48 bits.
[0052] In an optional embodiment, when the mode flag indicates that the connection is a long connection and the content information is a thunk function pointer, the execution of the send completion callback process through the connection object indicated by the content information further includes: executing the thunk function pointed to by the thunk function pointer. When the thunk function is executed, it compares the generation number in the user data with the current generation number stored in the high-order bits of the connection object pointer embedded in the thunk function. If they match, the callback process is executed.
[0053] In this embodiment, for persistent connections, a thunk callback approach can be used when the compilation environment supports nested functions. A thunk function is a nested function generated when the connection is established, and it embeds a pointer to the connection object. A nested function is a function defined inside another function, and it can access the local variables and parameters of the outer function. After the outer function returns, the nested function can still access these local variables and parameters, provided that the lifetime of these variables and parameters is long enough. In this application, the thunk function is generated when the connection is established and embeds a pointer to the connection object; as long as the connection object is not released, the thunk function can correctly access the connection object.
[0054] When the asynchronous transmission is complete, the `thunk` function is executed directly to access the connection object and execute the callback logic without any lookup operations. This method has extremely low callback overhead because it doesn't require any indexing or lookup operations; it simply jumps directly to the address of the `thunk` function to execute.
[0055] It's important to note that, to ensure the connection object remains valid, the `thunk` function compares the generation number in the user data with the current generation number stored in the high-order bits of the embedded connection object pointer before executing the callback logic. If they match, the connection object has not been closed or reused, and the callback processing is executed. If they don't match, the connection has been closed, and the callback processing is skipped, and the function returns directly. This check serves as a fallback, preventing dangling pointer issues caused by the `thunk` function still executing callback logic after the connection is closed. Although long-lived connections have a long lifespan, they can still be closed, for example, due to network interruption or client-initiated disconnection. Therefore, adding generation number verification is necessary to improve system stability.
[0056] For example, when a connection is established, a thunk function is generated, which embeds a pointer to the connection object (0x55555578a000). The high 16 bits of this connection object pointer store the generation number 0x0001. When an asynchronous send request is submitted, the pointer to the thunk function is used as content information, combined with the mode flag and the generation number 0x0001 to form user data. When the asynchronous send is complete, the thunk function is executed. The thunk function first extracts the generation number 0x0001 from the user data, then extracts the high 16 bits of the embedded connection object pointer to obtain the current generation number 0x0001. Since they match, the callback logic is executed to update the connection's sending status and reclaim the send buffer.
[0057] If the connection is closed before the asynchronous transmission completes, the generation number of the corresponding slot in the client array will be incremented to 0x0002. When the asynchronous transmission completes, the thunk function is executed. The thunk function extracts the generation number 0x0001 from the user data, then extracts the high 16 bits of the embedded connection object pointer to obtain the current generation number 0x0002. Since the two are inconsistent, the callback logic is not executed, and the function returns directly, avoiding dangling pointer access.
[0058] Those skilled in the art will understand that the generation and use of thunk functions require the support of the compilation environment. For example, the GCC compiler supports nested function extensions, while some other compilers may not. Therefore, in compilation environments that do not support nested functions, the thunk callback method cannot be used; direct pointer references must be used instead.
[0059] In an optional embodiment, depending on whether the compilation environment supports nested functions, either a thunk callback method or a direct pointer reference method is selected for long connections, and the mode flag and content information are set accordingly.
[0060] In this embodiment of the disclosure, to improve the versatility of the solution, different callback methods are selected for long connections during connection establishment based on whether the compilation environment supports nested functions. If the compilation environment supports nested functions, the thunk callback method is selected, and the content information stores a pointer to the thunk function; if the compilation environment does not support nested functions, the direct pointer reference method is selected, and the content information stores a pointer to the connection object. A corresponding mode flag is set according to the selected callback method.
[0061] It should be noted that the advantage of the thunk callback method is that it eliminates the need for lookup and verification, resulting in low callback overhead, but it relies on specific compiler extensions. The advantage of the direct pointer reference method is its versatility and independence from the compilation environment, but it requires generation number verification during callbacks, resulting in slightly higher overhead than the thunk callback method. By adaptively selecting the callback method, better performance can be achieved in environments that support nested functions, while still functioning correctly in environments that do not. This adaptive approach gives the technical solution of this application better compatibility, allowing deployment in different compilation environments and operating systems.
[0062] Whether a compilation environment supports nested functions can be detected using preprocessor directives. For example, in a GCC compiler, the `_GNUC_` macro can be defined to detect if it's a GCC compiler, and then the GCC version can be checked to determine if nested functions are supported. If nested functions are detected, code using thunk callbacks is included at compile time; otherwise, only code using direct pointer references is included. This approach determines which callback method to use at compile time, without increasing runtime overhead.
[0063] For example, during compilation, if the current compilation environment is detected as GCC 8.5, which supports nested functions, when a long-lived connection is established, the thunk callback method is selected, a thunk function is generated, the pointer to the thunk function is used as the content information, and the mode is marked as long-lived connection thunk mode. When the asynchronous transmission is complete, the thunk function is executed directly, and the callback processing is performed. If a different compilation environment is detected, and nested functions are not supported, when a long-lived connection is established, the direct pointer reference method is selected, the pointer to the connection object is used as the content information, and the mode is marked as long-lived connection pointer mode. When the asynchronous transmission is complete, the connection object pointer is accessed directly, the generation number is compared, and if the verification passes, the callback processing is performed.
[0064] Those skilled in the art will understand that, besides nested functions, similar thunk functionality can be achieved in other ways, such as using function objects or closures. However, these methods typically incur additional memory and access overhead, making them less efficient than nested functions. Therefore, in environments that support nested functions, the thunk callback approach is preferred.
[0065] In an optional embodiment, the method further includes: when the connection is closed, clearing the connection object pointers in the client array corresponding to the file descriptor of the connection, and incrementing the generation number of the slot, wherein the generation number carried in submitted and en route asynchronous send requests remains unchanged.
[0066] In this embodiment of the disclosure, when a connection is closed, corresponding processing operations need to be performed to ensure that subsequent asynchronous transmission completion events can be correctly verified and discarded. Connection closure may be caused by various reasons, such as the client actively disconnecting, network interruption, connection timeout, or the server actively closing the connection. Regardless of the cause of connection closure, the following processing steps need to be performed.
[0067] First, clear the connection object pointers in the client array corresponding to the file descriptor slot for this connection. This ensures that subsequent indexing of this slot via the file descriptor will return a null pointer, preventing access to a released connection object. Next, release the memory resources occupied by the connection object, including the send buffer, receive buffer, and protocol state information. Finally, increment the generation number of this slot by 1. Incrementing the generation number is an atomic operation; in Redis's single-threaded environment, no additional synchronization mechanism is required.
[0068] It's important to note that the generation number carried in submitted and en route asynchronous requests is read when the request is submitted. Therefore, these generation numbers remain unchanged after the connection is closed. When the completion events for these requests return, the generation number in the user data is compared with the current generation number of the corresponding slot in the client array. Since the current generation number has already been incremented, the comparison result will be inconsistent, and these completion events will be discarded without executing callback processing. This approach eliminates the need to traverse the queue of en route asynchronous requests; simply incrementing the generation number automatically invalidates all older requests, significantly reducing the overhead of connection closure.
[0069] In existing technologies, when using direct references to connection object pointers, all in-transit asynchronous requests must be traversed and associated pointers marked as invalid when the connection is closed. This is because if not marked, subsequent callbacks will access already released memory after the connection object is released, leading to dangling pointers. The overhead of traversing the in-transit request queue is very high in high-concurrency scenarios, especially when a large number of short connections are frequently closed; the traversal operation consumes a significant amount of CPU time, impacting system performance. This disclosure avoids traversing the in-transit request queue by using an incrementing generation number, reducing the connection closing overhead from O(n) to O(1), greatly improving system performance.
[0070] For example, suppose a connection's file descriptor is 2048, and the corresponding client array slot's generation number is 0x0003. When this connection is closed, the connection object pointer in client array 2048 is cleared, the memory resources occupied by the connection object are released, and the generation number of that slot is incremented to 0x0004. At this time, there is an asynchronous send request in transit, whose user data has a generation number of 0x0003. When the completion event of this request returns, the client array is indexed according to file descriptor 2048, and the connection object pointer is found to be null. Comparing the generation number 0x0003 in the user data with the current generation number 0x0004, the result is inconsistent; therefore, the completion event is discarded, and no callback processing is executed.
[0071] If a new connection is established after the previous connection is closed, the kernel reallocates file descriptor 2048. At this time, the generation number of slot 2048 in the client array is 0x0004. Generation number 0x0004 is written to the high-order bits of the new connection object pointer. The asynchronous send request submitted for the new connection carries generation number 0x0004. When the completion event of these requests returns, the generation number 0x0004 in the user data is compared with the current generation number 0x0004. The result is consistent, so the verification passes, and the callback processing is executed. The generation number in the old request is 0x0003, which is inconsistent with the current generation number 0x0004, so it is discarded and does not affect the new connection.
[0072] In an optional embodiment, the generation number is stored in the high-order bits of the connection object pointer, wherein the high-order bits of the connection object pointer are the high 16 bits of a 64-bit address, the generation number occupies 15 bits of the high 16 bits, and the generation number is written into the high-order bits of the pointer when the connection is established.
[0073] In this embodiment, the connection object pointer is a 64-bit virtual address, with its high 16 bits reserved for signature extension and not used for actual addressing. Therefore, this 16-bit redundant space can be used to store the generation number. Specifically, the generation number occupies 15 of the high 16 bits, with the remaining bit reserved for future expansion. During connection establishment, the generation number of the current client array slot is written into the high 16 bits of the connection object pointer. When accessing the connection object is required, the lower 48 bits of the actual address are extracted through bitmasking operations, allowing correct access to the connection object.
[0074] It's important to note that this storage method doesn't require additional memory to store the generation number. The generation number is bound to the connection object pointer, and the overhead of accessing the generation number is the same as accessing the connection object pointer. Furthermore, since the generation number is stored in the connection object pointer, it can be quickly retrieved as long as the connection object pointer is available, without requiring additional lookup operations. This method fully leverages the characteristics of both hardware and the operating system, achieving zero-cost generation number storage.
[0075] In existing technologies, an additional field is typically allocated to store the generation number for each connection object, which increases the memory overhead of the connection object. In scenarios with millions of connections, adding a 4-byte generation number field to each connection object would increase memory overhead by 4MB. Although this overhead may seem small, it is still a consideration in scenarios with limited memory resources. This application avoids the additional memory overhead and improves memory utilization by storing the generation number in the high-order bits of the connection object pointer.
[0076] For example, suppose the real address of the connection object is 0x55555578a000, and the corresponding generation number is 0x0001. Shifting the generation number left by 48 bits yields 0x00010000000000000. Performing a bitwise OR operation between this value and the real address gives the connection object pointer value as 0x000155555578a000. When accessing the connection object, performing a bitwise AND operation on the connection object pointer using the bitmask 0x0000ffffffffffff gives the real address 0x55555578a000, allowing correct access to the connection object. When retrieving the generation number, performing a bitwise AND operation on the connection object pointer using the bitmask 0xffff000000000000, then shifting it right by 48 bits, yields the generation number 0x0001.
[0077] Those skilled in the art will understand that memory allocation for link objects is typically performed according to a certain alignment, such as 8-byte alignment or 16-byte alignment. This means that the lower bits of the actual address of the link object are always 0. Therefore, in addition to the redundant space of the high 16 bits, the lower bits can also be used to store additional information. However, in this application, only the redundant space of the high 16 bits is used to store the generation number because the redundant space of the high 16 bits is available in all 64-bit systems and has better versatility.
[0078] In an alternative embodiment, the generation number in the client array is initialized to zero when the service starts and incremented each time a connection is closed, with the incremented generation number written to the high bit of the pointer of the newly allocated connection object.
[0079] In this embodiment, each slot in the client array corresponds to a unique generation number. The generation number is an unsigned integer used to identify the lifecycle of the connection on that slot. When the Redis service starts, the generation numbers of all slots are initialized to zero. When a connection is closed, the generation number of the corresponding slot is incremented by 1. When a new connection is established, a file descriptor is allocated, corresponding to a slot in the client array. The current generation number of that slot is written to the high-order bits of the newly allocated connection object pointer. Thus, the high-order bits of each connection object pointer store the generation number corresponding to that connection.
[0080] It's important to note that the generation number is an unsigned integer that overflows and returns to zero after reaching its maximum value. Since a 15-bit generation number can represent 32,768 distinct values, and file descriptors are typically reused for a long period, under normal circumstances, false positives due to duplicate generation numbers will not occur. Even if the generation number overflows, due to the time difference, older requests have usually already completed and will not conflict with new requests. For example, assuming a file descriptor is reused once per second, a 15-bit generation number can support approximately 9 hours of non-repeating requests. Furthermore, the timeout for asynchronous requests is typically only a few seconds; therefore, before the generation number overflows, all older requests have already completed or timed out, preventing conflicts with new requests.
[0081] In existing technologies, reference counting is typically used to manage the lifecycle of connection objects. When an asynchronous request is submitted, the reference count of the connection object is incremented; when the callback processing is complete, the reference count is decremented. When the reference count reaches zero, the connection object is released. This approach avoids dangling pointer problems but increases system overhead because the reference count needs to be modified with each request submission and callback processing. Moreover, in a multi-threaded environment, modifications to the reference count require atomic operations, further increasing overhead. This application avoids the use of reference counting by using generation numbers, thus reducing system overhead.
[0082] For example, when the Redis service starts, the generation number of all slots in the client array is initialized to zero. When the first connection is established, file descriptor 1024 is allocated, and the generation number of the corresponding slot is 0. The generation number 0 is written to the high-order bits of the newly allocated connection object pointer. When the connection is closed, the generation number of the corresponding slot is incremented to 1. When a new connection is established and file descriptor 1024 is allocated again, the current generation number 1 is written to the high-order bits of the new connection object pointer. In this way, the generation number stored in the high-order bits of the new connection object pointer is 1, which is different from the generation number 0 in the old request. Therefore, the old request will fail the validation during the callback.
[0083] Those skilled in the art will understand that the length of the generation number can be adjusted according to actual needs. If the file descriptor is reused frequently, the length of the generation number can be increased, for example, by using 16 bits or 20 bits. However, it should be noted that increasing the length of the generation number will reduce the number of bits available for storing other information, so a trade-off needs to be struck between the two.
[0084] Another aspect of this disclosure provides a callback processing system for asynchronous sending in Redis, such as... Figure 4 As shown, it includes: Event acquisition unit 10 is used to acquire user data corresponding to the asynchronous sending completion event. The user data includes a mode flag, a generation number, and content information. The mode flag is used to indicate whether the connection is a long connection or a short connection. The generation number is a count value read from the slot corresponding to the file descriptor of the connection in the client array when the connection is established. The client array is an array in the Redis server with file descriptors as the index and the slots are not released when the connection is closed. The content information is a pointer to the connection object or a file descriptor stored according to the connection type. The verification unit 20 is used to verify the validity of the connection indicated by the content information according to the pattern marker and the generation number. If the pattern marker indicates that the connection is a long connection, the connection object is directly obtained from the content information, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the verification passes. If the pattern marker indicates that the connection is a short connection, the client array is indexed according to the file descriptor in the content information, the connection object pointer of the corresponding slot is obtained, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the verification passes. The callback execution unit 30 is used to execute the send completion callback process through the connection object indicated by the content information after the verification is passed.
[0085] It should be noted that the specific implementation of the callback processing method of the callback processing system for asynchronous sending to Redis in this disclosure has been described in detail in the above method process, and will not be repeated here.
[0086] In the embodiments of this disclosure, by providing a callback processing system for asynchronous Redis sending, the user data obtained when the asynchronous sending completion event occurs already carries the pattern flag and generation number. This directly utilizes the permanent nature of client array slots and the zero-cost storage characteristic of the generation number in the high-order bits of the pointer, so that the information required for verification can be attached to the event without loss or additional overhead when submitting the asynchronous request, without performing any form of global lookup in the callback phase. During the validity verification process, the branch judgment based on the pattern flag separates the processing paths of long connections and short connections: for long connections, the content information directly provides the connection object pointer or function pointer, and the connection validity can be confirmed without array indexing and lookup by comparing the generation number, completely eliminating the matching overhead of long connection callbacks; for short connections, the connection object pointer is obtained by directly indexing the client array through the file descriptor in the content information and the generation number is compared, requiring only one array reference operation, avoiding the linear time consumption required to traverse the in-transit requests.
[0087] Meanwhile, since closing a connection only involves constant-time operations such as clearing the pointer and incrementing the generation number, without modifying the asynchronous queue, all old requests in transit are silently discarded during the callback verification phase because their generation numbers do not match the incremented current generation number. This eliminates access to dangling pointers to released or reused connection memory while avoiding traversal overhead. These technical features are interconnected at runtime, forming a lightweight verification closed loop from request submission to callback processing. This ensures that the overall solution consistently achieves safe matching of asynchronous callbacks with low and stable computational cost when facing mixed loads of millions of long connections and hundreds of thousands of short connections.
[0088] Those skilled in the art will understand that the above description is merely a preferred embodiment of this application and is not intended to limit the scope of protection of this application. Any modifications, equivalent substitutions, improvements, etc., made within the spirit and principles of this application should be included within the scope of protection of this application. Further details are omitted here.
Claims
1. A callback processing method for asynchronous sending in Redis, characterized in that, include: Retrieve user data corresponding to the asynchronous send completion event. The user data includes a mode flag, a generation number, and content information. The mode flag is used to indicate whether the connection is a long connection or a short connection. The generation number is a count value read from the slot corresponding to the file descriptor of the connection in the client array when the connection is established. The client array is an array in the Redis server with file descriptors as indices and the slots are not released when the connection is closed. The content information is a pointer to the connection object or a file descriptor stored according to the connection type. Based on the pattern marker and the generation number, the connection indicated by the content information is validated. After successful validation, a send completion callback is executed through the connection object indicated by the content information. Specifically, if the pattern marker indicates a long connection, the connection object is directly obtained from the content information, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the validation passes. If the pattern marker indicates a short connection, the client array is indexed based on the file descriptor in the content information, the connection object pointer for the corresponding slot is obtained, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the validation passes.
2. The method according to claim 1, characterized in that, Before obtaining the user data corresponding to the asynchronous send completion event, the method further includes: The mode flag is set according to the type of connection associated with the data to be sent; Read the connection object pointer and the generation number from the slot corresponding to the file descriptor of the connection in the client array, and combine the read connection object pointer or the file descriptor as content information with the mode tag and the generation number to form the user data according to the type of the connection; Submit the asynchronous send request carrying the user data to the asynchronous queue.
3. The method according to claim 1, characterized in that, The generation number in the user data is stored in the high-order part of the user data, and the file descriptor is stored in the low-order part; The step of indexing the client array based on the file descriptor in the content information, obtaining the connection object pointer for the corresponding slot, and comparing the generation number in the user data with the current generation number stored in the high-order bits of the obtained connection object pointer further includes: Extract the file descriptor from the low-order part of the user data, access the corresponding slot of the client array using the extracted file descriptor as an index, and obtain the connection object pointer stored in the slot; Extract the current generation number from the high-order bits of the obtained connection object pointer and compare it with the generation number stored in the high-order bits of the user data.
4. The method according to claim 1, characterized in that, When the mode flag indicates that the connection is a long connection, and the content information is a thunk function pointer, the step of executing the send completion callback process through the connection object indicated by the content information further includes: The thunk function pointed to by the thunk function pointer is executed. When the thunk function is executed, the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer to the embedded connection object in the thunk function. If they match, a callback process is executed.
5. The method according to any one of claims 1 to 4, characterized in that, Also includes: When the connection is closed, the connection object pointers in the client array corresponding to the file descriptor of the connection are cleared, and the generation number of the slot is incremented. The generation number carried in the submitted and en route asynchronous send requests remains unchanged.
6. The method according to claim 1, characterized in that, The generation number is stored in the high-order bits of the connection object pointer. The high-order bits of the connection object pointer are the high 16 bits of a 64-bit address. The generation number occupies 15 bits of the high 16 bits and is written into the high-order bits of the pointer when the connection is established.
7. The method according to claim 1, characterized in that, When establishing a connection, depending on whether the compilation environment supports nested functions, the thunk callback method or the direct pointer reference method is selected for the long connection, and the mode flag and the content information are set accordingly.
8. The method according to claim 2, characterized in that, Setting the mode flag according to the type of connection associated with the data to be sent further includes: If the connection is a master-slave replication connection, a cluster bus connection, or a connection that has been configured with Transmission Control Protocol keep-alive and whose lifespan exceeds a preset duration, then the mode flag is set to a long connection flag. Otherwise, the pattern marker is set to a short connection marker.
9. The method according to claim 1, characterized in that, The generation number in the client array is initialized to zero when the service starts and incremented each time a connection is closed. The incremented generation number is then written to the high bit of the pointer of the newly allocated connection object.
10. A callback processing system for asynchronous sending to Redis, characterized in that, include: The event acquisition unit is used to acquire user data corresponding to the asynchronous sending completion event. The user data includes a mode flag, a generation number, and content information. The mode flag is used to indicate whether the connection is a long connection or a short connection. The generation number is a count value read from the slot corresponding to the file descriptor of the connection in the client array when the connection is established. The client array is an array in the Redis server with file descriptors as the index and the slots are not released when the connection is closed. The content information is a pointer to the connection object or a file descriptor stored according to the connection type. The verification unit is used to verify the validity of the connection indicated by the content information based on the pattern marker and the generation number. If the pattern marker indicates that the connection is a long connection, the connection object is directly obtained from the content information, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the verification passes. If the pattern marker indicates that the connection is a short connection, the client array is indexed according to the file descriptor in the content information, the connection object pointer of the corresponding slot is obtained, and the generation number in the user data is compared with the current generation number stored in the high-order bits of the pointer of the obtained connection object. If they match, the verification passes. The callback execution unit is used to execute the send completion callback process through the connection object indicated by the content information after the verification is passed.