Chapter 2 Deepdive
2.1 Tricky bug
2.1.1 GRPC Carsh after pointer conversion in some platform
Ref: https://gcc.gnu.org/ml/gcc-bugs/2000-03/msg00155.html
C99 - http://www.coding-guidelines.com/C99/html/6.3.2.3.html
# A pointer to an object or incomplete type may be converted to a
# pointer to a different object or incomplete type. If the resulting
# pointer is not correctly aligned for the pointed-to type, the
# behavior is undefined. Otherwise, when converted back again, the
# result shall compare equal to the original pointer.
C17: Programming languages — C Page 41
Fix alignment issue in gpr_murmur_hash3 This function cast a void* to a uint32_t*. This is invalid, since a uint32_t* must be 32-bit-aligned, while the input key clearly isn't. Even though the function later uses memcpy to access the memory, by that point the compiler is allowed to assume that the pointer is aligned, and so it can output code that does an unaligned memory access. In practice, this resulted in a crash on some devices when this code is compiled with optimizations for 32-bit ARM with the Android NDK r14.
https://stackoverflow.com/questions/13696218/converting-a-pointer-to-different-type-in-c
http://blog.qt.io/blog/2011/06/10/type-punning-and-strict-aliasing/
- Strict Alias
https://blog.csdn.net/dbzhang800/article/details/6720141
https://blog.csdn.net/liaofengjun/article/details/52743452
2.2 TimerWheel
2.2.1 Goal
- insert message O(1)
- delete message O(1)
- time wheel progressing O(1)
- 10 milliseconds precision
- 1 million message 8 bytes on average
2.2.2 Workflow/MegaWatch
Data Structure: blocking queue,
Thread 1 - TimerWheelInserter (main thread)
Thread 2 - InterrupteableSleeper (Producer)
Thread 3 - Dispatcher (consumer)
API:
getClosestMsgBucket() return { starting time of the cell, unorder vector of message and scheduled time}
advance(time_t)
At time 0, we inserted a,b,c,d for message with delayed delivery time.
Global var sleepUntil;
Thread 2 - InterrupteableSleeper:
- getClosestMsgBucket() return {32 seconds, {a:35, b:39}} // insert?
- sleepUntil=32
- sleep until 32 seconds
// TODO - message(e:17) inserted
Thread 1 - TimerWheelInserter:
called by other threads to insert message, if delayed time is less than sleepUntil, wake up Thread 1 and update sleeping time
Thread 2 - InterrupteableSleeper:
at time 32, wake up
coz 32!=35, advances time by 32 seconds, moving a to (0,3), b to (0,6).
getClosestMsgBucket() return {35 seconds, {a:35}}
sleepUntil=35, sleep until 35 seconds
wake up and remove msg a
getClosestMsgBucket() return {39 seconds, {b:39}}
sleepUntil=39, sleep until 39 seconds
wake up and remove msg b
getClosestMsgBucket() return {192 seconds, {c:195, d:252}}
sleepUntil=192, sleep until 192 seconds
Thread 2 - InterrupteableSleeper:
If no new younger messager, at time 192, InterrupteableSleeper wakes up
advances time by 192 seconds, moving c to (0,3), d to (1,7).
getClosestMsgBucket() return {192 seconds, {c:195}}
sleepUntil=195
sleep until 195 seconds
wake up and remove msg c
getClosestMsgBucket() return {248 seconds, {d:252}}
sleepUntil=248
sleep until 248 seconds
- wake up
- coz 248!=252, advance 248 seconds, moving d to (0,4)
- getClosestMsgBucket() return {252 seconds, {d:252}}
- sleepUntil=252 , sleep until 252 seconds
wake up and remove msg d
After wake up:
if max(scheduled time in the cell) > cell starting time:
advance(cell starting time)
else
process_msg()
- How to get cell starting time?
use tick to represent time. the following is starting time of different cells:
tick = [0,0,0] is time 0
tick = [0,4,0] is time 0+32+0
tick = [3,4,0] is time 3+32+0=35
tick = [0,0,3] is time 19
tick = [0,7,3] is time 192+56+0=248
2.2.3 API Implementation
- advance by time and promote messages in cell, the time is the starting time of the cell
(cell){
advance= get_tick_array(cell.starting_time) // assuming current time is at cell.starting_time
tick_arry for (message in cell)
,j = find_position(messge.scheduled_time)
i[i][j] = message
cell.clear()
cell}
()
getClosestMsgBucket(i,0,8)
REP(j,0,3)
REPif (!megawatch[i][j].messages.empty()){
return get_cell_starting_time(i,j);
}
int get_cell_starting_time(x,y,watch_tick[3]){
=0
sumfor(i=2;i>=x;i--){
if(x==i)
+=time_bitmap[i][y];
sumelse
+=time_bitmap[i][watch_tick[i]];
sum}
return sum;
}
// x/*=2*/,y/*=3*/,watch_tick[3]/*0,7,3*/ => 192
// x/*=1*/,y/*=7*/,watch_tick[3]/*0,7,3*/ => 192+56
// x/*=1*/,y/*=6*/,watch_tick[3]/*0,7,3*/ => 192+56