/************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2016 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * 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 * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ //------------------------------------------------------------------------------ //! @author Elvin-Alin Sindrilaru //! @brief Class representing the file metadata //------------------------------------------------------------------------------ #ifndef EOS_NS_FILE_MD_HH #define EOS_NS_FILE_MD_HH #include "common/SharedMutexWrapper.hh" #include "namespace/interface/IFileMD.hh" #include "namespace/ns_quarkdb/persistency/FileMDSvc.hh" #include "proto/FileMd.pb.h" #include #include #define FRIEND_TEST(test_case_name, test_name)\ friend class test_case_name##_##test_name##_Test EOSNSNAMESPACE_BEGIN //! Forward declaration class IFileMDSvc; class IContainerMD; //------------------------------------------------------------------------------ //! Class holding the metadata information concerning a single file //------------------------------------------------------------------------------ class QuarkFileMD : public IFileMD { friend class FileSystemView; public: //---------------------------------------------------------------------------- //! Empty constructor //---------------------------------------------------------------------------- QuarkFileMD(); //---------------------------------------------------------------------------- //! Constructor //---------------------------------------------------------------------------- QuarkFileMD(IFileMD::id_t id, IFileMDSvc* fileMDSvc); //---------------------------------------------------------------------------- //! Destructor //---------------------------------------------------------------------------- virtual ~QuarkFileMD() {}; //---------------------------------------------------------------------------- //! Copy constructor //---------------------------------------------------------------------------- QuarkFileMD(const QuarkFileMD& other); //---------------------------------------------------------------------------- //! Virtual copy constructor //---------------------------------------------------------------------------- virtual QuarkFileMD* clone() const override; //---------------------------------------------------------------------------- //! Assignment operator //---------------------------------------------------------------------------- QuarkFileMD& operator=(const QuarkFileMD& other); //---------------------------------------------------------------------------- //! Get creation time //---------------------------------------------------------------------------- void getCTime(ctime_t& ctime) const override; //---------------------------------------------------------------------------- //! Set creation time //---------------------------------------------------------------------------- void setCTime(ctime_t ctime) override; //---------------------------------------------------------------------------- //! Set creation time to now //---------------------------------------------------------------------------- void setCTimeNow() override; //---------------------------------------------------------------------------- //! Get access time //---------------------------------------------------------------------------- void getATime(ctime_t& atime) const override; //---------------------------------------------------------------------------- //! Set access time //---------------------------------------------------------------------------- void setATime(ctime_t atime) override; //---------------------------------------------------------------------------- //! Set access time to now if older than olderthan //---------------------------------------------------------------------------- bool setATimeNow(uint64_t olderthan) override; //---------------------------------------------------------------------------- //! Get modification time //---------------------------------------------------------------------------- void getMTime(ctime_t& mtime) const override; //---------------------------------------------------------------------------- //! Set modification time //---------------------------------------------------------------------------- void setMTime(ctime_t mtime) override; //---------------------------------------------------------------------------- //! Set modification time to now //---------------------------------------------------------------------------- void setMTimeNow() override; //---------------------------------------------------------------------------- //! get sync time //---------------------------------------------------------------------------- void getSyncTime(ctime_t& stime) const override; //---------------------------------------------------------------------------- //! set sync time //---------------------------------------------------------------------------- void setSyncTime(ctime_t stime) override; //---------------------------------------------------------------------------- //! set sync time to now //---------------------------------------------------------------------------- void setSyncTimeNow() override; //---------------------------------------------------------------------------- //! Get file id //---------------------------------------------------------------------------- inline IFileMD::id_t getId() const override { return runReadOp([this]() { return mFile.id(); }); } //---------------------------------------------------------------------------- //! Get file identifier //---------------------------------------------------------------------------- inline identifier_t getIdentifier() const override { return this->runReadOp([this]() { return identifier_t(mFile.id()); }); } //---------------------------------------------------------------------------- //! Get size //---------------------------------------------------------------------------- inline uint64_t getSize() const override { return this->runReadOp([this]() { return mFile.size(); }); } //---------------------------------------------------------------------------- //! Set size - 48 bytes will be used //---------------------------------------------------------------------------- void setSize(uint64_t size) override; //---------------------------------------------------------------------------- //! Get cloneId //---------------------------------------------------------------------------- inline uint64_t getCloneId() const override { return runReadOp([this]() { return mFile.cloneid(); }); } //---------------------------------------------------------------------------- //! Set cloneId //---------------------------------------------------------------------------- void setCloneId(uint64_t id) override { return runWriteOp([this, id]() { mFile.set_cloneid(id); }); } //---------------------------------------------------------------------------- //! Get cloneFST //---------------------------------------------------------------------------- const std::string getCloneFST() const override { return runReadOp([this]() { return mFile.clonefst(); }); } //---------------------------------------------------------------------------- //! Set cloneFST //---------------------------------------------------------------------------- void setCloneFST(const std::string& data) override { runWriteOp([this,data](){ mFile.set_clonefst(data); }); } //---------------------------------------------------------------------------- //! Get parent id //---------------------------------------------------------------------------- inline IContainerMD::id_t getContainerId() const override { return this->runReadOp([this]() { return mFile.cont_id(); }); } //---------------------------------------------------------------------------- //! Set parent id //---------------------------------------------------------------------------- void setContainerId(IContainerMD::id_t containerId) override { runWriteOp([this, containerId]() { mFile.set_cont_id(containerId); }); } //---------------------------------------------------------------------------- //! Get checksum //---------------------------------------------------------------------------- inline const Buffer getChecksum() const override { return runReadOp([this]() { Buffer buff(mFile.checksum().size()); buff.putData((void*)mFile.checksum().data(), mFile.checksum().size()); return buff; }); } //---------------------------------------------------------------------------- //! Set checksum //---------------------------------------------------------------------------- void setChecksum(const Buffer& checksum) override { runWriteOp([this, &checksum]() { mFile.set_checksum(checksum.getDataPtr(), checksum.getSize()); }); } //---------------------------------------------------------------------------- //! Clear checksum //---------------------------------------------------------------------------- void clearChecksum(uint8_t size = 20) override { runWriteOp([this]() { mFile.clear_checksum(); }); } //---------------------------------------------------------------------------- //! Set checksum //! //! @param checksum address of a memory location storing the checksum //! @param size size of the checksum in bytes //---------------------------------------------------------------------------- void setChecksum(const void* checksum, uint8_t size) override { runWriteOp( [this, checksum, size]() { mFile.set_checksum(checksum, size); }); } //---------------------------------------------------------------------------- //! Get name //---------------------------------------------------------------------------- inline const std::string getName() const override { return runReadOp([this]() { return mFile.name(); }); } //---------------------------------------------------------------------------- //! Set name //! Warning: Only calling this method to rename a file will not work as the //! container containing it needs also to update its files cache //---------------------------------------------------------------------------- void setName(const std::string& name) override; //---------------------------------------------------------------------------- //! Add location //---------------------------------------------------------------------------- void addLocation(location_t location) override; //---------------------------------------------------------------------------- //! Get vector with all the locations //---------------------------------------------------------------------------- inline LocationVector getLocations() const override { return this->runReadOp([this]() { LocationVector locations(mFile.locations().begin(), mFile.locations().end()); return locations; }); } //---------------------------------------------------------------------------- //! Get location //---------------------------------------------------------------------------- location_t getLocation(unsigned int index) override { return this->runReadOp([this, index]() { if (index < (unsigned int)mFile.locations_size()) { return mFile.locations(index); } return (location_t)0; }); } //---------------------------------------------------------------------------- //! Remove location that was previously unlinked //---------------------------------------------------------------------------- void removeLocation(location_t location) override; //---------------------------------------------------------------------------- //! Remove all locations that were previously unlinked //---------------------------------------------------------------------------- void removeAllLocations() override; //---------------------------------------------------------------------------- //! Clear locations without notifying the listeners //---------------------------------------------------------------------------- void clearLocations() override { this->runWriteOp([this]() { mFile.clear_locations(); }); } //---------------------------------------------------------------------------- //! Test if location exists, without taking lock //---------------------------------------------------------------------------- bool hasLocationNoLock(location_t location) { for (int i = 0; i < mFile.locations_size(); i++) { if (mFile.locations(i) == location) { return true; } } return false; } //---------------------------------------------------------------------------- //! Test if location exists //---------------------------------------------------------------------------- bool hasLocation(location_t location) override { return this->runReadOp( [this, location]() { return hasLocationNoLock(location); }); } //---------------------------------------------------------------------------- //! Get number of locations //---------------------------------------------------------------------------- inline size_t getNumLocation() const override { return runReadOp([this]() { return mFile.locations_size(); }); } //---------------------------------------------------------------------------- //! Get vector with all unlinked locations //---------------------------------------------------------------------------- inline LocationVector getUnlinkedLocations() const override { return this->runReadOp([this]() { LocationVector unlinked_locations(mFile.unlink_locations().begin(), mFile.unlink_locations().end()); return unlinked_locations; }); } //---------------------------------------------------------------------------- //! Unlink location //---------------------------------------------------------------------------- void unlinkLocation(location_t location) override; //---------------------------------------------------------------------------- //! Unlink all locations //---------------------------------------------------------------------------- void unlinkAllLocations() override; //---------------------------------------------------------------------------- //! Clear unlinked locations without notifying the listeners //---------------------------------------------------------------------------- inline void clearUnlinkedLocations() override { this->runWriteOp([this]() { mFile.clear_unlink_locations(); }); } //---------------------------------------------------------------------------- //! Test the unlinked location //---------------------------------------------------------------------------- bool hasUnlinkedLocation(location_t location) override; //---------------------------------------------------------------------------- //! Get number of unlinked locations //---------------------------------------------------------------------------- inline size_t getNumUnlinkedLocation() const override { return runReadOp([this]() { return mFile.unlink_locations_size(); }); } //---------------------------------------------------------------------------- //! Get uid //---------------------------------------------------------------------------- inline uid_t getCUid() const override { return runReadOp([this]() { return mFile.uid(); }); } //---------------------------------------------------------------------------- //! Set uid //---------------------------------------------------------------------------- inline void setCUid(uid_t uid) override { runWriteOp([this, uid]() { mFile.set_uid(uid); }); } //---------------------------------------------------------------------------- //! Get gid //---------------------------------------------------------------------------- inline gid_t getCGid() const override { return runReadOp([this]() { return mFile.gid(); }); } //---------------------------------------------------------------------------- //! Set gid //---------------------------------------------------------------------------- inline void setCGid(gid_t gid) override { runWriteOp([this, gid]() { mFile.set_gid(gid); }); } //---------------------------------------------------------------------------- //! Get layout //---------------------------------------------------------------------------- inline layoutId_t getLayoutId() const override { return runReadOp([this]() { return mFile.layout_id(); }); } //---------------------------------------------------------------------------- //! Set layout //---------------------------------------------------------------------------- inline void setLayoutId(layoutId_t layoutId) override { runWriteOp([this, layoutId]() { mFile.set_layout_id(layoutId); }); } //---------------------------------------------------------------------------- //! Get flags //---------------------------------------------------------------------------- inline uint16_t getFlags() const override { return runReadOp([this]() { return mFile.flags(); }); } //---------------------------------------------------------------------------- //! Get the n-th flag //---------------------------------------------------------------------------- inline bool getFlag(uint8_t n) override { return runReadOp( [this, n]() { return (bool)(mFile.flags() & (0x0001 << n)); }); } //---------------------------------------------------------------------------- //! Set flags //---------------------------------------------------------------------------- inline void setFlags(uint16_t flags) override { return runWriteOp([this, flags]() { mFile.set_flags(flags); }); } //---------------------------------------------------------------------------- //! Set the n-th flag //---------------------------------------------------------------------------- void setFlag(uint8_t n, bool flag) override { return runWriteOp([this, n, flag]() { if (flag) { mFile.set_flags(mFile.flags() | (1 << n)); } else { mFile.set_flags(mFile.flags() & (~(1 << n))); } }); } //---------------------------------------------------------------------------- //! Env Representation //---------------------------------------------------------------------------- void getEnv(std::string& env, bool escapeAnd = false) override; //---------------------------------------------------------------------------- //! Set the FileMDSvc object //---------------------------------------------------------------------------- inline void setFileMDSvc(IFileMDSvc* fileMDSvc) override { runWriteOp([this, fileMDSvc]() { pFileMDSvc = static_cast(fileMDSvc); }); } //---------------------------------------------------------------------------- //! Get the FileMDSvc object //---------------------------------------------------------------------------- inline virtual IFileMDSvc* getFileMDSvc() override { return runReadOp([this]() { return pFileMDSvc; }); } //---------------------------------------------------------------------------- //! Get symbolic link //---------------------------------------------------------------------------- inline std::string getLink() const override { return runReadOp([this]() { return mFile.link_name(); }); } //---------------------------------------------------------------------------- //! Set symbolic link //---------------------------------------------------------------------------- inline void setLink(std::string link_name) override { runWriteOp([this, link_name]() { mFile.set_link_name(link_name); }); } //---------------------------------------------------------------------------- //! Check if symbolic link //---------------------------------------------------------------------------- bool isLink() const override { return runReadOp([this]() { return !mFile.link_name().empty(); }); } //---------------------------------------------------------------------------- //! Add extended attribute //---------------------------------------------------------------------------- void setAttribute(const std::string& name, const std::string& value) override { runWriteOp( [this, name, value]() { (*mFile.mutable_xattrs())[name] = value; }); } //---------------------------------------------------------------------------- //! Remove attribute //---------------------------------------------------------------------------- void removeAttribute(const std::string& name) override { runWriteOp([this, name]() { auto it = mFile.xattrs().find(name); if (it != mFile.xattrs().end()) { mFile.mutable_xattrs()->erase(it->first); } }); } //---------------------------------------------------------------------------- //! Remove all attributes //---------------------------------------------------------------------------- void clearAttributes() override { runWriteOp([this]() { mFile.clear_xattrs(); }); } //---------------------------------------------------------------------------- //! Check if the attribute exist //---------------------------------------------------------------------------- bool hasAttribute(const std::string& name) const override { return runReadOp([this, name]() { return (mFile.xattrs().find(name) != mFile.xattrs().end()); }); } //---------------------------------------------------------------------------- //! Return number of attributes //---------------------------------------------------------------------------- inline size_t numAttributes() const override { return runReadOp([this]() { return mFile.xattrs().size(); }); } //---------------------------------------------------------------------------- //! Get the attribute //---------------------------------------------------------------------------- std::string getAttribute(const std::string& name) const override { return runReadOp([this, &name] { auto it = mFile.xattrs().find(name); if (it == mFile.xattrs().end()) { MDException e(ENOENT); e.getMessage() << "Attribute: " << name << " not found"; throw e; } return it->second; }); } //---------------------------------------------------------------------------- //! Get map copy of the extended attributes //! //! @return std::map containing all the extended attributes //---------------------------------------------------------------------------- eos::IFileMD::XAttrMap getAttributes() const override; //---------------------------------------------------------------------------- //! Serialize the object to a buffer //---------------------------------------------------------------------------- void serialize(Buffer& buffer) override; //---------------------------------------------------------------------------- //! Initialize from protobuf contents //---------------------------------------------------------------------------- void initialize(eos::ns::FileMdProto&& proto); //---------------------------------------------------------------------------- //! Deserialize the class to a buffer //---------------------------------------------------------------------------- void deserialize(const Buffer& buffer) override; //---------------------------------------------------------------------------- //! Get reference to underlying protobuf object //---------------------------------------------------------------------------- const eos::ns::FileMdProto& getProto() const; //---------------------------------------------------------------------------- //! Get value tracking changes to the metadata object //---------------------------------------------------------------------------- virtual uint64_t getClock() const override { return runReadOp([this](){ return mClock; }); }; protected: IFileMDSvc* pFileMDSvc; private: FRIEND_TEST(VariousTests, EtagFormatting); //---------------------------------------------------------------------------- //! Get modification time, no locks //---------------------------------------------------------------------------- void getMTimeNoLock(ctime_t& mtime) const; //---------------------------------------------------------------------------- //! Get access time, no locks //---------------------------------------------------------------------------- void getATimeNoLock(ctime_t& atime) const; //---------------------------------------------------------------------------- //! Get modification time, no locks //---------------------------------------------------------------------------- void getSyncTimeNoLock(ctime_t& stime) const; //---------------------------------------------------------------------------- //! Get creation time, no locks //---------------------------------------------------------------------------- void getCTimeNoLock(ctime_t& ctime) const; //---------------------------------------------------------------------------- //! Test the unlinked location, no locks //---------------------------------------------------------------------------- bool hasUnlinkedLocationNoLock(location_t location) const; eos::ns::FileMdProto mFile; ///< Protobuf file representation uint64_t mClock; ///< Value tracking metadata changes }; EOSNSNAMESPACE_END #endif // __EOS_NS_FILE_MD_HH__