Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
a1cb6f6
fix (UI): Fix display of path in grid (incorrectly concatenating part…
jafin Jun 6, 2026
f02f1cb
build: Migrate build automation from Nuke to Fallout
jafin Jun 6, 2026
a10a84d
perf(catalog): add memory + search measurement harness and baseline (…
jafin Jun 6, 2026
8a9067c
perf(catalog): 7-49x faster find + 8 bytes/entry (Phase 1, non-breaking)
jafin Jun 6, 2026
15a3068
perf(find): allocation-free path search via single-pass path build (P…
jafin Jun 6, 2026
58481c8
perf(catalog): lean files via ExtraData side-object (Phase 3, no form…
jafin Jun 6, 2026
b6545c4
docs(perf): investigate entry-name memory (names are ~35% of footprint)
jafin Jun 6, 2026
8efea3c
fix(find): make Cancel Search responsive again
jafin Jun 6, 2026
ef4a733
perf(find): stream search progress on a 100ms timer (sync path respon…
jafin Jun 6, 2026
9a6449c
fix(cdeWin): make search result collection thread-safe across catalogs
jafin Jun 6, 2026
e2c4bc0
perf(spike): prototype + measure struct-of-arrays EntryStore
jafin Jun 6, 2026
079149e
perf(soa): production EntryStore + index search + equivalence tests (…
jafin Jun 6, 2026
7569736
refactor(soa): abstract ICommonEntry.Children to IReadOnlyList<ICommo…
jafin Jun 6, 2026
a4488b1
perf(soa): EntryRef adapter - run ICommonEntry consumers on SoA (migr…
jafin Jun 6, 2026
b2c3375
perf(soa): wire CLI find onto EntryStore + reuse interned names (migr…
jafin Jun 6, 2026
d00a01a
perf(soa): EntryStore carries catalog metadata (GUI wiring foundation)
jafin Jun 6, 2026
cf8ccb7
perf(soa): filter-capable EntryStoreSearch for GUI parity (cdeWin wir…
jafin Jun 6, 2026
5d6e60f
perf(soa): wire cdeWin (GUI) to hold catalogs as EntryStores (migrati…
jafin Jun 6, 2026
a4c2e41
spike(mmap): zero-copy columnar catalog format + one-way migration
jafin Jun 6, 2026
183fadc
feat(columnar): promote zero-copy mmap catalog format to cdeLib + cde…
jafin Jun 6, 2026
52c347d
feat(find): search .cdex catalogs zero-copy over mmap (promotion stag…
jafin Jun 6, 2026
164349c
refactor(soa): unify EntryStore + mmap reader behind IEntrySource (st…
jafin Jun 6, 2026
017a29e
feat(cdeWin): hold catalogs as mmap .cdex readers, preferring zero-co…
jafin Jun 6, 2026
4c5724f
feat(hash,dupes): operate on columnar .cdex catalogs
jafin Jun 6, 2026
6c2c12f
feat(scan): write columnar .cdex directly; fix hash-reuse on rescan
jafin Jun 6, 2026
2d4631e
feat(hash): live on-screen progress for hash command
jafin Jun 7, 2026
2431eaa
docs: add cde migrate, fix .NET version and Nuke->Fallout
jafin Jun 7, 2026
8f90904
docs: correct CLAUDE.md serialization and messaging libs
jafin Jun 7, 2026
4ba5a3e
feat(scan): add --follow-junctions option (default off)
jafin Jun 8, 2026
8d89363
docs(claude): add shell here-string rule to prevent tooling mistakes
jafin Jun 8, 2026
d01e07c
refactor(di): simplify AppContainerBuilder registration
jafin Jun 8, 2026
a0f3f18
tidy: Remove unused parameter
jafin Jun 8, 2026
73abbf9
refactor(cde): extract command logic into injected CdeApp
jafin Jun 8, 2026
5bbffc0
task: spelling
jafin Jun 8, 2026
95e4fd4
refactor(cde): make CLI path fully async, drop sync-over-async
jafin Jun 8, 2026
1480ec7
refactor: replace global Hack.BreakConsoleFlag with injectable Operat…
jafin Jun 8, 2026
389137c
build(cde): suppress MA0048 for MigrateOptions, drop stale UpgradeOpt…
jafin Jun 8, 2026
a0656b5
refactor(cde): split scan MainLoop to clear MA0051 (method too long)
jafin Jun 8, 2026
61a84f9
style: repo-wide IDE code cleanup
jafin Jun 8, 2026
546df4d
tidy: minor tidy. Mostly spelling, separate type per file.
jafin Jun 9, 2026
e4de8c5
Potential fix for pull request finding
jafin Jun 10, 2026
cd2d7f0
Potential fix for pull request finding
jafin Jun 10, 2026
aba79b2
fix: review fixes for search allocations, hash progress threading, an…
jafin Jun 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .nuke/build.schema.json → .fallout/build.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"Quiet"
]
},
"NukeBuild": {
"FalloutBuild": {
"properties": {
"Continue": {
"type": "boolean",
Expand Down Expand Up @@ -120,7 +120,7 @@
}
},
{
"$ref": "#/definitions/NukeBuild"
"$ref": "#/definitions/FalloutBuild"
}
]
}
File renamed without changes.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,6 @@ src/.vs/config/applicationhost.config
**/Properties/launchSettings.json
/.claude/settings.local.json
/src/.claude/settings.local.json

# BenchmarkDotNet writes results here when running cdeBenchmarks
**/BenchmarkDotNet.Artifacts/
36 changes: 35 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ This application reads and writes a configuration file `cdeWinView.cfg`.
- size of all the columns in list views
- values of fields in the search parameters

The executable `cdeWin.exe` can be copied around by it self to be used anywhere that .Net7 is available with the behavior of the cdeWinView.cfg file as described just above.
The executable `cdeWin.exe` can be copied around by it self to be used anywhere that .NET 10 is available with the behavior of the cdeWinView.cfg file as described just above.

#### cdeWeb (unreleased)

Expand Down Expand Up @@ -109,13 +109,21 @@ cde path -find afilename
[`-maxDateTime`](#parameter-options)
[`-minTime`](#parameter-options)
[`-maxTime`](#parameter-options)
[`--desc`](#parameter-options)
[`--follow-junctions`](#parameter-options)

This is the mode of operation that creates and updates catalog files.

When it creates new catalog files it will detect an old catalog file for the given scan target and copy any Hash values from the old file to the new file for matching file paths, file dates and sizes.

Only Last Modified Time of file system entries is captured into .cde files.

By default cde records directory junctions and symbolic links (reparse points) in the catalog but does **not** descend into them, which avoids scan cycles (for example a junction pointing back at an ancestor directory) and duplicated content. Pass `--follow-junctions` to descend into them.

```
cde scan C:\ --follow-junctions
```

### cde find String

#### Valid Options for this mode
Expand Down Expand Up @@ -186,6 +194,30 @@ Consider using -minHourAge to limit Hash and Dupes work if your are cleanign up

Output the full tree of file entries in the catologs in text format.

### cde migrate \[Path\]

#### Valid Options for this mode

`No filter options supported.`

This mode performs a one-way conversion of the original MessagePack `.cde` catalogs into the newer zero-copy columnar `.cdex` format. The `.cdex` format is laid out so it can be memory-mapped and searched without first deserialising the whole catalog into objects, which lowers memory use and speeds up load on large catalogs.

- With a path argument, only that single `.cde` file is converted:

```batch
cde migrate C-V3Win7-C__users.cde
```

- With no argument, every catalog discovered in the current directory and one directory below is converted (the same discovery rule used when loading catalogs):

```batch
cde migrate
```

For each catalog a `.cdex` file is written beside the source `.cde`, keeping the same base name. The original `.cde` file is left in place and is not deleted, so the conversion is non-destructive. Re-running migrate simply overwrites the `.cdex` output.

For each file converted cde prints the source and destination file names, their byte sizes and the entry count, then a summary of how many catalogs were migrated. Files that cannot be loaded are skipped and reported.

### Parameter Options

| | Parameter&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | Description |
Expand All @@ -204,6 +236,8 @@ Output the full tree of file entries in the catologs in text format.
| | `-maxResults {Int}` | Maximum number of results returned by cde. |
| | `-exclude {Regex}` | A filter to exclude only entries that match these regexes for processing. |
| | `-include {Regex}` | A filter to include only entries that match these Regexes for processing. |
| | `--desc {Text}` | (scan) Description text to store in the catalog file. |
| | `--follow-junctions` | (scan) Descend into directory junctions and symbolic links (reparse points). Off by default; reparse points are recorded but not followed, avoiding scan cycles and duplicated content. |

##### Date Time Format for parameters

Expand Down
2 changes: 1 addition & 1 deletion build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
###########################################################################

$BuildProjectFile = "$PSScriptRoot\build\_build.csproj"
$TempDirectory = "$PSScriptRoot\\.nuke\temp"
$TempDirectory = "$PSScriptRoot\\.fallout\temp"

$DotNetGlobalFile = "$PSScriptRoot\\global.json"
$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
###########################################################################

BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj"
TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
TEMP_DIRECTORY="$SCRIPT_DIR//.fallout/temp"

DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
Expand Down
18 changes: 9 additions & 9 deletions build/Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
using JetBrains.Annotations;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Locator;
using Nuke.Common;
using Nuke.Common.CI;
using Nuke.Common.Git;
using Nuke.Common.IO;
using Nuke.Common.ProjectModel;
using Nuke.Common.Tools.DotNet;
using Nuke.Common.Utilities.Collections;
using static Nuke.Common.Tools.DotNet.DotNetTasks;
using Fallout.Common;
using Fallout.Common.CI;
using Fallout.Common.Git;
using Fallout.Common.IO;
using Fallout.Common.ProjectModel;
using Fallout.Common.Tools.DotNet;
using Fallout.Common.Utilities.Collections;
using static Fallout.Common.Tools.DotNet.DotNetTasks;
// ReSharper disable AllUnderscoreLocalParameterName

[ShutdownDotNetAfterServerBuild]
class Build : NukeBuild
class Build : FalloutBuild
{
public Build()
{
Expand Down
2 changes: 1 addition & 1 deletion build/Configuration.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using System.ComponentModel;
using Nuke.Common.Tooling;
using Fallout.Common.Tooling;

[TypeConverter(typeof(TypeConverter<Configuration>))]
public class Configuration : Enumeration
Expand Down
11 changes: 6 additions & 5 deletions build/_build.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@
<TargetFramework>net10.0</TargetFramework>
<RootNamespace></RootNamespace>
<NoWarn>CS0649;CS0169</NoWarn>
<NukeRootDirectory>..</NukeRootDirectory>
<NukeScriptDirectory>..</NukeScriptDirectory>
<NukeTelemetryVersion>1</NukeTelemetryVersion>
<FalloutRootDirectory>..</FalloutRootDirectory>
<FalloutScriptDirectory>..</FalloutScriptDirectory>
<FalloutTelemetryVersion>1</FalloutTelemetryVersion>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
<LangVersion>default</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2025.2.4" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.11.2" />
<PackageReference Include="NuGet.Frameworks" Version="7.3.0" ExcludeAssets="runtime" PrivateAssets="all">
<PackageReference Include="NuGet.Frameworks" Version="7.6.0" ExcludeAssets="runtime" PrivateAssets="all">
<IncludeAssets>compile; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Nuke.Common" Version="10.1.0" />
<PackageReference Include="Fallout.Common" Version="10.3.49" />
<PackageDownload Include="GitVersion.Tool" Version="[5.6.7]" />
</ItemGroup>

Expand Down
63 changes: 40 additions & 23 deletions claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ CDE is a high-performance file system cataloging utility written in C# that crea
- Target: .NET 10
- Cross-platform: win-x64, linux-x64, osx-x64
- Entry point for scan, find, hash, dupes, dump commands
- Dependencies: Autofac, MediatR, CommandLineParser, Spectre.Console
- Dependencies: Autofac, SlimMessageBus, CommandLineParser, Spectre.Console

- **cdeLib** - Core library containing business logic
- Target: .NET 10
- Contains all catalog operations, hashing, duplicate detection
- Uses CQRS pattern with MediatR
- Serialization: MessagePack, FlatSharp
- Key dependencies: Autofac, MediatR, Serilog
- Uses CQRS pattern with SlimMessageBus
- Serialization: columnar `.cdex` (zero-copy, memory-mapped), plus MessagePack/FlatSharp/protobuf-net for the legacy `.cde` tree format
- Key dependencies: Autofac, SlimMessageBus, Serilog

- **cdeWin** - Windows Forms GUI application
- Target: .NET 10 (Windows)
Expand Down Expand Up @@ -52,7 +52,7 @@ CDE is a high-performance file system cataloging utility written in C# that crea

### Architecture Patterns

- **CQRS (Command Query Responsibility Segregation)**: Commands and queries handled via MediatR
- **CQRS (Command Query Responsibility Segregation)**: Commands and queries handled via SlimMessageBus (`IRequestHandler`, `IMessageBus`)
- Commands: `CreateCacheCommand`, `HashCatalogCommand`, `FindDuplicatesCommand`, `UpdateCommand`
- Handlers: Separate handlers for each command
- Events: `ScanProgressEvent` for progress tracking
Expand All @@ -69,9 +69,12 @@ CDE is a high-performance file system cataloging utility written in C# that crea

### Serialization

Multiple serialization formats supported:
- **MessagePack** - Primary catalog file format (.cde files)
- **FlatSharp** - FlatBuffers support (alternative)
Two on-disk catalog formats:

- **Columnar `.cdex`** (`Entities/Columnar/ColumnarFormat.cs`) - **Current/primary format.** A struct-of-arrays layout designed for *zero-copy reads over a memory-mapped file*: "loading" a catalog is mmap-ing it, so no managed object graph is materialised and the working set is only the file pages a query touches (reclaimable OS page cache, not GC heap). Custom binary layout with a `"CDEX"` magic header and dense, homogeneous columns (names, sizes, timestamps, hashes, tree links) — a name-only search scans just the name columns and never pages in the rest. Written directly by `scan`; read via `ColumnarCatalogReader`.
- **Legacy `.cde` tree format** - The original materialised directory-tree format, serialized via a pluggable `SerializerProtocol` in `Catalog/CatalogRepository.cs`:
- **MessagePack** - default protocol for `.cde` (`MessagePackConfig.Options`, custom `Hash16Formatter`/resolver)
- **FlatSharp** (FlatBuffers) and **protobuf-net** - alternative protocols selectable via `SerializerProtocol`

### Hashing

Expand Down Expand Up @@ -126,15 +129,16 @@ Entry (base class)

### Build System

- **Nuke Build** - Build automation
- `build.cmd` / `build.ps1` / `build.sh` - Build scripts
- `build/Build.cs` - Build definition
- **Fallout Build** - Build automation (replaced Nuke)
- `build.cmd` / `build.ps1` / `build.sh` - Build scripts (bootstrap `build/_build.csproj`)
- `build/Build.cs` - Build definition (uses `Fallout.Common`)
- `.fallout/` - Fallout config, parameters, and temp/log output
- Command: `build.cmd publish` - Creates artifacts in `./artifacts`

### Key Command Handlers

Located in `cdeLib/`:
- `Catalog/CreateCacheCommandHandler.cs` - Scans file systems, creates .cde files
- `Catalog/CreateCacheCommandHandler.cs` - Scans file systems, writes columnar `.cdex` catalogs (reusing hashes from an existing `.cdex` when present)
- `Hashing/HashCatalogCommandHandler.cs` - Adds MD5 hashes to catalogs
- `Duplicates/FindDuplicateCommandHandler.cs` - Identifies duplicate files
- `FindService.cs` - File search functionality
Expand All @@ -148,16 +152,18 @@ Located in `cdeLib/Infrastructure/`:
- `WorkStealingTreeTraversal.cs` - Parallel directory traversal
- `Config/` - Configuration classes

## Catalog File Format (.cde)
## Catalog File Formats (.cdex / .cde)

- **Extension**: `.cde`
- **Extensions**: `.cdex` (current columnar format) and `.cde` (legacy tree format)
- **Naming**: Derived from drive letter, volume name, and path
- Example: `C-V3Win7-C__users.cde` for `C:\users\`
- Example: `UNC-toothless_c__users_.cde` for `\\unc\toothless\c$\users`
- **Loading**: All .cde files in current directory or one level down are loaded
- **Content**: Directory tree with optional MD5 hashes
- Example: `C-V3Win7-C__users.cdex` for `C:\users\`
- Example: `UNC-toothless_c__users_.cdex` for `\\unc\toothless\c$\users`
- **Loading**: All catalog files in the current directory or one level down are loaded (`GetColumnarFileList` for `.cdex`, `GetCacheFileList` for `.cde`)
- **Content**: Directory tree (or columns) with optional MD5 hashes
- **Size**: Highly efficient - 500MB for 11 billion entries
- **Format**: MessagePack binary serialization (not compressed)
- **Format**:
- `.cdex` - custom columnar binary, memory-mapped for zero-copy loads (not compressed)
- `.cde` - MessagePack binary serialization by default (not compressed); protobuf/FlatBuffers selectable in code

## Common Operations

Expand Down Expand Up @@ -228,7 +234,7 @@ This branch focuses on performance improvements and refactoring. Recent commits
- Use object pooling for frequently allocated objects
- Benchmark changes that affect hot paths

2. **Catalog Compatibility**: Changes to serialization affect .cde file format
2. **Catalog Compatibility**: Changes to serialization affect the `.cdex`/`.cde` file formats
- Hash size changes require catalog recreation
- Document breaking changes

Expand All @@ -240,9 +246,18 @@ This branch focuses on performance improvements and refactoring. Recent commits
- Unit tests in cdeLibTest
- Specification tests in cdeLibSpec/cdeLibSpec2

### Shell & Tooling

This is a Windows environment with both PowerShell and Bash available. The two shells have **incompatible** here-string / quoting syntax — never mix them.

- **PowerShell here-string** is `@'` ... `'@` (closing `'@` must be at column 0). Only valid in the PowerShell tool.
- **Bash here-doc** is `<<'EOF'` ... `EOF`. Only valid in the Bash tool.
- Passing `@'...'@` to the Bash tool does **not** create a here-string — Bash treats the `@` characters as literal text, which (for example) prepends a stray `@` to git commit messages.
- For multi-line text (commit messages, file content) prefer the matching syntax for the tool you're calling, or write the text to a file and pass it with `-F <file>`.

### Code Patterns

- **MediatR Commands**: Business operations are commands/queries
- **SlimMessageBus Commands**: Business operations are commands/queries (`IRequestHandler<T>.OnHandle`)
- **Dependency Injection**: Constructor injection via Autofac
- **Logging**: Serilog with structured logging
- **Configuration**: Microsoft.Extensions.Configuration with appsettings.json
Expand All @@ -268,8 +283,10 @@ Standard .NET test runners (tests use NUnit, xUnit)
## Dependencies to Note

- **Autofac** - Dependency injection
- **MediatR** - Command/query pattern
- **MessagePack** - Primary serialization
- **SlimMessageBus** - Command/query and pub/sub messaging (in-memory)
- **MessagePack** - Serialization for the legacy `.cde` tree format (current `.cdex` format uses a custom columnar layout)
- **FlatSharp** - FlatBuffers serialization (alternative `.cde` protocol)
- **protobuf-net** - Protobuf serialization (alternative `.cde` protocol)
- **Serilog** - Structured logging
- **CommandLineParser** - CLI argument parsing
- **Spectre.Console** - Rich console output
Expand Down
12 changes: 11 additions & 1 deletion developer.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@

## Building the app

The build uses Nuke to perform the steps.
The build uses Fallout to perform the steps. (It replaced Nuke.)

The build definition lives in `build/Build.cs` (built on `Fallout.Common`), and the
`build.cmd` / `build.ps1` / `build.sh` scripts bootstrap `build/_build.csproj`.
Fallout config, parameters and temp/log output are kept under `.fallout/`.

To build the app on windows run:

```shell
build.cmd publish
```

On Linux/macOS run:

```shell
./build.sh publish
```

Artifacts from the build will be built to `.\artifacts`

Loading
Loading