/** * Copyright (C) 2018-present MongoDB, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the Server Side Public License, version 1, * as published by MongoDB, Inc. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Server Side Public License for more details. * * You should have received a copy of the Server Side Public License * along with this program. If not, see * . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the Server Side Public License in all respects for * all of the code used other than as permitted herein. If you modify file(s) * with this exception, you may extend this exception to your version of the * file(s), but you are not obligated to do so. If you do not wish to do so, * delete this exception statement from your version. If you delete this * exception statement from all source files in the program, then also delete * it in the license file. */ #pragma once #include #include #include #include "mongo/db/storage/durable_catalog_impl.h" namespace mongo { class OperationContext; class RecordId; class RecordStore; /** * Manages the contents of a document in the DurableCatalogImpl used to restrict downgrade * compatibility. * * When a new feature is enabled on a collection or index in the data files, a bit is set in one of * the fields of the document. Older versions won't recognize this bit and will fail to start up as * a result. */ class DurableCatalogImpl::FeatureTracker { public: /** * Bit flags representing whether a particular feature is enabled on a least one collection or * index in the data files. Features included in this enumeration always require user * intervention on downgrade. * * The next feature added to this enumeration should use the current value of 'kNextFeatureBit', * and 'kNextFeatureBit' should be changed to the next largest power of two. */ enum class NonRepairableFeature : std::uint64_t { kCollation = 1 << 0, kNextFeatureBit = 1 << 1 }; using NonRepairableFeatureMask = std::underlying_type::type; /** * Bit flags representing whether a particular feature is enabled on a least one collection or * index in the data files. Features included in this enumeration either (a) don't require user * intervention on downgrade, or (b) are no longer enabled if --repair is done with an older * version. * * The next feature added to this enumeration should use the current value of 'kNextFeatureBit', * and 'kNextFeatureBit' should be changed to the next largest power of two. */ enum class RepairableFeature : std::uint64_t { kPathLevelMultikeyTracking = 1 << 0, kIndexKeyStringWithLongTypeBits = 1 << 1, kNextFeatureBit = 1 << 2 }; using RepairableFeatureMask = std::underlying_type::type; /** * Returns true if 'obj' represents the contents of the feature document that was previously * inserted into the DurableCatalogImpl, and returns false otherwise. * * This function should return true for at most one document in the DurableCatalogImpl. */ static bool isFeatureDocument(BSONObj obj); /** * Returns a FeatureTracker instance to manage the contents of the feature document located at * 'rid' in the record store 'catalog->_rs'. * * It is invalid to call this function when isFeatureDocument() returns false for the record * data associated with 'rid'. */ static std::unique_ptr get(OperationContext* opCtx, DurableCatalogImpl* catalog, RecordId rid); /** * Returns a FeatureTracker instance to manage the contents of a feature document. The feature * document isn't inserted into 'rs' as a result of calling this function. Instead, the feature * document is inserted into 'rs' when putInfo() is first called. * * It is invalid to call this function when isFeatureDocument() returns true for some document * in the record store 'catalog->_rs'. */ static std::unique_ptr create(OperationContext* opCtx, DurableCatalogImpl* catalog); /** * Returns whethers the data files are compatible with the current code: * * - Status::OK() if the data files are compatible with the current code. * * - ErrorCodes::CanRepairToDowngrade if the data files are incompatible with the current * code, but a --repair would make them compatible. For example, when rebuilding all indexes * in the data files would resolve the incompatibility. * * - ErrorCodes::MustUpgrade if the data files are incompatible with the current code and a * newer version is required to start up. */ Status isCompatibleWithCurrentCode(OperationContext* opCtx) const; /** * Returns true if 'feature' is tracked in the document, and returns false otherwise. */ bool isNonRepairableFeatureInUse(OperationContext* opCtx, NonRepairableFeature feature) const; /** * Sets the specified non-repairable feature as being enabled on at least one collection or * index in the data files. */ void markNonRepairableFeatureAsInUse(OperationContext* opCtx, NonRepairableFeature feature); /** * Sets the specified non-repairable feature as not being enabled on any collection or index in * the data files. */ void markNonRepairableFeatureAsNotInUse(OperationContext* opCtx, NonRepairableFeature feature); /** * Returns true if 'feature' is tracked in the document, and returns false otherwise. */ bool isRepairableFeatureInUse(OperationContext* opCtx, RepairableFeature feature) const; /** * Sets the specified repairable feature as being enabled on at least one collection or index in * the data files. */ void markRepairableFeatureAsInUse(OperationContext* opCtx, RepairableFeature feature); /** * Sets the specified repairable feature as not being enabled on any collection or index in the * data files. */ void markRepairableFeatureAsNotInUse(OperationContext* opCtx, RepairableFeature feature); void setUsedNonRepairableFeaturesMaskForTestingOnly(NonRepairableFeatureMask mask) { _usedNonRepairableFeaturesMask = mask; } void setUsedRepairableFeaturesMaskForTestingOnly(RepairableFeatureMask mask) { _usedRepairableFeaturesMask = mask; } struct FeatureBits { NonRepairableFeatureMask nonRepairableFeatures; RepairableFeatureMask repairableFeatures; }; FeatureBits getInfo(OperationContext* opCtx) const; void putInfo(OperationContext* opCtx, const FeatureBits& versionInfo); private: // Must go through FeatureTracker::get() or FeatureTracker::create(). FeatureTracker(DurableCatalogImpl* catalog, RecordId rid) : _catalog(catalog), _rid(rid) {} DurableCatalogImpl* _catalog; RecordId _rid; NonRepairableFeatureMask _usedNonRepairableFeaturesMask = static_cast(NonRepairableFeature::kNextFeatureBit) - 1; RepairableFeatureMask _usedRepairableFeaturesMask = static_cast(RepairableFeature::kNextFeatureBit) - 1; }; } // namespace mongo