AuthorizationManager::AuthorizationManager(AuthzManagerExternalState* externalState) :
         _authEnabled(false),
         _externalState(externalState),
         _version(schemaVersionInvalid),
         _isFetchPhaseBusy(false) {
     _updateCacheGeneration_inlock();
 }
void AuthorizationManagerImpl::_invalidateUserCache_inlock(const CacheGuard& guard) {
    _updateCacheGeneration_inlock(guard);
    _userCache.invalidateIf([](const UserName& a, const User*) { return true; });

    // Reread the schema version before acquiring the next user.
    _version = schemaVersionInvalid;
}
std::vector<UserHandle> AuthorizationManagerImpl::invalidateUserByNameNoPin(
    OperationContext* opCtx, const UserName& userName) {
    CacheGuard guard(opCtx, this);
    _updateCacheGeneration_inlock(guard);
    _userCache.invalidate(userName);

    return _fetchPinnedUsers(guard, opCtx);
}
void AuthorizationManagerImpl::invalidateUsersFromDB(OperationContext* opCtx, StringData dbname) {
    CacheGuard guard(opCtx, this);
    _updateCacheGeneration_inlock(guard);
    _userCache.invalidateIf(
        [&](const UserName& user, const User*) { return user.getDB() == dbname; });


    setPinnedUsers_inlock(guard, _fetchPinnedUsers(guard, opCtx));
}
    void AuthorizationManager::_invalidateUserCache_inlock() {
        _updateCacheGeneration_inlock();
        for (unordered_map<UserName, User*>::iterator it = _userCache.begin();
                it != _userCache.end(); ++it) {
            fassert(17266, it->second != internalSecurity.user);
            it->second->invalidate();
        }
        _userCache.clear();

        // Reread the schema version before acquiring the next user.
        _version = schemaVersionInvalid;
    }
    void AuthorizationManager::invalidateUserByName(const UserName& userName) {
        CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
        _updateCacheGeneration_inlock();
        unordered_map<UserName, User*>::iterator it = _userCache.find(userName);
        if (it == _userCache.end()) {
            return;
        }

        User* user = it->second;
        _userCache.erase(it);
        user->invalidate();
    }
StatusWith<UserHandle> AuthorizationManagerImpl::acquireUser(OperationContext* opCtx,
                                                             const UserName& userName) {
    if (userName == internalSecurity.user->getName()) {
        return internalSecurity.user;
    }

    boost::optional<UserHandle> cachedUser = _userCache.get(userName);
    auto returnUser = [&](boost::optional<UserHandle> cachedUser) {
        auto ret = *cachedUser;
        fassert(16914, ret.get());

        LOG(1) << "Returning user " << userName << " from cache";
        return ret;
    };

    // The userCache is thread-safe, so if we can get a user out of the cache we don't need to
    // take any locks!
    if (cachedUser) {
        return returnUser(cachedUser);
    }

    // Otherwise make sure we have the locks we need and check whether and wait on another
    // thread is fetching into the cache
    CacheGuard guard(opCtx, this);

    while ((boost::none == (cachedUser = _userCache.get(userName))) &&
           guard.otherUpdateInFetchPhase()) {
        guard.wait();
    }

    if (cachedUser != boost::none) {
        return returnUser(cachedUser);
    }

    guard.beginFetchPhase();
    // If there's still no user in the cache, then we need to go to disk. Take the slow path.
    LOG(1) << "Getting user " << userName << " from disk";
    auto ret = _acquireUserSlowPath(guard, opCtx, userName);

    guard.endFetchPhase();
    if (!ret.isOK()) {
        return ret.getStatus();
    }

    auto user = std::move(ret.getValue());
    if (user->isValid()) {
        _updateCacheGeneration_inlock(guard);
    }

    return user;
}
 void AuthorizationManager::invalidateUsersFromDB(const std::string& dbname) {
     CacheGuard guard(this, CacheGuard::fetchSynchronizationManual);
     _updateCacheGeneration_inlock();
     unordered_map<UserName, User*>::iterator it = _userCache.begin();
     while (it != _userCache.end()) {
         User* user = it->second;
         if (user->getName().getDB() == dbname) {
             _userCache.erase(it++);
             user->invalidate();
         } else {
             ++it;
         }
     }
 }
std::vector<UserHandle> AuthorizationManagerImpl::_fetchPinnedUsers(CacheGuard& guard,
                                                                    OperationContext* opCtx) {
    // Get the list of users to pin
    const auto usersToPin = authorizationManagerPinnedUsers.getUserNames();
    if (usersToPin.empty()) {
        return {};
    }

    // Remove any users that shouldn't be pinned anymore or that are invalid.
    std::vector<UserHandle> newPinnedUsers;
    std::copy_if(_pinnedUsers.begin(),
                 _pinnedUsers.end(),
                 std::back_inserter(newPinnedUsers),
                 [&](const UserHandle& user) {
                     if (!user->isValid())
                         return false;
                     return std::any_of(
                         usersToPin.begin(), usersToPin.end(), [&](const UserName& userName) {
                             return (user->getName() == userName);
                         });
                 });

    const auto findPinnedUser = [&](const auto& userName) {
        return std::find_if(
            newPinnedUsers.begin(), newPinnedUsers.end(), [&](const auto& userHandle) {
                return (userHandle->getName() == userName);
            });
    };


    while (guard.otherUpdateInFetchPhase()) {
        guard.wait();
    }

    // Begin the fetch phase but don't yield any locks. We want re-pinning of users to block other
    // operations until all the users are refreshed.
    guard.beginFetchPhaseNoYield();

    bool cacheUpdated = false;
    for (const auto& userName : usersToPin) {
        auto existingPin = findPinnedUser(userName);
        if (existingPin != newPinnedUsers.end()) {
            newPinnedUsers.push_back(*existingPin);
            continue;
        }

        cacheUpdated = true;
        auto swUser = _acquireUserSlowPath(guard, opCtx, userName);
        if (swUser.isOK()) {
            newPinnedUsers.emplace(newPinnedUsers.end(), std::move(swUser.getValue()));
        } else {
            const auto& status = swUser.getStatus();
            // If the user is not found, then it might just not exist yet. Skip this user for now.
            if (status != ErrorCodes::UserNotFound) {
                warning() << "Unable to fetch pinned user " << userName.toString() << ": "
                          << status;
            }
        }
    }

    if (cacheUpdated)
        _updateCacheGeneration_inlock(guard);

    return newPinnedUsers;
}