blob: e6a5d78f50a15813bfed96aa66074e8d13473a77 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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
//
// http://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.
//
// Flag Tags provide a way to attach arbitrary textual tags to gflags in
// a global registry. Kudu uses the following flag tags:
//
// - "stable":
// These flags are considered user-facing APIs. Therefore, the
// semantics of the flag should not be changed except between major
// versions. Similarly, they must not be removed except between major
// versions.
//
// - "evolving":
// These flags are considered user-facing APIs, but are not yet
// locked down. For example, they may pertain to a newly introduced
// feature that is still being actively developed. These may be changed
// between minor versions, but should be suitably release-noted.
//
// This is the default assumed stability level, but can be tagged
// if you'd like to make it explicit.
//
// - "experimental":
// These flags are considered user-facing APIs, but are related to
// an experimental feature, or otherwise likely to change or be
// removed at any point. Users should not expect any compatibility
// of these flags.
//
// Users must pass --unlock_experimental_flags to use any of these
// flags.
//
// - "hidden":
// These flags are for internal use only (e.g. testing) and should
// not be included in user-facing documentation.
//
// - "advanced":
// These flags are for advanced users or debugging purposes. While
// they aren't likely to be actively harmful (see "unsafe" below),
// they're also likely to be used only rarely and should be relegated
// to more detailed sections of documentation.
//
// - "unsafe":
// These flags are for internal use only (e.g. testing), and changing
// them away from the defaults may result in arbitrarily bad things
// happening. These flags are automatically excluded from user-facing
// documentation even if they are not also marked 'hidden'.
//
// Users must pass --unlock_unsafe_flags to use any of these
// flags.
//
// - "runtime":
// These flags can be safely changed at runtime via an RPC to the
// server. Changing a flag at runtime that does not have this tag is allowed
// only if the user specifies a "force_unsafe_change" flag in the RPC.
//
// NOTE: because gflags are simple global variables, it's important to
// think very carefully before tagging a flag with 'runtime'. In particular,
// if a string-type flag is marked 'runtime', you should never access it
// using the raw 'FLAGS_foo_bar' name. Instead, you must use the
// google::GetCommandLineFlagInfo(...) API to make a copy of the flag value
// under a lock. Otherwise, the 'std::string' instance could be mutated
// underneath the reader causing a crash.
//
// For primitive-type flags, we assume that reading a variable is atomic.
// That is to say that a reader will either see the old value or the new
// one, but not some invalid value. However, for the runtime change to
// have any effect, you must be sure to use the FLAGS_foo_bar variable directly
// rather than initializing some instance variable during program startup.
//
// - "sensitive":
// The values of these flags are considered sensitive and will be redacted
// if redaction is enabled.
//
// A given flag may have zero or more tags associated with it. The system does
// not make any attempt to check integrity of the tags - for example, it allows
// you to mark a flag as both stable and unstable, even though this makes no
// real sense. Nevertheless, you should strive to meet the following requirements:
//
// - A flag should have exactly no more than one of stable/evolving/experimental
// indicating its stability. 'evolving' is considered the default.
// - A flag should have no more than one of advanced/hidden indicating visibility
// in documentation. If neither is specified, the flag will be in the main
// section of the documentation.
// - It is likely that most 'experimental' flags will also be 'advanced' or 'hidden',
// and that 'stable' flags are not likely to be 'hidden' or 'unsafe'.
//
// To add a tag to a flag, use the TAG_FLAG macro. For example:
//
// DEFINE_bool(sometimes_crash, false, "This flag makes Kudu crash a lot");
// TAG_FLAG(sometimes_crash, unsafe);
// TAG_FLAG(sometimes_crash, runtime);
//
// To fetch the list of tags associated with a flag, use 'GetFlagTags'.
#ifndef KUDU_UTIL_FLAG_TAGS_H
#define KUDU_UTIL_FLAG_TAGS_H
#include "kudu/gutil/macros.h"
#include <string>
#include <unordered_set>
namespace kudu {
struct FlagTags {
enum {
stable,
evolving,
experimental,
hidden,
advanced,
unsafe,
runtime,
sensitive
};
};
// Tag the flag 'flag_name' with the given tag 'tag'.
//
// This verifies that 'flag_name' is a valid gflag, which must be defined
// or declared above the use of the TAG_FLAG macro.
//
// This also validates that 'tag' is a valid flag as defined in the FlagTags
// enum above.
#define TAG_FLAG(flag_name, tag) \
namespace { \
::kudu::flag_tags_internal::FlagTagger t_##flag_name##_##tag( \
AS_STRING(flag_name), AS_STRING(tag)); \
} \
COMPILE_ASSERT(sizeof(decltype(FLAGS_##flag_name)), flag_does_not_exist); \
COMPILE_ASSERT(sizeof(::kudu::FlagTags::tag), invalid_tag)
// Fetch the list of flags associated with the given flag.
//
// If the flag is invalid or has no tags, sets 'tags' to be empty.
void GetFlagTags(const std::string& flag_name,
std::unordered_set<std::string>* tags);
// ------------------------------------------------------------
// Internal implementation details
// ------------------------------------------------------------
namespace flag_tags_internal {
class FlagTagger {
public:
FlagTagger(const char* name, const char* tag);
~FlagTagger();
private:
DISALLOW_COPY_AND_ASSIGN(FlagTagger);
};
} // namespace flag_tags_internal
} // namespace kudu
#endif /* KUDU_UTIL_FLAG_TAGS_H */