protobuf/api/memcache_service.proto (426 lines of code) (raw):

/* * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // Copyright 2008 Google Inc. // All Rights Reserved. // // The memcache API provides a memcached-alike API to Prometheus applications. // // If anything in this document is unclear, refer to the official // memcached protocol specs, which this service attempts to mimic: // http://code.sixapart.com/svn/memcached/tags/1.2.4/doc/protocol.txt // // These stubby definitions are closely related to those from // google3/cacheserving/memcacheg/proto/rpc.proto, but differ in a few ways: // * intended to be visible to external developers // * missing some functionality that may be available in memcacheg, allowing // memcacheg to move independently from memcache API. // * the name_space fields exposed here are used to build // the namespace, but do not specify it completely. The app_id is // used as the top level namespace, and name_space is immediately below. // If the name_space field is "", it is mapped to the app's root namespace. // // LINT: ALLOW_GROUPS syntax = "proto2"; // Some generic_services option(s) added automatically. // See: http://go/proto2-generic-services-default package java.apphosting; option java_generic_services = true; // auto-added option java_package = "com.google.appengine.api.memcache"; option java_outer_classname = "MemcacheServicePb"; message MemcacheServiceError { enum ErrorCode { OK = 0; // This could be any error including including misconfiguration, // client-caused bad keys, and some types of temporary // unavailability. UNSPECIFIED_ERROR = 1; // Can currently (Mar 2014) only be returned by GrabTail, which is // not exposed to customer. NAMESPACE_NOT_SET = 2; // A non-superuser app attempted to use app_override. PERMISSION_DENIED = 3; // obsolete NUM_BACKENDS_UNSPECIFIED = 4; // obsolete MEMCACHE_POOL_HINT_UNSPECIFIED = 5; // An attempt was made to increment a value that was not a valid // number. INVALID_VALUE = 6; // obsolete MEMCACHE_SHARDING_STRATEGY_UNSPECIFIED = 7; // obsolete APP_CONFIG_ACCESS_ERROR = 8; // The memcache_service is currently unavailable. This is a most // likely a transient condition and may be corrected by retrying // with a backoff. Possible reasons include not being able to // connect to memcacheg backends because of shardmap changes or // global chubby outages. For historical reasons the runtimes // convert this into a capability-disabled exception or error. UNAVAILABLE = 9; } } // This message allows you to manipulate the memcache of a different // application (not the memcache that belongs to the app initiating // the request). If you are working with your own memcache (the usual case) // you shouldn't specify it. // // Originally this mechanism required the client to pass along details // of the backend configuration, since the appserver hosting the app // performing the override would not have this info for the target app. The // current memcache service implementation has been improved to obviate this, // and the fields marked deprecated below will be ignored by the new server. // // TODO: Remove uses of deprecated fields once the new memcache // service implementation is deployed. message AppOverride { // The app_id of the target memcache. required string app_id = 1; // Do not reuse ids of removed fields: 2, 3, 4, 5; // NB: Can't use 'reserved' in this file, it needs to work with proto1. } // Next tag: 7 message MemcacheGetRequest { repeated bytes key = 1; optional string name_space = 2 [default = ""]; // If set true, returned items will include a "cas_id" value needed // to do a future atomic compare-and-swap operation. This allocates // and initializes the cas_id on each returned item, even if it // wasn't put into memcacheg initially with cas set. Because the // cas_id takes memory in the server and bandwidth in the response, // you should only set this if you're actually planning to use CAS. optional bool for_cas = 4; optional AppOverride override = 5; // If set true, returned items will include timestamps and indicate whether // the item is delete_locked or not. Peeking at items will update stats, but // will not alter the eviction order of the item. optional bool for_peek = 6; // default=FALSE } // Timestamps relevant to a memcache item. // Next tag: 4 message ItemTimestamps { // Absolute expiration timestamp of the item. Unset if this item has no // expiration timestamp. optional int64 expiration_time_sec = 1; // Absolute last accessed timestamp of the item. optional int64 last_access_time_sec = 2; // Absolute delete_time timestamp of the item. Unset if this item is not // delete locked. optional int64 delete_lock_time_sec = 3; } // Next tag: 10 message MemcacheGetResponse { // One item will be returned for each HIT, i.e. where the value was found for // the requested key. Order is not specified. repeated group Item = 1 { required bytes key = 2; required bytes value = 3; optional fixed32 flags = 4; // server-opaque (app-owned) flags // The compare-and-swap ID, if requested. Opaque to the client. // All the client needs to know is that if they do a get request // with "for_cas" set above, then get a cas_id, and then do a // SetRequest with policy CAS, passing along the same opaque // cas_id, it will only succeed if nobody else has replaced the // value since then. The cas_ids won't be reused between versions // of the value. optional fixed64 cas_id = 5; // Relative to now. Unset if this item has no expiration timestamp. optional int32 expires_in_seconds = 6; // Item timestamps. Only returned if for_peek is set on the request. optional ItemTimestamps timestamps = 8; // Item is delete_locked. Only returned if for_peek is set on the request. optional bool is_delete_locked = 9; } enum GetStatusCode { // Key was found and value successfully returned. HIT = 1; // Key does not exist on the backend. MISS = 2; // Key was found, but value not returned because the response was truncated // to fit into limited length of response. // // This is expected only if many keys were requested in a batch request; // the default response size limit is 32 MiB, while items cannot be larger // than 1 MiB. TRUNCATED = 3; // Response from backend not received in time. It's not known whether the // key exists. DEADLINE_EXCEEDED = 4; // Could not reach memcacheg backend (may be dead). It's not known whether // the key exists. UNREACHABLE = 5; // Other service error, e.g. other RPC errors, shardlock failure, missing // config (ServingState). It's not known whether the key exists. OTHER_ERROR = 6; } // One get_status will be returned for each requested key, in the same order // that the requests were in. // TODO(b/290098535) This can return the wrong status code when there's a mix // of hit/miss. repeated GetStatusCode get_status = 7; } message MemcacheSetRequest { enum SetPolicy { SET = 1; // set value in memcached, unconditionally ADD = 2; // add to memcached, if it doesn't already exist REPLACE = 3; // put it in memcached, but only if it's already in there // Compare-and-swap. If using this policy, the 'cas_id' optional // field is required, else NOT_STORED will be returned. This // policy is like REPLACE, but a smart replace that only updates // the value if nobody else has between your Get and your Set. // See the docs in MemcacheGetRequest and MemcacheGetResponse. CAS = 4; } repeated group Item = 1 { required bytes key = 2; // max 250 bytes, per upstream spec required bytes value = 3; // From the docs above: // <flags> is an arbitrary 32-bit unsigned integer that the server // stores along with the data and sends back when the item is // retrieved. Clients may use this as a bit field to store // data-specific information; this field is opaque to the server. optional fixed32 flags = 4; optional SetPolicy set_policy = 5 [default = SET]; // unixtime to expire key. 0 or unset means "no expiration" // From the memcached documentation: // <exptime> is expiration time. If it's 0, the item never expires // (although it may be deleted from the cache to make place for // other items). If it's non-zero (either Unix time or offset in // seconds from current time), it is guaranteed that clients will // not be able to retrieve this item after the expiration time // arrives (measured by server time). optional fixed32 expiration_time = 6 [default = 0]; // Required if using the CAS (compare & swap) set_policy. This is // the cas_id as returned in MemcacheGetResponse, requested in // MemacheGetResponse. The value, opaque to the client, is the handle // the guarantees that nobody modified the value from the time you // requested it until the time you replaced it with CAS. Holding a // a cas_id is not a lock though: anybody can beat you to the CAS. // If you lose the race, you'll get the status code EXISTS returned. // See docs in MemcacheSetResponse. optional fixed64 cas_id = 8; // Optionally set this when doing a SET or ADD if you plan to do a // CAS operation on this item in the future, which will cause the // item's internal cas_id to be allocated early, rather than the // server upgrading it to include a cas_id in the future when you // do a Get. You may still do a CAS operation in the future on // any key without setting this. This is purely an optimization // hint to the server. optional bool for_cas = 9; } optional string name_space = 7 [default = ""]; optional AppOverride override = 10; } message MemcacheSetResponse { enum SetStatusCode { // Key-value pair was successfully stored. STORED = 1; // Not stored for policy reasons (e.g. policy=ADD but item exists), // not error reasons. NOT_STORED = 2; // Not stored due to bad request, e.g. invalid key, item too large, ... ERROR = 3; // If you lost a CAS race. From the memcached docs: "to indicate // that the item you are trying to store with a CAS command has // been modified since you last fetched it." If instead the item // being CAS'd has fallen out of memcacheg, NOT_STORED will be // returned instead. EXISTS = 4; // Response from backend not received in time. It's not known whether the // item was stored. DEADLINE_EXCEEDED = 5; // Could not reach memcacheg backend (may be dead). The item was // definitively not stored. UNREACHABLE = 6; // Other service error, e.g. other RPC errors, shardlock failure, missing // config (ServingState). It's not known whether the item was stored or // not. OTHER_ERROR = 7; } // One set_status will be returned for each set key, in the same // order that the requests were in. repeated SetStatusCode set_status = 1; } message MemcacheDeleteRequest { repeated group Item = 1 { required bytes key = 2; // max 250 bytes, per upstream spec // From the upstream memcached protocol docs on delete time: // // - <time> is the amount of time in seconds (or Unix time until which) // the client wishes the server to refuse "add" and "replace" commands // with this key. For this amount of item, the item is put into a // delete queue, which means that it won't possible to retrieve it by // the "get" command, but "add" and "replace" command with this key // will also fail (the "set" command will succeed, however). After the // time passes, the item is finally deleted from server memory. // // The parameter <time> is optional, and, if absent, defaults to 0 // (which means that the item will be deleted immediately and further // storage commands with this key will succeed). // There's no limit to what this value may be, outside of the limit of // it being a 32-bit int. optional fixed32 delete_time = 3 [default = 0]; } optional string name_space = 4 [default = ""]; optional AppOverride override = 5; } message MemcacheDeleteResponse { enum DeleteStatusCode { // The key existed and was deleted. DELETED = 1; // The key didn't exist and therefore didn't need to be deleted. NOT_FOUND = 2; // Response from backend not received in time. It's not known whether the // item existed and it's also not known whether it was deleted. DEADLINE_EXCEEDED = 3; // Could not reach memcacheg backend (may be dead). It's not known whether // the item existed, but it definitively was not deleted. UNREACHABLE = 4; // Other service error, e.g. other RPC errors, shardlock failure, missing // config (ServingState). It's not known whether the item existed and // it's also not known whether it was deleted. OTHER_ERROR = 5; } // one set_status will be returned for each set key, matching the // order of the requested items to delete. repeated DeleteStatusCode delete_status = 1; } // The memcached protocol spec defines the deltas for both "incr" // and "decr" as uint64 values. Since we're lumping these together // as one RPC, we also need the optional direction to specify decrementing. // By default the delta is '1' and direction is increment (the common use case). // Note that this mutation request doesn't support multiple operations // at once, intentionally, as that's a rare operation. message MemcacheIncrementRequest { enum Direction { INCREMENT = 1; DECREMENT = 2; } required bytes key = 1; // max 250 bytes, per upstream spec optional string name_space = 4 [default = ""]; // The amount to increment/decrement the value by, if it already // exists in the cache. Note that this does not implicitly create a // new counter starting at the specified delta. To initialize a new // counter, the client must Set an initial value. (which they send // as a decimal string, just like memcached). optional uint64 delta = 2 [default = 1]; optional Direction direction = 3 [default = INCREMENT]; // If set (even if set to 0), traditional memcached semantics around // needing to set the value in the cache before doing an increment // are ignored and the value is instead initialized to this value if // it's not already in the cache. If you want this before, you'll // probably want to set this to zero, where most apps count from. optional uint64 initial_value = 5; // If set, determines the flags that are used for a value // initialized from initial_value. optional fixed32 initial_flags = 6; // server-opaque (app-owned) flags optional AppOverride override = 7; } message MemcacheIncrementResponse { enum IncrementStatusCode { // Key was found and incremented. OK = 1; // For policy reasons, e.g. key doesn't exist and initial value was not // specified, existing value wasn't a number, or invalid request. NOT_CHANGED = 2; // May or may not have been incremented due to some server error. // // DEPRECATED in favor of the 3 status codes below. As of April 2017, only // ERROR is returned. Once we change all clients to understand the new codes // below, we'll flip --memcache_return_better_errors and ERROR will never be // returned (tracked in b/25965653). ERROR = 3; // Response from backend not received in time. It's not known whether the // key exists and it's also not known whether it was incremented. DEADLINE_EXCEEDED = 4; // Could not reach memcacheg backend (may be dead). It's not known whether // the key exists, but it definitively was not incremented. UNREACHABLE = 5; // Other service error, e.g. other RPC errors, shardlock failure, missing // config (ServingState). It's not known whether the key exists and it's // also not known whether it was incremented. OTHER_ERROR = 6; } // The new value, only set if the item was found. Per the spec, // underflow is capped at zero, but overflow wraps around. optional uint64 new_value = 1; // Always set, unlike cacheserving_memcacheg::MemcacheIncrementResponse which // is set only if part of BatchIncrement() call. optional IncrementStatusCode increment_status = 2; } // Allow for multiple increment/decrements in parallel. Combined with the // 'initial_value' field of the MemcacheIncrementRequest message, this can // be used to track a large set of counters with low-latency. message MemcacheBatchIncrementRequest { optional string name_space = 1 [default = ""]; repeated MemcacheIncrementRequest item = 2; optional AppOverride override = 3; } message MemcacheBatchIncrementResponse { // One 'item' will always be returned in the response for each 'item' in the // request, with no exceptions. repeated MemcacheIncrementResponse item = 1; } message MemcacheFlushRequest { // Note: There is no name_space parameter. This request flushes // all memcache data for an app. // Note: we don't support upstream's flush_all 'time' parameter optional AppOverride override = 1; } message MemcacheFlushResponse { // This space intentionally left blank. Reserved for future // expansion. } message MemcacheStatsRequest { // N.B.(jackkelly): Stats for the entire app are returned, regardless of which // namespaces (if any) are used. optional AppOverride override = 1; // Number of hot key requested. optional int32 max_hotkey_count = 2 [default = 0]; } // This is a merge of all the NamespaceStats for each of the namespaces owned by // the requesting application. message MergedNamespaceStats { // All these stats reset whenever the process starts up or the task // moves around. They may also reset if the namespace becomes empty // (due to evictions or explicit deletes) and the server removes its // Namespace data structure. // Counters: (only increase, except when stats reset) required uint64 hits = 1; required uint64 misses = 2; required uint64 byte_hits = 3; // bytes transferred on gets // Not counters: required uint64 items = 4; required uint64 bytes = 5; // How long (in seconds) it's been since the oldest item in the // namespace's LRU chain has been accessed. This is how long a new // item can currently be put in the cache and survive without being // accessed. This is _not_ about the time since the item was // created, but how long it's been since it was accessed. required fixed32 oldest_item_age = 6; // Only set when hot keys are present and requested through stats. repeated MemcacheHotKey hotkeys = 7; } // Memcache key that has a hit rate higher than a certain threshold. This // threshold is controlled by the flag --hotkey_threshold_qps in memcacheg. message MemcacheHotKey { required bytes key = 1; // Max 250 bytes. // A query is defined as an individual key operation, i.e. a single GET // operation on one particular key. A memcache API call can contain multiple // key operations in a single call. required double qps = 2; // Queries per second. // The namespace this key belongs to. optional string name_space = 3; } message MemcacheStatsResponse { // This is set if the namespace was found: optional MergedNamespaceStats stats = 1; }