<commit_before>﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Buffers;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace Microsoft.Diagnostics.Runtime.Windows
{
    internal sealed class Minidump : IDisposable
    {
        private readonly string _crashDump;

        private readonly MinidumpDirectory[] _directories;

        private readonly Task<ImmutableArray<MinidumpContextData>> _threadTask;
        private readonly MemoryMappedFile? _file;
        private ImmutableArray<MinidumpContextData> _contextsCached;

        public MinidumpMemoryReader MemoryReader { get; }

        public ImmutableArray<MinidumpContextData> ContextData
        {
            get
            {
                if (!_contextsCached.IsDefault)
                    return _contextsCached;

                _contextsCached = _threadTask.Result;
                return _contextsCached;
            }
        }

        public ImmutableArray<MinidumpModule> Modules { get; }

        public MinidumpProcessorArchitecture Architecture { get; }

        public int PointerSize
        {
            get
            {
                switch (Architecture)
                {
                    case MinidumpProcessorArchitecture.Arm64:
                    case MinidumpProcessorArchitecture.Amd64:
                        return 8;

                    case MinidumpProcessorArchitecture.Intel:
                    case MinidumpProcessorArchitecture.Arm:
                        return 4;

                    default:
                        throw new NotImplementedException($"Not implemented for architecture {Architecture}.");
                }
            }
        }

        public Minidump(string crashDump, FileStream stream, CacheOptions cacheOptions)
        {
            if (!File.Exists(crashDump))
                throw new FileNotFoundException(crashDump);

            _crashDump = crashDump;

            // Load header
            MinidumpHeader header = Read<MinidumpHeader>(stream);
            if (!header.IsValid)
                throw new InvalidDataException($"File '{crashDump}' is not a Minidump.");

            _directories = new MinidumpDirectory[header.NumberOfStreams];

            stream.Position = header.StreamDirectoryRva;
            if (!Read(stream, _directories))
                throw new InvalidDataException($"Unable to read directories from minidump '{crashDump} offset 0x{header.StreamDirectoryRva:x}");

            (int systemInfoIndex, int moduleListIndex) = FindImportantStreams(crashDump);

            // Architecture is the first entry in MINIDUMP_SYSTEM_INFO.  We need nothing else out of that struct,
            // so we only read the first entry.
            // https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_system_info
            Architecture = Read<MinidumpProcessorArchitecture>(stream, _directories[systemInfoIndex].Rva);

            // Initialize modules.  DataTarget will need a module list immediately, so there's no reason to delay
            // filling in the module list.
            long rva = _directories[moduleListIndex].Rva;
            uint count = Read<uint>(stream, rva);

            rva += sizeof(uint);
            MinidumpModule[] modules = new MinidumpModule[count];

            if (Read(stream, rva, modules))
                Modules = modules.AsImmutableArray();
            else
                Modules = ImmutableArray<MinidumpModule>.Empty;

            // Read segments async.
            //_nativeMemory = new CachedMemoryReader(pointerSize, dumpPath, cacheSize, CacheTechnology.ArrayPool, _segments.ToImmutableArray());
            ImmutableArray<MinidumpSegment> segments = GetSegments(stream);

            int cacheSize = cacheOptions.MaxDumpCacheSize > int.MaxValue ? int.MaxValue : (int)cacheOptions.MaxDumpCacheSize;

            if (cacheSize <= CachedMemoryReader.MinimumCacheSize || new FileInfo(crashDump).Length <= cacheSize)
            {
                _file = MemoryMappedFile.CreateFromFile(stream, null, 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false);
                MemoryMappedViewStream mmStream = _file.CreateViewStream(0, 0, MemoryMappedFileAccess.Read);
                MemoryReader = new UncachedMemoryReader(segments, mmStream, PointerSize);
            }
            else
            {
                CacheTechnology technology = cacheOptions.UseOSMemoryFeatures ? CacheTechnology.AWE : CacheTechnology.ArrayPool;
                MemoryReader = new CachedMemoryReader(segments, crashDump, stream, cacheSize, technology, PointerSize);
            }

            _threadTask = ReadThreadData(stream);
        }

        public void Dispose()<commit_msg>Fix exception when we specify a very small cache size (#729)<commit_after>﻿// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Buffers;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;

namespace Microsoft.Diagnostics.Runtime.Windows
{
    internal sealed class Minidump : IDisposable
    {
        private readonly string _crashDump;

        private readonly MinidumpDirectory[] _directories;

        private readonly Task<ImmutableArray<MinidumpContextData>> _threadTask;
        private readonly MemoryMappedFile? _file;
        private ImmutableArray<MinidumpContextData> _contextsCached;

        public MinidumpMemoryReader MemoryReader { get; }

        public ImmutableArray<MinidumpContextData> ContextData
        {
            get
            {
                if (!_contextsCached.IsDefault)
                    return _contextsCached;

                _contextsCached = _threadTask.Result;
                return _contextsCached;
            }
        }

        public ImmutableArray<MinidumpModule> Modules { get; }

        public MinidumpProcessorArchitecture Architecture { get; }

        public int PointerSize
        {
            get
            {
                switch (Architecture)
                {
                    case MinidumpProcessorArchitecture.Arm64:
                    case MinidumpProcessorArchitecture.Amd64:
                        return 8;

                    case MinidumpProcessorArchitecture.Intel:
                    case MinidumpProcessorArchitecture.Arm:
                        return 4;

                    default:
                        throw new NotImplementedException($"Not implemented for architecture {Architecture}.");
                }
            }
        }

        public Minidump(string crashDump, FileStream stream, CacheOptions cacheOptions)
        {
            if (!File.Exists(crashDump))
                throw new FileNotFoundException(crashDump);

            _crashDump = crashDump;

            // Load header
            MinidumpHeader header = Read<MinidumpHeader>(stream);
            if (!header.IsValid)
                throw new InvalidDataException($"File '{crashDump}' is not a Minidump.");

            _directories = new MinidumpDirectory[header.NumberOfStreams];

            stream.Position = header.StreamDirectoryRva;
            if (!Read(stream, _directories))
                throw new InvalidDataException($"Unable to read directories from minidump '{crashDump} offset 0x{header.StreamDirectoryRva:x}");

            (int systemInfoIndex, int moduleListIndex) = FindImportantStreams(crashDump);

            // Architecture is the first entry in MINIDUMP_SYSTEM_INFO.  We need nothing else out of that struct,
            // so we only read the first entry.
            // https://docs.microsoft.com/en-us/windows/win32/api/minidumpapiset/ns-minidumpapiset-minidump_system_info
            Architecture = Read<MinidumpProcessorArchitecture>(stream, _directories[systemInfoIndex].Rva);

            // Initialize modules.  DataTarget will need a module list immediately, so there's no reason to delay
            // filling in the module list.
            long rva = _directories[moduleListIndex].Rva;
            uint count = Read<uint>(stream, rva);

            rva += sizeof(uint);
            MinidumpModule[] modules = new MinidumpModule[count];

            if (Read(stream, rva, modules))
                Modules = modules.AsImmutableArray();
            else
                Modules = ImmutableArray<MinidumpModule>.Empty;

            // Read segments async.
            //_nativeMemory = new CachedMemoryReader(pointerSize, dumpPath, cacheSize, CacheTechnology.ArrayPool, _segments.ToImmutableArray());
            ImmutableArray<MinidumpSegment> segments = GetSegments(stream);

            int cacheSize = cacheOptions.MaxDumpCacheSize > int.MaxValue ? int.MaxValue : (int)cacheOptions.MaxDumpCacheSize;

            bool isTinyDump = new FileInfo(crashDump).Length <= cacheSize;
            if (isTinyDump)
            {
                _file = MemoryMappedFile.CreateFromFile(stream, null, 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false);
                MemoryMappedViewStream mmStream = _file.CreateViewStream(0, 0, MemoryMappedFileAccess.Read);
                MemoryReader = new UncachedMemoryReader(segments, mmStream, PointerSize);
            }
            else if (cacheSize < CachedMemoryReader.MinimumCacheSize)
            {
                // this will be very slow
                MemoryReader = new UncachedMemoryReader(segments, stream, PointerSize);
            }
            else
            {
                CacheTechnology technology = cacheOptions.UseOSMemoryFeatures ? CacheTechnology.AWE : CacheTechnology.ArrayPool;
                MemoryReader = new CachedMemoryReader(segments, crashDump, stream, cacheSize, technology, PointerSize);
            }

            _threadTask = ReadThreadData(stream);
        }

        public void Dispose()
{'fraction_non_alphanumeric': 0.07140833097194672, 'fraction_numerical': 0.0025502975347123833, 'mean_word_length': 2.271940667490729, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 25, 'https://': 2, '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': '3136698', 'n_tokens_mistral': 2747, 'n_tokens_neox': 2592, 'n_words': 654}