Status processUsers(OperationContext* opCtx,
                        AuthorizationManager* authzManager,
                        StringData usersCollName,
                        StringData db,
                        bool drop) {
        // When the "drop" argument has been provided, we use this set to store the users
        // that are currently in the system, and remove from it as we encounter
        // same-named users in the collection we are restoring from.  Once we've fully
        // moved over the temp users collection into its final location, we drop
        // any users that previously existed there but weren't in the temp collection.
        // This is so that we can completely replace the system.users
        // collection with the users from the temp collection, without removing all
        // users at the beginning and thus potentially locking ourselves out by having
        // no users in the whole system for a time.
        stdx::unordered_set<UserName> usersToDrop;

        if (drop) {
            // Create map of the users currently in the DB
            BSONObj query =
                db.empty() ? BSONObj() : BSON(AuthorizationManager::USER_DB_FIELD_NAME << db);
            BSONObj fields = BSON(AuthorizationManager::USER_NAME_FIELD_NAME
                                  << 1
                                  << AuthorizationManager::USER_DB_FIELD_NAME
                                  << 1);

            Status status =
                queryAuthzDocument(opCtx,
                                   AuthorizationManager::usersCollectionNamespace,
                                   query,
                                   fields,
                                   [&](const BSONObj& userObj) {
                                       usersToDrop.insert(extractUserNameFromBSON(userObj));
                                   });
            if (!status.isOK()) {
                return status;
            }
        }

        Status status = queryAuthzDocument(
            opCtx,
            NamespaceString(usersCollName),
            db.empty() ? BSONObj() : BSON(AuthorizationManager::USER_DB_FIELD_NAME << db),
            BSONObj(),
            [&](const BSONObj& userObj) {
                return addUser(opCtx, authzManager, db, drop, &usersToDrop, userObj);
            });
        if (!status.isOK()) {
            return status;
        }

        if (drop) {
            long long numRemoved;
            for (const UserName& userName : usersToDrop) {
                audit::logDropUser(Client::getCurrent(), userName);
                status = removePrivilegeDocuments(opCtx,
                                                  BSON(AuthorizationManager::USER_NAME_FIELD_NAME
                                                       << userName.getUser().toString()
                                                       << AuthorizationManager::USER_DB_FIELD_NAME
                                                       << userName.getDB().toString()),
                                                  &numRemoved);
                if (!status.isOK()) {
                    return status;
                }
                dassert(numRemoved == 1);
            }
        }

        return Status::OK();
    }