Wiki source code of The Attachment Store
Last modified by Eleni Cojocariu on 2026/09/18 15:29
Hide last authors
| author | version | line-number | content |
|---|---|---|---|
![]() |
2.1 | 1 | Whatever store holds the content of an attachment, its metadata stays in the database: a row of ##xwikiattachment## while the attachment is there, a row of ##xwikiattrecyclebin## once it is deleted. That row also records the store holding **that** attachment's content, so two attachments of the same Page can sit in different stores. The store configured on a wiki is therefore the one the next attachment saved will use, not the one every attachment uses, and changing it leaves the files already stored exactly where they are. |
| 2 | |||
| 3 | {{version since="17.10.0RC1"}}The file-based stores no longer write to the filesystem themselves. They write through a blob store, whose type decides where the files finally land; [[Blob Store>>doc:documentation.xs.admin.store.blob.WebHome]] documents it and the S3 alternative.{{/version}} | ||
| 4 | |||
| 5 | |=|=Filesystem store|=Database store | ||
| 6 | |Default for a new wiki|Since XWiki 10.5|Until XWiki 10.5 | ||
| 7 | |Where the content is|Files under the [[permanent directory>>doc:documentation.xs.admin.configuration.directories.permanent-directory.WebHome]]|Three tables of the wiki database | ||
| 8 | |Largest attachment|Over a gigabyte|About 30 MB | ||
| 9 | |To back up|The database and the directory, in step|The database alone | ||
| 10 | |||
| 11 | == The filesystem attachment store == | ||
| 12 | |||
| 13 | The filesystem store keeps the content of each attachment as a file, and [[Optional Store Features>>doc:documentation.xs.admin.store.optional-features.WebHome]] is where that choice and the other store hints are made. Keeping the content out of the database has three consequences: | ||
| 14 | |||
| 15 | * a dump of the database is no longer a complete copy of the wiki: the files have to be saved with it, and restoring one without the other leaves attachments that are listed but cannot be downloaded, or files no Page points at; | ||
| 16 | * an attachment may be larger than a gigabyte, which the database store cannot hold; | ||
| 17 | * saving one is a two-stage commit, so the file on disk and the row in the database stay consistent even when the database fails to commit the attachment metadata. | ||
| 18 | |||
| 19 | [[Sub-Directories in the Permanent Directory>>doc:documentation.xs.admin.configuration.directories.permanent-directory.sub-directories.WebHome]] says which sub-directory holds them, and how to move that one sub-directory elsewhere. | ||
| 20 | |||
| 21 | Every node of a cluster needs to see the same storage directory, mounted over NFS or by any other means of giving each node the same disk. Give each node a directory of its own and an attachment ends up readable only on the node that happened to receive it. | ||
| 22 | |||
| 23 | XWiki removes empty directories as it deletes files, and ##store.fsattach.cleanOnStartup## in ##xwiki.properties##, ##true## by default, sweeps the whole tree again at startup as a safeguard for the rare cases where that fails. Set it to ##false## if the sweep costs too much on a large store. | ||
| 24 | |||
| 25 | === The format on disk === | ||
| 26 | |||
| 27 | The tree follows the entities it stores, a wiki holding Pages holding attachments, except that each name is replaced by its MD5 hash, split into a one-character directory, a second one, and the thirty characters left: | ||
| 28 | |||
| 29 | {{code language="none"}} | ||
| 30 | <wiki>/<hash of the Page reference>/attachments/<hash of the attachment name>/<file> | ||
| 31 | {{/code}} | ||
| 32 | |||
| 33 | Hashing keeps the paths short and free of the characters that filesystems restrictive about encoding or path length handle badly. A Page carrying one attachment, ##team-photo.jpg##, saved once, is stored like this: | ||
| 34 | |||
| 35 | {{code language="none"}} | ||
| 36 | xwiki/0/e/8da809e5683e667d5b771cf3b3a508/ the Page | ||
| 37 | attachments/ | ||
| 38 | e/d/9f721f27c98900522d4353e958307b/ the attachment | ||
| 39 | fv1.1.jpg the content of version 1.1 | ||
| 40 | f.jpg.lnk the current content, a link to fv1.1.jpg | ||
| 41 | ~METADATA.xml the list of stored versions | ||
| 42 | {{/code}} | ||
| 43 | |||
| 44 | A stored version is named ##fv##, then the version number, then the extension of the attachment. The current content is the same name without the version number, ##f.jpg## here, and when it would be identical to a stored version, which is the usual case, XWiki writes a one-line link file pointing at that version rather than a second copy of the file. Deleted attachments are kept beside the live ones, in a ##deleted-attachments## directory of the same Page; [[Deleted Attachments and the Recycle Bin>>doc:documentation.xs.admin.attachments.deleted-attachments.WebHome]] covers what becomes of them. | ||
| 45 | |||
| 46 | == The database attachment store == | ||
| 47 | |||
| 48 | This was the default until the filesystem store took over, so a wiki upgraded from an older version may still be on it without anyone having chosen it. It keeps the content in three tables beside the metadata: ##xwikiattachment_content## for the current content of each attachment, ##xwikiattachment_archive## for its older versions, and ##xwikiattrecyclebin## for what the attachment recycle bin holds. | ||
| 49 | |||
| 50 | What it costs is size. An attachment is read and written with its content and its whole archive held in memory, so as a rule of thumb one larger than 30 MB is not possible, which is what makes the filesystem store the better default. | ||
| 51 | |||
| 52 | [[Switch to the Database Attachment Store>>doc:documentation.xs.admin.store.attachment-store.switch-database-store.WebHome]] is the procedure. |
