1 #include "ace/Filecache.h"
2 #include "ace/Object_Manager.h"
3 #include "ace/Log_Category.h"
5 #include "ace/Guard_T.h"
6 #include "ace/OS_NS_string.h"
7 #include "ace/OS_NS_time.h"
8 #include "ace/OS_NS_unistd.h"
9 #include "ace/OS_NS_fcntl.h"
10 #include "ace/Truncate.h"
12 #if defined (ACE_WIN32)
13 // Specifies no sharing flags.
14 #define R_MASK ACE_DEFAULT_OPEN_PERMS
17 #define R_MASK S_IRUSR|S_IRGRP|S_IROTH
18 #define W_MASK S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH
19 #endif /* ACE_WIN32 */
21 #if defined (ACE_WIN32)
22 // See if you can get rid of some of these.
23 #define READ_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \
24 FILE_FLAG_OVERLAPPED | \
26 // static const int RCOPY_FLAGS = (FILE_FLAG_SEQUENTIAL_SCAN |
28 #define WRITE_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \
29 FILE_FLAG_OVERLAPPED | \
30 O_RDWR | O_CREAT | O_TRUNC)
31 // static const int WCOPY_FLAGS = (FILE_FLAG_SEQUENTIAL_SCAN |
32 // O_RDWR | O_CREAT | O_TRUNC);
34 #define READ_FLAGS O_RDONLY
35 // static const int RCOPY_FLAGS = O_RDONLY;
36 #define WRITE_FLAGS (O_RDWR | O_CREAT | O_TRUNC)
37 // static const int WCOPY_FLAGS = O_RDWR | O_CREAT | O_TRUNC;
38 #endif /* ACE_WIN32 */
40 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
42 // static data members
43 ACE_Filecache
*ACE_Filecache::cvf_
= 0;
46 ACE_Filecache_Handle::init ()
49 this->handle_
= ACE_INVALID_HANDLE
;
52 ACE_Filecache_Handle::ACE_Filecache_Handle ()
53 : file_ (0), handle_ (0)
58 ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR
*filename
,
59 ACE_Filecache_Flag mapit
)
60 : file_ (0), handle_ (0)
63 // Fetch the file from the Virtual_Filesystem let the
64 // Virtual_Filesystem do the work of cache coherency.
66 // Filecache will also do the acquire, since it holds the lock at
68 this->file_
= ACE_Filecache::instance ()->fetch (filename
, mapit
);
71 ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR
*filename
,
74 : file_ (0), handle_ (0)
79 ACE_Filecache::instance ()->remove (filename
);
82 // Since this is being opened for a write, simply create a new
83 // ACE_Filecache_Object now, and let the destructor add it into CVF
86 // Filecache will also do the acquire, since it holds the lock at
88 this->file_
= ACE_Filecache::instance ()->create (filename
, size
);
92 ACE_Filecache_Handle::~ACE_Filecache_Handle ()
94 if (this->handle_
!= ACE_INVALID_HANDLE
)
96 ACE_OS::close (this->handle_
);
98 ACE_Filecache::instance ()->finish (this->file_
);
102 ACE_Filecache_Handle::address () const
104 return this->file_
== 0 ? 0 : this->file_
->address ();
108 ACE_Filecache_Handle::handle () const
110 if (this->handle_
== ACE_INVALID_HANDLE
&& this->file_
!= 0)
112 ACE_Filecache_Handle
*mutable_this
=
113 const_cast<ACE_Filecache_Handle
*> (this);
114 mutable_this
->handle_
= ACE_OS::dup (this->file_
->handle ());
116 return this->handle_
;
120 ACE_Filecache_Handle::error () const
122 if (this->file_
== 0)
125 return this->file_
->error ();
129 ACE_Filecache_Handle::size () const
131 if (this->file_
== 0)
134 return this->file_
->size ();
137 // ------------------
138 // ACE_Filecache_Hash
139 // ------------------
141 #define ACE_Filecache_Hash \
142 ACE_Hash_Map_Manager_Ex<const ACE_TCHAR *, ACE_Filecache_Object *, ACE_Hash<const ACE_TCHAR *>, ACE_Equal_To<const ACE_TCHAR *>, ACE_Null_Mutex>
143 #define ACE_Filecache_Hash_Entry \
144 ACE_Hash_Map_Entry<const ACE_TCHAR *, ACE_Filecache_Object *>
147 ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (
148 const ACE_TCHAR
*const &ext_id
,
149 ACE_Filecache_Object
*const &int_id
,
150 ACE_Filecache_Hash_Entry
*next
,
151 ACE_Filecache_Hash_Entry
*prev
)
153 ? ACE_OS::strdup (ext_id
)
154 : ACE_OS::strdup (ACE_TEXT (""))),
162 ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (ACE_Filecache_Hash_Entry
*next
,
163 ACE_Filecache_Hash_Entry
*prev
)
172 ACE_Filecache_Hash_Entry::~ACE_Hash_Map_Entry ()
174 #if defined (ACE_HAS_ALLOC_HOOKS)
175 ACE_Allocator::instance()->free ((void *) ext_id_
);
177 ACE_OS::free ((void *) ext_id_
);
178 #endif /* ACE_HAS_ALLOC_HOOKS */
181 // We need these template specializations since KEY is defined as a
182 // ACE_TCHAR*, which doesn't have a hash() or equal() method defined on it.
186 ACE_Filecache_Hash::hash (const ACE_TCHAR
*const &ext_id
)
188 return ACE::hash_pjw (ext_id
);
193 ACE_Filecache_Hash::equal (const ACE_TCHAR
*const &id1
,
194 const ACE_TCHAR
*const &id2
)
196 return ACE_OS::strcmp (id1
, id2
) == 0;
199 #undef ACE_Filecache_Hash
200 #undef ACE_Filecache_Hash_Entry
208 ACE_Filecache::instance ()
210 // Double check locking pattern.
211 if (ACE_Filecache::cvf_
== 0)
213 ACE_SYNCH_RW_MUTEX
&lock
=
214 *ACE_Managed_Object
<ACE_SYNCH_RW_MUTEX
>::get_preallocated_object
215 (ACE_Object_Manager::ACE_FILECACHE_LOCK
);
216 ACE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX
, ace_mon
, lock
, 0);
218 // @@ James, please check each of the ACE_NEW_RETURN calls to
219 // make sure that it is safe to return if allocation fails.
220 if (ACE_Filecache::cvf_
== 0)
221 ACE_NEW_RETURN (ACE_Filecache::cvf_
,
226 return ACE_Filecache::cvf_
;
229 ACE_Filecache::ACE_Filecache ()
230 : size_ (ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE
),
235 ACE_Filecache::~ACE_Filecache ()
239 ACE_ALLOC_HOOK_DEFINE(ACE_Filecache
)
241 ACE_Filecache_Object
*
242 ACE_Filecache::insert_i (const ACE_TCHAR
*filename
,
243 ACE_SYNCH_RW_MUTEX
&filelock
,
246 ACE_Filecache_Object
*handle
= 0;
248 if (this->hash_
.find (filename
, handle
) == -1)
250 ACE_NEW_RETURN (handle
,
251 ACE_Filecache_Object (filename
, filelock
, 0, mapit
),
254 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) CVF: creating %s\n"), filename));
256 if (this->hash_
.bind (filename
, handle
) == -1)
268 ACE_Filecache_Object
*
269 ACE_Filecache::remove_i (const ACE_TCHAR
*filename
)
271 ACE_Filecache_Object
*handle
= 0;
273 // Disassociate file from the cache.
274 if (this->hash_
.unbind (filename
, handle
) == 0)
278 // Try a lock. If it succeeds, we can delete it now.
279 // Otherwise, it will clean itself up later.
280 if (handle
->lock_
.tryacquire_write () == 0)
292 ACE_Filecache_Object
*
293 ACE_Filecache::update_i (const ACE_TCHAR
*filename
,
294 ACE_SYNCH_RW_MUTEX
&filelock
,
297 ACE_Filecache_Object
*handle
= 0;
299 handle
= this->remove_i (filename
);
300 handle
= this->insert_i (filename
, filelock
, mapit
);
306 ACE_Filecache::find (const ACE_TCHAR
*filename
)
308 return this->hash_
.find (filename
);
312 ACE_Filecache_Object
*
313 ACE_Filecache::remove (const ACE_TCHAR
*filename
)
315 ACE_Filecache_Object
*handle
= 0;
317 ACE_OFF_T loc
= ACE::hash_pjw (filename
) % this->size_
;
318 ACE_SYNCH_RW_MUTEX
&hashlock
= this->hash_lock_
[loc
];
319 // ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc];
321 if (this->hash_
.find (filename
, handle
) != -1)
323 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX
,
328 return this->remove_i (filename
);
335 ACE_Filecache_Object
*
336 ACE_Filecache::fetch (const ACE_TCHAR
*filename
, int mapit
)
338 ACE_Filecache_Object
*handle
= 0;
340 ACE_OFF_T loc
= ACE::hash_pjw (filename
) % this->size_
;
341 ACE_SYNCH_RW_MUTEX
&hashlock
= this->hash_lock_
[loc
];
342 ACE_SYNCH_RW_MUTEX
&filelock
= this->file_lock_
[loc
];
344 filelock
.acquire_read ();
346 if (this->hash_
.find (filename
, handle
) == -1)
348 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX
,
353 // Second check in the method call
354 handle
= this->insert_i (filename
, filelock
, mapit
);
361 if (handle
->update ())
364 // Double check locking pattern
365 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX
,
370 // Second check in the method call
371 handle
= this->update_i (filename
, filelock
, mapit
);
377 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) CVF: found %s\n"), filename));
383 ACE_Filecache_Object
*
384 ACE_Filecache::create (const ACE_TCHAR
*filename
, int size
)
386 ACE_Filecache_Object
*handle
= 0;
388 ACE_OFF_T loc
= ACE::hash_pjw (filename
) % this->size_
;
389 ACE_SYNCH_RW_MUTEX
&filelock
= this->file_lock_
[loc
];
391 ACE_NEW_RETURN (handle
,
392 ACE_Filecache_Object (filename
, size
, filelock
),
399 ACE_Filecache_Object
*
400 ACE_Filecache::finish (ACE_Filecache_Object
*&file
)
405 ACE_OFF_T loc
= ACE::hash_pjw (file
->filename_
) % this->size_
;
406 ACE_SYNCH_RW_MUTEX
&hashlock
= this->hash_lock_
[loc
];
409 switch (file
->action_
)
411 case ACE_Filecache_Object::ACE_WRITING
:
413 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX
,
420 this->remove_i (file
->filename_
);
422 int result
= this->hash_
.bind (file
->filename (), file
);
427 // Last one using a stale file is resposible for deleting it.
430 // Try a lock. If it succeds, we can delete it now.
431 // Otherwise, it will clean itself up later.
432 if (file
->lock_
.tryacquire_write () == 0)
445 // Last one using a stale file is resposible for deleting it.
448 // Try a lock. If it succeds, we can delete it now.
449 // Otherwise, it will clean itself up later.
450 if (file
->lock_
.tryacquire_write () == 0)
464 ACE_Filecache_Object::init ()
466 this->filename_
[0] = '\0';
467 this->handle_
= ACE_INVALID_HANDLE
;
468 this->error_
= ACE_SUCCESS
;
472 ACE_OS::memset (&(this->stat_
), 0, sizeof (this->stat_
));
475 ACE_Filecache_Object::ACE_Filecache_Object ()
491 ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR
*filename
,
492 ACE_SYNCH_RW_MUTEX
&lock
,
493 LPSECURITY_ATTRIBUTES sa
,
509 // ASSERT strlen(filename) < sizeof (this->filename_)
510 ACE_OS::strcpy (this->filename_
, filename
);
511 this->action_
= ACE_Filecache_Object::ACE_READING
;
512 // place ourselves into the READING state
514 // Can we access the file?
515 if (ACE_OS::access (this->filename_
, R_OK
) == -1)
517 this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED
);
521 // Can we stat the file?
522 if (ACE_OS::stat (this->filename_
, &this->stat_
) == -1)
524 this->error_i (ACE_Filecache_Object::ACE_STAT_FAILED
);
528 this->size_
= ACE_Utils::truncate_cast
<ACE_OFF_T
> (this->stat_
.st_size
);
529 this->tempname_
= this->filename_
;
531 // Can we open the file?
532 this->handle_
= ACE_OS::open (this->tempname_
,
533 READ_FLAGS
, R_MASK
, this->sa_
);
534 if (this->handle_
== ACE_INVALID_HANDLE
)
536 this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED
,
537 ACE_TEXT ("ACE_Filecache_Object::ctor: open"));
543 // Can we map the file?
544 if (this->mmap_
.map (this->handle_
, static_cast<size_t> (-1),
545 PROT_READ
, ACE_MAP_PRIVATE
, 0, 0, this->sa_
) != 0)
547 this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED
,
548 ACE_TEXT ("ACE_Filecache_Object::ctor: map"));
549 ACE_OS::close (this->handle_
);
550 this->handle_
= ACE_INVALID_HANDLE
;
556 this->action_
= ACE_Filecache_Object::ACE_READING
;
559 ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR
*filename
,
561 ACE_SYNCH_RW_MUTEX
&lock
,
562 LPSECURITY_ATTRIBUTES sa
)
570 ACE_OS::strcpy (this->filename_
, filename
);
571 this->action_
= ACE_Filecache_Object::ACE_WRITING
;
573 // Can we access the file?
574 if (ACE_OS::access (this->filename_
, R_OK
|W_OK
) == -1
576 && ACE_OS::access (this->filename_
, F_OK
) != -1)
578 // File exists, but we cannot access it.
579 this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED
);
583 this->tempname_
= this->filename_
;
585 // Can we open the file?
586 this->handle_
= ACE_OS::open (this->tempname_
, WRITE_FLAGS
, W_MASK
, this->sa_
);
587 if (this->handle_
== ACE_INVALID_HANDLE
)
589 this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED
,
590 ACE_TEXT ("ACE_Filecache_Object::acquire: open"));
595 if (ACE_OS::pwrite (this->handle_
, "", 1, this->size_
- 1) != 1)
597 this->error_i (ACE_Filecache_Object::ACE_WRITE_FAILED
,
598 ACE_TEXT ("ACE_Filecache_Object::acquire: write"));
599 ACE_OS::close (this->handle_
);
604 if (this->mmap_
.map (this->handle_
, this->size_
, PROT_RDWR
, MAP_SHARED
,
605 0, 0, this->sa_
) != 0)
607 this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED
,
608 ACE_TEXT ("ACE_Filecache_Object::acquire: map"));
609 ACE_OS::close (this->handle_
);
615 ACE_Filecache_Object::~ACE_Filecache_Object ()
617 if (this->error_
== ACE_SUCCESS
)
619 this->mmap_
.unmap ();
620 ACE_OS::close (this->handle_
);
621 this->handle_
= ACE_INVALID_HANDLE
;
624 this->lock_
.release ();
627 ACE_ALLOC_HOOK_DEFINE(ACE_Filecache_Object
)
630 ACE_Filecache_Object::acquire ()
632 return this->lock_
.tryacquire_read ();
636 ACE_Filecache_Object::release ()
638 if (this->action_
== ACE_WRITING
)
640 // We are safe since only one thread has a writable Filecache_Object
643 ACE_HANDLE original
= ACE_OS::open (this->filename_
, WRITE_FLAGS
, W_MASK
,
645 if (original
== ACE_INVALID_HANDLE
)
646 this->error_
= ACE_Filecache_Object::ACE_OPEN_FAILED
;
647 else if (ACE_OS::write (original
, this->mmap_
.addr (),
650 this->error_
= ACE_Filecache_Object::ACE_WRITE_FAILED
;
651 ACE_OS::close (original
);
652 ACE_OS::unlink (this->filename_
);
654 else if (ACE_OS::stat (this->filename_
, &this->stat_
) == -1)
655 this->error_
= ACE_Filecache_Object::ACE_STAT_FAILED
;
658 this->mmap_
.unmap ();
659 ACE_OS::close (this->handle_
);
660 this->handle_
= ACE_INVALID_HANDLE
;
663 // Leave the file in an acquirable state.
664 this->handle_
= ACE_OS::open (this->tempname_
, READ_FLAGS
, R_MASK
);
665 if (this->handle_
== ACE_INVALID_HANDLE
)
667 this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED
,
668 "ACE_Filecache_Object::acquire: open");
670 else if (this->mmap_
.map (this->handle_
, -1,
677 this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED
,
678 "ACE_Filecache_Object::acquire: map");
679 ACE_OS::close (this->handle_
);
680 this->handle_
= ACE_INVALID_HANDLE
;
683 this->action_
= ACE_Filecache_Object::ACE_READING
;
687 return this->lock_
.release ();
691 ACE_Filecache_Object::error () const
693 // The existence of the object means a read lock is being held.
698 ACE_Filecache_Object::error_i (int error_value
, const ACE_TCHAR
*s
)
701 ACELIB_ERROR ((LM_ERROR
, ACE_TEXT ("%p.\n"), s
));
702 this->error_
= error_value
;
707 ACE_Filecache_Object::filename () const
709 // The existence of the object means a read lock is being held.
710 return this->filename_
;
714 ACE_Filecache_Object::size () const
716 // The existence of the object means a read lock is being held.
721 ACE_Filecache_Object::handle () const
723 // The existence of the object means a read lock is being held.
724 return this->handle_
;
728 ACE_Filecache_Object::address () const
730 // The existence of the object means a read lock is being held.
731 return this->mmap_
.addr ();
735 ACE_Filecache_Object::update () const
737 // The existence of the object means a read lock is being held.
741 if (ACE_OS::stat (this->filename_
, &statbuf
) == -1)
744 result
= ACE_OS::difftime (this->stat_
.st_mtime
, statbuf
.st_mtime
) < 0;
749 ACE_END_VERSIONED_NAMESPACE_DECL