Wiki source code of Filesystem Store

Last modified by Vincent Massol on 2025/11/17 17:19

Show last authors
1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc start="2"/}}
3 {{/box}}
4
5 By default, in XWiki the content of attachments and deleted attachments and documents are stored in what we call the "filesystem store". Its default location is ##<permanentdir>/store/file##.
6
7 {{version since="17.10.0RC1"}}
8 Despite its name, this "filesystem" store uses whatever [[blob store is configured>>documentation.xs.admin.store.blob.WebHome]] and can thus store attachments and deleted attachments and documents also in other blob stores like S3. The naming of the blobs is independent of the configured blob store.
9 {{/version}}
10
11 It's a simple file based storage in which documents and attachments references are (md5) hashed, to avoid problems with various limited (in terms of encoding and path size) file systems/blob stores. The filesystem store implements a two stage commit mechanism to maintain integrity even if the database fails to commit the attachment meta-data for example.
12
13 For example the attachment ##XWikiLogo.png## in document ##Sandbox.WebHome## is stored in the following location: ##/1/0/5d42329a923e687f5dff4887d80098/attachments/9/2/0bc685fa0da28168319c0126def81b##.
14
15 {{box title="And where is my entity located ?"}}
16 {{velocity}}
17 {{html}}
18 <form>
19 <input type="text" name="reference"#if($request.reference) value="$escapetool.xml($request.reference)#end"/>
20 <button name="serialize_document">Document</button>
21 <button name="serialize_attachment">Attachment</button>
22 </form>
23 {{/html}}
24 {{/velocity}}
25
26 {{groovy}}
27 def hash(str)
28 {
29 md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(str)
30 println "1. It's then md5 hashed (##${md5}##)."
31
32 char0 = md5.charAt(0)
33 println "1. A first folder is created with the first character of the hash (##${char0}##)."
34
35 char1 = md5.charAt(1)
36 println "1. A second folder is created with the second character of the hash (##${char1}##)."
37
38 charn = md5.substring(2)
39 println "1. A third folder is created with the remaining characters (##${charn}##)."
40
41 return "**$char0**/**$char1**/**$charn**"
42 }
43
44 def encodeDocument(documentReference) {
45 path = ""
46 if (documentReference.root.type == org.xwiki.model.EntityType.WIKI) {
47 println "1. A folder with the wiki name (##${documentReference.root.name}##) is created."
48 path = documentReference.root.name
49 }
50
51 localuid = services.component.getInstance(org.xwiki.model.reference.EntityReferenceSerializer.TYPE_STRING, "local/uid").serialize(documentReference)
52 println "1. The document reference is serialized using the local uid serializer (##${localuid}##)."
53
54 path += "/" + hash(localuid)
55
56 return path;
57 }
58
59 def encodeAttachment(attachmentReference) {
60 path = ""
61 if (reference.parent) {
62 path = encodeDocument(attachmentReference.parent)
63 }
64
65 path += "/attachments"
66 println "1. An ##attachments## folder is created."
67
68 name = attachmentReference.name
69 println "1. The attachment name (##$name##) is extracted from the reference."
70
71 path += "/" + hash(name) + ""
72 }
73
74 if (request.serialize_document != null) {
75 reference = services.component.getInstance(org.xwiki.model.reference.EntityReferenceResolver.TYPE_STRING, "relative").resolve(request.reference, org.xwiki.model.EntityType.DOCUMENT)
76
77 println "{{info}}"
78 path = encodeDocument(reference)
79 println "{{/info}}"
80
81 println ""
82 print "The final path of the folder which contains the content of this attachment is ##$path##."
83 } else if (request.serialize_attachment != null) {
84 reference = services.component.getInstance(org.xwiki.model.reference.EntityReferenceResolver.TYPE_STRING, "relative").resolve(request.reference, org.xwiki.model.EntityType.ATTACHMENT)
85
86 println "{{info}}"
87 path = encodeAttachment(reference)
88 println "{{/info}}"
89
90 println ""
91 print "The final path of the folder which contains the content of this document is ##$path##."
92 }
93 {{/groovy}}
94 {{/box}}
95
96 == Attachments and deleted attachments ==
97
98 By default, inside the attachment folder, you will find both the current version of the attachment and its history. The file name is always ##f##, it's then optionally followed by the version (when it's a piece of the history) and the original file extension.
99
100 For example for an image of type png:
101
102 * ##f.png##
103 * ##fv1.1.png##
104 * ##fv2.1.png##
105
106 {{version since="16.4.0"}}
107 Most of the time, instead of the current version of the attachment, a "link" is created. It's a file which name is suffixed with ##.lnk## which contains the relative path it's representing. In standard condition, it always points to the latest version of the attachment.
108
109 For example for an image of type png:
110
111 * ##f.png.lnk## {{info}}contains the string ##fv2.1.png##{{/info}}
112 * ##fv1.1.png##
113 * ##fv2.1.png##
114 {{/version}}
115
116 The different between attachments and deleted attachment is the location of that folder inside the document folder:
117
118 * an attachment is located in ##/attachments/<hash/based/on the attachment name>/##
119 * a deleted is located in ##/deleted-attachments/<hash/based/on the attachment name>/<index of the deleted attachment>/##
120
121 == Deleted documents ==
122
123 {{todo/}}

Get Connected