~ubuntu-branches/ubuntu/saucy/db/saucy-proposed

« back to all changes in this revision

Viewing changes to sql/examples/c/ex_sql_multi_thread.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2010-11-05 15:02:09 UTC
  • mfrom: (13.1.12 sid)
  • Revision ID: james.westby@ubuntu.com-20101105150209-ppvyn0619pu014xo
Tags: 5.1.19-1ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - Pass --build/--host to configure to support cross-building, and don't
    override CC.
  - Disable the Java build when cross-building, for now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*-
2
 
 * See the file LICENSE for redistribution information.
3
 
 *
4
 
 * Copyright (c) 1997-2010 Oracle.  All rights reserved.
5
 
 *
6
 
 */
7
 
 
8
 
#include "ex_sql_utils.h"
9
 
 
10
 
/*
11
 
 * Create dozens of writer threads to insert data in parallel. The key point
12
 
 * is that this program has to detect busy/locked status and retry if necessary.
13
 
 * sqlite3_busy_handler() detects busy/locked status.
14
 
 */
15
 
 
16
 
typedef struct {
17
 
        const char* db_name;        /* The filename of db. */
18
 
        int num_of_records;   /* The number of records to insert. */
19
 
        int thread_sn;              /* Serial number of thread. */
20
 
} thread_attr;
21
 
 
22
 
typedef struct {
23
 
        int thread_sn;  /* Serial number of thread. */
24
 
        int max_retry;  /* Max retry times. */
25
 
        int sleep_ms;   /* Time to sleep before retry again. */
26
 
} busy_handler_attr;
27
 
 
28
 
 
29
 
/*
30
 
 * Busy callback handler for all operations. If the busy callback handler is 
31
 
 * NULL, then SQLITE_BUSY or SQLITE_IOERR_BLOCKED is returned immediately upon 
32
 
 * encountering the lock. If the busy callback is not NULL, then the callback 
33
 
 * might be invoked.
34
 
 *
35
 
 * This callback will be registered by SQLite's API:
36
 
 *    int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
37
 
 * That's very useful to deal with SQLITE_BUSY event automatically. Otherwise,
38
 
 * you have to check the return code, reset statement and do retry manually.
39
 
 *
40
 
 * We've to use ANSI C declaration here to eliminate warnings in Visual Studio.
41
 
 */
42
 
static int
43
 
busy_handler(void *data, int retry)
44
 
{
45
 
        busy_handler_attr* attr = (busy_handler_attr*)data;
46
 
 
47
 
        if (retry < attr->max_retry) {
48
 
                /* Sleep a while and retry again. */
49
 
                printf("Thread %d hits SQLITE_BUSY %d times, retry again.\n",
50
 
                        attr->thread_sn, retry);
51
 
                sqlite3_sleep(attr->sleep_ms);
52
 
                /* Return non-zero to let caller retry again. */
53
 
                return 1;
54
 
        }
55
 
        /* Return zero to let caller return SQLITE_BUSY immediately. */
56
 
        printf("Error: Thread %d had retried %d times, exit.\n",
57
 
                attr->thread_sn, retry);
58
 
        return 0;
59
 
}
60
 
 
61
 
/*
62
 
 * Define the writer thread's workload.
63
 
 * The writer would insert 5000 records in its thread. Commit if succeeded 
64
 
 * and rollback if failed.
65
 
 */
66
 
static void*
67
 
writer(arg)
68
 
        void *arg;
69
 
{
70
 
        const char* sql;
71
 
        int txn_begin;
72
 
        int num_of_records;
73
 
        int thread_sn;
74
 
        int i, rc;
75
 
        sqlite3* db;
76
 
        sqlite3_stmt* stmt;
77
 
        busy_handler_attr bh_attr;
78
 
 
79
 
        txn_begin = 0; /* Mark that explicit txn does not begin yet. */
80
 
 
81
 
        /* Open database. */
82
 
        sqlite3_open(((thread_attr *)arg)->db_name, &db);
83
 
        error_handler(db);
84
 
 
85
 
        /* Fetch attributes. */
86
 
        num_of_records = ((thread_attr *)arg)->num_of_records;
87
 
        thread_sn = ((thread_attr *)arg)->thread_sn;
88
 
 
89
 
        /* Setup busy handler for all following operations. */
90
 
        bh_attr.thread_sn = thread_sn;
91
 
        bh_attr.max_retry = 100;  /* Max retry times */
92
 
        bh_attr.sleep_ms = 100;   /* Sleep 100ms before each retry */
93
 
        sqlite3_busy_handler(db, busy_handler, &bh_attr);
94
 
 
95
 
        /* Prepare the statement for use, many times over. */
96
 
        sql = "INSERT INTO university VALUES"
97
 
              "(147, 'Tsinghua University China', 'tsinghua.edu.cn',"
98
 
              "'cn', 'Asia', 237,63,432,303);";
99
 
        rc = sqlite3_prepare_v2(db, sql, (int)strlen(sql), &stmt, NULL);
100
 
        if (rc != SQLITE_OK)
101
 
                goto cleanup;
102
 
 
103
 
        /* 
104
 
         * When we insert data many times over, we shall use explicit
105
 
         * transaction to speed up the operations.
106
 
         */
107
 
        rc = sqlite3_exec(db, "BEGIN TRANSACTION", NULL, 0, NULL);
108
 
        if (rc != SQLITE_OK)
109
 
                goto cleanup;
110
 
        txn_begin = 1; /* Mark that explicit txn began. */
111
 
 
112
 
        for (i = 0; i < num_of_records; i++) {
113
 
                rc = sqlite3_step(stmt);
114
 
                /*
115
 
                 * Even if we encounter errors, the statement still has 
116
 
                 * to be reset. Otherwise following rollback always 
117
 
                 * hits SQLITE_BUSY 
118
 
                 */
119
 
                sqlite3_reset(stmt);
120
 
                if (rc != SQLITE_DONE) {
121
 
                        /* We can not return here. Rollback is required. */
122
 
                        goto cleanup;
123
 
                        break;
124
 
                }
125
 
        }
126
 
 
127
 
        /* Commit if no errors. */
128
 
        rc = sqlite3_exec(db, "COMMIT TRANSACTION", NULL, 0, NULL);
129
 
        if (rc != SQLITE_OK)
130
 
                goto cleanup;
131
 
 
132
 
cleanup:
133
 
        /* Error handle. */
134
 
        if (rc != SQLITE_OK && rc != SQLITE_DONE) {
135
 
                fprintf(stderr, "ERROR: %s. ERRCODE: %d.\n",
136
 
                        sqlite3_errmsg(db), rc);
137
 
                /* Rollback if explict txn had begined. */
138
 
                if (txn_begin)
139
 
                        sqlite3_exec(db, "ROLLBACK TRANSACTION", NULL, 0, NULL);
140
 
        }
141
 
 
142
 
        /* Final cleanup. */
143
 
        sqlite3_finalize(stmt);
144
 
 
145
 
        sqlite3_close(db);
146
 
        return NULL;
147
 
}
148
 
 
149
 
/* Example body. */
150
 
static int
151
 
ex_sql_multi_thread(db, db_name)
152
 
        db_handle *db;
153
 
        const char* db_name;
154
 
{
155
 
        const char* sql;
156
 
        int nthreads;
157
 
        int ninsert;
158
 
        int i;
159
 
        thread_attr attr;
160
 
        os_thread_t pid;
161
 
 
162
 
        nthreads = 20;
163
 
        ninsert  = 5000;
164
 
 
165
 
        /* Display current status. */
166
 
        echo_info("Check existing record number of the table");
167
 
        sql = "SELECT count(*) FROM university;"; 
168
 
        exec_sql(db, sql);
169
 
 
170
 
        /*
171
 
         * Create n threads and write in parallel.
172
 
         */
173
 
        echo_info("Now we begin to insert records by multi-writers.");
174
 
        attr.db_name = db_name;
175
 
        attr.num_of_records = ninsert;
176
 
 
177
 
        for (i = 0; i < nthreads; i++) {
178
 
                attr.thread_sn = i;
179
 
                if (os_thread_create(&pid, writer, (void *)&attr)) {
180
 
                        register_thread_id(pid);
181
 
                        printf("%02dth writer starts to write %d rows\n",
182
 
                                i + 1, ninsert);
183
 
                        sqlite3_sleep(20);      /* Milliseconds. */
184
 
                } else {
185
 
                        fprintf(stderr, "Failed to create thread\n");
186
 
                }
187
 
        }
188
 
        join_threads();
189
 
 
190
 
        /* Display result. */
191
 
        echo_info("Check existing record number of the table");
192
 
        sql = "SELECT count(*) FROM university;"; 
193
 
        exec_sql(db, sql);
194
 
 
195
 
        return 0;
196
 
}
197
 
 
198
 
int
199
 
main()
200
 
{
201
 
        db_handle *db;
202
 
        const char* db_name = "ex_sql_multi_thread.db";
203
 
 
204
 
        /* Check if current lib is threadsafe. */
205
 
        if(!sqlite3_threadsafe()) {
206
 
                fprintf(stderr,
207
 
                        "ERROR: The libsqlite version is NOT threadsafe!\n");
208
 
                exit(EXIT_FAILURE);
209
 
        }
210
 
 
211
 
        /* Setup environment and preload data. */
212
 
        db = setup(db_name);
213
 
        load_table_from_file(db, university_sample_data, 1/* Silent */);
214
 
 
215
 
        /* Run example. */
216
 
        ex_sql_multi_thread(db, db_name);
217
 
 
218
 
        /* End. */
219
 
        cleanup(db);
220
 
        return 0;
221
 
}
222