00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
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
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 }
00271
00272 #endif