| 262 | } |
| 263 | |
| 264 | void SlowLog_Replay |
| 265 | ( |
| 266 | const SlowLog *slowlog, |
| 267 | RedisModuleCtx *ctx |
| 268 | ) { |
| 269 | int my_t_id = ThreadPools_GetThreadID(); |
| 270 | SlowLog *aggregated_slowlog = SlowLog_New(); |
| 271 | |
| 272 | for(int t_id = 0; t_id < slowlog->count; t_id++) { |
| 273 | // don't lock ourselves |
| 274 | if(my_t_id != t_id) { |
| 275 | if(pthread_mutex_lock(slowlog->locks + t_id) != 0) { |
| 276 | // failed to lock, skip aggregating this thread slowlog entries |
| 277 | continue; |
| 278 | } |
| 279 | } |
| 280 | { |
| 281 | // critical section |
| 282 | rax *lookup = slowlog->lookup[t_id]; |
| 283 | raxIterator iter; |
| 284 | raxStart(&iter, lookup); |
| 285 | raxSeek(&iter, "^", NULL, 0); |
| 286 | while(raxNext(&iter)) { |
| 287 | SlowLogItem *item = iter.data; |
| 288 | SlowLog_Add(aggregated_slowlog, item->cmd, item->query, |
| 289 | item->latency, &item->time); |
| 290 | } |
| 291 | raxStop(&iter); |
| 292 | // end of critical section |
| 293 | } |
| 294 | if(my_t_id != t_id) { |
| 295 | pthread_mutex_unlock(slowlog->locks + t_id); |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | heap_t *heap = aggregated_slowlog->min_heap[my_t_id]; |
| 300 | RedisModule_ReplyWithArray(ctx, Heap_count(heap)); |
| 301 | |
| 302 | while(Heap_count(heap)) { |
| 303 | SlowLogItem *item = Heap_poll(heap); |
| 304 | RedisModule_ReplyWithArray(ctx, 4); |
| 305 | RedisModule_ReplyWithDouble(ctx, item->time); |
| 306 | RedisModule_ReplyWithStringBuffer(ctx, (const char *)item->cmd, strlen(item->cmd)); |
| 307 | RedisModule_ReplyWithStringBuffer(ctx, (const char *)item->query, strlen(item->query)); |
| 308 | _ReplyWithRoundedDouble(ctx, item->latency); |
| 309 | } |
| 310 | |
| 311 | SlowLog_Free(aggregated_slowlog); |
| 312 | } |
| 313 | |
| 314 | void SlowLog_Free(SlowLog *slowlog) { |
| 315 | for(int i = 0; i < slowlog->count; i++) { |
no test coverage detected