00001
00002
00003 #include "ace/Filecache.h"
00004 #include "ace/Object_Manager.h"
00005 #include "ace/Log_Msg.h"
00006 #include "ace/ACE.h"
00007 #include "ace/Guard_T.h"
00008 #include "ace/OS_NS_string.h"
00009 #include "ace/OS_NS_time.h"
00010 #include "ace/OS_NS_unistd.h"
00011 #include "ace/OS_NS_fcntl.h"
00012 #include "ace/Truncate.h"
00013
00014 ACE_RCSID (ace,
00015 Filecache,
00016 "$Id: Filecache.cpp 79134 2007-07-31 18:23:50Z johnnyw $")
00017
00018 #if defined (ACE_WIN32)
00019
00020 #define R_MASK ACE_DEFAULT_OPEN_PERMS
00021 #define W_MASK 0
00022 #else
00023 #define R_MASK S_IRUSR|S_IRGRP|S_IROTH
00024 #define W_MASK S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH
00025 #endif
00026
00027 #if defined (ACE_WIN32)
00028
00029 #define READ_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \
00030 FILE_FLAG_OVERLAPPED | \
00031 O_RDONLY)
00032
00033
00034 #define WRITE_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \
00035 FILE_FLAG_OVERLAPPED | \
00036 O_RDWR | O_CREAT | O_TRUNC)
00037
00038
00039 #else
00040 #define READ_FLAGS O_RDONLY
00041
00042 #define WRITE_FLAGS (O_RDWR | O_CREAT | O_TRUNC)
00043
00044 #endif
00045
00046 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00047
00048
00049 ACE_Filecache *ACE_Filecache::cvf_ = 0;
00050
00051 void
00052 ACE_Filecache_Handle::init (void)
00053 {
00054 this->file_ = 0;
00055 this->handle_ = ACE_INVALID_HANDLE;
00056 }
00057
00058 ACE_Filecache_Handle::ACE_Filecache_Handle (void)
00059 : file_ (0), handle_ (0), mapit_ (0)
00060 {
00061 this->init ();
00062 }
00063
00064 ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename,
00065 ACE_Filecache_Flag mapit)
00066 : file_ (0), handle_ (0), mapit_ (mapit)
00067 {
00068 this->init ();
00069
00070
00071
00072
00073
00074 this->file_ = ACE_Filecache::instance ()->fetch (filename, mapit);
00075 }
00076
00077 ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename,
00078 int size,
00079 ACE_Filecache_Flag mapit)
00080 : file_ (0), handle_ (0), mapit_ (mapit)
00081 {
00082 this->init ();
00083
00084 if (size == 0)
00085 ACE_Filecache::instance ()->remove (filename);
00086 else
00087 {
00088
00089
00090
00091
00092
00093
00094 this->file_ = ACE_Filecache::instance ()->create (filename, size);
00095 }
00096 }
00097
00098 ACE_Filecache_Handle::~ACE_Filecache_Handle (void)
00099 {
00100 if (this->handle_ != ACE_INVALID_HANDLE)
00101
00102 ACE_OS::close (this->handle_);
00103
00104 ACE_Filecache::instance ()->finish (this->file_);
00105 }
00106
00107 void *
00108 ACE_Filecache_Handle::address (void) const
00109 {
00110 return this->file_ == 0 ? 0 : this->file_->address ();
00111 }
00112
00113 ACE_HANDLE
00114 ACE_Filecache_Handle::handle (void) const
00115 {
00116 if (this->handle_ == ACE_INVALID_HANDLE && this->file_ != 0)
00117 {
00118 ACE_Filecache_Handle *mutable_this =
00119 const_cast<ACE_Filecache_Handle *> (this);
00120 mutable_this->handle_ = ACE_OS::dup (this->file_->handle ());
00121 }
00122 return this->handle_;
00123 }
00124
00125 int
00126 ACE_Filecache_Handle::error (void) const
00127 {
00128 if (this->file_ == 0)
00129 return -1;
00130 else
00131 return this->file_->error ();
00132 }
00133
00134 ACE_OFF_T
00135 ACE_Filecache_Handle::size (void) const
00136 {
00137 if (this->file_ == 0)
00138 return -1;
00139 else
00140 return this->file_->size ();
00141 }
00142
00143
00144
00145
00146
00147 #define ACE_Filecache_Hash \
00148 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>
00149 #define ACE_Filecache_Hash_Entry \
00150 ACE_Hash_Map_Entry<const ACE_TCHAR *, ACE_Filecache_Object *>
00151
00152 template <>
00153 ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (
00154 const ACE_TCHAR *const &ext_id,
00155 ACE_Filecache_Object *const &int_id,
00156 ACE_Filecache_Hash_Entry *next,
00157 ACE_Filecache_Hash_Entry *prev)
00158 : ext_id_ (ext_id
00159 ? ACE_OS::strdup (ext_id)
00160 : ACE_OS::strdup (ACE_TEXT (""))),
00161 int_id_ (int_id),
00162 next_ (next),
00163 prev_ (prev)
00164 {
00165 }
00166
00167 template <>
00168 ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (ACE_Filecache_Hash_Entry *next,
00169 ACE_Filecache_Hash_Entry *prev)
00170 : ext_id_ (0),
00171 next_ (next),
00172 prev_ (prev)
00173 {
00174 }
00175
00176 template <>
00177 ACE_Filecache_Hash_Entry::~ACE_Hash_Map_Entry (void)
00178 {
00179 ACE_OS::free ((void *) ext_id_);
00180 }
00181
00182
00183
00184
00185 template <>
00186 unsigned long
00187 ACE_Filecache_Hash::hash (const ACE_TCHAR *const &ext_id)
00188 {
00189 return ACE::hash_pjw (ext_id);
00190 }
00191
00192 template <>
00193 int
00194 ACE_Filecache_Hash::equal (const ACE_TCHAR *const &id1,
00195 const ACE_TCHAR *const &id2)
00196 {
00197 return ACE_OS::strcmp (id1, id2) == 0;
00198 }
00199
00200 #undef ACE_Filecache_Hash
00201 #undef ACE_Filecache_Hash_Entry
00202
00203
00204
00205
00206
00207
00208 ACE_Filecache *
00209 ACE_Filecache::instance (void)
00210 {
00211
00212 if (ACE_Filecache::cvf_ == 0)
00213 {
00214 ACE_SYNCH_RW_MUTEX &lock =
00215 *ACE_Managed_Object<ACE_SYNCH_RW_MUTEX>::get_preallocated_object
00216 (ACE_Object_Manager::ACE_FILECACHE_LOCK);
00217 ACE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX, ace_mon, lock, 0);
00218
00219
00220
00221 if (ACE_Filecache::cvf_ == 0)
00222 ACE_NEW_RETURN (ACE_Filecache::cvf_,
00223 ACE_Filecache,
00224 0);
00225 }
00226
00227 return ACE_Filecache::cvf_;
00228 }
00229
00230 ACE_Filecache::ACE_Filecache (void)
00231 : size_ (ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE),
00232 hash_ (size_)
00233 {
00234 }
00235
00236 ACE_Filecache::~ACE_Filecache (void)
00237 {
00238 }
00239
00240 ACE_Filecache_Object *
00241 ACE_Filecache::insert_i (const ACE_TCHAR *filename,
00242 ACE_SYNCH_RW_MUTEX &filelock,
00243 int mapit)
00244 {
00245 ACE_Filecache_Object *handle = 0;
00246
00247 if (this->hash_.find (filename, handle) == -1)
00248 {
00249 ACE_NEW_RETURN (handle,
00250 ACE_Filecache_Object (filename, filelock, 0, mapit),
00251 0);
00252
00253
00254
00255 if (this->hash_.bind (filename, handle) == -1)
00256 {
00257 delete handle;
00258 handle = 0;
00259 }
00260 }
00261 else
00262 handle = 0;
00263
00264 return handle;
00265 }
00266
00267 ACE_Filecache_Object *
00268 ACE_Filecache::remove_i (const ACE_TCHAR *filename)
00269 {
00270 ACE_Filecache_Object *handle = 0;
00271
00272
00273 if (this->hash_.unbind (filename, handle) == 0)
00274 {
00275 handle->stale_ = 1;
00276
00277
00278
00279 if (handle->lock_.tryacquire_write () == 0)
00280 {
00281 delete handle;
00282 handle = 0;
00283 }
00284 }
00285 else
00286 handle = 0;
00287
00288 return handle;
00289 }
00290
00291 ACE_Filecache_Object *
00292 ACE_Filecache::update_i (const ACE_TCHAR *filename,
00293 ACE_SYNCH_RW_MUTEX &filelock,
00294 int mapit)
00295 {
00296 ACE_Filecache_Object *handle = 0;
00297
00298 handle = this->remove_i (filename);
00299 handle = this->insert_i (filename, filelock, mapit);
00300
00301 return handle;
00302 }
00303
00304 int
00305 ACE_Filecache::find (const ACE_TCHAR *filename)
00306 {
00307 return this->hash_.find (filename);
00308 }
00309
00310
00311 ACE_Filecache_Object *
00312 ACE_Filecache::remove (const ACE_TCHAR *filename)
00313 {
00314 ACE_Filecache_Object *handle = 0;
00315
00316 ACE_OFF_T loc = ACE::hash_pjw (filename) % this->size_;
00317 ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
00318
00319
00320 if (this->hash_.find (filename, handle) != -1)
00321 {
00322 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
00323 ace_mon,
00324 hashlock,
00325 0);
00326
00327 return this->remove_i (filename);
00328 }
00329
00330 return 0;
00331 }
00332
00333
00334 ACE_Filecache_Object *
00335 ACE_Filecache::fetch (const ACE_TCHAR *filename, int mapit)
00336 {
00337 ACE_Filecache_Object *handle = 0;
00338
00339 ACE_OFF_T loc = ACE::hash_pjw (filename) % this->size_;
00340 ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
00341 ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc];
00342
00343 filelock.acquire_read ();
00344
00345 if (this->hash_.find (filename, handle) == -1)
00346 {
00347 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
00348 ace_mon,
00349 hashlock,
00350 0);
00351
00352
00353 handle = this->insert_i (filename, filelock, mapit);
00354
00355 if (handle == 0)
00356 filelock.release ();
00357 }
00358 else
00359 {
00360 if (handle->update ())
00361 {
00362 {
00363
00364 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
00365 ace_mon,
00366 hashlock,
00367 0);
00368
00369
00370 handle = this->update_i (filename, filelock, mapit);
00371
00372 if (handle == 0)
00373 filelock.release ();
00374 }
00375 }
00376
00377 }
00378
00379 return handle;
00380 }
00381
00382 ACE_Filecache_Object *
00383 ACE_Filecache::create (const ACE_TCHAR *filename, int size)
00384 {
00385 ACE_Filecache_Object *handle = 0;
00386
00387 ACE_OFF_T loc = ACE::hash_pjw (filename) % this->size_;
00388 ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc];
00389
00390 ACE_NEW_RETURN (handle,
00391 ACE_Filecache_Object (filename, size, filelock),
00392 0);
00393 handle->acquire ();
00394
00395 return handle;
00396 }
00397
00398 ACE_Filecache_Object *
00399 ACE_Filecache::finish (ACE_Filecache_Object *&file)
00400 {
00401 if (file == 0)
00402 return file;
00403
00404 ACE_OFF_T loc = ACE::hash_pjw (file->filename_) % this->size_;
00405 ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc];
00406
00407 if (file != 0)
00408 switch (file->action_)
00409 {
00410 case ACE_Filecache_Object::ACE_WRITING:
00411 {
00412 ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX,
00413 ace_mon,
00414 hashlock,
00415 0);
00416
00417 file->release ();
00418
00419 this->remove_i (file->filename_);
00420 #if 0
00421 int result = this->hash_.bind (file->filename (), file);
00422
00423 if (result == 0)
00424 file->acquire ();
00425 #else
00426
00427 if (file->stale_)
00428 {
00429
00430
00431 if (file->lock_.tryacquire_write () == 0)
00432 {
00433 delete file;
00434 file = 0;
00435 }
00436 }
00437 #endif
00438 }
00439
00440 break;
00441 default:
00442 file->release ();
00443
00444
00445 if (file->stale_)
00446 {
00447
00448
00449 if (file->lock_.tryacquire_write () == 0)
00450 {
00451 delete file;
00452 file = 0;
00453 }
00454 }
00455
00456 break;
00457 }
00458
00459 return file;
00460 }
00461
00462 void
00463 ACE_Filecache_Object::init (void)
00464 {
00465 this->filename_[0] = '\0';
00466 this->handle_ = ACE_INVALID_HANDLE;
00467 this->error_ = ACE_SUCCESS;
00468 this->tempname_ = 0;
00469 this->size_ = 0;
00470
00471 ACE_OS::memset (&(this->stat_), 0, sizeof (this->stat_));
00472 }
00473
00474 ACE_Filecache_Object::ACE_Filecache_Object (void)
00475 : tempname_ (0),
00476 mmap_ (),
00477 handle_ (0),
00478
00479 size_ (0),
00480 action_ (0),
00481 error_ (0),
00482 stale_ (0),
00483
00484 junklock_ (),
00485 lock_ (junklock_)
00486 {
00487 this->init ();
00488 }
00489
00490 ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename,
00491 ACE_SYNCH_RW_MUTEX &lock,
00492 LPSECURITY_ATTRIBUTES sa,
00493 int mapit)
00494 : tempname_ (0),
00495 mmap_ (),
00496 handle_ (0),
00497
00498 size_ (0),
00499 action_ (0),
00500 error_ (0),
00501 stale_ (0),
00502 sa_ (sa),
00503 junklock_ (),
00504 lock_ (lock)
00505 {
00506 this->init ();
00507
00508
00509 ACE_OS::strcpy (this->filename_, filename);
00510 this->action_ = ACE_Filecache_Object::ACE_READING;
00511
00512
00513
00514 if (ACE_OS::access (this->filename_, R_OK) == -1)
00515 {
00516 this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED);
00517 return;
00518 }
00519
00520
00521 if (ACE_OS::stat (this->filename_, &this->stat_) == -1)
00522 {
00523 this->error_i (ACE_Filecache_Object::ACE_STAT_FAILED);
00524 return;
00525 }
00526
00527 this->size_ = ACE_Utils::truncate_cast<ACE_OFF_T> (this->stat_.st_size);
00528 this->tempname_ = this->filename_;
00529
00530
00531 this->handle_ = ACE_OS::open (this->tempname_,
00532 READ_FLAGS, R_MASK, this->sa_);
00533 if (this->handle_ == ACE_INVALID_HANDLE)
00534 {
00535 this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED,
00536 ACE_TEXT ("ACE_Filecache_Object::ctor: open"));
00537 return;
00538 }
00539
00540 if (mapit)
00541 {
00542
00543 if (this->mmap_.map (this->handle_, static_cast<size_t> (-1),
00544 PROT_READ, ACE_MAP_PRIVATE, 0, 0, this->sa_) != 0)
00545 {
00546 this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED,
00547 ACE_TEXT ("ACE_Filecache_Object::ctor: map"));
00548 ACE_OS::close (this->handle_);
00549 this->handle_ = ACE_INVALID_HANDLE;
00550 return;
00551 }
00552 }
00553
00554
00555 this->action_ = ACE_Filecache_Object::ACE_READING;
00556 }
00557
00558 ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename,
00559 ACE_OFF_T size,
00560 ACE_SYNCH_RW_MUTEX &lock,
00561 LPSECURITY_ATTRIBUTES sa)
00562 : stale_ (0),
00563 sa_ (sa),
00564 lock_ (lock)
00565 {
00566 this->init ();
00567
00568 this->size_ = size;
00569 ACE_OS::strcpy (this->filename_, filename);
00570 this->action_ = ACE_Filecache_Object::ACE_WRITING;
00571
00572
00573 if (ACE_OS::access (this->filename_, R_OK|W_OK) == -1
00574
00575 && ACE_OS::access (this->filename_, F_OK) != -1)
00576 {
00577
00578 this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED);
00579 return;
00580 }
00581
00582 this->tempname_ = this->filename_;
00583
00584
00585 this->handle_ = ACE_OS::open (this->tempname_, WRITE_FLAGS, W_MASK, this->sa_);
00586 if (this->handle_ == ACE_INVALID_HANDLE)
00587 {
00588 this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED,
00589 ACE_TEXT ("ACE_Filecache_Object::acquire: open"));
00590 return;
00591 }
00592
00593
00594 if (ACE_OS::pwrite (this->handle_, "", 1, this->size_ - 1) != 1)
00595 {
00596 this->error_i (ACE_Filecache_Object::ACE_WRITE_FAILED,
00597 ACE_TEXT ("ACE_Filecache_Object::acquire: write"));
00598 ACE_OS::close (this->handle_);
00599 return;
00600 }
00601
00602
00603 if (this->mmap_.map (this->handle_, this->size_, PROT_RDWR, MAP_SHARED,
00604 0, 0, this->sa_) != 0)
00605 {
00606 this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED,
00607 ACE_TEXT ("ACE_Filecache_Object::acquire: map"));
00608 ACE_OS::close (this->handle_);
00609 }
00610
00611
00612 }
00613
00614 ACE_Filecache_Object::~ACE_Filecache_Object (void)
00615 {
00616 if (this->error_ == ACE_SUCCESS)
00617 {
00618 this->mmap_.unmap ();
00619 ACE_OS::close (this->handle_);
00620 this->handle_ = ACE_INVALID_HANDLE;
00621 }
00622
00623 this->lock_.release ();
00624 }
00625
00626 int
00627 ACE_Filecache_Object::acquire (void)
00628 {
00629 return this->lock_.tryacquire_read ();
00630 }
00631
00632 int
00633 ACE_Filecache_Object::release (void)
00634 {
00635 if (this->action_ == ACE_WRITING)
00636 {
00637
00638
00639 #if 0
00640 ACE_HANDLE original = ACE_OS::open (this->filename_, WRITE_FLAGS, W_MASK,
00641 this->sa_);
00642 if (original == ACE_INVALID_HANDLE)
00643 this->error_ = ACE_Filecache_Object::ACE_OPEN_FAILED;
00644 else if (ACE_OS::write (original, this->mmap_.addr (),
00645 this->size_) == -1)
00646 {
00647 this->error_ = ACE_Filecache_Object::ACE_WRITE_FAILED;
00648 ACE_OS::close (original);
00649 ACE_OS::unlink (this->filename_);
00650 }
00651 else if (ACE_OS::stat (this->filename_, &this->stat_) == -1)
00652 this->error_ = ACE_Filecache_Object::ACE_STAT_FAILED;
00653 #endif
00654
00655 this->mmap_.unmap ();
00656 ACE_OS::close (this->handle_);
00657 this->handle_ = ACE_INVALID_HANDLE;
00658
00659 #if 0
00660
00661 this->handle_ = ACE_OS::open (this->tempname_, READ_FLAGS, R_MASK);
00662 if (this->handle_ == ACE_INVALID_HANDLE)
00663 {
00664 this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED,
00665 "ACE_Filecache_Object::acquire: open");
00666 }
00667 else if (this->mmap_.map (this->handle_, -1,
00668 PROT_READ,
00669 ACE_MAP_PRIVATE,
00670 0,
00671 0,
00672 this->sa_) != 0)
00673 {
00674 this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED,
00675 "ACE_Filecache_Object::acquire: map");
00676 ACE_OS::close (this->handle_);
00677 this->handle_ = ACE_INVALID_HANDLE;
00678 }
00679
00680 this->action_ = ACE_Filecache_Object::ACE_READING;
00681 #endif
00682 }
00683
00684 return this->lock_.release ();
00685 }
00686
00687 int
00688 ACE_Filecache_Object::error (void) const
00689 {
00690
00691 return this->error_;
00692 }
00693
00694 int
00695 ACE_Filecache_Object::error_i (int error_value, const ACE_TCHAR *s)
00696 {
00697 s = s;
00698 ACE_ERROR ((LM_ERROR, ACE_TEXT ("%p.\n"), s));
00699 this->error_ = error_value;
00700 return error_value;
00701 }
00702
00703 const ACE_TCHAR *
00704 ACE_Filecache_Object::filename (void) const
00705 {
00706
00707 return this->filename_;
00708 }
00709
00710 ACE_OFF_T
00711 ACE_Filecache_Object::size (void) const
00712 {
00713
00714 return this->size_;
00715 }
00716
00717 ACE_HANDLE
00718 ACE_Filecache_Object::handle (void) const
00719 {
00720
00721 return this->handle_;
00722 }
00723
00724 void *
00725 ACE_Filecache_Object::address (void) const
00726 {
00727
00728 return this->mmap_.addr ();
00729 }
00730
00731 int
00732 ACE_Filecache_Object::update (void) const
00733 {
00734
00735 int result;
00736 ACE_stat statbuf;
00737
00738 if (ACE_OS::stat (this->filename_, &statbuf) == -1)
00739 result = 1;
00740 else
00741
00742 #if defined (ACE_HAS_WINCE)
00743
00744
00745
00746 result = 1;
00747 #else
00748 result = ACE_OS::difftime (this->stat_.st_mtime, statbuf.st_mtime) < 0;
00749 #endif
00750
00751 return result;
00752 }
00753
00754 ACE_END_VERSIONED_NAMESPACE_DECL