1 /**
2  * Модуль подключения к базе данных
3  *
4  * Copyright: (c) 2015-2017, Milofon Project.
5  * License: Subject to the terms of the BSD license, as written in the included LICENSE.txt file.
6  * Authors: Maksim Galanin
7  */
8 module dango.system.database.pool;
9 
10 private
11 {
12     import std.container : SList;
13 
14     import vibe.core.sync;
15     import vibe.core.core : Mutex;
16 }
17 
18 
19 /**
20   * Интерфейс объекта с возможностью хранения в пуле
21   */
22 interface Connection
23 {
24     bool connected() @property;
25 
26     void connect();
27 
28     void disconnect();
29 }
30 
31 
32 /**
33   * Интерфейс пула
34   */
35 interface ConnectionPool(C)
36 {
37     /**
38      * Получить подключение из пула
39      */
40     C connection() @safe;
41 
42     /**
43      * Вернуть подключение в пул
44      * Params:
45      *
46      * conn = Освобождаемое подключение
47      */
48     void freeConnection(C conn) @safe;
49 
50     /**
51      * Создание нового подключения
52      */
53     C createNewConnection();
54 }
55 
56 
57 abstract class BaseConnectionPool(C) : ConnectionPool!C
58 {
59     private
60     {
61         SList!C _pool;
62         Mutex _mutex;
63         TaskCondition _condition;
64         uint _size;
65     }
66 
67 
68     this(uint size)
69     {
70         _mutex = new Mutex();
71         _condition = new TaskCondition(_mutex);
72         _size = size;
73         initializePool();
74     }
75 
76 
77     /**
78      * Получить подключение из пула
79      */
80     C connection() @safe
81     {
82         _mutex.lock();
83         while (_pool.empty)
84             _condition.wait();
85 
86         auto conn = () @trusted {
87             auto conn = _pool.front();
88             if (!conn.connected)
89                 conn.connect();
90             return conn;
91         } ();
92 
93         _pool.removeFront();
94         _mutex.unlock();
95         return conn;
96     }
97 
98     /**
99      * Вернуть подключение в пул
100      * Params:
101      *
102      * conn = Освобождаемое подключение
103      */
104     void freeConnection(C conn) @safe
105     {
106         _mutex.lock();
107         _pool.insertFront(conn);
108         _condition.notify();
109         _mutex.unlock();
110     }
111 
112 
113     private void initializePool()
114     {
115         _mutex.lock();
116         foreach (i; 0.._size)
117             _pool.insertFront(createNewConnection());
118         _mutex.unlock();
119     }
120 }