Как поймать/сгенерировать событие Redis, доступное для записи, в основном цикле событий?

#redis #gdb #ld-preload

Вопрос:

Недавно я попытался изменить Redis, поэтому мне нужно отследить исходный код и выяснить, как он работает. И я обнаружил кое-что странное, чего не могу объяснить.

Redis-это программа, управляемая событиями, и ее основной цикл событий расположен по адресу ae.c#L402. На каждой итерации он сначала обрабатывает событие, доступное для чтения, а затем обрабатывает событие, доступное для записи.

         for (j = 0; j < numevents; j  ) {
            int fd = eventLoop->fired[j].fd;
            aeFileEvent *fe = amp;eventLoop->events[fd];
            int mask = eventLoop->fired[j].mask;
            int fired = 0; /* Number of events fired for current fd. */

            /* Normally we execute the readable event first, and the writable
             * event later. This is useful as sometimes we may be able
             * to serve the reply of a query immediately after processing the
             * query.
             *
             * However if AE_BARRIER is set in the mask, our application is
             * asking us to do the reverse: never fire the writable event
             * after the readable. In such a case, we invert the calls.
             * This is useful when, for instance, we want to do things
             * in the beforeSleep() hook, like fsyncing a file to disk,
             * before replying to a client. */
            int invert = fe->mask amp; AE_BARRIER;

            /* Note the "fe->mask amp; mask amp; ..." code: maybe an already
             * processed event removed an element that fired and we still
             * didn't processed, so we check if the event is still valid.
             *
             * Fire the readable event if the call sequence is not
             * inverted. */
            if (!invert amp;amp; fe->mask amp; mask amp; AE_READABLE) {
                fe->rfileProc(eventLoop,fd,fe->clientData,mask);
                fired  ;
                fe = amp;eventLoop->events[fd]; /* Refresh in case of resize. */
            }

            /* Fire the writable event. */
            if (fe->mask amp; mask amp; AE_WRITABLE) {
                if (!fired || fe->wfileProc != fe->rfileProc) {
                    fe->wfileProc(eventLoop,fd,fe->clientData,mask);
                    fired  ;
                }
            }

            /* If we have to invert the call, fire the readable event now
             * after the writable one. */
            if (invert) {
                fe = amp;eventLoop->events[fd]; /* Refresh in case of resize. */
                if ((fe->mask amp; mask amp; AE_READABLE) amp;amp;
                    (!fired || fe->wfileProc != fe->rfileProc))
                {
                    fe->rfileProc(eventLoop,fd,fe->clientData,mask);
                    fired  ;
                }
            }

            processed  ;
        }
    }
 

Я попытался выяснить, можно ли обрабатывать записываемые события в цикле for. С помощью GDB или LD_PRELOAD я почти уверен read , что событие будет обработано в цикле for, но я не могу найти (с помощью GDB или LD_PRELOAD), чтобы в нем обрабатывалось какое-либо записываемое событие.

По-другому, я добавляю printf /* Fire the writable event. */ утверждение if. Если будет обработана запись, она сбросит какое-нибудь сообщение,

но я нашел:

В запущенном терминале redis-server нет никакого сообщения. Но в запущенном терминале redis-benchmark есть несколько сообщений. Вот два коротких вопроса:

  1. Подразумевало ли это, что в цикле for обрабатывается событие, доступное для записи?
  2. Почему сообщение сбрасывается в redis-benchmark терминал s, а redis-server не в s?

[ps] моя redis-benchmark команда такова ./redis-benchmark -t set,lpush -n 100000 -q .

Как я использую GDB и LD_PRELOAD для перехвата события записи в цикле for?

Кстати strace , я обнаружил redis , что использую системный вызов write , поэтому в GDB:

Я с помощью catch syscall write where обнаружил, что записываемые события всегда обрабатываются в beforeSleep функции, расположенной по адресу ae.c#L391.

С помощью LD_PRELOAD я перехватываю write функцию glibc и вставляю какое-то сообщение, если write оно было вызвано для цикла, сообщение появится. К сожалению, write в цикле for ничего не произошло.

The last question is:

  1. I using three method to check if the writable event been handled in for loop, but there’re different answer, which is right? If there’re writable event be handled in for loop, why I can’t catch it by GDB or LD_PRELOAD?