1 module geario.util.pool.PooledObject; 2 3 import core.atomic; 4 import std.datetime; 5 6 import geario.util.pool.PooledObjectState; 7 8 /** 9 * Defines the wrapper that is used to track the additional information, such as 10 * state, for the pooled objects. 11 * <p> 12 * Implementations of this class are required to be thread-safe. 13 * 14 * @param <T> the type of object in the pool 15 * 16 */ 17 class PooledObject(T) { 18 private size_t _id; 19 private T _obj; 20 private PooledObjectState _state; 21 private SysTime _createTime; 22 private SysTime _lastBorrowTime; 23 private SysTime _lastUseTime; 24 private SysTime _lastReturnTime; 25 private shared long _borrowedCount = 0; 26 private static shared size_t _counter; 27 28 this(T obj) { 29 _obj = obj; 30 _state = PooledObjectState.IDLE; 31 _createTime = Clock.currTime; 32 _id = atomicOp!("+=")(_counter, 1); 33 } 34 35 size_t Id() { 36 return _id; 37 } 38 39 /** 40 * Obtains the underlying object that is wrapped by this instance of 41 * {@link PooledObject}. 42 * 43 * @return The wrapped object 44 */ 45 T GetObject() { 46 return _obj; 47 } 48 49 SysTime CreateTime() { 50 return _createTime; 51 } 52 53 SysTime LastBorrowTime() { 54 return _lastBorrowTime; 55 } 56 57 SysTime LastReturnTime() { 58 return _lastReturnTime; 59 } 60 61 /** 62 * Get the number of times this object has been borrowed. 63 * @return The number of times this object has been borrowed. 64 */ 65 long BorrowedCount() { 66 return _borrowedCount; 67 } 68 69 /** 70 * Returns the state of this object. 71 * @return state 72 */ 73 PooledObjectState State() { 74 return _state; 75 } 76 77 /** 78 * Allocates the object. 79 * 80 * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE} 81 */ 82 bool Allocate() { 83 if (_state == PooledObjectState.IDLE) { 84 _state = PooledObjectState.ALLOCATED; 85 _lastBorrowTime = Clock.currTime; 86 _lastUseTime = _lastBorrowTime; 87 atomicOp!("+=")(_borrowedCount, 1); 88 // if (logAbandoned) { 89 // borrowedBy.fillInStackTrace(); 90 // } 91 return true; 92 } 93 94 // else if (state == PooledObjectState.EVICTION) { 95 // // TODO Allocate anyway and ignore eviction test 96 // state = PooledObjectState.EVICTION_RETURN_TO_HEAD; 97 // return false; 98 // } 99 // TODO if validating and testOnBorrow == true then pre-allocate for 100 // performance 101 return false; 102 } 103 104 /** 105 * Deallocates the object and sets it {@link PooledObjectState#IDLE IDLE} 106 * if it is currently {@link PooledObjectState#ALLOCATED ALLOCATED}. 107 * 108 * @return {@code true} if the state was {@link PooledObjectState#ALLOCATED ALLOCATED} 109 */ 110 bool Deallocate() { 111 112 if (_state == PooledObjectState.ALLOCATED || _state == PooledObjectState.RETURNING) { 113 _state = PooledObjectState.IDLE; 114 _lastReturnTime = Clock.currTime; 115 return true; 116 } 117 118 return false; 119 } 120 121 /** 122 * Sets the state to {@link PooledObjectState#INVALID INVALID} 123 */ 124 void Invalidate() { // synchronized 125 _state = PooledObjectState.INVALID; 126 } 127 128 129 /** 130 * Marks the pooled object as abandoned. 131 */ 132 void Abandoned() { // synchronized 133 _state = PooledObjectState.ABANDONED; 134 } 135 136 /** 137 * Marks the object as returning to the pool. 138 */ 139 void Returning() { // synchronized 140 _state = PooledObjectState.RETURNING; 141 } 142 143 bool IsIdle() { 144 return _state == PooledObjectState.IDLE; 145 } 146 147 bool IsInUse() { 148 return _state == PooledObjectState.ALLOCATED; 149 } 150 151 bool IsInvalid() { 152 return _state == PooledObjectState.INVALID; 153 } 154 }