1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2015 Couchbase, Inc.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 #pragma once
18 
19 #include <cstdint>
20 #include <mutex>
21 #include <memcached/types.h>
22 
23 /**
24  * Structure to save ns_server's session cas token.
25  */
26 class SessionCas {
27 public:
SessionCas()28     SessionCas()
29         : value(0xdeadbeef),
30           counter(0) {
31         // empty
32     }
33 
34     /**
35      * Set the the current session cas value.
36      *
37      * @param newValue the new session cas value
38      * @param casval the current cas value (0 is cas wildcard and overrides
39      *               any value)
40      * @param currentValue the current value (the new value if succeeded, the
41      *                     previous value if failure)
42      * @return ENGINE_SUCCESS upon success,
43      *         ENGINE_BUSY if an operation is currently being performed
44      *                     so the cas value can't be modified
45      *         ENGINE_KEY_EEXISTS if the provided cas value is incorrect
46      */
47     ENGINE_ERROR_CODE cas(uint64_t newValue,
48                           uint64_t casval,
49                           uint64_t& currentValue);
50 
51     /**
52      * Get the current CAS value
53      */
54     uint64_t getCasValue();
55 
56     /**
57      * Increment the session counter if the cas matches
58      *
59      * @param cas the cas value for the operation
60      * @return true if the session counter was incremented, false otherwise
61      */
62     bool increment_session_counter(const uint64_t cas);
63 
64     /**
65      * Decrement the session counter (note this is _ONLY_ legal if you
66      * ran a successful increment of the session counter!!)
67      */
68     void decrement_session_counter();
69 
70 private:
71     /**
72      * The current CAS value. Do <b>not</b> modify this directly, but
73      * use <code>cas</code> to update (it may not be modified unless
74      * counter == 0)
75      */
76     uint64_t value;
77 
78     /**
79      * Whenever we need to perform a potentially long-lived operation
80      * protected by the session cas, we bump this counter and no one may
81      * change the CAS value until we're done (used to protect ourself from
82      * race conditions)
83      */
84     uint64_t counter;
85 
86     /**
87      * All members in the class is protected with this mutex
88      */
89     std::mutex mutex;
90 };
91 
92 extern SessionCas session_cas;
93