2 * Copyright 2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Paweł Dziepak, pdziepak@quarnos.org
10 #include "DirectoryCache.h"
13 #include <NodeMonitor.h>
19 NameCacheEntry::NameCacheEntry(const char* name
, ino_t node
)
28 NameCacheEntry::NameCacheEntry(const NameCacheEntry
& entry
)
31 fName(strdup(entry
.fName
))
36 NameCacheEntry::~NameCacheEntry()
38 free(const_cast<char*>(fName
));
42 DirectoryCacheSnapshot::DirectoryCacheSnapshot()
44 mutex_init(&fLock
, NULL
);
48 DirectoryCacheSnapshot::DirectoryCacheSnapshot(
49 const DirectoryCacheSnapshot
& snapshot
)
51 mutex_init(&fLock
, NULL
);
53 MutexLocker
_(snapshot
.fLock
);
54 NameCacheEntry
* entry
= snapshot
.fEntries
.Head();
55 NameCacheEntry
* new_entry
;
57 new_entry
= new NameCacheEntry(*entry
);
58 if (new_entry
== NULL
)
61 fEntries
.Add(new_entry
);
63 entry
= snapshot
.fEntries
.GetNext(entry
);
68 DirectoryCacheSnapshot::~DirectoryCacheSnapshot()
70 while (!fEntries
.IsEmpty()) {
71 NameCacheEntry
* current
= fEntries
.RemoveHead();
75 mutex_destroy(&fLock
);
79 DirectoryCache::DirectoryCache(Inode
* inode
, bool attr
)
81 fExpirationTime(inode
->fFileSystem
->GetConfiguration().fDirectoryCacheTime
),
82 fDirectoryCache(NULL
),
87 ASSERT(inode
!= NULL
);
89 mutex_init(&fLock
, NULL
);
93 DirectoryCache::~DirectoryCache()
95 mutex_destroy(&fLock
);
100 DirectoryCache::Reset()
103 fExpireTime
= system_time() + fExpirationTime
;
109 DirectoryCache::Trash()
111 while (!fNameCache
.IsEmpty()) {
112 NameCacheEntry
* current
= fNameCache
.RemoveHead();
113 entry_cache_remove(fInode
->GetFileSystem()->DevId(), fInode
->ID(),
125 DirectoryCache::AddEntry(const char* name
, ino_t node
, bool created
)
127 ASSERT(name
!= NULL
);
129 NameCacheEntry
* entry
= new(std::nothrow
) NameCacheEntry(name
, node
);
132 if (entry
->fName
== NULL
) {
137 fNameCache
.Add(entry
);
139 if (created
&& fDirectoryCache
!= NULL
) {
140 MutexLocker
_(fDirectoryCache
->fLock
);
141 NameCacheEntry
* entry
= new(std::nothrow
) NameCacheEntry(name
, node
);
144 if (entry
->fName
== NULL
) {
149 fDirectoryCache
->fEntries
.Add(entry
);
153 return entry_cache_add(fInode
->GetFileSystem()->DevId(), fInode
->ID(),
162 DirectoryCache::RemoveEntry(const char* name
)
164 ASSERT(name
!= NULL
);
166 SinglyLinkedList
<NameCacheEntry
>::Iterator iterator
167 = fNameCache
.GetIterator();
168 NameCacheEntry
* previous
= NULL
;
169 NameCacheEntry
* current
= iterator
.Next();
170 while (current
!= NULL
) {
171 if (strcmp(current
->fName
, name
) == 0) {
172 fNameCache
.Remove(previous
, current
);
178 current
= iterator
.Next();
181 if (fDirectoryCache
!= NULL
) {
182 MutexLocker
_(fDirectoryCache
->fLock
);
183 iterator
= fDirectoryCache
->fEntries
.GetIterator();
185 current
= iterator
.Next();
186 while (current
!= NULL
) {
187 if (strcmp(current
->fName
, name
) == 0) {
188 fDirectoryCache
->fEntries
.Remove(previous
, current
);
194 current
= iterator
.Next();
199 entry_cache_remove(fInode
->GetFileSystem()->DevId(), fInode
->ID(),
206 DirectoryCache::_SetSnapshot(DirectoryCacheSnapshot
* snapshot
)
208 if (fDirectoryCache
!= NULL
)
209 fDirectoryCache
->ReleaseReference();
210 fDirectoryCache
= snapshot
;
215 DirectoryCache::_LoadSnapshot(bool trash
)
217 DirectoryCacheSnapshot
* oldSnapshot
= fDirectoryCache
;
218 if (oldSnapshot
!= NULL
)
219 oldSnapshot
->AcquireReference();
224 DirectoryCacheSnapshot
* newSnapshot
;
225 status_t result
= fInode
->GetDirSnapshot(&newSnapshot
, NULL
, &fChange
,
227 if (result
!= B_OK
) {
228 if (oldSnapshot
!= NULL
)
229 oldSnapshot
->ReleaseReference();
232 newSnapshot
->AcquireReference();
234 _SetSnapshot(newSnapshot
);
235 fExpireTime
= system_time() + fExpirationTime
;
239 if (oldSnapshot
!= NULL
)
240 NotifyChanges(oldSnapshot
, newSnapshot
);
242 if (oldSnapshot
!= NULL
)
243 oldSnapshot
->ReleaseReference();
245 newSnapshot
->ReleaseReference();
251 DirectoryCache::Revalidate()
253 if (fExpireTime
> system_time())
257 if (fInode
->GetChangeInfo(&change
, fAttrDir
) != B_OK
) {
262 if (change
== fChange
) {
263 fExpireTime
= system_time() + fExpirationTime
;
267 return _LoadSnapshot(true);
272 DirectoryCache::NotifyChanges(DirectoryCacheSnapshot
* oldSnapshot
,
273 DirectoryCacheSnapshot
* newSnapshot
)
275 ASSERT(newSnapshot
!= NULL
);
276 ASSERT(oldSnapshot
!= NULL
);
278 MutexLocker
_(newSnapshot
->fLock
);
280 SinglyLinkedList
<NameCacheEntry
>::Iterator oldIt
281 = oldSnapshot
->fEntries
.GetIterator();
282 NameCacheEntry
* oldCurrent
;
284 SinglyLinkedList
<NameCacheEntry
>::Iterator newIt
285 = newSnapshot
->fEntries
.GetIterator();
286 NameCacheEntry
* newCurrent
= newIt
.Next();
287 while (newCurrent
!= NULL
) {
288 oldIt
= oldSnapshot
->fEntries
.GetIterator();
289 oldCurrent
= oldIt
.Next();
292 NameCacheEntry
* prev
= NULL
;
293 while (oldCurrent
!= NULL
) {
294 if (oldCurrent
->fNode
== newCurrent
->fNode
295 && strcmp(oldCurrent
->fName
, newCurrent
->fName
) == 0) {
301 oldCurrent
= oldIt
.Next();
306 notify_attribute_changed(fInode
->GetFileSystem()->DevId(),
307 fInode
->ID(), newCurrent
->fName
, B_ATTR_CREATED
);
309 notify_entry_created(fInode
->GetFileSystem()->DevId(),
310 fInode
->ID(), newCurrent
->fName
, newCurrent
->fNode
);
313 oldSnapshot
->fEntries
.Remove(prev
, oldCurrent
);
315 newCurrent
= newIt
.Next();
318 oldIt
= oldSnapshot
->fEntries
.GetIterator();
319 oldCurrent
= oldIt
.Next();
321 while (oldCurrent
!= NULL
) {
323 notify_attribute_changed(fInode
->GetFileSystem()->DevId(),
324 fInode
->ID(), oldCurrent
->fName
, B_ATTR_REMOVED
);
326 notify_entry_removed(fInode
->GetFileSystem()->DevId(), fInode
->ID(),
327 oldCurrent
->fName
, oldCurrent
->fNode
);
329 oldCurrent
= oldIt
.Next();