OpenFdCache.h

Go to the documentation of this file.
00001 /*
00002  *    Copyright 2006 Intel Corporation
00003  * 
00004  *    Licensed under the Apache License, Version 2.0 (the "License");
00005  *    you may not use this file except in compliance with the License.
00006  *    You may obtain a copy of the License at
00007  * 
00008  *        http://www.apache.org/licenses/LICENSE-2.0
00009  * 
00010  *    Unless required by applicable law or agreed to in writing, software
00011  *    distributed under the License is distributed on an "AS IS" BASIS,
00012  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *    See the License for the specific language governing permissions and
00014  *    limitations under the License.
00015  */
00016 
00017 #ifndef __OPENFDCACHE_H__
00018 #define __OPENFDCACHE_H__
00019 
00020 #include <map>
00021 
00022 #include "../debug/Logger.h"
00023 #include "../thread/SpinLock.h"
00024 #include "../io/IO.h"
00025 #include "../util/LRUList.h"
00026 
00027 namespace oasys {
00028 
00029 struct OpenFdCacheClose {
00030     static void close(int fd) {
00031 //        log_debug("/OpenFdCacheClose", "closed %d", fd);
00032         IO::close(fd);
00033     }
00034 };
00035 
00040 template<typename _Key, typename _CloseFcn = OpenFdCacheClose>
00041 class OpenFdCache : Logger {
00042 public:
00046     struct FdListEnt {
00047         FdListEnt(const _Key& key,
00048                   int fd        = -1,
00049                   int pin_count = 0)
00050             : key_(key), fd_(fd), pin_count_(pin_count)
00051         {}
00052         
00053         _Key key_;
00054         int  fd_;
00055         int  pin_count_;
00056     };
00057 
00058     typedef LRUList<FdListEnt>                        FdList;
00059     typedef std::map<_Key, typename FdList::iterator> FdMap;
00060 
00061     OpenFdCache(const char* logpath,
00062                 size_t      max)
00063         : Logger("OpenFdCache", "%s/%s", logpath, "cache"),
00064           max_(max)
00065     {}
00066 
00071     int get_and_pin(const _Key& key) 
00072     {
00073         ScopeLock l(&lock_, "OpenFdCache::get_and_pin");
00074 
00075         typename FdMap::iterator i = open_fds_map_.find(key);
00076         if (i == open_fds_map_.end()) 
00077         {
00078             return -1;
00079         }
00080         
00081         open_fds_.move_to_back(i->second);
00082         ++(i->second->pin_count_);
00083 
00084         log_debug("Got entry fd=%d pin_count=%d size=%u", 
00085                   i->second->fd_, 
00086                   i->second->pin_count_,
00087                   (u_int)open_fds_map_.size());
00088 
00089         ASSERT(i->second->fd_ != -1);
00090 
00091         return i->second->fd_;
00092     }
00093 
00097     void unpin(const _Key& key) 
00098     {
00099         ScopeLock l(&lock_, "OpenFdCache::unpin");
00100 
00101         typename FdMap::iterator i = open_fds_map_.find(key);
00102         ASSERT(i != open_fds_map_.end());
00103         
00104         --(i->second->pin_count_);
00105 
00106         log_debug("Unpin entry fd=%d pin_count=%d size=%u", 
00107                   i->second->fd_, 
00108                   i->second->pin_count_,
00109                   (u_int)open_fds_map_.size());
00110     }
00111 
00115     class ScopedUnpin {
00116     public:
00117         ScopedUnpin(OpenFdCache* cache, const _Key& key)
00118             : cache_(cache), key_(key) {}
00119 
00120         ~ScopedUnpin()
00121         {
00122             cache_->unpin(key_);
00123         }
00124 
00125     private:
00126         OpenFdCache* cache_;
00127         _Key         key_;
00128     };
00129 
00141     int put_and_pin(const _Key& key, int fd) 
00142     {
00143         ScopeLock l(&lock_, "OpenFdCache::put_and_pin");
00144 
00145         ASSERT(fd != -1);
00146 
00147         typename FdMap::iterator i = open_fds_map_.find(key);
00148         if (i != open_fds_map_.end()) 
00149         {
00150             ++(i->second->pin_count_);
00151             log_debug("Added entry but already there fd=%d pin_count=%d size=%u", 
00152                       i->second->fd_, 
00153                       i->second->pin_count_,
00154                       (u_int)open_fds_map_.size());
00155 
00156             return i->second->fd_;
00157         }
00158 
00159         while (open_fds_map_.size() + 1> max_) 
00160         {
00161             if (evict() == -1) 
00162             {
00163                 break;
00164             }
00165         }
00166         
00167         // start off with pin count 1
00168         typename FdList::iterator new_ent = open_fds_.insert(open_fds_.end(),
00169                                                              FdListEnt(key, fd, 1));
00170         log_debug("Added entry fd=%d pin_count=%d size=%u", 
00171                   new_ent->fd_, 
00172                   new_ent->pin_count_,
00173                   (u_int)open_fds_map_.size());
00174 
00175         open_fds_map_[key] = new_ent;
00176 
00177         return fd;
00178     }
00179 
00183     void close(const _Key& key) 
00184     {
00185         ScopeLock l(&lock_, "OpenFdCache::close");
00186         
00187         typename FdMap::iterator i = open_fds_map_.find(key);
00188 
00189         if (i == open_fds_map_.end()) 
00190         {
00191             return;
00192         }
00193 
00194         _CloseFcn::close(i->second->fd_);
00195         log_debug("Closed %d size=%u", i->second->fd_, (u_int)open_fds_map_.size());
00196 
00197         open_fds_.erase(i->second);
00198         open_fds_map_.erase(i);       
00199     }
00200     
00204     void close_all() {
00205         ScopeLock l(&lock_, "OpenFdCache::close_all");
00206         
00207         log_debug("There were %u open fds upon close.", open_fds_.size());
00208         
00209         for (typename FdList::iterator i = open_fds_.begin(); 
00210              i != open_fds_.end(); ++i)
00211         {
00212             if (i->pin_count_ > 0) {
00213                 log_warn("fd=%d was busy", i->fd_);
00214             }
00215 
00216             log_debug("Closing fd=%d", i->fd_);
00217             _CloseFcn::close(i->fd_);
00218         }
00219 
00220         open_fds_.clear();
00221         open_fds_map_.clear();
00222     }
00223 
00224 private:
00225     SpinLock lock_;
00226 
00227     FdList open_fds_;
00228     FdMap  open_fds_map_;
00229 
00230     size_t max_;
00231 
00239     int evict()
00240     {
00241         bool found = false;
00242         typename FdList::iterator i;
00243         for (i = open_fds_.begin(); i != open_fds_.end(); ++i)
00244         {
00245             if (i->pin_count_ == 0) {
00246                 found = true;
00247                 break;
00248             }
00249         }
00250         
00251         if (found) 
00252         {
00253             ASSERT(i->fd_ < 8*1024);
00254             
00255             log_debug("Evicting fd=%d size=%u", i->fd_, (u_int)open_fds_map_.size());
00256             _CloseFcn::close(i->fd_);
00257             open_fds_map_.erase(i->key_);
00258             open_fds_.erase(i);
00259         }
00260         else
00261         {
00262             log_warn("All of the fds are busy! size=%u", (u_int)open_fds_map_.size());
00263             return -1;
00264         }
00265 
00266         return 0;
00267     }
00268 };
00269 
00270 } // namespace oasys
00271 
00272 #endif /* __OPENFDCACHE_H__ */

Generated on Thu Jun 7 16:56:51 2007 for DTN Reference Implementation by  doxygen 1.5.1