1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H 18 #define ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H 19 20 #include <utils/Condition.h> 21 #include <utils/Mutex.h> 22 #include <utils/Timers.h> 23 24 #include <algorithm> 25 #include <utility> 26 #include <vector> 27 #include <set> 28 #include <map> 29 #include <memory> 30 31 namespace android { 32 namespace resource_policy { 33 34 // -------------------------------------------------------------------------------- 35 36 /** 37 * The ClientDescriptor class is a container for a given key/value pair identifying a shared 38 * resource, and the corresponding cost, priority, owner ID, and conflicting keys list used 39 * in determining eviction behavior. 40 * 41 * Aside from the priority, these values are immutable once the ClientDescriptor has been 42 * constructed. 43 */ 44 template<class KEY, class VALUE> 45 class ClientDescriptor final { 46 public: 47 ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost, 48 const std::set<KEY>& conflictingKeys, int32_t priority, int32_t ownerId); 49 ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, std::set<KEY>&& conflictingKeys, 50 int32_t priority, int32_t ownerId); 51 52 ~ClientDescriptor(); 53 54 /** 55 * Return the key for this descriptor. 56 */ 57 const KEY& getKey() const; 58 59 /** 60 * Return the value for this descriptor. 61 */ 62 const VALUE& getValue() const; 63 64 /** 65 * Return the cost for this descriptor. 66 */ 67 int32_t getCost() const; 68 69 /** 70 * Return the priority for this descriptor. 71 */ 72 int32_t getPriority() const; 73 74 /** 75 * Return the owner ID for this descriptor. 76 */ 77 int32_t getOwnerId() const; 78 79 /** 80 * Return true if the given key is in this descriptor's conflicting keys list. 81 */ 82 bool isConflicting(const KEY& key) const; 83 84 /** 85 * Return the set of all conflicting keys for this descriptor. 86 */ 87 std::set<KEY> getConflicting() const; 88 89 /** 90 * Set the proirity for this descriptor. 91 */ 92 void setPriority(int32_t priority); 93 94 // This class is ordered by key 95 template<class K, class V> 96 friend bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b); 97 98 private: 99 KEY mKey; 100 VALUE mValue; 101 int32_t mCost; 102 std::set<KEY> mConflicting; 103 int32_t mPriority; 104 int32_t mOwnerId; 105 }; // class ClientDescriptor 106 107 template<class K, class V> 108 bool operator < (const ClientDescriptor<K, V>& a, const ClientDescriptor<K, V>& b) { 109 return a.mKey < b.mKey; 110 } 111 112 template<class KEY, class VALUE> 113 ClientDescriptor<KEY, VALUE>::ClientDescriptor(const KEY& key, const VALUE& value, int32_t cost, 114 const std::set<KEY>& conflictingKeys, int32_t priority, int32_t ownerId) : mKey{key}, 115 mValue{value}, mCost{cost}, mConflicting{conflictingKeys}, mPriority{priority}, 116 mOwnerId{ownerId} {} 117 118 template<class KEY, class VALUE> 119 ClientDescriptor<KEY, VALUE>::ClientDescriptor(KEY&& key, VALUE&& value, int32_t cost, 120 std::set<KEY>&& conflictingKeys, int32_t priority, int32_t ownerId) : 121 mKey{std::forward<KEY>(key)}, mValue{std::forward<VALUE>(value)}, mCost{cost}, 122 mConflicting{std::forward<std::set<KEY>>(conflictingKeys)}, mPriority{priority}, 123 mOwnerId{ownerId} {} 124 125 template<class KEY, class VALUE> 126 ClientDescriptor<KEY, VALUE>::~ClientDescriptor() {} 127 128 template<class KEY, class VALUE> 129 const KEY& ClientDescriptor<KEY, VALUE>::getKey() const { 130 return mKey; 131 } 132 133 template<class KEY, class VALUE> 134 const VALUE& ClientDescriptor<KEY, VALUE>::getValue() const { 135 return mValue; 136 } 137 138 template<class KEY, class VALUE> 139 int32_t ClientDescriptor<KEY, VALUE>::getCost() const { 140 return mCost; 141 } 142 143 template<class KEY, class VALUE> 144 int32_t ClientDescriptor<KEY, VALUE>::getPriority() const { 145 return mPriority; 146 } 147 148 template<class KEY, class VALUE> 149 int32_t ClientDescriptor<KEY, VALUE>::getOwnerId() const { 150 return mOwnerId; 151 } 152 153 template<class KEY, class VALUE> 154 bool ClientDescriptor<KEY, VALUE>::isConflicting(const KEY& key) const { 155 if (key == mKey) return true; 156 for (const auto& x : mConflicting) { 157 if (key == x) return true; 158 } 159 return false; 160 } 161 162 template<class KEY, class VALUE> 163 std::set<KEY> ClientDescriptor<KEY, VALUE>::getConflicting() const { 164 return mConflicting; 165 } 166 167 template<class KEY, class VALUE> 168 void ClientDescriptor<KEY, VALUE>::setPriority(int32_t priority) { 169 mPriority = priority; 170 } 171 172 // -------------------------------------------------------------------------------- 173 174 /** 175 * A default class implementing the LISTENER interface used by ClientManager. 176 */ 177 template<class KEY, class VALUE> 178 class DefaultEventListener { 179 public: 180 void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor); 181 void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor); 182 }; 183 184 template<class KEY, class VALUE> 185 void DefaultEventListener<KEY, VALUE>::onClientAdded( 186 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {} 187 188 template<class KEY, class VALUE> 189 void DefaultEventListener<KEY, VALUE>::onClientRemoved( 190 const ClientDescriptor<KEY, VALUE>& /*descriptor*/) {} 191 192 // -------------------------------------------------------------------------------- 193 194 /** 195 * The ClientManager class wraps an LRU-ordered list of active clients and implements eviction 196 * behavior for handling shared resource access. 197 * 198 * When adding a new descriptor, eviction behavior is as follows: 199 * - Keys are unique, adding a descriptor with the same key as an existing descriptor will 200 * result in the lower-priority of the two being removed. Priority ties result in the 201 * LRU descriptor being evicted (this means the incoming descriptor be added in this case). 202 * - Any descriptors with keys that are in the incoming descriptor's 'conflicting keys' list 203 * will be removed if they have an equal or lower priority than the incoming descriptor; 204 * if any have a higher priority, the incoming descriptor is removed instead. 205 * - If the sum of all descriptors' costs, including the incoming descriptor's, is more than 206 * the max cost allowed for this ClientManager, descriptors with non-zero cost, equal or lower 207 * priority, and a different owner will be evicted in LRU order until either the cost is less 208 * than the max cost, or all descriptors meeting this criteria have been evicted and the 209 * incoming descriptor has the highest priority. Otherwise, the incoming descriptor is 210 * removed instead. 211 */ 212 template<class KEY, class VALUE, class LISTENER=DefaultEventListener<KEY, VALUE>> 213 class ClientManager { 214 public: 215 // The default maximum "cost" allowed before evicting 216 static constexpr int32_t DEFAULT_MAX_COST = 100; 217 218 ClientManager(); 219 ClientManager(int32_t totalCost); 220 221 /** 222 * Add a given ClientDescriptor to the managed list. ClientDescriptors for clients that 223 * are evicted by this action are returned in a vector. 224 * 225 * This may return the ClientDescriptor passed in if it would be evicted. 226 */ 227 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> addAndEvict( 228 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client); 229 230 /** 231 * Given a map containing owner (pid) -> priority mappings, update the priority of each 232 * ClientDescriptor with an owner in this mapping. 233 */ 234 void updatePriorities(const std::map<int32_t,int32_t>& ownerPriorityList); 235 236 /** 237 * Remove all ClientDescriptors. 238 */ 239 void removeAll(); 240 241 /** 242 * Remove and return the ClientDescriptor with a given key. 243 */ 244 std::shared_ptr<ClientDescriptor<KEY, VALUE>> remove(const KEY& key); 245 246 /** 247 * Remove the given ClientDescriptor. 248 */ 249 void remove(const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value); 250 251 /** 252 * Return a vector of the ClientDescriptors that would be evicted by adding the given 253 * ClientDescriptor. 254 * 255 * This may return the ClientDescriptor passed in if it would be evicted. 256 */ 257 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvict( 258 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const; 259 260 /** 261 * Return a vector of active ClientDescriptors that prevent this client from being added. 262 */ 263 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getIncompatibleClients( 264 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const; 265 266 /** 267 * Return a vector containing all currently active ClientDescriptors. 268 */ 269 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> getAll() const; 270 271 /** 272 * Return a vector containing all keys of currently active ClientDescriptors. 273 */ 274 std::vector<KEY> getAllKeys() const; 275 276 /** 277 * Return a vector of the owner tags of all currently active ClientDescriptors (duplicates 278 * will be removed). 279 */ 280 std::vector<int32_t> getAllOwners() const; 281 282 /** 283 * Return the ClientDescriptor corresponding to the given key, or an empty shared pointer 284 * if none exists. 285 */ 286 std::shared_ptr<ClientDescriptor<KEY, VALUE>> get(const KEY& key) const; 287 288 /** 289 * Block until the given client is no longer in the active clients list, or the timeout 290 * occurred. 291 * 292 * Returns NO_ERROR if this succeeded, -ETIMEDOUT on a timeout, or a negative error code on 293 * failure. 294 */ 295 status_t waitUntilRemoved(const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client, 296 nsecs_t timeout) const; 297 298 /** 299 * Set the current listener for client add/remove events. 300 * 301 * The listener instance must inherit from the LISTENER class and implement the following 302 * methods: 303 * void onClientRemoved(const ClientDescriptor<KEY, VALUE>& descriptor); 304 * void onClientAdded(const ClientDescriptor<KEY, VALUE>& descriptor); 305 * 306 * These callback methods will be called with the ClientManager's lock held, and should 307 * not call any further ClientManager methods. 308 * 309 * The onClientRemoved method will be called when the client has been removed or evicted 310 * from the ClientManager that this event listener has been added to. The onClientAdded 311 * method will be called when the client has been added to the ClientManager that this 312 * event listener has been added to. 313 */ 314 void setListener(const std::shared_ptr<LISTENER>& listener); 315 316 protected: 317 ~ClientManager(); 318 319 private: 320 321 /** 322 * Return a vector of the ClientDescriptors that would be evicted by adding the given 323 * ClientDescriptor. If returnIncompatibleClients is set to true, instead, return the 324 * vector of ClientDescriptors that are higher priority than the incoming client and 325 * either conflict with this client, or contribute to the resource cost if that would 326 * prevent the incoming client from being added. 327 * 328 * This may return the ClientDescriptor passed in. 329 */ 330 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> wouldEvictLocked( 331 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client, 332 bool returnIncompatibleClients = false) const; 333 334 int64_t getCurrentCostLocked() const; 335 336 mutable Mutex mLock; 337 mutable Condition mRemovedCondition; 338 int32_t mMaxCost; 339 // LRU ordered, most recent at end 340 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> mClients; 341 std::shared_ptr<LISTENER> mListener; 342 }; // class ClientManager 343 344 template<class KEY, class VALUE, class LISTENER> 345 ClientManager<KEY, VALUE, LISTENER>::ClientManager() : 346 ClientManager(DEFAULT_MAX_COST) {} 347 348 template<class KEY, class VALUE, class LISTENER> 349 ClientManager<KEY, VALUE, LISTENER>::ClientManager(int32_t totalCost) : mMaxCost(totalCost) {} 350 351 template<class KEY, class VALUE, class LISTENER> 352 ClientManager<KEY, VALUE, LISTENER>::~ClientManager() {} 353 354 template<class KEY, class VALUE, class LISTENER> 355 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 356 ClientManager<KEY, VALUE, LISTENER>::wouldEvict( 357 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const { 358 Mutex::Autolock lock(mLock); 359 return wouldEvictLocked(client); 360 } 361 362 template<class KEY, class VALUE, class LISTENER> 363 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 364 ClientManager<KEY, VALUE, LISTENER>::getIncompatibleClients( 365 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) const { 366 Mutex::Autolock lock(mLock); 367 return wouldEvictLocked(client, /*returnIncompatibleClients*/true); 368 } 369 370 template<class KEY, class VALUE, class LISTENER> 371 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 372 ClientManager<KEY, VALUE, LISTENER>::wouldEvictLocked( 373 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client, 374 bool returnIncompatibleClients) const { 375 376 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> evictList; 377 378 // Disallow null clients, return input 379 if (client == nullptr) { 380 evictList.push_back(client); 381 return evictList; 382 } 383 384 const KEY& key = client->getKey(); 385 int32_t cost = client->getCost(); 386 int32_t priority = client->getPriority(); 387 int32_t owner = client->getOwnerId(); 388 389 int64_t totalCost = getCurrentCostLocked() + cost; 390 391 // Determine the MRU of the owners tied for having the highest priority 392 int32_t highestPriorityOwner = owner; 393 int32_t highestPriority = priority; 394 for (const auto& i : mClients) { 395 int32_t curPriority = i->getPriority(); 396 if (curPriority >= highestPriority) { 397 highestPriority = curPriority; 398 highestPriorityOwner = i->getOwnerId(); 399 } 400 } 401 402 if (highestPriority == priority) { 403 // Switch back owner if the incoming client has the highest priority, as it is MRU 404 highestPriorityOwner = owner; 405 } 406 407 // Build eviction list of clients to remove 408 for (const auto& i : mClients) { 409 const KEY& curKey = i->getKey(); 410 int32_t curCost = i->getCost(); 411 int32_t curPriority = i->getPriority(); 412 int32_t curOwner = i->getOwnerId(); 413 414 bool conflicting = (curKey == key || i->isConflicting(key) || 415 client->isConflicting(curKey)); 416 417 if (!returnIncompatibleClients) { 418 // Find evicted clients 419 420 if (conflicting && curPriority > priority) { 421 // Pre-existing conflicting client with higher priority exists 422 evictList.clear(); 423 evictList.push_back(client); 424 return evictList; 425 } else if (conflicting || ((totalCost > mMaxCost && curCost > 0) && 426 (curPriority <= priority) && 427 !(highestPriorityOwner == owner && owner == curOwner))) { 428 // Add a pre-existing client to the eviction list if: 429 // - We are adding a client with higher priority that conflicts with this one. 430 // - The total cost including the incoming client's is more than the allowable 431 // maximum, and the client has a non-zero cost, lower priority, and a different 432 // owner than the incoming client when the incoming client has the 433 // highest priority. 434 evictList.push_back(i); 435 totalCost -= curCost; 436 } 437 } else { 438 // Find clients preventing the incoming client from being added 439 440 if (curPriority > priority && (conflicting || (totalCost > mMaxCost && curCost > 0))) { 441 // Pre-existing conflicting client with higher priority exists 442 evictList.push_back(i); 443 } 444 } 445 } 446 447 // Immediately return the incompatible clients if we are calculating these instead 448 if (returnIncompatibleClients) { 449 return evictList; 450 } 451 452 // If the total cost is too high, return the input unless the input has the highest priority 453 if (totalCost > mMaxCost && highestPriorityOwner != owner) { 454 evictList.clear(); 455 evictList.push_back(client); 456 return evictList; 457 } 458 459 return evictList; 460 461 } 462 463 template<class KEY, class VALUE, class LISTENER> 464 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 465 ClientManager<KEY, VALUE, LISTENER>::addAndEvict( 466 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& client) { 467 Mutex::Autolock lock(mLock); 468 auto evicted = wouldEvictLocked(client); 469 auto it = evicted.begin(); 470 if (it != evicted.end() && *it == client) { 471 return evicted; 472 } 473 474 auto iter = evicted.cbegin(); 475 476 if (iter != evicted.cend()) { 477 478 if (mListener != nullptr) mListener->onClientRemoved(**iter); 479 480 // Remove evicted clients from list 481 mClients.erase(std::remove_if(mClients.begin(), mClients.end(), 482 [&iter] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { 483 if (curClientPtr->getKey() == (*iter)->getKey()) { 484 iter++; 485 return true; 486 } 487 return false; 488 }), mClients.end()); 489 } 490 491 if (mListener != nullptr) mListener->onClientAdded(*client); 492 mClients.push_back(client); 493 mRemovedCondition.broadcast(); 494 495 return evicted; 496 } 497 498 template<class KEY, class VALUE, class LISTENER> 499 std::vector<std::shared_ptr<ClientDescriptor<KEY, VALUE>>> 500 ClientManager<KEY, VALUE, LISTENER>::getAll() const { 501 Mutex::Autolock lock(mLock); 502 return mClients; 503 } 504 505 template<class KEY, class VALUE, class LISTENER> 506 std::vector<KEY> ClientManager<KEY, VALUE, LISTENER>::getAllKeys() const { 507 Mutex::Autolock lock(mLock); 508 std::vector<KEY> keys(mClients.size()); 509 for (const auto& i : mClients) { 510 keys.push_back(i->getKey()); 511 } 512 return keys; 513 } 514 515 template<class KEY, class VALUE, class LISTENER> 516 std::vector<int32_t> ClientManager<KEY, VALUE, LISTENER>::getAllOwners() const { 517 Mutex::Autolock lock(mLock); 518 std::set<int32_t> owners; 519 for (const auto& i : mClients) { 520 owners.emplace(i->getOwnerId()); 521 } 522 return std::vector<int32_t>(owners.begin(), owners.end()); 523 } 524 525 template<class KEY, class VALUE, class LISTENER> 526 void ClientManager<KEY, VALUE, LISTENER>::updatePriorities( 527 const std::map<int32_t,int32_t>& ownerPriorityList) { 528 Mutex::Autolock lock(mLock); 529 for (auto& i : mClients) { 530 auto j = ownerPriorityList.find(i->getOwnerId()); 531 if (j != ownerPriorityList.end()) { 532 i->setPriority(j->second); 533 } 534 } 535 } 536 537 template<class KEY, class VALUE, class LISTENER> 538 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::get( 539 const KEY& key) const { 540 Mutex::Autolock lock(mLock); 541 for (const auto& i : mClients) { 542 if (i->getKey() == key) return i; 543 } 544 return std::shared_ptr<ClientDescriptor<KEY, VALUE>>(nullptr); 545 } 546 547 template<class KEY, class VALUE, class LISTENER> 548 void ClientManager<KEY, VALUE, LISTENER>::removeAll() { 549 Mutex::Autolock lock(mLock); 550 if (mListener != nullptr) { 551 for (const auto& i : mClients) { 552 mListener->onClientRemoved(*i); 553 } 554 } 555 mClients.clear(); 556 mRemovedCondition.broadcast(); 557 } 558 559 template<class KEY, class VALUE, class LISTENER> 560 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ClientManager<KEY, VALUE, LISTENER>::remove( 561 const KEY& key) { 562 Mutex::Autolock lock(mLock); 563 564 std::shared_ptr<ClientDescriptor<KEY, VALUE>> ret; 565 566 // Remove evicted clients from list 567 mClients.erase(std::remove_if(mClients.begin(), mClients.end(), 568 [this, &key, &ret] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { 569 if (curClientPtr->getKey() == key) { 570 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr); 571 ret = curClientPtr; 572 return true; 573 } 574 return false; 575 }), mClients.end()); 576 577 mRemovedCondition.broadcast(); 578 return ret; 579 } 580 581 template<class KEY, class VALUE, class LISTENER> 582 status_t ClientManager<KEY, VALUE, LISTENER>::waitUntilRemoved( 583 const std::shared_ptr<ClientDescriptor<KEY, VALUE>> client, 584 nsecs_t timeout) const { 585 status_t ret = NO_ERROR; 586 Mutex::Autolock lock(mLock); 587 588 bool isRemoved = false; 589 590 // Figure out what time in the future we should hit the timeout 591 nsecs_t failTime = systemTime(SYSTEM_TIME_MONOTONIC) + timeout; 592 593 while (!isRemoved) { 594 isRemoved = true; 595 for (const auto& i : mClients) { 596 if (i == client) { 597 isRemoved = false; 598 } 599 } 600 601 if (!isRemoved) { 602 ret = mRemovedCondition.waitRelative(mLock, timeout); 603 if (ret != NO_ERROR) { 604 break; 605 } 606 timeout = failTime - systemTime(SYSTEM_TIME_MONOTONIC); 607 } 608 } 609 610 return ret; 611 } 612 613 template<class KEY, class VALUE, class LISTENER> 614 void ClientManager<KEY, VALUE, LISTENER>::setListener(const std::shared_ptr<LISTENER>& listener) { 615 Mutex::Autolock lock(mLock); 616 mListener = listener; 617 } 618 619 template<class KEY, class VALUE, class LISTENER> 620 void ClientManager<KEY, VALUE, LISTENER>::remove( 621 const std::shared_ptr<ClientDescriptor<KEY, VALUE>>& value) { 622 Mutex::Autolock lock(mLock); 623 // Remove evicted clients from list 624 mClients.erase(std::remove_if(mClients.begin(), mClients.end(), 625 [this, &value] (std::shared_ptr<ClientDescriptor<KEY, VALUE>>& curClientPtr) { 626 if (curClientPtr == value) { 627 if (mListener != nullptr) mListener->onClientRemoved(*curClientPtr); 628 return true; 629 } 630 return false; 631 }), mClients.end()); 632 mRemovedCondition.broadcast(); 633 } 634 635 template<class KEY, class VALUE, class LISTENER> 636 int64_t ClientManager<KEY, VALUE, LISTENER>::getCurrentCostLocked() const { 637 int64_t totalCost = 0; 638 for (const auto& x : mClients) { 639 totalCost += x->getCost(); 640 } 641 return totalCost; 642 } 643 644 // -------------------------------------------------------------------------------- 645 646 }; // namespace resource_policy 647 }; // namespace android 648 649 #endif // ANDROID_SERVICE_UTILS_EVICTION_POLICY_MANAGER_H 650