summaryrefslogtreecommitdiff
path: root/client/connpool.h
blob: fafee2b7ab136fdb1dd07bc82ea516632148e593 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* connpool.h */

/**
*    Copyright (C) 2008 10gen Inc.
*
*    This program is free software: you can redistribute it and/or  modify
*    it under the terms of the GNU Affero General Public License, version 3,
*    as published by the Free Software Foundation.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <queue>
#include "dbclient.h"

struct PoolForHost {
    queue<DBClientConnection*> pool;
};

class DBConnectionPool {
    boost::mutex poolMutex;
    map<string,PoolForHost*> pools;
public:

    /* generally, use ScopedDbConnection and do not call these directly */
    DBClientConnection *get(const string& host);
    void release(const string& host, DBClientConnection *c) {
        boostlock L(poolMutex);
        pools[host]->pool.push(c);
    }
};

extern DBConnectionPool pool;

/* Use to get a connection from the pool.  On exceptions things
   clean up nicely.
*/
class ScopedDbConnection {
    const string host;
    DBClientConnection *_conn;
public:
    DBClientConnection& conn() {
        return *_conn;
    }

    /* throws UserAssertionAcception if can't connect */
    ScopedDbConnection(const string& _host) :
            host(_host), _conn( pool.get(_host) ) { }

    /* Force closure of the connection.  You should call this if you leave it in
       a bad state.  Destructor will do this too, but it is verbose.
    */
    void kill() {
        delete _conn;
        _conn = 0;
    }

    /* Call this when you are done with the ocnnection.
         Why?  See note in the destructor below.
    */
    void done() {
        if ( _conn->isFailed() )
            kill();
        else
            pool.release(host, _conn);
        _conn = 0;
    }

    ~ScopedDbConnection() {
        if ( _conn ) {
            /* you are supposed to call done().  if you did that, correctly, we
               only get here if an exception was thrown.  in such a scenario, we can't
               be sure we fully read all expected data of a reply on the socket.  so
               we don't try to reuse the connection.  The cout is just informational.
               */
            cout << "~ScopedDBConnection: _conn != null\n";
            kill();
        }
    }
};