File: repl_connext.c

package info (click to toggle)
389-ds-base 2.3.1%2Bdfsg1-1%2Bdeb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 37,536 kB
  • sloc: ansic: 306,972; python: 96,937; cpp: 10,257; perl: 2,854; makefile: 2,046; sh: 925; yacc: 806; xml: 379; lex: 366; javascript: 148; java: 50
file content (237 lines) | stat: -rw-r--r-- 10,290 bytes parent folder | download | duplicates (3)
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/** BEGIN COPYRIGHT BLOCK
 * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
 * Copyright (C) 2005 Red Hat, Inc.
 * All rights reserved.
 *
 * License: GPL (version 3 or any later version).
 * See LICENSE for details.
 * END COPYRIGHT BLOCK **/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/* repl_connext.c - replication extension to the Connection object
 */

#include "repl5.h"


/* ***** Supplier side ***** */

/* NOT NEEDED YET */

/* ***** Consumer side ***** */

/* consumer connection extension constructor */
void *
consumer_connection_extension_constructor(void *object __attribute__((unused)), void *parent __attribute__((unused)))
{
    consumer_connection_extension *ext = (consumer_connection_extension *)slapi_ch_malloc(sizeof(consumer_connection_extension));
    if (ext == NULL) {
        slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name, "consumer_connection_extension_constructor - "
                                                          "Unable to create replication consumer connection extension - out of memory\n");
    } else {
        ext->repl_protocol_version = REPL_PROTOCOL_UNKNOWN;
        ext->replica_acquired = NULL;
        ext->isreplicationsession = 0;
        ext->supplier_ruv = NULL;
        ext->connection = NULL;
        ext->in_use_opid = -1;
        ext->lock = PR_NewLock();
        if (NULL == ext->lock) {
            slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name, "consumer_connection_extension_constructor - "
                                                              "Unable to create replication consumer connection extension lock - out of memory\n");
            /* no need to go through the full destructor, but still need to free up this memory */
            slapi_ch_free((void **)&ext);
            ext = NULL;
        }
    }

    return ext;
}

/* consumer connection extension destructor */
void
consumer_connection_extension_destructor(void *ext, void *object __attribute__((unused)), void *parent __attribute__((unused)))
{
    PRUint64 connid = 0;
    if (ext) {
        /* Check to see if this replication session has acquired
         * a replica. If so, release it here.
         */
        consumer_connection_extension *connext = (consumer_connection_extension *)ext;
        if (NULL != connext->replica_acquired) {
            Replica *r = connext->replica_acquired;
            /* If a total update was in progress, abort it */
            if (REPL_PROTOCOL_50_TOTALUPDATE == connext->repl_protocol_version) {
                Slapi_PBlock *pb = slapi_pblock_new();
                const Slapi_DN *repl_root_sdn = replica_get_root(r);
                PR_ASSERT(NULL != repl_root_sdn);
                if (NULL != repl_root_sdn) {
                    slapi_pblock_set(pb, SLAPI_CONNECTION, connext->connection);
                    slapi_pblock_set(pb, SLAPI_TARGET_SDN, (void *)repl_root_sdn);
                    slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
                    slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                                  "consumer_connection_extension_destructor - "
                                  "Aborting total update in progress for replicated "
                                  "area %s connid=%" PRIu64 "\n",
                                  slapi_sdn_get_dn(repl_root_sdn), connid);
                    slapi_stop_bulk_import(pb);
                } else {
                    slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
                                  "consumer_connection_extension_destructor - Can't determine root "
                                  "of replicated area.\n");
                }
                slapi_pblock_destroy(pb);

                /* allow reaping again */
                replica_set_tombstone_reap_stop(r, PR_FALSE);
            }
            replica_relinquish_exclusive_access(r, connid, -1);
            connext->replica_acquired = NULL;
        }

        if (connext->supplier_ruv) {
            ruv_destroy((RUV **)&connext->supplier_ruv);
        }

        if (connext->lock) {
            PR_DestroyLock(connext->lock);
            connext->lock = NULL;
        }

        connext->in_use_opid = -1;

        connext->connection = NULL;
        slapi_ch_free((void **)&ext);
    }
}

/* Obtain exclusive access to this connection extension.
 * Returns the consumer_connection_extension* if successful, else NULL.
 *
 * This is similar to obtaining exclusive access to the replica, but not identical.
 * For the connection extension, you only want to hold on to exclusive access as
 * long as it is being actively used to process an operation.  Mainly that means
 * while processing either a 'start' or an 'end' extended operation.  This makes
 * certain that if another 'start' or 'end' operation is received on the connection,
 * the ops will not trample on each other's state.  As soon as you are done with
 * that single operation, it is time to relinquish the connection extension.
 * That differs from acquiring exclusive access to the replica, which is held over
 * after the 'start' operation and relinquished during the 'end' operation.
 */
consumer_connection_extension *
consumer_connection_extension_acquire_exclusive_access(void *conn, PRUint64 connid, int opid)
{
    consumer_connection_extension *ret = NULL;

    /* step 1, grab the connext */
    consumer_connection_extension *connext = (consumer_connection_extension *)
        repl_con_get_ext(REPL_CON_EXT_CONN, conn);

    if (NULL != connext) {
        /* step 2, acquire its lock */
        PR_Lock(connext->lock);

        /* step 3, see if it is not in use, or in use by us */
        if (0 > connext->in_use_opid) {
            /* step 4, take it! */
            connext->in_use_opid = opid;
            ret = connext;
            slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                          "consumer_connection_extension_acquire_exclusive_access - "
                          "conn=%" PRIu64 " op=%d Acquired consumer connection extension\n",
                          connid, opid);
        } else if (opid == connext->in_use_opid) {
            ret = connext;
            slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                          "consumer_connection_extension_acquire_exclusive_access - "
                          "conn=%" PRIu64 " op=%d Reacquired consumer connection extension\n",
                          connid, opid);
        } else {
            slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                          "consumer_connection_extension_acquire_exclusive_access - "
                          "conn=%" PRIu64 " op=%d Could not acquire consumer connection extension; it is in use by op=%d\n",
                          connid, opid, connext->in_use_opid);
        }

        /* step 5, drop the lock */
        PR_Unlock(connext->lock);
    } else {
        slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                      "consumer_connection_extension_acquire_exclusive_access - "
                      "conn=%" PRIu64 " op=%d Could not acquire consumer extension, it is NULL!\n",
                      connid, opid);
    }

    return ret;
}

/* Relinquish exclusive access to this connection extension.
 * Returns 0 if exclusive access could NOT be relinquished, and non-zero if it was.
 * Specifically:
 *      1 if the extension was in use and was relinquished.
 *      2 if the extension was not in use to begin with.
 *
 * The extension will only be relinquished if it was first acquired by this op,
 * or if 'force' is TRUE.  Do not use 'force' without a legitimate reason, such
 * as when destroying the parent connection.
 *
 * cf. consumer_connection_extension_acquire_exclusive_access() for details on how,
 * when, and why you would want to acquire and relinquish exclusive access.
 */
int
consumer_connection_extension_relinquish_exclusive_access(void *conn, PRUint64 connid, int opid, PRBool force)
{
    int ret = 0;

    /* step 1, grab the connext */
    consumer_connection_extension *connext = (consumer_connection_extension *)
        repl_con_get_ext(REPL_CON_EXT_CONN, conn);

    if (NULL != connext) {
        /* step 2, acquire its lock */
        PR_Lock(connext->lock);

        /* step 3, see if it is in use */
        if (0 > connext->in_use_opid) {
            slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                          "consumer_connection_extension_relinquish_exclusive_access - "
                          "conn=%" PRIu64 " op=%d Consumer connection extension is not in use\n",
                          connid, opid);
            ret = 2;
        } else if (opid == connext->in_use_opid) {
            /* step 4, relinquish it (normal) */
            slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                          "consumer_connection_extension_relinquish_exclusive_access - "
                          "conn=%" PRIu64 " op=%d Relinquishing consumer connection extension\n",
                          connid, opid);
            connext->in_use_opid = -1;
            ret = 1;
        } else if (force) {
            /* step 4, relinquish it (forced) */
            slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                          "consumer_connection_extension_relinquish_exclusive_access - "
                          "conn=%" PRIu64 " op=%d Forced to relinquish consumer connection extension held by op=%d\n",
                          connid, opid, connext->in_use_opid);
            connext->in_use_opid = -1;
            ret = 1;
        } else {
            slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                          "consumer_connection_extension_relinquish_exclusive_access - "
                          "conn=%" PRIu64 " op=%d Not relinquishing consumer connection extension, it is held by op=%d!\n",
                          connid, opid, connext->in_use_opid);
        }

        /* step 5, drop the lock */
        PR_Unlock(connext->lock);
    } else {
        slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
                      "consumer_connection_extension_relinquish_exclusive_access - "
                      "conn=%" PRIu64 " op=%d Could not relinquish consumer extension, it is NULL!\n",
                      connid, opid);
    }

    return ret;
}