public void Dispose()
        {
            if (m_Disposed)
            {
                return;
            }

            if (m_DelayedSync)
            {
                Sync();
            }

            m_StringTable.UnregisterStringTableChangedHandler(HandleStringTableChanged);
            m_Fs?.Dispose();
            m_StringTable = null;
        }
        public PropertyDatabase(string filePath, bool autoBackgroundUpdate, double backgroundUpdateDebounceInSeconds = k_DefaultBackgroundUpdateDebounceInSeconds)
        {
            this.filePath        = filePath;
            stringTableFilePath  = GetStringTablePath(filePath);
            m_LocalVolatileStore = new PropertyDatabaseVolatileMemoryStore();
            m_LocalStore         = new PropertyDatabaseMemoryStore();
            m_FileStore          = new PropertyDatabaseFileStore(filePath);
            m_StringTable        = new PropertyStringTable(stringTableFilePath, 30);

            // Do not allow automatic background updates while running tests. The writing of the file
            // causes an assembly leak during the test Unity.IntegrationTests.Scripting.AssemblyReloadTest.AssemblyReloadDoesntLeakAssemblies
            // on MacOs. I haven't found out why exactly does the writing of a file causes an assembly to be held, so instead I deactivate
            // the automatic update during tests.
            this.autoBackgroundUpdate = autoBackgroundUpdate && !Utils.IsRunningTests();

            m_Debounce = Delayer.Debounce(_ => TriggerPropertyDatabaseBackgroundUpdate(), backgroundUpdateDebounceInSeconds);
        }
        static void GetStringTableInfo(PropertyStringTable st, StringBuilder sb)
        {
            var longestStringsCount = 5;

            using (var view = st.GetView())
            {
                sb.AppendLine($"\tString Table: {st.filePath}");
                sb.AppendLine($"\t\tVersion: {view.version}");
                sb.AppendLine($"\t\tCount: {view.count}");
                sb.AppendLine($"\t\tSymbols slots: {view.symbolSlots}");
                sb.AppendLine($"\t\tAllocated bytes for strings: {Utils.FormatBytes(view.allocatedStringBytes)}");
                sb.AppendLine($"\t\tUsed bytes for strings: {Utils.FormatBytes(view.usedStringBytes)}");
                sb.AppendLine($"\t\tAverage byte size for strings: {Utils.FormatBytes(view.GetAverageBytesPerString())}");
                sb.AppendLine($"\t\tFile size: {Utils.FormatBytes(view.fileSize)}");
                sb.AppendLine($"\t\tTop {longestStringsCount} longest strings:");

                var strings = view.GetAllStrings();
                foreach (var str in strings.OrderByDescending(s => s.Length).Take(longestStringsCount))
                {
                    sb.AppendLine($"\t\t\t{str}");
                }
            }
        }
        public PropertyStringTableView(PropertyStringTable stringTable, bool delayedSync)
        {
            m_StringTable = stringTable;
            m_Disposed    = false;
            m_DelayedSync = delayedSync;

            using (LockRead())
            {
                m_Fs = File.Open(stringTable.filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete);
                m_Br = new BinaryReader(m_Fs, PropertyStringTable.encoding, true);
                m_Bw = new BinaryWriter(m_Fs, PropertyStringTable.encoding, true);
            }
            stringTable.RegisterStringTableChangedHandler(HandleStringTableChanged);

            m_Header = ReadHeader();
            using (LockUpgradeableRead())
            {
                if (m_Header.version != PropertyStringTable.Version)
                {
                    Clear();
                }
            }
        }
        public void Clear()
        {
            using (LockWrite())
            {
                m_Header.version     = PropertyStringTable.Version;
                m_Header.count       = 0;
                m_Header.symbolSlots = Math.Max(PropertyStringTable.DefaultStringCount * PropertyStringTable.HashFactor, 1);

                var bytesPerString = PropertyStringTable.GetStringByteSize(PropertyStringTable.DefaultAverageStringSize);
                m_Header.allocatedStringBytes = PropertyStringTable.DefaultStringCount * bytesPerString;
                m_Header.usedStringBytes      = PropertyStringTable.StringLengthByteSize;

                var newFileSize = PropertyStringTableHeader.size + PropertyStringTable.GetSymbolsByteSize(m_Header.symbolSlots) + m_Header.allocatedStringBytes;
                m_Fs.Seek(0, SeekOrigin.Begin);
                for (var i = 0; i < newFileSize; ++i)
                {
                    m_Fs.WriteByte(0);
                }
                m_Fs.Seek(0, SeekOrigin.Begin);
                WriteHeader(false);
                m_Fs.SetLength(newFileSize);
                Sync();
            }
        }
        public PropertyStringTableView(PropertyStringTable stringTable, bool delayedSync)
        {
            m_StringTable  = stringTable;
            m_Disposed     = false;
            m_DelayedSync  = delayedSync;
            m_SymbolBuffer = new byte[PropertyStringTable.SymbolByteSize];
            m_StringBuffer = new byte[PropertyStringTable.DefaultAverageStringSize * sizeof(char)];
            m_HeaderBuffer = new byte[Marshal.SizeOf <PropertyStringTableHeader>()];

            using (LockRead())
            {
                m_Fs = File.Open(stringTable.filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite | FileShare.Delete);
            }
            stringTable.RegisterStringTableChangedHandler(HandleStringTableChanged);

            m_Header = ReadHeader();
            using (LockUpgradeableRead())
            {
                if (m_Header.version != PropertyStringTable.Version)
                {
                    Clear();
                }
            }
        }
 public PropertyDatabaseView(PropertyDatabase propertyDatabase, PropertyDatabaseVolatileMemoryStore volatileMemoryStore, PropertyDatabaseMemoryStore memoryStore, PropertyDatabaseFileStore fileStore, PropertyStringTable stringTable, bool delayedSync)
 {
     m_PropertyDatabase        = propertyDatabase;
     m_MemoryStore             = memoryStore;
     m_FileStore               = fileStore;
     m_VolatileMemoryStoreView = (PropertyDatabaseVolatileMemoryStoreView)volatileMemoryStore.GetView();
     m_MemoryStoreView         = (PropertyDatabaseMemoryStoreView)memoryStore.GetView();
     m_FileStoreView           = (PropertyDatabaseFileStoreView)fileStore.GetView();
     m_StringTableView         = stringTable.GetView(delayedSync);
     m_Disposed    = false;
     m_DelayedSync = delayedSync;
 }