Как использовать пессимистичную блокировку Couchbase с C API?

Это невероятно расстраивает ... Я использую API Couchbase v3 C, и я столкнулся с проблемой, которую можно было бы идеально решить с помощью их пессимистической блокировки. После долгих усилий я считаю, что наконец-то понял, как с его помощью блокировать записи (с lcb_cmdget_locktime(), который предположительно принимает параметр в микросекундах), но я не могу понять, как разблокировать запись один раз. Я покончил с этим, кроме как дать ему тайм-аут, что не является приемлемым решением.

В документации приводится один пример, здесь, но по какой-то неизвестной причине он в Javascript вместо C (!!!), и концепции не отображаются в C API.

Кто-нибудь знает, как разблокировать пессимистическую блокировку или иметь какой-либо пример кода C / C ++ с использованием этого API? Если исключить это, знает ли кто-нибудь, где найти исходный код для любого из API-интерфейсов, отличных от C, которые используют C, поскольку я должен иметь возможность работать с ним оттуда? (Я тоже не смог найти ни одного из них, не уверен, что у них открытый исходный код.)


person Head Geek    schedule 02.12.2020    source источник
comment
Я не разработчик C, но вы можете найти некоторую помощь в справочнике по SDK здесь: docs.couchbase.com/sdk-api/couchbase-c-client/   -  person Matthew Groves    schedule 03.12.2020
comment
(Кроме того, я постараюсь помочь исправить / обновить эту страницу)   -  person Matthew Groves    schedule 03.12.2020
comment
Спасибо, @MatthewGroves. Я не нашел, что документация по клиенту C очень удобна, извините ... Я не нашел способа найти ее или любую страницу, которая включает все имена функций в одном месте, поэтому я приходится копаться, чтобы найти нужные мне функции, а это занимает слишком много времени, чтобы быть полезным.   -  person Head Geek    schedule 03.12.2020
comment
(Я нашел в нем некоторую информацию с помощью поисковой системы, но она не очень ясна по этому поводу.)   -  person Head Geek    schedule 03.12.2020


Ответы (1)


Спасибо за вопрос

Время в секундах, обратите внимание, что сервер может сбросить время на значение по умолчанию, если оно больше максимального времени (оба значения можно настроить). Следующая команда поможет определить эффективные значения функции.

$ cbstats -u Administrator -p password  localhost all | grep ep_getl
ep_getl_default_timeout:                               15
ep_getl_max_timeout:                                   30

Чтобы заблокировать ключ, необходимо использовать операцию получения и установить время блокировки с помощью lcb_cmdget_locktime и захватить значение CAS в случае успешной блокировки, например, как это

struct my_result {
    lcb_STATUS status{LCB_SUCCESS};
    uint64_t cas{0};
};

static void get_callback(lcb_INSTANCE *instance, lcb_CALLBACK_TYPE, const lcb_RESPGET *resp)
{
    my_result *res = nullptr;
    lcb_respget_cookie(resp, (void **)&res);
    res->status = lcb_respget_status(resp);
    if (res->status == LCB_SUCCESS) {
        lcb_respget_cas(resp, &res->cas);
    }
}

Хорошая идея - поместить команду get с кодом блокировки в цикл

uint64_t locked_cas{0};
int retries = 3;
while (retries > 0) {
    std::string document_id{"foo"};
    my_result result{};
    lcb_CMDGET* cmd = nullptr;
    lcb_cmdget_create(&cmd);
    lcb_cmdget_key(cmd, document_id.c_str(), document_id.size());
    lcb_cmdget_locktime(cmd, 5);
    lcb_get(instance, &result, cmd);
    lcb_cmdget_destroy(cmd);
    lcb_wait(instance, LCB_WAIT_DEFAULT);

    if (result.rc == LCB_SUCCESS) {
        locked_cas = result.cas;
        break;
    } else if (result.rc == LCB_ERR_DOCUMENT_LOCKED || result.rc == LCB_ERR_TEMPORARY_FAILURE) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        --retries;
        continue;
    } else {
        std::cerr << "Unexpected issue during get with lock: " << lcb_strerror_short(result.rc) << "\n";
        break;
    }
}

После блокировки ключа операция обновления может быть выполнена, но имейте в виду, что она ДОЛЖНА использовать locked_cas, иначе операция мутации завершится неудачно.

std::string document_id{"foo"};
std::string new_value{"new value"};
lcb_CMDSTORE* cmd = nullptr;
lcb_cmdstore_create(&cmd, LCB_STORE_REPLACE);
lcb_cmdstore_key(cmd, document_id.c_str(), document_id.size());
lcb_cmdstore_value(cmd, new_value.c_str(), new_value.size());
lcb_cmdstore_cas(cmd, locked_cas);
lcb_store(instance, nullptr, cmd);
lcb_cmdstore_destroy(cmd);
lcb_wait(instance, LCB_WAIT_DEFAULT);

Чтобы разблокировать ключ, вам также понадобится locked_cas, или просто подождите, пока сервер автоматически разблокирует документ.

std::string document_id{"foo"};
lcb_CMDUNLOCK *cmd = nullptr;
lcb_cmdunlock_create(&cmd);
lcb_cmdunlock_key(cmd, document_id.c_str(), document_id.size());
lcb_cmdunlock_cas(cmd, locked_cas);
lcb_unlock(instance, nullptr, cmd);
lcb_cmdunlock_destroy(cmd);
lcb_wait(instance, LCB_WAIT_DEFAULT);
person avsej    schedule 04.12.2020
comment
Спасибо! Это сводило меня с ума, не имея приличной документации. - person Head Geek; 05.12.2020