<commit_before>/**
 * @file metadataCache.cc
 * @author <NAME>
 * @copyright (C) 2015 ACK CYFRONET AGH
 * @copyright This software is released under the MIT license cited in
 * 'LICENSE.txt'
 */

#include "metadataCache.h"
#include "fuseOperations.h"

#include "logging.h"
#include "messages/fuse/getFileAttr.h"
#include "messages/fuse/getFileLocation.h"
#include "messages/fuse/rename.h"
#include "scheduler.h"

#include <chrono>

using namespace std::literals;

namespace one {
namespace client {

MetadataCache::MetadataCache(communication::Communicator &communicator)
    : m_communicator{communicator}
{
}

MetadataCache::FileAttr MetadataCache::getAttr(const Path &path)
{
    ConstUuidAccessor constUuidAcc;
    if (m_pathToUuid.find(constUuidAcc, path))
        return getAttr(constUuidAcc->second);

    UuidAccessor uuidAcc;
    MetaAccessor metaAcc;
    getAttr(uuidAcc, metaAcc, path);
    return metaAcc->second.attr.get();
}

MetadataCache::FileAttr MetadataCache::getAttr(const std::string &uuid)
{
    ConstMetaAccessor constAcc;
    if (m_metaCache.find(constAcc, uuid)) {
        if (constAcc->second.attr)
            return constAcc->second.attr.get();

        constAcc.release();
    }

    MetaAccessor acc;
    getAttr(acc, uuid);
    return acc->second.attr.get();
}

MetadataCache::FileLocation MetadataCache::getLocation(
    const std::string &uuid, const one::helpers::FlagsSet flags)
{
    ConstMetaAccessor constAcc;
    if (m_metaCache.find(constAcc, uuid)) {
        if (constAcc->second.location)
            return constAcc->second.location.get();

        constAcc.release();
    }

    MetaAccessor acc;
    getLocation(acc, uuid, flags);
    return acc->second.location.get();
}

void MetadataCache::getAttr(MetaAccessor &metaAcc, const Path &path)
{
    UuidAccessor uuidAcc;
    getAttr(uuidAcc, metaAcc, path);
}

void MetadataCache::getAttr(
    UuidAccessor &uuidAcc, MetaAccessor &metaAcc, const Path &path)
{
    if (!m_pathToUuid.insert(uuidAcc, path)) {
        getAttr(metaAcc, uuidAcc->second);
        metaAcc->second.paths.emplace(path);
        return;
    }

    try {
        DLOG(INFO) << "Fetching attributes for " << path;
        auto attr = fetchAttr(messages::fuse::GetFileAttr{path});
        uuidAcc->second = attr.uuid();
        if (m_metaCache.insert(metaAcc, attr.uuid())) {
            // In this case we're fetching attributes because we didn't know
            // the path mapped to an already cached uuid. Do not update attrs
            // to avoid race conditions with our own write events.
            metaAcc->second.attr = std::move(attr);
        }
        metaAcc->second.paths.emplace(path);
    }
    catch (...) {
        if (!metaAcc.empty())
            m_metaCache.erase(metaAcc);

        m_pathToUuid.erase(uuidAcc);
        throw;
    }
}

bool MetadataCache::get(MetaAccessor &metaAcc, const std::string &uuid)
{
    return m_metaCache.find(metaAcc, uuid);
}

void MetadataCache::getAttr(MetaAccessor &metaAcc, const std::string &uuid)
{
    if (!m_metaCache.insert(metaAcc, uuid)) {
        if (metaAcc->second.attr)
            return;
    }

    try {
        DLOG(INFO) << "Fetching attributes for " << uuid;
        metaAcc->second.attr = fetchAttr(messages::fuse::GetFileAttr{uuid});
    }
    catch (...) {
        m_metaCache.erase(metaAcc);
        throw;
    }
}

void MetadataCache::getLocation(MetadataCache::MetaAccessor &metaAcc,
    const std::string &uuid, const one::helpers::FlagsSet flags)
{
    if (!m_metaCache.insert(metaAcc, uuid)) {
        if (metaAcc->second.location)
            return;
    }

    try {
        DLOG(INFO) << "Fetching file location for " << uuid;
        auto future = m_communicator.communicate<FileLocation>(
            messages::fuse::GetFileLocation{uuid, flags});

        metaAcc->second.location = communication::wait(future);
    }
    catch (...) {
        m_metaCache.erase(metaAcc);
        throw;
    }
}

void MetadataCache::rename(
    const MetadataCache::Path &oldPath, const MetadataCache::Path &newPath)
{
    // By convention, to avoid deadlocks, always lock on path before metadata
    UuidAccessor newUuidAcc;
    m_pathToUuid.insert(newUuidAcc, newPath);

    try {
        UuidAccessor oldUuidAcc;
        MetaAccessor metaAcc;
        getAttr(oldUuidAcc, metaAcc, oldPath);
        auto &uuid = metaAcc->second.attr.get().uuid();

        DLOG(INFO) << "Renaming file " << uuid << " to " << newPath;
        auto paths = metaAcc->second.paths;

        m_pathToUuid.erase(oldUuidAcc);
        if (metaAcc->second.removedUpstream) {
            // Only oldPath is changed to newPath
            metaAcc->second.paths.erase(oldPath);
            metaAcc->second.paths.emplace(newPath);
            newUuidAcc->second = uuid;
        }
        else {
            auto future =
                m_communicator.communicate<messages::fuse::FuseResponse>(
                    messages::fuse::Rename{uuid, newPath});

            communication::wait(future);

            // File is renamed, uuid may have changed - remove all mappings
            metaAcc->second.paths.clear();
            metaAcc.release();
            for (auto &path : paths)
                m_pathToUuid.erase(path);
            m_pathToUuid.erase(newUuidAcc);
            m_metaCache.erase(uuid);
        }
    }
    catch (...) {
        m_pathToUuid.erase(newUuidAcc);
        throw;
    }
}

void MetadataCache::map(Path path, std::string uuid)
{
    UuidAccessor uuidAcc;
    m_pathToUuid.insert(uuidAcc, path);

    MetaAccessor metaAcc;
    m_metaCache.insert(metaAcc, uuid);

    uuidAcc->second = std::move(uuid);
    metaAcc->second.paths.emplace(std::move(path));
}<commit_msg>Removing path from target file attrs after overwrite in rename<commit_after>/**
 * @file metadataCache.cc
 * @author <NAME>
 * @copyright (C) 2015 ACK CYFRONET AGH
 * @copyright This software is released under the MIT license cited in
 * 'LICENSE.txt'
 */

#include "metadataCache.h"
#include "fuseOperations.h"

#include "logging.h"
#include "messages/fuse/getFileAttr.h"
#include "messages/fuse/getFileLocation.h"
#include "messages/fuse/rename.h"
#include "scheduler.h"

#include <chrono>

using namespace std::literals;

namespace one {
namespace client {

MetadataCache::MetadataCache(communication::Communicator &communicator)
    : m_communicator{communicator}
{
}

MetadataCache::FileAttr MetadataCache::getAttr(const Path &path)
{
    ConstUuidAccessor constUuidAcc;
    if (m_pathToUuid.find(constUuidAcc, path))
        return getAttr(constUuidAcc->second);

    UuidAccessor uuidAcc;
    MetaAccessor metaAcc;
    getAttr(uuidAcc, metaAcc, path);
    return metaAcc->second.attr.get();
}

MetadataCache::FileAttr MetadataCache::getAttr(const std::string &uuid)
{
    ConstMetaAccessor constAcc;
    if (m_metaCache.find(constAcc, uuid)) {
        if (constAcc->second.attr)
            return constAcc->second.attr.get();

        constAcc.release();
    }

    MetaAccessor acc;
    getAttr(acc, uuid);
    return acc->second.attr.get();
}

MetadataCache::FileLocation MetadataCache::getLocation(
    const std::string &uuid, const one::helpers::FlagsSet flags)
{
    ConstMetaAccessor constAcc;
    if (m_metaCache.find(constAcc, uuid)) {
        if (constAcc->second.location)
            return constAcc->second.location.get();

        constAcc.release();
    }

    MetaAccessor acc;
    getLocation(acc, uuid, flags);
    return acc->second.location.get();
}

void MetadataCache::getAttr(MetaAccessor &metaAcc, const Path &path)
{
    UuidAccessor uuidAcc;
    getAttr(uuidAcc, metaAcc, path);
}

void MetadataCache::getAttr(
    UuidAccessor &uuidAcc, MetaAccessor &metaAcc, const Path &path)
{
    if (!m_pathToUuid.insert(uuidAcc, path)) {
        getAttr(metaAcc, uuidAcc->second);
        metaAcc->second.paths.emplace(path);
        return;
    }

    try {
        DLOG(INFO) << "Fetching attributes for " << path;
        auto attr = fetchAttr(messages::fuse::GetFileAttr{path});
        uuidAcc->second = attr.uuid();
        if (m_metaCache.insert(metaAcc, attr.uuid())) {
            // In this case we're fetching attributes because we didn't know
            // the path mapped to an already cached uuid. Do not update attrs
            // to avoid race conditions with our own write events.
            metaAcc->second.attr = std::move(attr);
        }
        metaAcc->second.paths.emplace(path);
    }
    catch (...) {
        if (!metaAcc.empty())
            m_metaCache.erase(metaAcc);

        m_pathToUuid.erase(uuidAcc);
        throw;
    }
}

bool MetadataCache::get(MetaAccessor &metaAcc, const std::string &uuid)
{
    return m_metaCache.find(metaAcc, uuid);
}

void MetadataCache::getAttr(MetaAccessor &metaAcc, const std::string &uuid)
{
    if (!m_metaCache.insert(metaAcc, uuid)) {
        if (metaAcc->second.attr)
            return;
    }

    try {
        DLOG(INFO) << "Fetching attributes for " << uuid;
        metaAcc->second.attr = fetchAttr(messages::fuse::GetFileAttr{uuid});
    }
    catch (...) {
        m_metaCache.erase(metaAcc);
        throw;
    }
}

void MetadataCache::getLocation(MetadataCache::MetaAccessor &metaAcc,
    const std::string &uuid, const one::helpers::FlagsSet flags)
{
    if (!m_metaCache.insert(metaAcc, uuid)) {
        if (metaAcc->second.location)
            return;
    }

    try {
        DLOG(INFO) << "Fetching file location for " << uuid;
        auto future = m_communicator.communicate<FileLocation>(
            messages::fuse::GetFileLocation{uuid, flags});

        metaAcc->second.location = communication::wait(future);
    }
    catch (...) {
        m_metaCache.erase(metaAcc);
        throw;
    }
}

void MetadataCache::rename(
    const MetadataCache::Path &oldPath, const MetadataCache::Path &newPath)
{
    // By convention, to avoid deadlocks, always lock on path before metadata
    UuidAccessor newUuidAcc;
    m_pathToUuid.insert(newUuidAcc, newPath);

    try {
        UuidAccessor oldUuidAcc;
        MetaAccessor metaAcc;
        getAttr(oldUuidAcc, metaAcc, oldPath);
        auto &uuid = metaAcc->second.attr.get().uuid();

        DLOG(INFO) << "Renaming file " << uuid << " to " << newPath;
        auto paths = metaAcc->second.paths;

        m_pathToUuid.erase(oldUuidAcc);
        if (metaAcc->second.removedUpstream) {
            // Only oldPath is changed to newPath
            metaAcc->second.paths.erase(oldPath);
            metaAcc->second.paths.emplace(newPath);
            newUuidAcc->second = uuid;
        }
        else {
            auto targetExists = false;

            MetaAccessor targetMetaAcc;
            if (newUuidAcc->second != "") {
                if(get(targetMetaAcc, newUuidAcc->second))
                    targetExists = true;
            }

            auto future =
                m_communicator.communicate<messages::fuse::FuseResponse>(
                    messages::fuse::Rename{uuid, newPath});

            communication::wait(future);

            if (targetExists) {
                targetMetaAcc->second.paths.erase(newPath);
                targetMetaAcc.release();
            }

            // File is renamed, uuid may have changed - remove all mappings
            metaAcc->second.paths.clear();
            metaAcc.release();
            for (auto &path : paths)
                m_pathToUuid.erase(path);
            m_pathToUuid.erase(newUuidAcc);
            m_metaCache.erase(uuid);
        }
    }
    catch (...) {
        m_pathToUuid.erase(newUuidAcc);
        throw;
    }
}

void MetadataCache::map(Path path, std::string uuid)
{
    UuidAccessor uuidAcc;
    m_pathToUuid.insert(uuidAcc, path);

    MetaAccessor metaAcc;
    m_metaCache.insert(metaAcc, uuid);

    uuidAcc->second = std::move(uuid);
    metaAcc->second.paths.emplace(std::move(path));
}
{'fraction_non_alphanumeric': 0.12324953602159608, 'fraction_numerical': 0.0006748776784207862, 'mean_word_length': 2.7163009404388716, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 66, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '90920', 'n_tokens_mistral': 3658, 'n_tokens_neox': 3653, 'n_words': 744}