~ubuntu-branches/debian/sid/sqlheavy/sid

« back to all changes in this revision

Viewing changes to sqlheavy/sqlheavy-transaction.vala

  • Committer: Package Import Robot
  • Author(s): Devid Antonio Filoni
  • Date: 2011-10-23 15:43:22 UTC
  • Revision ID: package-import@ubuntu.com-20111023154322-unzj3fz2aj4g6cl8
Tags: upstream-0.1.0
ImportĀ upstreamĀ versionĀ 0.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
namespace SQLHeavy {
 
2
  /**
 
3
   * Object representing an SQLite transaction
 
4
   *
 
5
   * Note that this is implemented using SQLite's
 
6
   * [[http://sqlite.org/lang_savepoint.html|SAVEPOINT]] feature,
 
7
   * meaning that by default it is like that of a
 
8
   * {@link TransactionType.DEFERRED} transaction. This behaviour may
 
9
   * be modified by first manually running a
 
10
   * [[http://sqlite.org/lang_transaction.html|transaction]] in SQL,
 
11
   * but remember that such transactions cannot be nested.
 
12
   */
 
13
  public class Transaction : GLib.Object, Queryable {
 
14
    /**
 
15
     * Status of the transaction.
 
16
     */
 
17
    public TransactionStatus status { get; private set; default = TransactionStatus.UNRESOLVED; }
 
18
 
 
19
    /**
 
20
     * Parent querayble
 
21
     */
 
22
    public SQLHeavy.Queryable? parent { get; construct; }
 
23
 
 
24
    /**
 
25
     * {@inheritDoc}
 
26
     */
 
27
    public SQLHeavy.Database database { owned get { return this.parent.database; } }
 
28
 
 
29
    private Sqlite.Mutex? _transaction_lock = new Sqlite.Mutex (Sqlite.MUTEX_FAST);
 
30
 
 
31
    /**
 
32
     * {@inheritDoc}
 
33
     */
 
34
    public void @lock () {
 
35
      this._transaction_lock.enter ();
 
36
    }
 
37
 
 
38
    /**
 
39
     * {@inheritDoc}
 
40
     */
 
41
    public void @unlock () {
 
42
      lock ( this._queue ) {
 
43
        if ( this._queue != null && (this._queue.get_length () > 0) ) {
 
44
          try {
 
45
            for ( GLib.SequenceIter<SQLHeavy.Query> iter = this._queue.get_begin_iter () ;
 
46
                  !iter.is_end () ;
 
47
                  iter = iter.next () ) {
 
48
              SQLHeavy.QueryResult result = new SQLHeavy.QueryResult.no_exec (iter.get ());
 
49
              result.next_internal ();
 
50
              this._queue.remove (iter);
 
51
            }
 
52
          } catch ( SQLHeavy.Error e ) {
 
53
            GLib.critical ("Unable to execute queued query: %s", e.message);
 
54
          }
 
55
        }
 
56
      }
 
57
 
 
58
      this._transaction_lock.leave ();
 
59
    }
 
60
 
 
61
    private GLib.Sequence<SQLHeavy.Query>? _queue = null;
 
62
 
 
63
    /**
 
64
     * {@inheritDoc}
 
65
     */
 
66
    public void queue (SQLHeavy.Query query) throws SQLHeavy.Error {
 
67
      lock ( this._queue ) {
 
68
        if ( this._queue == null )
 
69
          this._queue = new GLib.Sequence<SQLHeavy.Query> (GLib.g_object_unref);
 
70
 
 
71
        this._queue.append (query);
 
72
      }
 
73
    }
 
74
 
 
75
    /**
 
76
     * The transaction has been resolved (committed or rolled back)
 
77
     *
 
78
     * @param status whether the transaction was committed or rolled back
 
79
     */
 
80
    public signal void resolved (SQLHeavy.TransactionStatus status);
 
81
 
 
82
    /**
 
83
     * Resolve the transaction
 
84
     *
 
85
     * @param commit whether to commit the transaction or roll it back
 
86
     */
 
87
    private void resolve (bool commit) throws SQLHeavy.Error {
 
88
      if ( this.status != TransactionStatus.UNRESOLVED )
 
89
        throw new SQLHeavy.Error.TRANSACTION ("Refusing to resolve an already resolved transaction.");
 
90
 
 
91
      SQLHeavy.Query query = this.parent.prepare ("%s SAVEPOINT 'SQLHeavy-0x%x';".printf (commit ? "RELEASE" : "ROLLBACK TRANSACTION TO", (uint)this));
 
92
      this.parent.queue (query);
 
93
 
 
94
      this.status = commit ? TransactionStatus.COMMITTED : TransactionStatus.ROLLED_BACK;
 
95
      this.parent.@unlock ();
 
96
      this.resolved (this.status);
 
97
    }
 
98
 
 
99
 
 
100
    /**
 
101
     * Resolve the transaction asychronously
 
102
     *
 
103
     * @param commit whether to commit the transaction or roll it back
 
104
     */
 
105
    private async void resolve_async (bool commit) throws SQLHeavy.Error {
 
106
      if ( this.status != TransactionStatus.UNRESOLVED )
 
107
        throw new SQLHeavy.Error.TRANSACTION ("Refusing to resolve an already resolved transaction.");
 
108
 
 
109
      SQLHeavy.Query query = this.prepare ("%s SAVEPOINT 'SQLHeavy-0x%x';".printf (commit ? "RELEASE" : "ROLLBACK TRANSACTION TO", (uint)this));
 
110
      yield query.execute_async ();
 
111
 
 
112
      this.status = commit ? TransactionStatus.COMMITTED : TransactionStatus.ROLLED_BACK;
 
113
      this.parent.@unlock ();
 
114
      this.resolved (this.status);
 
115
    }
 
116
 
 
117
    /**
 
118
     * Commit the transaction to the database
 
119
     */
 
120
    public void commit () throws SQLHeavy.Error {
 
121
      this.resolve (true);
 
122
    }
 
123
 
 
124
    /**
 
125
     * Commit the transaction to the database asynchronously
 
126
     */
 
127
    public async void commit_async () throws SQLHeavy.Error {
 
128
      yield this.resolve_async (true);
 
129
    }
 
130
 
 
131
    /**
 
132
     * Rollback the transaction
 
133
     */
 
134
    public void rollback () throws SQLHeavy.Error {
 
135
      this.resolve (false);
 
136
    }
 
137
 
 
138
    /**
 
139
     * Rollback the transaction asynchronously
 
140
     */
 
141
    public async void rollback_async () throws SQLHeavy.Error {
 
142
      yield this.resolve_async (false);
 
143
    }
 
144
 
 
145
    ~ Transaction () {
 
146
      if ( this.status == TransactionStatus.UNRESOLVED )
 
147
        this.rollback ();
 
148
    }
 
149
 
 
150
    private SQLHeavy.Error? err = null;
 
151
 
 
152
    construct {
 
153
      this.parent.@lock ();
 
154
 
 
155
      try {
 
156
        this.prepare ("SAVEPOINT 'SQLHeavy-0x%x';".printf ((uint)this)).execute ();
 
157
      }
 
158
      catch ( SQLHeavy.Error e ) {
 
159
        this.err = e;
 
160
        GLib.critical ("Unable to create transaction: %s (%d)", e.message, e.code);
 
161
        this.parent.@unlock ();
 
162
      }
 
163
    }
 
164
 
 
165
    /**
 
166
     * Create a new transaction.
 
167
     *
 
168
     * @param parent The queryable to create the transaction on top of
 
169
     */
 
170
    public Transaction (SQLHeavy.Queryable parent) throws SQLHeavy.Error {
 
171
      Object (parent: parent);
 
172
      if ( this.err != null )
 
173
        throw this.err;
 
174
    }
 
175
  }
 
176
}