[7297] Fixed profession spells sorting in trainer spell list at client.
[getmangos.git] / dep / ACE_wrappers / ace / Filecache.cpp
blob3a7e3da0a4cdea247396a8223fa4f98907065e0e
1 // $Id: Filecache.cpp 80826 2008-03-04 14:51:23Z wotte $
3 #include "ace/Filecache.h"
4 #include "ace/Object_Manager.h"
5 #include "ace/Log_Msg.h"
6 #include "ace/ACE.h"
7 #include "ace/Guard_T.h"
8 #include "ace/OS_NS_string.h"
9 #include "ace/OS_NS_time.h"
10 #include "ace/OS_NS_unistd.h"
11 #include "ace/OS_NS_fcntl.h"
12 #include "ace/Truncate.h"
14 ACE_RCSID (ace,
15 Filecache,
16 "$Id: Filecache.cpp 80826 2008-03-04 14:51:23Z wotte $")
18 #if defined (ACE_WIN32)
19 // Specifies no sharing flags.
20 #define R_MASK ACE_DEFAULT_OPEN_PERMS
21 #define W_MASK 0
22 #else
23 #define R_MASK S_IRUSR|S_IRGRP|S_IROTH
24 #define W_MASK S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH
25 #endif /* ACE_WIN32 */
27 #if defined (ACE_WIN32)
28 // See if you can get rid of some of these.
29 #define READ_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \
30 FILE_FLAG_OVERLAPPED | \
31 O_RDONLY)
32 // static const int RCOPY_FLAGS = (FILE_FLAG_SEQUENTIAL_SCAN |
33 // O_RDONLY);
34 #define WRITE_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \
35 FILE_FLAG_OVERLAPPED | \
36 O_RDWR | O_CREAT | O_TRUNC)
37 // static const int WCOPY_FLAGS = (FILE_FLAG_SEQUENTIAL_SCAN |
38 // O_RDWR | O_CREAT | O_TRUNC);
39 #else
40 #define READ_FLAGS O_RDONLY
41 // static const int RCOPY_FLAGS = O_RDONLY;
42 #define WRITE_FLAGS (O_RDWR | O_CREAT | O_TRUNC)
43 // static const int WCOPY_FLAGS = O_RDWR | O_CREAT | O_TRUNC;
44 #endif /* ACE_WIN32 */
46 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
48 // static data members
49 ACE_Filecache *ACE_Filecache::cvf_ = 0;
51 void
52 ACE_Filecache_Handle::init (void)
54 this->file_ = 0;
55 this->handle_ = ACE_INVALID_HANDLE;
58 ACE_Filecache_Handle::ACE_Filecache_Handle (void)
59 : file_ (0), handle_ (0), mapit_ (0)
61 this->init ();
64 ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename,
65 ACE_Filecache_Flag mapit)
66 : file_ (0), handle_ (0), mapit_ (mapit)
68 this->init ();
69 // Fetch the file from the Virtual_Filesystem let the
70 // Virtual_Filesystem do the work of cache coherency.
72 // Filecache will also do the acquire, since it holds the lock at
73 // that time.
74 this->file_ = ACE_Filecache::instance ()->fetch (filename, mapit);
77 ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename,
78 int size,
79 ACE_Filecache_Flag mapit)
80 : file_ (0), handle_ (0), mapit_ (mapit)
82 this->init ();
84 if (size == 0)
85 ACE_Filecache::instance ()->remove (filename);
86 else
88 // Since this is being opened for a write, simply create a new
89 // ACE_Filecache_Object now, and let the destructor add it into CVF
90 // later
92 // Filecache will also do the acquire, since it holds the lock at
93 // that time.
94 this->file_ = ACE_Filecache::instance ()->create (filename, size);
98 ACE_Filecache_Handle::~ACE_Filecache_Handle (void)
100 if (this->handle_ != ACE_INVALID_HANDLE)
101 // this was dup ()'d
102 ACE_OS::close (this->handle_);
104 ACE_Filecache::instance ()->finish (this->file_);
107 void *
108 ACE_Filecache_Handle::address (void) const
110 return this->file_ == 0 ? 0 : this->file_->address ();
113 ACE_HANDLE
114 ACE_Filecache_Handle::handle (void) const
116 if (this->handle_ == ACE_INVALID_HANDLE && this->file_ != 0)
118 ACE_Filecache_Handle *mutable_this =
119 const_cast<ACE_Filecache_Handle *> (this);
120 mutable_this->handle_ = ACE_OS::dup (this->file_->handle ());
122 return this->handle_;
126 ACE_Filecache_Handle::error (void) const
128 if (this->file_ == 0)
129 return -1;
130 else
131 return this->file_->error ();
134 ACE_OFF_T
135 ACE_Filecache_Handle::size (void) const
137 if (this->file_ == 0)
138 return -1;
139 else
140 return this->file_->size ();
143 // ------------------
144 // ACE_Filecache_Hash
145 // ------------------
147 #define ACE_Filecache_Hash \
148 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>
149 #define ACE_Filecache_Hash_Entry \
150 ACE_Hash_Map_Entry<const ACE_TCHAR *, ACE_Filecache_Object *>
152 template <>
153 ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (
154 const ACE_TCHAR *const &ext_id,
155 ACE_Filecache_Object *const &int_id,
156 ACE_Filecache_Hash_Entry *next,
157 ACE_Filecache_Hash_Entry *prev)
158 : ext_id_ (ext_id
159 ? ACE_OS::strdup (ext_id)
160 : ACE_OS::strdup (ACE_TEXT (""))),
161 int_id_ (int_id),
162 next_ (next),
163 prev_ (prev)
167 template <>
168 ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (ACE_Filecache_Hash_Entry *next,
169 ACE_Filecache_Hash_Entry *prev)
170 : ext_id_ (0),
171 next_ (next),
172 prev_ (prev)
176 template <>
177 ACE_Filecache_Hash_Entry::~ACE_Hash_Map_Entry (void)
179 ACE_OS::free ((void *) ext_id_);
182 // We need these template specializations since KEY is defined as a
183 // ACE_TCHAR*, which doesn't have a hash() or equal() method defined on it.
185 template <>
186 unsigned long
187 ACE_Filecache_Hash::hash (const ACE_TCHAR *const &ext_id)
189 return ACE::hash_pjw (ext_id);
192 template <>
194 ACE_Filecache_Hash::equal (const ACE_TCHAR *const &id1,
195 const ACE_TCHAR *const &id2)
197 return ACE_OS::strcmp (id1, id2) == 0;
200 #undef ACE_Filecache_Hash
201 #undef ACE_Filecache_Hash_Entry
204 // -------------
205 // ACE_Filecache
206 // -------------
208 ACE_Filecache *
209 ACE_Filecache::instance (void)
211 // Double check locking pattern.
212 if (ACE_Filecache::cvf_ == 0)
214 ACE_SYNCH_RW_MUTEX &lock =
215 *ACE_Managed_Object<ACE_SYNCH_RW_MUTEX>::get_preallocated_object
216 (ACE_Object_Manager::ACE_FILECACHE_LOCK);
217 ACE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX, ace_mon, lock, 0);
219 // @@ James, please check each of the ACE_NEW_RETURN calls to
220 // make sure that it is safe to return if allocation fails.
221 if (ACE_Filecache::cvf_ == 0)
222 ACE_NEW_RETURN (ACE_Filecache::cvf_,
223 ACE_Filecache,
227 return ACE_Filecache::cvf_;
230 ACE_Filecache::ACE_Filecache (void)
231 : size_ (ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE),
232 hash_ (size_)
236 ACE_Filecache::~ACE_Filecache (void)
240 ACE_Filecache_Object *
241 ACE_Filecache::insert_i (const ACE_TCHAR *filename,
242 ACE_SYNCH_RW_MUTEX &filelock,
243 int mapit)
245 ACE_Filecache_Object *handle = 0;
247 if (this->hash_.find (filename, handle) == -1)
249 ACE_NEW_RETURN (handle,
250 ACE_Filecache_Object (filename, filelock, 0, mapit),
253 // ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) CVF: creating %s\n"), filename));
255 if (this->hash_.bind (filename, handle) == -1)
257 delete handle;
258 handle = 0;
261 else
262 handle = 0;
264 return handle;
267 ACE_Filecache_Object *
268 ACE_Filecache::remove_i (const ACE_TCHAR *filename)
270 ACE_Filecache_Object *handle = 0;
272 // Disassociate file from the cache.
273 if (this->hash_.unbind (filename, handle) == 0)
275 handle->stale_ = 1;
277 // Try a lock. If it succeeds, we can delete it now.
278 // Otherwise, it will clean itself up later.
279 if (handle->lock_.tryacquire_write () == 0)
281 delete handle;
282 handle = 0;
285 else
286 handle = 0;
288 return handle;
291 ACE_Filecache_Object *
292 ACE_Filecache::update_i (const ACE_TCHAR *filename,
293 ACE_SYNCH_RW_MUTEX &filelock,
294 int mapit)
296 ACE_Filecache_Object *handle = 0;
298 handle = this->remove_i (filename);
299 handle = this->insert_i (filename, filelock, mapit);
301 return handle;
305 ACE_Filecache::find (const ACE_TCHAR *filename)
307 return this->hash_.find (filename);
311 ACE_Filecache_Object *
312 ACE_Filecache::remove (const ACE_TCHAR *filename)
314 ACE_Filecache_Object *handle = 0;
316 ACE_OFF_T loc = ACE::hash_pjw (filename) % this->size_;
317 ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
318 // ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc];
320 if (this->hash_.find (filename, handle) != -1)
322 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
323 ace_mon,
324 hashlock,
327 return this->remove_i (filename);
330 return 0;
334 ACE_Filecache_Object *
335 ACE_Filecache::fetch (const ACE_TCHAR *filename, int mapit)
337 ACE_Filecache_Object *handle = 0;
339 ACE_OFF_T loc = ACE::hash_pjw (filename) % this->size_;
340 ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
341 ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc];
343 filelock.acquire_read ();
345 if (this->hash_.find (filename, handle) == -1)
347 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
348 ace_mon,
349 hashlock,
352 // Second check in the method call
353 handle = this->insert_i (filename, filelock, mapit);
355 if (handle == 0)
356 filelock.release ();
358 else
360 if (handle->update ())
363 // Double check locking pattern
364 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
365 ace_mon,
366 hashlock,
369 // Second check in the method call
370 handle = this->update_i (filename, filelock, mapit);
372 if (handle == 0)
373 filelock.release ();
376 // ACE_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) CVF: found %s\n"), filename));
379 return handle;
382 ACE_Filecache_Object *
383 ACE_Filecache::create (const ACE_TCHAR *filename, int size)
385 ACE_Filecache_Object *handle = 0;
387 ACE_OFF_T loc = ACE::hash_pjw (filename) % this->size_;
388 ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc];
390 ACE_NEW_RETURN (handle,
391 ACE_Filecache_Object (filename, size, filelock),
393 handle->acquire ();
395 return handle;
398 ACE_Filecache_Object *
399 ACE_Filecache::finish (ACE_Filecache_Object *&file)
401 if (file == 0)
402 return file;
404 ACE_OFF_T loc = ACE::hash_pjw (file->filename_) % this->size_;
405 ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
407 if (file != 0)
408 switch (file->action_)
410 case ACE_Filecache_Object::ACE_WRITING:
412 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
413 ace_mon,
414 hashlock,
417 file->release ();
419 this->remove_i (file->filename_);
420 #if 0
421 int result = this->hash_.bind (file->filename (), file);
423 if (result == 0)
424 file->acquire ();
425 #else
426 // Last one using a stale file is resposible for deleting it.
427 if (file->stale_)
429 // Try a lock. If it succeds, we can delete it now.
430 // Otherwise, it will clean itself up later.
431 if (file->lock_.tryacquire_write () == 0)
433 delete file;
434 file = 0;
437 #endif
440 break;
441 default:
442 file->release ();
444 // Last one using a stale file is resposible for deleting it.
445 if (file->stale_)
447 // Try a lock. If it succeds, we can delete it now.
448 // Otherwise, it will clean itself up later.
449 if (file->lock_.tryacquire_write () == 0)
451 delete file;
452 file = 0;
456 break;
459 return file;
462 void
463 ACE_Filecache_Object::init (void)
465 this->filename_[0] = '\0';
466 this->handle_ = ACE_INVALID_HANDLE;
467 this->error_ = ACE_SUCCESS;
468 this->tempname_ = 0;
469 this->size_ = 0;
471 ACE_OS::memset (&(this->stat_), 0, sizeof (this->stat_));
474 ACE_Filecache_Object::ACE_Filecache_Object (void)
475 : tempname_ (0),
476 mmap_ (),
477 handle_ (0),
478 // stat_ (),
479 size_ (0),
480 action_ (0),
481 error_ (0),
482 stale_ (0),
483 // sa_ (),
484 junklock_ (),
485 lock_ (junklock_)
487 this->init ();
490 ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename,
491 ACE_SYNCH_RW_MUTEX &lock,
492 LPSECURITY_ATTRIBUTES sa,
493 int mapit)
494 : tempname_ (0),
495 mmap_ (),
496 handle_ (0),
497 // stat_ (),
498 size_ (0),
499 action_ (0),
500 error_ (0),
501 stale_ (0),
502 sa_ (sa),
503 junklock_ (),
504 lock_ (lock)
506 this->init ();
508 // ASSERT strlen(filename) < sizeof (this->filename_)
509 ACE_OS::strcpy (this->filename_, filename);
510 this->action_ = ACE_Filecache_Object::ACE_READING;
511 // place ourselves into the READING state
513 // Can we access the file?
514 if (ACE_OS::access (this->filename_, R_OK) == -1)
516 this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED);
517 return;
520 // Can we stat the file?
521 if (ACE_OS::stat (this->filename_, &this->stat_) == -1)
523 this->error_i (ACE_Filecache_Object::ACE_STAT_FAILED);
524 return;
527 this->size_ = ACE_Utils::truncate_cast<ACE_OFF_T> (this->stat_.st_size);
528 this->tempname_ = this->filename_;
530 // Can we open the file?
531 this->handle_ = ACE_OS::open (this->tempname_,
532 READ_FLAGS, R_MASK, this->sa_);
533 if (this->handle_ == ACE_INVALID_HANDLE)
535 this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED,
536 ACE_TEXT ("ACE_Filecache_Object::ctor: open"));
537 return;
540 if (mapit)
542 // Can we map the file?
543 if (this->mmap_.map (this->handle_, static_cast<size_t> (-1),
544 PROT_READ, ACE_MAP_PRIVATE, 0, 0, this->sa_) != 0)
546 this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED,
547 ACE_TEXT ("ACE_Filecache_Object::ctor: map"));
548 ACE_OS::close (this->handle_);
549 this->handle_ = ACE_INVALID_HANDLE;
550 return;
554 // Ok, finished!
555 this->action_ = ACE_Filecache_Object::ACE_READING;
558 ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename,
559 ACE_OFF_T size,
560 ACE_SYNCH_RW_MUTEX &lock,
561 LPSECURITY_ATTRIBUTES sa)
562 : stale_ (0),
563 sa_ (sa),
564 lock_ (lock)
566 this->init ();
568 this->size_ = size;
569 ACE_OS::strcpy (this->filename_, filename);
570 this->action_ = ACE_Filecache_Object::ACE_WRITING;
572 // Can we access the file?
573 if (ACE_OS::access (this->filename_, R_OK|W_OK) == -1
574 // Does it exist?
575 && ACE_OS::access (this->filename_, F_OK) != -1)
577 // File exists, but we cannot access it.
578 this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED);
579 return;
582 this->tempname_ = this->filename_;
584 // Can we open the file?
585 this->handle_ = ACE_OS::open (this->tempname_, WRITE_FLAGS, W_MASK, this->sa_);
586 if (this->handle_ == ACE_INVALID_HANDLE)
588 this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED,
589 ACE_TEXT ("ACE_Filecache_Object::acquire: open"));
590 return;
593 // Can we write?
594 if (ACE_OS::pwrite (this->handle_, "", 1, this->size_ - 1) != 1)
596 this->error_i (ACE_Filecache_Object::ACE_WRITE_FAILED,
597 ACE_TEXT ("ACE_Filecache_Object::acquire: write"));
598 ACE_OS::close (this->handle_);
599 return;
602 // Can we map?
603 if (this->mmap_.map (this->handle_, this->size_, PROT_RDWR, MAP_SHARED,
604 0, 0, this->sa_) != 0)
606 this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED,
607 ACE_TEXT ("ACE_Filecache_Object::acquire: map"));
608 ACE_OS::close (this->handle_);
611 // Ok, done!
614 ACE_Filecache_Object::~ACE_Filecache_Object (void)
616 if (this->error_ == ACE_SUCCESS)
618 this->mmap_.unmap ();
619 ACE_OS::close (this->handle_);
620 this->handle_ = ACE_INVALID_HANDLE;
623 this->lock_.release ();
627 ACE_Filecache_Object::acquire (void)
629 return this->lock_.tryacquire_read ();
633 ACE_Filecache_Object::release (void)
635 if (this->action_ == ACE_WRITING)
637 // We are safe since only one thread has a writable Filecache_Object
639 #if 0
640 ACE_HANDLE original = ACE_OS::open (this->filename_, WRITE_FLAGS, W_MASK,
641 this->sa_);
642 if (original == ACE_INVALID_HANDLE)
643 this->error_ = ACE_Filecache_Object::ACE_OPEN_FAILED;
644 else if (ACE_OS::write (original, this->mmap_.addr (),
645 this->size_) == -1)
647 this->error_ = ACE_Filecache_Object::ACE_WRITE_FAILED;
648 ACE_OS::close (original);
649 ACE_OS::unlink (this->filename_);
651 else if (ACE_OS::stat (this->filename_, &this->stat_) == -1)
652 this->error_ = ACE_Filecache_Object::ACE_STAT_FAILED;
653 #endif
655 this->mmap_.unmap ();
656 ACE_OS::close (this->handle_);
657 this->handle_ = ACE_INVALID_HANDLE;
659 #if 0
660 // Leave the file in an acquirable state.
661 this->handle_ = ACE_OS::open (this->tempname_, READ_FLAGS, R_MASK);
662 if (this->handle_ == ACE_INVALID_HANDLE)
664 this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED,
665 "ACE_Filecache_Object::acquire: open");
667 else if (this->mmap_.map (this->handle_, -1,
668 PROT_READ,
669 ACE_MAP_PRIVATE,
672 this->sa_) != 0)
674 this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED,
675 "ACE_Filecache_Object::acquire: map");
676 ACE_OS::close (this->handle_);
677 this->handle_ = ACE_INVALID_HANDLE;
680 this->action_ = ACE_Filecache_Object::ACE_READING;
681 #endif
684 return this->lock_.release ();
688 ACE_Filecache_Object::error (void) const
690 // The existence of the object means a read lock is being held.
691 return this->error_;
695 ACE_Filecache_Object::error_i (int error_value, const ACE_TCHAR *s)
697 s = s;
698 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p.\n"), s));
699 this->error_ = error_value;
700 return error_value;
703 const ACE_TCHAR *
704 ACE_Filecache_Object::filename (void) const
706 // The existence of the object means a read lock is being held.
707 return this->filename_;
710 ACE_OFF_T
711 ACE_Filecache_Object::size (void) const
713 // The existence of the object means a read lock is being held.
714 return this->size_;
717 ACE_HANDLE
718 ACE_Filecache_Object::handle (void) const
720 // The existence of the object means a read lock is being held.
721 return this->handle_;
724 void *
725 ACE_Filecache_Object::address (void) const
727 // The existence of the object means a read lock is being held.
728 return this->mmap_.addr ();
732 ACE_Filecache_Object::update (void) const
734 // The existence of the object means a read lock is being held.
735 int result;
736 ACE_stat statbuf;
738 if (ACE_OS::stat (this->filename_, &statbuf) == -1)
739 result = 1;
740 else
741 // non-portable code may follow
742 #if defined (ACE_HAS_WINCE)
743 // Yup, non-portable... there's probably a way to safely implement
744 // difftime() on WinCE, but for now, this will have to do. It flags
745 // every file as having changed since cached.
746 result = 1;
747 #else
748 result = ACE_OS::difftime (this->stat_.st_mtime, statbuf.st_mtime) < 0;
749 #endif /* ACE_HAS_WINCE */
751 return result;
754 ACE_END_VERSIONED_NAMESPACE_DECL