Example #1
0
        /// <inheritdoc />
        public int Optimize()
        {
            return(_storageOperationLocker.GlobalLock(() =>
            {
                _logger.Information("Start optimization process");

                var dataItemsMoved = 0;
                var initialDataSize = _filesystemDescriptorAccessor.Value.FilesDataLength;

                // 1. Get all descriptors
                var descriptors = _entryDescriptorRepository.ReadAll();

                _logger.Information($"There is {descriptors.Count} descriptors found");

                // 2. Sort by offset, filter zero-sized data because it is not necessary to move empty data
                var orderedDescriptors = descriptors
                                         .Where(descriptor => descriptor.Value.DataLength > 0)
                                         .OrderBy(descriptor => descriptor.Value.DataOffset)
                                         .ToArray();

                // 3a. Move first
                if (orderedDescriptors.Length > 0 && orderedDescriptors[0].Value.DataOffset != 0)
                {
                    ProcessGap(orderedDescriptors, 0, 0);
                    dataItemsMoved++;
                }

                // 3b. Iterate over all descriptors to find gaps
                for (var i = 0; i < orderedDescriptors.Length - 1; i++)
                {
                    var current = orderedDescriptors[i];
                    var next = orderedDescriptors[i + 1];
                    var currentEnd = current.Value.DataOffset + current.Value.DataLength;
                    var nextStart = next.Value.DataOffset;

                    // 4. Found a gap, write data of second right after first
                    if (nextStart - currentEnd > 0)
                    {
                        ProcessGap(orderedDescriptors, i + 1, currentEnd);
                        dataItemsMoved++;
                    }
                }

                // 4. Update new size of file data in descriptor.
                var allEntriesDataLength = orderedDescriptors.Select(descriptor => descriptor.Value.DataLength).Sum();

                _filesystemDescriptorAccessor.Update(filesDataLengthUpdater: _ => allEntriesDataLength);

                var bytesOptimized = initialDataSize - allEntriesDataLength;

                _logger.Information(
                    $"Optimization process completed, {dataItemsMoved} items moved, {bytesOptimized} bytes optimized");

                return bytesOptimized;
            }));
        }
Example #2
0
        private bool TryFindGap(int size, out Cursor cursor)
        {
            _logger.Information($"Trying to find existing gap of {size} bytes");

            cursor = default;

            // 1. Get all descriptors
            var descriptors = _entryDescriptorRepository.ReadAll();

            // 2. Sort by offset
            var orderedDescriptors = descriptors
                                     .Where(descriptor => descriptor.Value.DataLength > 0)
                                     .OrderBy(descriptor => descriptor.Value.DataOffset).ToArray();

            // 3. Check first gap
            if (orderedDescriptors.Length > 0 && orderedDescriptors[0].Value.DataOffset >= size)
            {
                // Start of storage is our gap
                cursor = new Cursor(0, SeekOrigin.Begin);

                _logger.Information($"Found gap of size {size} bytes at offset {cursor.Offset}");

                return(true);
            }

            // 4. Check other gaps
            // We should find minimal gap but bigger or equals in size
            var minimalGapSize   = int.MaxValue;
            var minimalGapCursor = default(Cursor);
            var found            = false;

            for (var i = 0; i < orderedDescriptors.Length - 1; i++)
            {
                var current    = orderedDescriptors[i];
                var next       = orderedDescriptors[i + 1];
                var currentEnd = current.Value.DataOffset + current.Value.DataLength;
                var nextStart  = next.Value.DataOffset;

                // If we have gap with specific size or between files
                var currentGapSize = nextStart - currentEnd;
                if (currentGapSize >= size && currentGapSize < minimalGapSize)
                {
                    minimalGapSize   = currentGapSize;
                    minimalGapCursor = new Cursor(currentEnd, SeekOrigin.Begin);

                    // We should know that we found at least one correct gap
                    found = true;
                }
            }

            if (found)
            {
                cursor = minimalGapCursor;

                _logger.Information($"Found gap of size {size} bytes at offset {cursor.Offset}");

                return(true);
            }

            _logger.Information($"Gap of size {size} bytes not found");

            return(false);
        }