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
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
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 }
00233
00234 #endif