Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / Filecache.cpp
blob3f4644d57a718e577a096b6c708585ade5d8cac8
1 #include "ace/Filecache.h"
2 #include "ace/Object_Manager.h"
3 #include "ace/Log_Category.h"
4 #include "ace/ACE.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
15 #define W_MASK 0
16 #else
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 | \
25 O_RDONLY)
26 // static const int RCOPY_FLAGS = (FILE_FLAG_SEQUENTIAL_SCAN |
27 // O_RDONLY);
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);
33 #else
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;
45 void
46 ACE_Filecache_Handle::init ()
48 this->file_ = 0;
49 this->handle_ = ACE_INVALID_HANDLE;
52 ACE_Filecache_Handle::ACE_Filecache_Handle ()
53 : file_ (0), handle_ (0)
55 this->init ();
58 ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename,
59 ACE_Filecache_Flag mapit)
60 : file_ (0), handle_ (0)
62 this->init ();
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
67 // that time.
68 this->file_ = ACE_Filecache::instance ()->fetch (filename, mapit);
71 ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename,
72 int size,
73 ACE_Filecache_Flag )
74 : file_ (0), handle_ (0)
76 this->init ();
78 if (size == 0)
79 ACE_Filecache::instance ()->remove (filename);
80 else
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
84 // later
86 // Filecache will also do the acquire, since it holds the lock at
87 // that time.
88 this->file_ = ACE_Filecache::instance ()->create (filename, size);
92 ACE_Filecache_Handle::~ACE_Filecache_Handle ()
94 if (this->handle_ != ACE_INVALID_HANDLE)
95 // this was dup ()'d
96 ACE_OS::close (this->handle_);
98 ACE_Filecache::instance ()->finish (this->file_);
101 void *
102 ACE_Filecache_Handle::address () const
104 return this->file_ == 0 ? 0 : this->file_->address ();
107 ACE_HANDLE
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)
123 return -1;
124 else
125 return this->file_->error ();
128 ACE_OFF_T
129 ACE_Filecache_Handle::size () const
131 if (this->file_ == 0)
132 return -1;
133 else
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 *>
146 template <>
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)
152 : ext_id_ (ext_id
153 ? ACE_OS::strdup (ext_id)
154 : ACE_OS::strdup (ACE_TEXT (""))),
155 int_id_ (int_id),
156 next_ (next),
157 prev_ (prev)
161 template <>
162 ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (ACE_Filecache_Hash_Entry *next,
163 ACE_Filecache_Hash_Entry *prev)
164 : ext_id_ (0),
165 int_id_ (0),
166 next_ (next),
167 prev_ (prev)
171 template <>
172 ACE_Filecache_Hash_Entry::~ACE_Hash_Map_Entry ()
174 #if defined (ACE_HAS_ALLOC_HOOKS)
175 ACE_Allocator::instance()->free ((void *) ext_id_);
176 #else
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.
184 template <>
185 unsigned long
186 ACE_Filecache_Hash::hash (const ACE_TCHAR *const &ext_id)
188 return ACE::hash_pjw (ext_id);
191 template <>
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
203 // -------------
204 // ACE_Filecache
205 // -------------
207 ACE_Filecache *
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_,
222 ACE_Filecache,
226 return ACE_Filecache::cvf_;
229 ACE_Filecache::ACE_Filecache ()
230 : size_ (ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE),
231 hash_ (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,
244 int mapit)
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)
258 delete handle;
259 handle = 0;
262 else
263 handle = 0;
265 return handle;
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)
276 handle->stale_ = 1;
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)
282 delete handle;
283 handle = 0;
286 else
287 handle = 0;
289 return handle;
292 ACE_Filecache_Object *
293 ACE_Filecache::update_i (const ACE_TCHAR *filename,
294 ACE_SYNCH_RW_MUTEX &filelock,
295 int mapit)
297 ACE_Filecache_Object *handle = 0;
299 handle = this->remove_i (filename);
300 handle = this->insert_i (filename, filelock, mapit);
302 return handle;
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,
324 ace_mon,
325 hashlock,
328 return this->remove_i (filename);
331 return 0;
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,
349 ace_mon,
350 hashlock,
353 // Second check in the method call
354 handle = this->insert_i (filename, filelock, mapit);
356 if (handle == 0)
357 filelock.release ();
359 else
361 if (handle->update ())
364 // Double check locking pattern
365 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
366 ace_mon,
367 hashlock,
370 // Second check in the method call
371 handle = this->update_i (filename, filelock, mapit);
373 if (handle == 0)
374 filelock.release ();
377 // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) CVF: found %s\n"), filename));
380 return handle;
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),
394 handle->acquire ();
396 return handle;
399 ACE_Filecache_Object *
400 ACE_Filecache::finish (ACE_Filecache_Object *&file)
402 if (file == 0)
403 return file;
405 ACE_OFF_T loc = ACE::hash_pjw (file->filename_) % this->size_;
406 ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
408 if (file != 0)
409 switch (file->action_)
411 case ACE_Filecache_Object::ACE_WRITING:
413 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
414 ace_mon,
415 hashlock,
418 file->release ();
420 this->remove_i (file->filename_);
421 #if 0
422 int result = this->hash_.bind (file->filename (), file);
424 if (result == 0)
425 file->acquire ();
426 #else
427 // Last one using a stale file is resposible for deleting it.
428 if (file->stale_)
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)
434 delete file;
435 file = 0;
438 #endif
441 break;
442 default:
443 file->release ();
445 // Last one using a stale file is resposible for deleting it.
446 if (file->stale_)
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)
452 delete file;
453 file = 0;
457 break;
460 return file;
463 void
464 ACE_Filecache_Object::init ()
466 this->filename_[0] = '\0';
467 this->handle_ = ACE_INVALID_HANDLE;
468 this->error_ = ACE_SUCCESS;
469 this->tempname_ = 0;
470 this->size_ = 0;
472 ACE_OS::memset (&(this->stat_), 0, sizeof (this->stat_));
475 ACE_Filecache_Object::ACE_Filecache_Object ()
476 : tempname_ (0),
477 mmap_ (),
478 handle_ (0),
479 // stat_ (),
480 size_ (0),
481 action_ (0),
482 error_ (0),
483 stale_ (0),
484 // sa_ (),
485 junklock_ (),
486 lock_ (junklock_)
488 this->init ();
491 ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename,
492 ACE_SYNCH_RW_MUTEX &lock,
493 LPSECURITY_ATTRIBUTES sa,
494 int mapit)
495 : tempname_ (0),
496 mmap_ (),
497 handle_ (0),
498 // stat_ (),
499 size_ (0),
500 action_ (0),
501 error_ (0),
502 stale_ (0),
503 sa_ (sa),
504 junklock_ (),
505 lock_ (lock)
507 this->init ();
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);
518 return;
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);
525 return;
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"));
538 return;
541 if (mapit)
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;
551 return;
555 // Ok, finished!
556 this->action_ = ACE_Filecache_Object::ACE_READING;
559 ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename,
560 ACE_OFF_T size,
561 ACE_SYNCH_RW_MUTEX &lock,
562 LPSECURITY_ATTRIBUTES sa)
563 : stale_ (0),
564 sa_ (sa),
565 lock_ (lock)
567 this->init ();
569 this->size_ = size;
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
575 // Does it exist?
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);
580 return;
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"));
591 return;
594 // Can we write?
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_);
600 return;
603 // Can we map?
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_);
612 // Ok, done!
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
642 #if 0
643 ACE_HANDLE original = ACE_OS::open (this->filename_, WRITE_FLAGS, W_MASK,
644 this->sa_);
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 (),
648 this->size_) == -1)
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;
656 #endif
658 this->mmap_.unmap ();
659 ACE_OS::close (this->handle_);
660 this->handle_ = ACE_INVALID_HANDLE;
662 #if 0
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,
671 PROT_READ,
672 ACE_MAP_PRIVATE,
675 this->sa_) != 0)
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;
684 #endif
687 return this->lock_.release ();
691 ACE_Filecache_Object::error () const
693 // The existence of the object means a read lock is being held.
694 return this->error_;
698 ACE_Filecache_Object::error_i (int error_value, const ACE_TCHAR *s)
700 ACE_UNUSED_ARG (s);
701 ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p.\n"), s));
702 this->error_ = error_value;
703 return error_value;
706 const ACE_TCHAR *
707 ACE_Filecache_Object::filename () const
709 // The existence of the object means a read lock is being held.
710 return this->filename_;
713 ACE_OFF_T
714 ACE_Filecache_Object::size () const
716 // The existence of the object means a read lock is being held.
717 return this->size_;
720 ACE_HANDLE
721 ACE_Filecache_Object::handle () const
723 // The existence of the object means a read lock is being held.
724 return this->handle_;
727 void *
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.
738 int result;
739 ACE_stat statbuf;
741 if (ACE_OS::stat (this->filename_, &statbuf) == -1)
742 result = 1;
743 else
744 result = ACE_OS::difftime (this->stat_.st_mtime, statbuf.st_mtime) < 0;
746 return result;
749 ACE_END_VERSIONED_NAMESPACE_DECL