Summary
The config server runs two parallel generation models. Per application, the generation number is the session id of the last activated deploy session. Per global “supermodel” (config shared across all applications, requested with configId ”*”), the generation is ConfigserverConfig.masterGeneration plus a distributed ZooKeeper counter. Both numbers are stamped into the ConfigResponse built for each RPC getConfig call, travel unchanged over the wire, and are the same values a subscriber later reports from ConfigSubscriber.getGeneration(). There is no separate “config payload generation” field fabricated at serve time: the stamp is either the active session id or the supermodel counter value. Deployment, activation, and generation are therefore one mechanism, not three. Administrative surface context: config-admin.
Key mechanisms
- Session id allocation: SessionCounter is a CuratorCounter on the ZK node tenants/
/sessionCounter, seeded at startup to the max existing session id under the tenant’s sessions dir (SessionCounter.java:13-28; InitializedCounter.java:27-40, 57-68). SessionRepository creates LocalSession objects wrapping ids from nextSessionId() (SessionRepository.java:1034, 248, 890, 998). - Activation equals generation bump: SessionRepository.activate(sessionId) calls tenantApplications.activateApplication(applicationVersions, sessionId) (SessionRepository.java:457-471, 508-509; the log line names the sessionId the “generation”). TenantApplications.activateApplication refuses stale activations by comparing applicationVersions.applicationGeneration() to activeSessionId (TenantApplications.java:254-262); ApplicationVersions.applicationGeneration() returns that generation field (ApplicationVersions.java:97-99).
- Per-app stamping: TenantApplications implements RequestHandler (TenantApplications.java:61); its resolveConfig delegates to application.resolveConfig (243-247), and Application.createConfigResponse stamps applicationGeneration into the response via responseFactory.createResponse (Application.java:127-138), cached per ConfigCacheKey in ServerCache (109-125).
- Supermodel counter: SuperModelGenerationCounter is a CuratorCounter at /config/v2/RPC/superModelGeneration with thread-safe increment()/get() (SuperModelGenerationCounter.java:14-38). SuperModelManager computes generation = masterGeneration + generationCounter.get() (SuperModelManager.java:123-126) and increments the counter on configActivated and applicationRemoved (lines 95, 108); masterGeneration defaults to 0 in configserver.def:32 (SuperModelManager.java:46-51).
- Supermodel stamping: SuperModelRequestHandler.updateHandler rebuilds a SuperModelController carrying superModelManager.getGeneration() (SuperModelRequestHandler.java:61-67); SuperModelController.resolveConfig stamps that generation into every global config response (SuperModelController.java:44-51).
- Delivery and delayed responses: GetConfigProcessor answers only when payload checksums differ from the request’s, when the response is newer than the request’s generation (ConfigResponse.hasNewerGeneration is getGeneration() > request.getRequestGeneration(), ConfigResponse.java:29-30), or when forceResponse; otherwise it parks a DelayedConfig (GetConfigProcessor.java:120-142, 178-193). On activation RpcServer records activeGeneration per ApplicationId from applicationVersions.applicationGeneration() and re-fires the supermodel (RpcServer.java:262-268, 252-253, 114-119).
- Client mapping: responses carry a slime field “generation” (SlimeResponseData.java:31, parsed at 53-57). Java ConfigSubscriber.getGeneration() returns “the current generation of configs known by this subscriber” (ConfigSubscriber.java:470-479), and nextGeneration() requires all subscriptions to agree on one generation (ConfigSubscriber.java:287-288). The C++ ConfigSubscriber::getGeneration mirrors this (configsubscriber.h:82-90), driven by per-subscription generations in ConfigSubscriptionSet (configsubscriptionset.cpp:80-82) with isGenerationNewer checks (configsubscription.cpp:38).
Open questions
- What besides deploy bumps the supermodel counter: SuperModelManager callers beyond SuperModelRequestHandler were not enumerated, so non-deploy increments (if any) are unconfirmed.
- How multi-configserver consistency is enforced across activation: SessionZooKeeperClient advertises “prepare and active barrier” creation in its javadoc (SessionZooKeeperClient.java:75-78), but the barrier wait/timeout code was not read line-by-line.
- Whether delayed-response replays can ever emit an older generation than one already delivered to a client (DelayedConfigResponses internals unread).
- Container-side consumers of these generations (container-jdisc) re-subscribe on change; exact proxy interaction deferred to GDN-NOTE-0036 follow-ups.