Um arquivo .mad é uma definição, não um conjunto de dados. Tudo o que um relatório exibe é derivado,
regenerável e deliberadamente mantido fora do arquivo compactado. Três tipos de arquivo são gerados ao lado dele:
| Arquivo | Gravado por | O que armazena |
|---|---|---|
<hash>.maddb |
MADDataTableFast |
os dados de linhas do relatório |
<hash>.mdcache |
MADDataTable (:354) |
uma plist descrevendo as tabelas virtuais sobre esses dados |
<hash>{ih,lh}{w, h}.madac |
MADArrayCaching, alimentado por MADReportFormatter (:179, :183) |
conteúdo de página renderizado — um banco de dados SQLite, indexado pelo identificador de layout e pelo tamanho da página. ih é o cache de índice do relatório, lh é o cache de layout do relatório |
Os três ficam juntos em um diretório por documento, nomeado por dataTableIdHash.
MADocument.m:286-300 constrói a tabela a partir de um diretório fornecido por
MADURLFactory newURLCacheFilesDirectoryForFilename: (MADURLFactory.m:47-49), que
resolve para um local por usuário e por dispositivo fora do documento:
MADDataTableFast *datatable = [[MADDataTableFast alloc] initWithId:dataTableIdHash];
...
NSURL *cacheUrl = [self newUrlCacheForFilename:cacheName];
self.urlDataTableCache = cacheUrl;
[datatable loadFromCacheWithUrl:cacheUrl error:&error];
Valores medidos em um diretório real de cache em Library/Caches/:
| Tipo | Arquivos | Total |
|---|---|---|
<hash>.maddb |
1 | 816 KB |
<hash>.mdcache |
1 | 1,7 KB |
<hash>{ih,lh}{...}.madac |
6 | ~15 MB |
Os arquivos .madac são o cache de páginas do formatador. As chaves ih e lh vêm de
MADReportFormatter.m:179 e :183, que montam <layoutIdentifier>ih<CGSize> e
<layoutIdentifier>lh<CGSize>; {612, 792} equivale ao tamanho US Letter em pontos. Portanto, o cache é
indexado pela identidade do layout e pela geometria da página — o que torna reais as duas armadilhas
descritas na §5.3.
Comparado a um documento de menos de 80 KB, o cache de renderização tem aproximadamente 200× o tamanho do documento. Os dados de linhas, que poderiam parecer o maior volume, representam menos de 6% do diretório.
Por que ele é deliberadamente desse tamanho. O tamanho é consequência do projeto arquitetural, não um acidente a ser otimizado. Há duas razões, ambas descritas pelo próprio autor (2026-10-01):
O cache poderia ser comprimido, mas essa não é uma mudança prioritária no momento.
.mad é pequeno e autocontido: é uma definição, não um conjunto de dados. Ambos
os exemplos distribuídos têm menos de 80 KB.refresh),
nunca a perda de um documento..mad não é um “arquivo SQLite comprimido com os dados dentro”, como poderia
parecer à primeira vista. É um arquivo SQLite comprimido com a definição dentro.O diretório é nomeado e populado pelo código, mas não possui especificação formal. Há três lacunas que uma segunda plataforma teria de adivinhar:
O cache de renderização é indexado pelo nome do arquivo, não pelo conteúdo — confirmado em 2026-10-01.
MADReportFormatter -layoutIdentifier (MADReportFormatter.m:186) retorna
_overrideIdentifier ? _overrideIdentifier.hash : _filename.hash. Assim, a chave é o
nome do documento mais o tamanho da página, e nada no caminho de carregamento verifica o conteúdo:
MADArrayCaching -initializeDatabase (MADArrayCaching.m:141) reutiliza o arquivo SQLite
existente sempre que sua tabela ac está presente, sem versão, timestamp ou hash de conteúdo
em lugar algum da chave ou do carregamento. Editar um documento mantendo o mesmo nome de arquivo
não invalida seus arquivos .madac — uma página defasada continua sendo exibida até que os arquivos sejam
apagados ou que um tamanho de página diferente seja renderizado.
Medido em 2026-10-01, consistente com esse comportamento. Uma atualização e exportação headless foram executadas contra o documento London às 15:22. No diretório de cache logo após:
| Arquivo | Tamanho | mtime |
|---|---|---|
<hash>.maddb |
835.584 | 15:22 |
<hash>.mdcache |
1.644 | 15:22 |
<layoutId>ih{612, 792}.madac |
81.920 | 15:22 |
<layoutId>lh{612, 792}.madac |
737.280 | 15:22 |
<layoutId>ih{0, 0}.madac |
1.867.776 | 10:52 |
<layoutId>lh{0, 0}.madac |
4.333.568 | 10:52 |
Uma atualização regrava apenas os arquivos de que precisa — as entradas {612, 792} (US Letter, a
geometria de página do PDF) — e deixa o restante intacto. As entradas {0, 0} não foram tocadas e,
juntas, somam 6,0 MB dos 15 MB do diretório. {0, 0} é o tamanho de página antes de uma
geometria real ser conhecida, portanto esses dois arquivos são quase certamente resultado de uma passagem de medição;
sob o esquema indexado por nome de arquivo, eles também nunca são invalidados por nada além da
exclusão manual.
.maddb de 0 bytes em um diretório de resto intocado mostra que o
diretório é criado antes de ser preenchido, e nada especifica se tal
diretório vazio tem algum significado..mdcache. Agora conhecido — trata-se do esquema serializado da tabela de
resultados, gravado por MADDataTableFast -copyPlist e lido por -loadWithPlist:. Chaves de nível
superior: name, columnKeys (array ordenado de IDs c<hash>), columns (um dicionário indexado por
c<hash>, sendo cada item uma plist MADDataColumn: caption, fieldName, identifier, type,
nativeType, dataLength, dataPercision, isPrimaryKey, isNotNull,
isAutoIncrement, defaultValue), rowCounter, sortDescriptors e o valor
bulkInsertLoop da tabela rápida. defaultValue usa a sentinela ~MTNull~
(MADDataColumnNullSentinel, MADDataColumn.m:23). Observe duas peculiaridades persistentes:
dataPercision está grafado incorretamente no formato, e a sentinela ~MTNull~ é um terceiro marcador de nulo,
distinto da família "<null>" / "(null)" documentada em docs/project/BUGS.md Track 1.5.Esta página é uma tradução para o português do Brasil do original em inglês; em caso de divergência, prevalece a versão original em inglês.