aboutsummaryrefslogblamecommitdiffstats
path: root/util/system/filemap.h
blob: 933d169adb75a10f58c26041b24f2d86a56043dd (plain) (tree)
1
2
3
4
5
6
7
8
9
            
 


                    
                                     
                                 
                                    
                               
                                


                 



                                                                                  
                         
                                                   

                               
                                                  
                                                              
         
                                               
                                  
         
                                      
                          





                     
 
                                   
                    
         
 
                        
                    
                      
 
                        
                        
                                                                                
      
                                              
       

                                                                  
                                            
  
                                                           
 
                                           

                                                              
                                                                           
                                                                                            
 
                  
 
                                            
                                  
 

                                                       
                                 
                                     
                                       
                                   
 

                                      
 


                                       
 


                                     
 
                                         


                                                            
                                                                                   
                                                                                                    
                                          
 
                
 
                                                       
                 
 

                                        
 

                                   
 

                                             
 

                                        
 
                                        
                             
 
                                         
                             
 


                                             


                                        
                                       
                                    
 
                                               
                                    
 
                                    
                              
 
                                                                   
 






                             
                                                  
 

                       
 
                  


                        

                                                     
                                  
 
       
                      
                       


                         
                       
     

                                              
     

                                                 
     
                              
                       
                  
                       
     

                                 
                                           
                               
                         
     
                                                               
                         
                     
     

                         
                                      

                             
     

                                                   
     
                                             







                                                
                                                                
                                                 
                       
 
                                                 
     
                                                                
                                     
                       
                                     
                    
     
                                                              
                                   
                    
     
                                   
                    
 
        
                                          







                                                                                 
  
                                    
       
                                                                                  
                          
                  
                                                           
                          
                                                                      

                          
                                                   
                       
                    
                                    
                                                             
     
                                  
                            
                                
                                      
                               
                     
     
                                                
 
        

                         
            
                             
      
  
                                               
       

                                

                        
                     
                  
                           
                                                        
                                              
                 
                                                  
                                        
                              
                   







                                               
                               
                               
                                
                                           
                               
                                
                
                         
              
                                                 
                         
                                        
     
                                      
     
#pragma once

#include "file.h"
#include "align.h"
#include "yassert.h"

#include <util/generic/noncopyable.h>
#include <util/generic/ptr.h>
#include <util/generic/utility.h>
#include <util/generic/yexception.h>
#include <util/generic/flags.h>
#include <util/generic/string.h>

#include <new>
#include <cstdio>

namespace NPrivate {
    // NB: use TFileMap::Precharge() and TFileMappedArray::Prechage()
    void Precharge(const void* data, size_t dataSize, size_t offset, size_t size);
}

struct TMemoryMapCommon {
    struct TMapResult {
        inline size_t MappedSize() const noexcept {
            return Size - Head;
        }

        inline void* MappedData() const noexcept {
            return Ptr ? (void*)((char*)Ptr + Head) : nullptr;
        }

        inline bool IsMapped() const noexcept {
            return Ptr != nullptr;
        }

        inline void Reset() noexcept {
            Ptr = nullptr;
            Size = 0;
            Head = 0;
        }

        void* Ptr;
        size_t Size;
        i32 Head;

        TMapResult(void) noexcept {
            Reset();
        }
    };

    enum EOpenModeFlag {
        oRdOnly = 1,
        oRdWr = 2,
        oCopyOnWr = 4,

        oAccessMask = 7,
        oNotGreedy = 8,
        oPrecharge = 16,
        oPopulate = 32, // Populate page table entries (see mmap's MAP_POPULATE)
    };
    Y_DECLARE_FLAGS(EOpenMode, EOpenModeFlag);

    /**
     * Name that will be printed in exceptions if not specified.
     * Overridden by name obtained from `TFile` if it's not empty.
     */
    static const TString& UnknownFileName();
};
Y_DECLARE_OPERATORS_FOR_FLAGS(TMemoryMapCommon::EOpenMode);

class TMemoryMap: public TMemoryMapCommon {
public:
    explicit TMemoryMap(const TString& name);
    explicit TMemoryMap(const TString& name, EOpenMode om);
    TMemoryMap(const TString& name, i64 length, EOpenMode om);
    TMemoryMap(FILE* f, TString dbgName = UnknownFileName());
    TMemoryMap(FILE* f, EOpenMode om, TString dbgName = UnknownFileName());
    TMemoryMap(const TFile& file, const TString& dbgName = UnknownFileName());
    TMemoryMap(const TFile& file, EOpenMode om, const TString& dbgName = UnknownFileName());

    ~TMemoryMap();

    TMapResult Map(i64 offset, size_t size);
    bool Unmap(TMapResult region);

    void ResizeAndReset(i64 size);
    TMapResult ResizeAndRemap(i64 offset, size_t size);

    i64 Length() const noexcept;
    bool IsOpen() const noexcept;
    bool IsWritable() const noexcept;
    EOpenMode GetMode() const noexcept;
    TFile GetFile() const noexcept;

    void SetSequential();
    void Evict(void* ptr, size_t len);
    void Evict();

    /*
     * deprecated
     */
    bool Unmap(void* ptr, size_t size);

private:
    class TImpl;
    TSimpleIntrusivePtr<TImpl> Impl_;
};

class TFileMap: public TMemoryMapCommon {
public:
    TFileMap(const TMemoryMap& map) noexcept;
    TFileMap(const TString& name);
    TFileMap(const TString& name, EOpenMode om);
    TFileMap(const TString& name, i64 length, EOpenMode om);
    TFileMap(FILE* f, EOpenMode om = oRdOnly, TString dbgName = UnknownFileName());
    TFileMap(const TFile& file, EOpenMode om = oRdOnly, const TString& dbgName = UnknownFileName());
    TFileMap(const TFileMap& fm) noexcept;

    ~TFileMap();

    TMapResult Map(i64 offset, size_t size);
    TMapResult ResizeAndRemap(i64 offset, size_t size);
    void Unmap();

    void Flush(void* ptr, size_t size) {
        Flush(ptr, size, true);
    }

    void Flush() {
        Flush(Ptr(), MappedSize());
    }

    void FlushAsync(void* ptr, size_t size) {
        Flush(ptr, size, false);
    }

    void FlushAsync() {
        FlushAsync(Ptr(), MappedSize());
    }

    inline i64 Length() const noexcept {
        return Map_.Length();
    }

    inline bool IsOpen() const noexcept {
        return Map_.IsOpen();
    }

    inline bool IsWritable() const noexcept {
        return Map_.IsWritable();
    }

    EOpenMode GetMode() const noexcept {
        return Map_.GetMode();
    }

    inline void* Ptr() const noexcept {
        return Region_.MappedData();
    }

    inline size_t MappedSize() const noexcept {
        return Region_.MappedSize();
    }

    TFile GetFile() const noexcept {
        return Map_.GetFile();
    }

    void Precharge(size_t pos = 0, size_t size = (size_t)-1) const;

    void SetSequential() {
        Map_.SetSequential();
    }

    void Evict() {
        Map_.Evict();
    }

private:
    void Flush(void* ptr, size_t size, bool sync);

    TMemoryMap Map_;
    TMapResult Region_;
};

template <class T>
class TFileMappedArray {
private:
    const T* Ptr_;
    const T* End_;
    size_t Size_;
    char DummyData_[sizeof(T) + PLATFORM_DATA_ALIGN];
    mutable THolder<T, TDestructor> Dummy_;
    THolder<TFileMap> DataHolder_;

public:
    TFileMappedArray()
        : Ptr_(nullptr)
        , End_(nullptr)
        , Size_(0)
    {
    }
    ~TFileMappedArray() {
        Ptr_ = nullptr;
        End_ = nullptr;
    }
    void Init(const char* name) {
        DataHolder_.Reset(new TFileMap(name));
        DoInit(name);
    }
    void Init(const TFileMap& fileMap) {
        DataHolder_.Reset(new TFileMap(fileMap));
        DoInit(fileMap.GetFile().GetName());
    }
    void Term() {
        DataHolder_.Destroy();
        Ptr_ = nullptr;
        Size_ = 0;
        End_ = nullptr;
    }
    void Precharge() {
        DataHolder_->Precharge();
    }
    const T& operator[](size_t pos) const {
        Y_ASSERT(pos < size());
        return Ptr_[pos];
    }
    /// for STL compatibility only, Size() usage is recommended
    size_t size() const {
        return Size_;
    }
    size_t Size() const {
        return Size_;
    }
    const T& GetAt(size_t pos) const {
        if (pos < Size_)
            return Ptr_[pos];
        return Dummy();
    }
    void SetDummy(const T& n_Dummy) {
        Dummy_.Destroy();
        Dummy_.Reset(new (DummyData()) T(n_Dummy));
    }
    inline char* DummyData() const noexcept {
        return AlignUp((char*)DummyData_);
    }
    inline const T& Dummy() const {
        if (!Dummy_) {
            Dummy_.Reset(new (DummyData()) T());
        }

        return *Dummy_;
    }
    /// for STL compatibility only, Empty() usage is recommended
    Y_PURE_FUNCTION bool empty() const noexcept {
        return Empty();
    }

    Y_PURE_FUNCTION bool Empty() const noexcept {
        return 0 == Size_;
    }
    /// for STL compatibility only, Begin() usage is recommended
    const T* begin() const noexcept {
        return Begin();
    }
    const T* Begin() const noexcept {
        return Ptr_;
    }
    /// for STL compatibility only, End() usage is recommended
    const T* end() const noexcept {
        return End_;
    }
    const T* End() const noexcept {
        return End_;
    }

private:
    void DoInit(const TString& fileName) {
        DataHolder_->Map(0, DataHolder_->Length());
        if (DataHolder_->Length() % sizeof(T)) {
            Term();
            ythrow yexception() << "Incorrect size of file " << fileName.Quote();
        }
        Ptr_ = (const T*)DataHolder_->Ptr();
        Size_ = DataHolder_->Length() / sizeof(T);
        End_ = Ptr_ + Size_;
    }
};

class TMappedAllocation: TMoveOnly {
public:
    TMappedAllocation(size_t size = 0, bool shared = false, void* addr = nullptr);
    ~TMappedAllocation() {
        Dealloc();
    }
    TMappedAllocation(TMappedAllocation&& other) noexcept {
        this->swap(other);
    }
    TMappedAllocation& operator=(TMappedAllocation&& other) noexcept {
        this->swap(other);
        return *this;
    }
    void* Alloc(size_t size, void* addr = nullptr);
    void Dealloc();
    void* Ptr() const {
        return Ptr_;
    }
    char* Data(ui32 pos = 0) const {
        return (char*)(Ptr_ ? ((char*)Ptr_ + pos) : nullptr);
    }
    char* Begin() const noexcept {
        return (char*)Ptr();
    }
    char* End() const noexcept {
        return Begin() + MappedSize();
    }
    size_t MappedSize() const {
        return Size_;
    }
    void swap(TMappedAllocation& with) noexcept;

private:
    void* Ptr_ = nullptr;
    size_t Size_ = 0;
    bool Shared_ = false;
#ifdef _win_
    void* Mapping_ = nullptr;
#endif
};

template <class T>
class TMappedArray: private TMappedAllocation {
public:
    TMappedArray(size_t siz = 0)
        : TMappedAllocation(0)
    {
        if (siz)
            Create(siz);
    }
    ~TMappedArray() {
        Destroy();
    }
    T* Create(size_t siz) {
        Y_ASSERT(MappedSize() == 0 && Ptr() == nullptr);
        T* arr = (T*)Alloc((sizeof(T) * siz));
        if (!arr)
            return nullptr;
        Y_ASSERT(MappedSize() == sizeof(T) * siz);
        for (size_t n = 0; n < siz; n++)
            new (&arr[n]) T();
        return arr;
    }
    void Destroy() {
        T* arr = (T*)Ptr();
        if (arr) {
            for (size_t n = 0; n < size(); n++)
                arr[n].~T();
            Dealloc();
        }
    }
    T& operator[](size_t pos) {
        Y_ASSERT(pos < size());
        return ((T*)Ptr())[pos];
    }
    const T& operator[](size_t pos) const {
        Y_ASSERT(pos < size());
        return ((T*)Ptr())[pos];
    }
    T* begin() {
        return (T*)Ptr();
    }
    T* end() {
        return (T*)((char*)Ptr() + MappedSize());
    }
    size_t size() const {
        return MappedSize() / sizeof(T);
    }
    void swap(TMappedArray<T>& with) {
        TMappedAllocation::swap(with);
    }
};