1 module hunt.util.pool.PooledObject;
2 
3 import core.atomic;
4 import std.datetime;
5 
6 import hunt.logging;
7 
8 import hunt.util.pool.PooledObjectState;
9 
10 /**
11  * Defines the wrapper that is used to track the additional information, such as
12  * state, for the pooled objects.
13  * <p>
14  * Implementations of this class are required to be thread-safe.
15  *
16  * @param <T> the type of object in the pool
17  *
18  */
19 class PooledObject(T) {
20     private size_t _id;
21     private T _obj;
22     private shared PooledObjectState _state;
23     private SysTime _createTime;
24     private SysTime _lastBorrowTime;
25     private SysTime _lastUseTime;
26     private SysTime _lastReturnTime;
27     private shared long _borrowedCount = 0;
28     private static shared size_t _counter;
29 
30     this() {
31         _state = PooledObjectState.UNUSABLE;
32         _createTime = Clock.currTime;
33         _id = atomicOp!("+=")(_counter, 1);
34     }
35 
36     this(T obj) {
37         assert(obj !is null);
38 
39         _obj = obj;
40         _state = PooledObjectState.IDLE;
41         _createTime = Clock.currTime;
42         _id = atomicOp!("+=")(_counter, 1);
43     }
44 
45     // package void bind(T obj) {
46     //     _obj = obj;
47     //     _state = PooledObjectState.IDLE;
48     // }
49 
50     size_t id() {
51         return _id;
52     }
53 
54     /**
55      * Obtains the underlying object that is wrapped by this instance of
56      * {@link PooledObject}.
57      *
58      * @return The wrapped object
59      */
60     T getObject() {
61         return _obj;
62     }  
63 
64     SysTime createTime() {
65         return _createTime;
66     }    
67 
68     SysTime lastBorrowTime() {
69         return _lastBorrowTime;
70     }
71 
72     SysTime lastReturnTime() {
73         return _lastReturnTime;
74     }
75 
76     /**
77      * Get the number of times this object has been borrowed.
78      * @return The number of times this object has been borrowed.
79      */
80     long borrowedCount() {
81         return _borrowedCount;
82     }
83 
84     /**
85      * Returns the state of this object.
86      * @return state
87      */
88     PooledObjectState state() {
89         return _state;
90     }
91 
92     /**
93      * Allocates the object.
94      *
95      * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
96      */
97     bool allocate() {
98         version(HUNT_POOL_DEBUG) tracef(toString());
99 
100         if(cas(&_state, PooledObjectState.IDLE, PooledObjectState.ALLOCATED)) {
101             _lastBorrowTime = Clock.currTime;
102             _lastUseTime = _lastBorrowTime;
103             atomicOp!("+=")(_borrowedCount, 1);
104             return true;
105         } else {
106             version(HUNT_DEBUG) warningf("allocate collision: %s", toString());
107         }
108         
109         return false;        
110     }
111 
112 
113     /**
114      * Allocates the object.
115      *
116      * @return {@code true} if the original state was {@link PooledObjectState#IDLE IDLE}
117      */
118     bool allocate(T obj) {
119         // version(HUNT_POOL_DEBUG) tracef(toString());
120 
121         if(cas(&_state, PooledObjectState.UNUSABLE, PooledObjectState.ALLOCATED)) {
122             _obj = obj;
123             _lastBorrowTime = Clock.currTime;
124             _lastUseTime = _lastBorrowTime;
125             atomicOp!("+=")(_borrowedCount, 1);
126             return true;
127         } else {
128             version(HUNT_DEBUG) warningf("allocate collision: %s", toString());
129         }
130         
131         return false;        
132     }    
133 
134     /**
135      * Sets the state to {@link PooledObjectState#INVALID INVALID}
136      */
137     void invalidate() {
138         _state = PooledObjectState.INVALID;
139     }
140 
141     /**
142      * Marks the pooled object as abandoned.
143      */
144     void abandoned() {
145         _state = PooledObjectState.ABANDONED;
146     }
147 
148     /**
149      * Marks the object as returning to the pool.
150      */
151     bool returning() { 
152         version(HUNT_POOL_DEBUG_MORE) tracef(toString());
153         if(cas(&_state, PooledObjectState.ALLOCATED, PooledObjectState.IDLE)) {
154             _lastReturnTime = Clock.currTime;
155             return true;
156         }
157 
158         return false;        
159     }
160 
161     bool isIdle() {
162         return _state == PooledObjectState.IDLE;
163     }
164 
165     bool isInUse() {
166         return _state == PooledObjectState.ALLOCATED;
167     }
168 
169     bool isInvalid() {
170         return _state == PooledObjectState.INVALID;
171     }
172 
173     bool isUnusable() {
174         return _state == PooledObjectState.UNUSABLE;
175     }
176 
177     override string toString() {
178         import std.format;
179         string str = format("id: %d, state: %s, binded: {%s}", 
180              id(), _state, _obj is null ? "null" : (cast(Object)_obj).toString());
181         return str;
182     }
183     
184 }