Рубрики
Uncategorized

[[red – это изучение исходного кода 5] анализ восстановления команды redis

Автор оригинала: David Wong.

Виноград

Синтаксис команд

Значение команды: десериализуйте заданное значение сериализации и свяжите его с заданным ключом.

Формат команды:

RESTORE key ttl serialized-value [REPLACE] [ABSTTL] [IDLETIME seconds] [FREQ frequency]

Командуйте реальным боем

redis> DEL mykey
0
redis> RESTORE mykey 0 "\n\x17\x17\x00\x00\x00\x12\x00\x00\x00\x03\x00\
                        x00\xc0\x01\x00\x04\xc0\x02\x00\x04\xc0\x03\x00\
                        xff\x04\x00u#<\xc0;.\xe9\xdd"
OK
redis> TYPE mykey
list
redis> LRANGE mykey 0 -1
1) "1"
2) "2"
3) "3"

Возвращаемое значение

Если десериализация прошла успешно, возвращается OK, в противном случае возвращается ошибка.

Анализ исходного кода

Часть анализа исходного кода разделена на несколько частей.

Обработка параметров

void restoreCommand(client *c) {
    long long ttl, lfu_freq = -1, lru_idle = -1, lru_clock = -1;
    rio payload;
    int j, type, replace = 0, absttl = 0;
    robj *obj;
    /*Analytic parameters*/
    for (j = 4; j < c->argc; j++) {
        int additional = c->argc-j-1;
        if (!strcasecmp(c->argv[j]->ptr,"replace")) {
            replace = 1;
        } else if (!strcasecmp(c->argv[j]->ptr,"absttl")) {
            absttl = 1;
        } else if (!strcasecmp(c->argv[j]->ptr,"idletime") && additional >= 1 &&
                   lfu_freq == -1)
        {
            if (getLongLongFromObjectOrReply(c,c->argv[j+1],&lru_idle,NULL)
                    != C_OK) return;
            if (lru_idle < 0) {
                addReplyError(c,"Invalid IDLETIME value, must be >= 0");
                return;
            }
            lru_clock = LRU_CLOCK();
            j++; /* Consume additional arg. */
        } else if (!strcasecmp(c->argv[j]->ptr,"freq") && additional >= 1 &&
                   lru_idle == -1)
        {
            if (getLongLongFromObjectOrReply(c,c->argv[j+1],&lfu_freq,NULL)
                    != C_OK) return;
            if (lfu_freq < 0 || lfu_freq > 255) {
                addReplyError(c,"Invalid FREQ value, must be >= 0 and <= 255");
                return;
            }
            j++; /* Consume additional arg. */
        } else {
            addReply(c,shared.syntaxerr);
            return;
        }
    }

Мы упомянули формат команды восстановления выше. Мы видим, что четвертый параметр в начале необязателен, поэтому параметр синтаксического анализа начинается с, и во время обхода будут выполняться различные операции в соответствии с различными параметрами. Давайте рассмотрим эти четыре команды по очереди:

  1. Заменить: если это поле замены, установите бит идентификатора заменить на 1.
  2. Битва: определите, является ли это полем битвы, и установите идентификационный бит absttl равным 1. Если используется модификатор битвы, ЗАГОЛОВОК должен представлять абсолютную метку времени UNIX (в миллисекундах), в течение которой ключ завершится.
  3. Время простоя и частота: эти два параметра подробно описаны в команде object. В объекте идеальное время-это количество секунд (чтение или запись не требуется), так как объект, хранящийся в указанном ключе, простаивает. Freq-это счетчик, который возвращает логарифмическую частоту доступа к объекту, хранящемуся в указанном ключе. Когда эти две команды разрешены в этой команде, ideltime устанавливает значение LRU ﹣ часов. Установите lru_freq в freq, установите частоту и определите, находится ли она в диапазоне 0-255.

Проверьте & & работу соответствующего режима

/*This is to ensure whether the key exists. This operation is only performed when the replace is equal to 0*/
    if (!replace && lookupKeyWrite(c->db,c->argv[1]) != NULL) {
        addReply(c,shared.busykeyerr);
        return;
    }
        
    /*Check whether TTL is legal. The rule is whether it is less than 0 and whether it can be converted to a number*/
    if (getLongLongFromObjectOrReply(c,c->argv[2],&ttl,NULL) != C_OK) {
        return;
    } else if (ttl < 0) {
        addReplyError(c,"Invalid TTL value, must be >= 0");
        return;
    }
    //Check RDB version and data checksum. If they do not match, an error is returned.
    if (verifyDumpPayload(c->argv[3]->ptr,sdslen(c->argv[3]->ptr)) == C_ERR)
    {
        addReplyError(c,"DUMP payload version or checksum are wrong");
        return;
    }
    rioInitWithBuffer(&payload,c->argv[3]->ptr);
    if (((type = rdbLoadObjectType(&payload)) == -1) ||
        ((obj = rdbLoadObject(type,&payload)) == NULL))
    {
        addReplyError(c,"Bad data format");
        return;
    }
    //If it is replace mode, delete the key
    if (replace) dbDelete(c->db,c->argv[1]);

Добавить ключ

/* Create the key and set the TTL if any */
    Dbadd (C - > dB, C - > argv [1], obj); // if the key exists, an error is reported
    if (ttl) {
        if (!absttl) ttl+=mstime();
        setExpire(c,c->db,c->argv[1],ttl);
    }
    //Create a new key.
    //Set if TTL is present
    //If TTL is 0, there will be no expiration when the key is created, otherwise the specified expiration time (in milliseconds) will be set
    objectSetLRUOrLFU(obj,lfu_freq,lru_idle,lru_clock);
    //Set frequency and time range limits
    signalModifiedKey(c->db,c->argv[1]);
    addReply(c,shared.ok);
    server.dirty++;
}

Расширять

Наименее часто используемый алгоритм замены страниц в LFU

Ведущий часто используемый алгоритм.lru-это первая страница, которая будет удалена с наименьшим количеством посещений за определенный период!

Основная идея алгоритма заключается в том, что “если к данным обращались много раз в прошлом, частота доступа в будущем будет выше”. Конкретный поток алгоритмов выглядит следующим образом:

В последнее время LRU не использовал алгоритм перестановок

Наименее недавно используемый алгоритм.lru первым устраняет страницы, которые не использовались в течение длительного времени!

Основная идея алгоритма заключается в том, что “если доступ к данным был получен недавно, вероятность доступа в будущем выше”. Конкретный поток алгоритмов выглядит следующим образом:

Алгоритм замены FIFO first in first out

ФИФО (первый вход, первый выход). На самом деле, в концепции дизайна операционной системы многие места использовали идею “первым пришел, первым вышел”, такую как планирование заданий (служба “первым пришел, первым вышел”). Почему этот принцип используется во многих местах? Поскольку этот принцип прост, соответствует инерционному мышлению людей, справедлив и прост в реализации, он может быть реализован непосредственно с помощью очереди в структуре данных.