aboutsummaryrefslogtreecommitdiffstats
path: root/config/src/vespa/config/frt/frtconfigagent.cpp
blob: 6a5b1ed09eafba4c2b74f8bd170ae1fb5735bfce (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "frtconfigagent.h"
#include "frtconfigrequestv3.h"
#include <vespa/config/common/trace.h>
#include <vespa/config/common/configresponse.h>
#include <vespa/config/common/iconfigholder.h>
#include <cinttypes>

#include <vespa/log/log.h>
LOG_SETUP(".config.frt.frtconfigagent");

namespace config {

FRTConfigAgent::FRTConfigAgent(std::shared_ptr<IConfigHolder> holder, const TimingValues & timingValues)
    : _holder(std::move(holder)),
      _timingValues(timingValues),
      _configState(),
      _latest(),
      _waitTime(0),
      _numConfigured(0),
      _failedRequests(0),
      _nextTimeout(_timingValues.initialTimeout)
{
}

FRTConfigAgent::~FRTConfigAgent() = default;

void
FRTConfigAgent::handleResponse(const ConfigRequest & request, std::unique_ptr<ConfigResponse> response)
{
    if (LOG_WOULD_LOG(spam)) {
        const ConfigKey & key(request.getKey());
        LOG(spam, "current state for %s: generation %" PRId64 " xxhash64 %s", key.toString().c_str(), _configState.generation, _configState.xxhash64.c_str());
    }
    if (response->validateResponse() && !response->isError()) {
        handleOKResponse(request, std::move(response));
    } else {
        handleErrorResponse(request, std::move(response));
    }
}

void
FRTConfigAgent::handleOKResponse(const ConfigRequest & request, std::unique_ptr<ConfigResponse> response)
{
    _failedRequests = 0;
    response->fill();
    if (LOG_WOULD_LOG(spam)) {
        LOG(spam, "trace(%s)", response->getTrace().toString().c_str());
    }

    ConfigState newState = response->getConfigState();
    if ( ! request.verifyState(newState)) {
        handleUpdatedGeneration(response->getKey(), newState, response->getValue());
    }
    setWaitTime(_timingValues.successDelay, 1);
    _nextTimeout = _timingValues.successTimeout;
}

void
FRTConfigAgent::handleUpdatedGeneration(const ConfigKey & key, const ConfigState & newState, const ConfigValue & configValue)
{
    if (LOG_WOULD_LOG(spam)) {
        LOG(spam, "new generation %" PRId64 " xxhash64:%s for key %s", newState.generation, newState.xxhash64.c_str(), key.toString().c_str());
        LOG(spam, "Old config: xxhash64:%s \n%s", _latest.getXxhash64().c_str(), _latest.asJson().c_str());
        LOG(spam, "New config: xxhash64:%s \n%s", configValue.getXxhash64().c_str(), configValue.asJson().c_str());
    }
    bool changed = false;
    if (_latest.getXxhash64() != configValue.getXxhash64()) {
        _latest = configValue;
        changed = true;
    }
    _configState = newState;

    if (LOG_WOULD_LOG(spam)) {
        LOG(spam, "updating holder for key %s,", key.toString().c_str());
    }
    _holder->handle(std::make_unique<ConfigUpdate>(_latest, changed, newState.generation));
    _numConfigured++;
}

using vespalib::to_s;

void
FRTConfigAgent::handleErrorResponse(const ConfigRequest & request, std::unique_ptr<ConfigResponse> response)
{
    _failedRequests++;
    int multiplier = std::min(_failedRequests, _timingValues.maxDelayMultiplier);
    setWaitTime(_numConfigured > 0 ? _timingValues.configuredErrorDelay : _timingValues.unconfiguredDelay, multiplier);
    _nextTimeout = _timingValues.errorTimeout;
    const ConfigKey & key(request.getKey());
    LOG(info, "No response / error from config server. This is normal before an application package is deployed. (key: %s) (errcode=%d, validresponse:%d), trying again in %f seconds",
        key.toString().c_str(), response->errorCode(), response->hasValidResponse() ? 1 : 0, to_s(_waitTime));
}

void
FRTConfigAgent::setWaitTime(duration delay, int multiplier)
{
    duration prevWait = _waitTime;
    _waitTime = _timingValues.fixedDelay + (multiplier * delay);
    LOG(spam, "Adjusting waittime from %f to %f", to_s(prevWait), to_s(_waitTime));
}

vespalib::duration FRTConfigAgent::getTimeout() const { return _nextTimeout; }
vespalib::duration FRTConfigAgent::getWaitTime() const { return _waitTime; }
const ConfigState & FRTConfigAgent::getConfigState() const { return _configState; }

}