OpenFdCache.h

Go to the documentation of this file.
00001 #ifndef __OPENFDCACHE_H__
00002 #define __OPENFDCACHE_H__
00003 
00004 #include <map>
00005 
00006 #include "../debug/Logger.h"
00007 #include "../thread/SpinLock.h"
00008 #include "../io/IO.h"
00009 #include "../util/LRUList.h"
00010 
00011 namespace oasys {
00012 
00013 struct OpenFdCacheClose {
00014     static void close(int fd) {
00015 //        log_debug("/OpenFdCacheClose", "closed %d", fd);
00016         IO::close(fd);
00017     }
00018 };
00019 
00024 template<typename _Key, typename _CloseFcn = OpenFdCacheClose>
00025 class OpenFdCache : Logger {
00026 public:
00030     struct FdListEnt {
00031         FdListEnt(const _Key& key,
00032                   int fd        = -1,
00033                   int pin_count = 0)
00034             : key_(key), fd_(fd), pin_count_(pin_count)
00035         {}
00036         
00037         _Key key_;
00038         int  fd_;
00039         int  pin_count_;
00040     };
00041 
00042     typedef LRUList<FdListEnt>                        FdList;
00043     typedef std::map<_Key, typename FdList::iterator> FdMap;
00044 
00045     OpenFdCache(const char* logpath,
00046                 size_t      max)
00047         : Logger("OpenFdCache", "%s/%s", logpath, "cache"),
00048           max_(max)
00049     {}
00050 
00055     int get_and_pin(const _Key& key) 
00056     {
00057         ScopeLock l(&lock_, "OpenFdCache::get_and_pin");
00058 
00059         typename FdMap::iterator i = open_fds_map_.find(key);
00060         if (i == open_fds_map_.end()) 
00061         {
00062             return -1;
00063         }
00064         
00065         open_fds_.move_to_back(i->second);
00066         ++(i->second->pin_count_);
00067 
00068         log_debug("Got entry fd=%d pin_count=%d size=%u", 
00069                   i->second->fd_, 
00070                   i->second->pin_count_,
00071                   (u_int)open_fds_map_.size());
00072 
00073         ASSERT(i->second->fd_ != -1);
00074 
00075         return i->second->fd_;
00076     }
00077 
00081     void unpin(const _Key& key) 
00082     {
00083         ScopeLock l(&lock_, "OpenFdCache::unpin");
00084 
00085         typename FdMap::iterator i = open_fds_map_.find(key);
00086         ASSERT(i != open_fds_map_.end());
00087         
00088         --(i->second->pin_count_);
00089 
00090         log_debug("Unpin entry fd=%d pin_count=%d size=%u", 
00091                   i->second->fd_, 
00092                   i->second->pin_count_,
00093                   (u_int)open_fds_map_.size());
00094     }
00095 
00107     int put_and_pin(const _Key& key, int fd) 
00108     {
00109         ScopeLock l(&lock_, "OpenFdCache::put_and_pin");
00110 
00111         ASSERT(fd != -1);
00112 
00113         typename FdMap::iterator i = open_fds_map_.find(key);
00114         if (i != open_fds_map_.end()) 
00115         {
00116             ++(i->second->pin_count_);
00117             log_debug("Added entry but already there fd=%d pin_count=%d size=%u", 
00118                       i->second->fd_, 
00119                       i->second->pin_count_,
00120                       (u_int)open_fds_map_.size());
00121 
00122             return i->second->fd_;
00123         }
00124 
00125         while (open_fds_map_.size() + 1> max_) 
00126         {
00127             if (evict() == -1) 
00128             {
00129                 break;
00130             }
00131         }
00132         
00133         // start off with pin count 1
00134         typename FdList::iterator new_ent = open_fds_.insert(open_fds_.end(),
00135                                                              FdListEnt(key, fd, 1));
00136         log_debug("Added entry fd=%d pin_count=%d size=%u", 
00137                   new_ent->fd_, 
00138                   new_ent->pin_count_,
00139                   (u_int)open_fds_map_.size());
00140 
00141         open_fds_map_[key] = new_ent;
00142 
00143         return fd;
00144     }
00145 
00149     void close(const _Key& key) 
00150     {
00151         typename FdMap::iterator i = open_fds_map_.find(key);
00152 
00153         if (i == open_fds_map_.end()) 
00154         {
00155             return;
00156         }
00157 
00158         _CloseFcn::close(i->second->fd_);
00159         log_debug("Closed %d size=%u", i->second->fd_, (u_int)open_fds_map_.size());
00160 
00161         open_fds_.erase(i->second);
00162         open_fds_map_.erase(i);       
00163     }
00164     
00168     void close_all() {
00169         log_debug("There were %u open fds upon close.", open_fds_.size());
00170         
00171         for (typename FdList::iterator i = open_fds_.begin(); 
00172              i != open_fds_.end(); ++i)
00173         {
00174             if (i->pin_count_ > 0) {
00175                 log_warn("fd=%d was busy", i->fd_);
00176             }
00177 
00178             log_debug("Closing fd=%d", i->fd_);
00179             _CloseFcn::close(i->fd_);
00180         }
00181 
00182         open_fds_.clear();
00183         open_fds_map_.clear();
00184     }
00185 
00186 private:
00187     SpinLock lock_;
00188 
00189     FdList open_fds_;
00190     FdMap  open_fds_map_;
00191 
00192     size_t max_;
00193 
00201     int evict()
00202     {
00203         bool found = false;
00204         typename FdList::iterator i;
00205         for (i = open_fds_.begin(); i != open_fds_.end(); ++i)
00206         {
00207             if (i->pin_count_ == 0) {
00208                 found = true;
00209                 break;
00210             }
00211         }
00212         
00213         if (found) 
00214         {
00215             ASSERT(i->fd_ < 8*1024);
00216             
00217             log_debug("Evicting fd=%d size=%u", i->fd_, (u_int)open_fds_map_.size());
00218             _CloseFcn::close(i->fd_);
00219             open_fds_map_.erase(i->key_);
00220             open_fds_.erase(i);
00221         }
00222         else
00223         {
00224             log_warn("All of the fds are busy! size=%u", (u_int)open_fds_map_.size());
00225             return -1;
00226         }
00227 
00228         return 0;
00229     }
00230 };
00231 
00232 } // namespace oasys
00233 
00234 #endif /* __OPENFDCACHE_H__ */

Generated on Fri Dec 22 14:48:00 2006 for DTN Reference Implementation by  doxygen 1.5.1