aboutsummaryrefslogtreecommitdiff
path: root/common/session/custom/session.hxx
blob: 29fb4a265a845d1e1299743c33b33612cebe0fee (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
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
// file      : common/session/custom/session.hxx
// copyright : Copyright (c) 2009-2015 Code Synthesis Tools CC
// license   : GNU GPL v2; see accompanying LICENSE file

#ifndef SESSION_HXX
#define SESSION_HXX

#include <map>
#include <memory>
#include <typeinfo>

#include <odb/database.hxx>
#include <odb/transaction.hxx>

#include <odb/traits.hxx>            // odb::object_traits
#include <odb/details/type-info.hxx> // odb::details::type_info_comparator

// This custom session implementation assumes we are working with
// one database at a time.
//
class session
{
public:
  session ();
  ~session ();

private:
  session (const session&);
  session& operator= (const session&);

  // Session for the current thread. This can be implemented in pretty
  // much any way that makes sense to the application. It can be a global
  // session as we have here. In multi-threaded applications we could use
  // TLS instead.
  //
public:
  static session* current;

  // Change tracking interface.
  //
public:
  // Call flush() within a transaction to apply the changes to the
  // database.
  //
  void
  flush (odb::database&);

private:
  struct object_map_base
  {
    virtual
    ~object_map_base () {}

    // Return true if we flushed anything.
    //
    virtual bool
    flush (odb::database&) = 0;

    virtual void
    mark (unsigned short event) = 0;
  };

  enum object_state
  {
    tracking, // Tracking any modifications by storing the original copy.
    changed,  // Known to be changed.
    flushed   // Flushed but not yet committed/rolled back.
  };

  template <typename T>
  struct object_data
  {
    typedef typename odb::object_traits<T>::pointer_type pointer_type;

    explicit
    object_data (pointer_type o): obj (o), state (tracking) {}

    pointer_type obj;
    pointer_type orig;
    object_state state;
  };

  template <typename T>
  struct object_map: object_map_base,
                     std::map<typename odb::object_traits<T>::id_type,
                              object_data<T> >
  {
    virtual bool
    flush (odb::database&);

    virtual void
    mark (unsigned short event);
  };

  // Object cache interface.
  //
public:
  template <typename T>
  struct cache_position
  {
    typedef object_map<T> map;
    typedef typename map::iterator iterator;

    cache_position (): map_ (0) {}
    cache_position (map& m, const iterator& p): map_ (&m), pos_ (p) {}

    cache_position&
    operator= (const cache_position& p)
    {
      // It might not be ok to use an uninitialized iterator on the rhs.
      //
      if (p.map_ != 0)
        pos_ = p.pos_;
      map_ = p.map_;
      return *this;
    }

    map* map_;
    iterator pos_;
  };

  // Cache management.
  //
  template <typename T>
  static cache_position<T>
  _cache_insert (odb::database&,
                 const typename odb::object_traits<T>::id_type&,
                 const typename odb::object_traits<T>::pointer_type&);

  template <typename T>
  static typename odb::object_traits<T>::pointer_type
  _cache_find (odb::database&, const typename odb::object_traits<T>::id_type&);

  template <typename T>
  static void
  _cache_erase (const cache_position<T>& p)
  {
    if (p.map_ != 0)
      p.map_->erase (p.pos_);
  }

  // Notifications.
  //
  template <typename T>
  static void
  _cache_persist (const cache_position<T>& p)
  {
    _cache_load (p);
  }

  template <typename T>
  static void
  _cache_load (const cache_position<T>&);

  template <typename T>
  static void
  _cache_update (odb::database&, const T&);

  template <typename T>
  static void
  _cache_erase (odb::database&,
                const typename odb::object_traits<T>::id_type&);

private:
  // Post-commit/rollback callback.
  //
  static void
  mark (unsigned short event, void* key, unsigned long long);

private:
  typedef std::map<const std::type_info*,
                   std::shared_ptr<object_map_base>,
                   odb::details::type_info_comparator> type_map;
  type_map map_;
  odb::transaction* tran_;
};

#include "session.txx"

#endif // SESSION_HXX