~ubuntu-branches/ubuntu/wily/evolution-data-server/wily

« back to all changes in this revision

Viewing changes to camel/camel-db.c

  • Committer: Package Import Robot
  • Author(s): Iain Lane
  • Date: 2015-07-20 13:34:59 UTC
  • mfrom: (1.1.126) (1.2.48 sid)
  • Revision ID: package-import@ubuntu.com-20150720133459-g6y46hnu5ewtoz08
Tags: 3.16.4-0ubuntu2
debian/patches/0001-Bug-752373-Monthly-events-do-not-recur-correctly.patch:
Cherry-pick patch from upstream to fix events not recurring correctly.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
 
/* camel-imap-folder.c: class for an imap folder */
3
 
 
4
2
/*
5
 
 * Authors:
6
 
 *   Sankar P <psankar@novell.com>
7
 
 *   Srinivasa Ragavan <sragavan@novell.com>
8
 
 *
9
3
 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
10
4
 *
11
 
 * This library is free software you can redistribute it and/or modify it
 
5
 * This library is free software: you can redistribute it and/or modify it
12
6
 * under the terms of the GNU Lesser General Public License as published by
13
7
 * the Free Software Foundation.
14
8
 *
15
9
 * This library is distributed in the hope that it will be useful, but
16
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17
 
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18
 
 *for more details.
 
11
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 
12
 * for more details.
19
13
 *
20
14
 * You should have received a copy of the GNU Lesser General Public License
21
 
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 
15
 * along with this library. If not, see <http://www.gnu.org/licenses/>.
 
16
 *
 
17
 * Authors: Sankar P <psankar@novell.com>
 
18
 *          Srinivasa Ragavan <sragavan@novell.com>
22
19
 */
23
20
 
24
21
#include "camel-db.h"
39
36
/* how long to wait before invoking sync on the file */
40
37
#define SYNC_TIMEOUT_SECONDS 5
41
38
 
42
 
#define READER_LOCK(cdb) g_rw_lock_reader_lock (&cdb->priv->rwlock)
43
 
#define READER_UNLOCK(cdb) g_rw_lock_reader_unlock (&cdb->priv->rwlock)
44
 
#define WRITER_LOCK(cdb) g_rw_lock_writer_lock (&cdb->priv->rwlock)
45
 
#define WRITER_UNLOCK(cdb) g_rw_lock_writer_unlock (&cdb->priv->rwlock)
46
 
 
47
39
static sqlite3_vfs *old_vfs = NULL;
48
40
static GThreadPool *sync_pool = NULL;
49
41
 
490
482
        GTimer *timer;
491
483
        GRWLock rwlock;
492
484
        gchar *file_name;
493
 
        gboolean transaction_is_on;
 
485
        GMutex transaction_lock;
 
486
        GThread *transaction_thread;
 
487
        guint32 transaction_level;
494
488
};
495
489
 
496
490
/**
591
585
        sqlite3_result_int (ctx, matches ? 1 : 0);
592
586
}
593
587
 
 
588
static void
 
589
cdb_writer_lock (CamelDB *cdb)
 
590
{
 
591
        g_return_if_fail (cdb != NULL);
 
592
 
 
593
        g_mutex_lock (&cdb->priv->transaction_lock);
 
594
        if (cdb->priv->transaction_thread != g_thread_self ()) {
 
595
                g_mutex_unlock (&cdb->priv->transaction_lock);
 
596
 
 
597
                g_rw_lock_writer_lock (&cdb->priv->rwlock);
 
598
 
 
599
                g_mutex_lock (&cdb->priv->transaction_lock);
 
600
 
 
601
                g_warn_if_fail (cdb->priv->transaction_thread == NULL);
 
602
                g_warn_if_fail (cdb->priv->transaction_level == 0);
 
603
 
 
604
                cdb->priv->transaction_thread = g_thread_self ();
 
605
        }
 
606
 
 
607
        cdb->priv->transaction_level++;
 
608
 
 
609
        g_mutex_unlock (&cdb->priv->transaction_lock);
 
610
}
 
611
 
 
612
static void
 
613
cdb_writer_unlock (CamelDB *cdb)
 
614
{
 
615
        g_return_if_fail (cdb != NULL);
 
616
 
 
617
        g_mutex_lock (&cdb->priv->transaction_lock);
 
618
 
 
619
        g_warn_if_fail (cdb->priv->transaction_thread == g_thread_self ());
 
620
        g_warn_if_fail (cdb->priv->transaction_level > 0);
 
621
 
 
622
        cdb->priv->transaction_level--;
 
623
 
 
624
        if (!cdb->priv->transaction_level) {
 
625
                cdb->priv->transaction_thread = NULL;
 
626
                g_mutex_unlock (&cdb->priv->transaction_lock);
 
627
 
 
628
                g_rw_lock_writer_unlock (&cdb->priv->rwlock);
 
629
        } else {
 
630
                g_mutex_unlock (&cdb->priv->transaction_lock);
 
631
        }
 
632
}
 
633
 
 
634
static void
 
635
cdb_reader_lock (CamelDB *cdb)
 
636
{
 
637
        g_return_if_fail (cdb != NULL);
 
638
 
 
639
        g_mutex_lock (&cdb->priv->transaction_lock);
 
640
        if (cdb->priv->transaction_thread == g_thread_self ()) {
 
641
                /* already holding write lock */
 
642
                g_mutex_unlock (&cdb->priv->transaction_lock);
 
643
        } else {
 
644
                g_mutex_unlock (&cdb->priv->transaction_lock);
 
645
 
 
646
                g_rw_lock_reader_lock (&cdb->priv->rwlock);
 
647
        }
 
648
}
 
649
 
 
650
static void
 
651
cdb_reader_unlock (CamelDB *cdb)
 
652
{
 
653
        g_return_if_fail (cdb != NULL);
 
654
 
 
655
        g_mutex_lock (&cdb->priv->transaction_lock);
 
656
        if (cdb->priv->transaction_thread == g_thread_self ()) {
 
657
                /* already holding write lock */
 
658
                g_mutex_unlock (&cdb->priv->transaction_lock);
 
659
        } else {
 
660
                g_mutex_unlock (&cdb->priv->transaction_lock);
 
661
 
 
662
                g_rw_lock_reader_unlock (&cdb->priv->rwlock);
 
663
        }
 
664
}
 
665
 
 
666
static gboolean
 
667
cdb_is_in_transaction (CamelDB *cdb)
 
668
{
 
669
        gboolean res;
 
670
 
 
671
        g_return_val_if_fail (cdb != NULL, FALSE);
 
672
 
 
673
        g_mutex_lock (&cdb->priv->transaction_lock);
 
674
        res = cdb->priv->transaction_level > 0 && cdb->priv->transaction_thread == g_thread_self ();
 
675
        g_mutex_unlock (&cdb->priv->transaction_lock);
 
676
 
 
677
        return res;
 
678
}
 
679
 
 
680
static gchar *
 
681
cdb_construct_transaction_stmt (CamelDB *cdb,
 
682
                                const gchar *prefix)
 
683
{
 
684
        gchar *name;
 
685
 
 
686
        g_return_val_if_fail (cdb != NULL, NULL);
 
687
 
 
688
        g_mutex_lock (&cdb->priv->transaction_lock);
 
689
        g_warn_if_fail (cdb->priv->transaction_thread == g_thread_self ());
 
690
        name = g_strdup_printf ("%sTN%d", prefix ? prefix : "", cdb->priv->transaction_level);
 
691
        g_mutex_unlock (&cdb->priv->transaction_lock);
 
692
 
 
693
        return name;
 
694
}
 
695
 
594
696
/**
595
697
 * camel_db_open:
596
698
 *
631
733
 
632
734
        cdb = g_new (CamelDB, 1);
633
735
        cdb->db = db;
634
 
        cdb->priv = g_new (CamelDBPrivate, 1);
 
736
        cdb->priv = g_new0 (CamelDBPrivate, 1);
635
737
        cdb->priv->file_name = g_strdup (path);
636
738
        g_rw_lock_init (&cdb->priv->rwlock);
 
739
        g_mutex_init (&cdb->priv->transaction_lock);
 
740
        cdb->priv->transaction_thread = NULL;
 
741
        cdb->priv->transaction_level = 0;
637
742
        cdb->priv->timer = NULL;
638
743
        d (g_print ("\nDatabase succesfully opened  \n"));
639
744
 
684
789
        if (cdb) {
685
790
                sqlite3_close (cdb->db);
686
791
                g_rw_lock_clear (&cdb->priv->rwlock);
 
792
                g_mutex_clear (&cdb->priv->transaction_lock);
687
793
                g_free (cdb->priv->file_name);
688
794
                g_free (cdb->priv);
689
795
                g_free (cdb);
707
813
                if (!cdb)
708
814
                        return 0;
709
815
 
710
 
                WRITER_LOCK (cdb);
 
816
                cdb_writer_lock (cdb);
711
817
                d (g_print ("Creating Collation %s on %s with %p\n", collate, col, (gpointer) func));
712
818
                if (collate && func)
713
819
                        ret = sqlite3_create_collation (cdb->db, collate, SQLITE_UTF8,  NULL, func);
714
 
                WRITER_UNLOCK (cdb);
 
820
                cdb_writer_unlock (cdb);
715
821
 
716
822
                return ret;
717
823
}
731
837
        if (!cdb)
732
838
                return TRUE;
733
839
 
734
 
        WRITER_LOCK (cdb);
 
840
        cdb_writer_lock (cdb);
735
841
 
736
842
        START (stmt);
737
843
        ret = cdb_sql_exec (cdb->db, stmt, NULL, NULL, error);
738
844
        END;
739
845
 
740
 
        WRITER_UNLOCK (cdb);
 
846
        cdb_writer_unlock (cdb);
741
847
 
742
848
        return ret;
743
849
}
751
857
camel_db_begin_transaction (CamelDB *cdb,
752
858
                            GError **error)
753
859
{
 
860
        gchar *stmt;
 
861
        gint res;
 
862
 
754
863
        if (!cdb)
755
864
                return -1;
756
865
 
757
 
        WRITER_LOCK (cdb);
758
 
        STARTTS ("BEGIN");
759
 
 
760
 
        cdb->priv->transaction_is_on = TRUE;
761
 
 
762
 
        return (cdb_sql_exec (cdb->db, "BEGIN", NULL, NULL, error));
 
866
        cdb_writer_lock (cdb);
 
867
 
 
868
        stmt = cdb_construct_transaction_stmt (cdb, "SAVEPOINT ");
 
869
 
 
870
        STARTTS (stmt);
 
871
        res = cdb_sql_exec (cdb->db, stmt, NULL, NULL, error);
 
872
        g_free (stmt);
 
873
 
 
874
        return res;
763
875
}
764
876
 
765
877
/**
771
883
camel_db_end_transaction (CamelDB *cdb,
772
884
                          GError **error)
773
885
{
 
886
        gchar *stmt;
774
887
        gint ret;
 
888
 
775
889
        if (!cdb)
776
890
                return -1;
777
891
 
778
 
        ret = cdb_sql_exec (cdb->db, "COMMIT", NULL, NULL, error);
779
 
        cdb->priv->transaction_is_on = FALSE;
 
892
        stmt = cdb_construct_transaction_stmt (cdb, "RELEASE SAVEPOINT ");
 
893
        ret = cdb_sql_exec (cdb->db, stmt, NULL, NULL, error);
 
894
        g_free (stmt);
780
895
 
781
896
        ENDTS;
782
 
        WRITER_UNLOCK (cdb);
 
897
        cdb_writer_unlock (cdb);
783
898
        CAMEL_DB_RELEASE_SQLITE_MEMORY;
784
899
 
785
900
        return ret;
794
909
camel_db_abort_transaction (CamelDB *cdb,
795
910
                            GError **error)
796
911
{
 
912
        gchar *stmt;
797
913
        gint ret;
798
914
 
799
 
        ret = cdb_sql_exec (cdb->db, "ROLLBACK", NULL, NULL, error);
800
 
        cdb->priv->transaction_is_on = FALSE;
 
915
        stmt = cdb_construct_transaction_stmt (cdb, "ROLLBACK TO SAVEPOINT ");
 
916
        ret = cdb_sql_exec (cdb->db, stmt, NULL, NULL, error);
 
917
        g_free (stmt);
801
918
 
802
 
        WRITER_UNLOCK (cdb);
 
919
        cdb_writer_unlock (cdb);
803
920
        CAMEL_DB_RELEASE_SQLITE_MEMORY;
804
921
 
805
922
        return ret;
818
935
        if (!cdb)
819
936
                return -1;
820
937
 
821
 
        g_assert (cdb->priv->transaction_is_on == TRUE);
 
938
        g_return_val_if_fail (cdb_is_in_transaction (cdb), -1);
822
939
 
823
940
        return (cdb_sql_exec (cdb->db, stmt, NULL, NULL, error));
824
941
}
833
950
                              GList *qry_list,
834
951
                              GError **error)
835
952
{
 
953
        gboolean in_transaction = FALSE;
836
954
        gint ret;
837
955
        const gchar *query;
838
956
 
839
957
        if (!cdb)
840
958
                return -1;
841
959
 
842
 
        WRITER_LOCK (cdb);
843
 
 
844
 
        STARTTS ("BEGIN");
845
 
        ret = cdb_sql_exec (cdb->db, "BEGIN", NULL, NULL, error);
 
960
        ret = camel_db_begin_transaction (cdb, error);
846
961
        if (ret)
847
962
                goto end;
848
963
 
 
964
        in_transaction = TRUE;
 
965
 
849
966
        while (qry_list) {
850
967
                query = qry_list->data;
851
968
                ret = cdb_sql_exec (cdb->db, query, NULL, NULL, error);
854
971
                qry_list = g_list_next (qry_list);
855
972
        }
856
973
 
857
 
        ret = cdb_sql_exec (cdb->db, "COMMIT", NULL, NULL, error);
858
 
        ENDTS;
 
974
        ret = camel_db_end_transaction (cdb, error);
 
975
        in_transaction = FALSE;
859
976
end:
860
 
        WRITER_UNLOCK (cdb);
 
977
        if (in_transaction)
 
978
                ret = camel_db_abort_transaction (cdb, error);
 
979
 
861
980
        return ret;
862
981
}
863
982
 
891
1010
{
892
1011
        gint ret = -1;
893
1012
 
894
 
        READER_LOCK (cdb);
 
1013
        cdb_reader_lock (cdb);
895
1014
 
896
1015
        START (query);
897
1016
        ret = cdb_sql_exec (cdb->db, query, count_cb, count, error);
898
1017
        END;
899
1018
 
900
 
        READER_UNLOCK (cdb);
 
1019
        cdb_reader_unlock (cdb);
901
1020
 
902
1021
        CAMEL_DB_RELEASE_SQLITE_MEMORY;
903
1022
 
1098
1217
                return ret;
1099
1218
 
1100
1219
        d (g_print ("\n%s:\n%s \n", G_STRFUNC, stmt));
1101
 
        READER_LOCK (cdb);
 
1220
        cdb_reader_lock (cdb);
1102
1221
 
1103
1222
        START (stmt);
1104
1223
        ret = cdb_sql_exec (cdb->db, stmt, callback, data, error);
1105
1224
        END;
1106
1225
 
1107
 
        READER_UNLOCK (cdb);
 
1226
        cdb_reader_unlock (cdb);
1108
1227
        CAMEL_DB_RELEASE_SQLITE_MEMORY;
1109
1228
 
1110
1229
        return ret;
1459
1578
 
1460
1579
        /* Migration stage one: storing the old data */
1461
1580
 
1462
 
        if (version < 1) {
 
1581
        if (version < 0) {
 
1582
                ret = camel_db_create_message_info_table (cdb, folder_name, error);
 
1583
                g_clear_error (error);
 
1584
        } else if (version < 1) {
1463
1585
 
1464
1586
                /* Between version 0-1 the following things are changed
1465
1587
                 * ADDED: created: time
1504
1626
                                folder_name);
1505
1627
                ret = camel_db_add_to_transaction (cdb, table_creation_query, error);
1506
1628
                sqlite3_free (table_creation_query);
 
1629
                g_clear_error (error);
1507
1630
 
1508
1631
                table_creation_query = sqlite3_mprintf (
1509
1632
                        "INSERT INTO 'mem.%q' SELECT "
1518
1641
                        folder_name, folder_name);
1519
1642
                ret = camel_db_add_to_transaction (cdb, table_creation_query, error);
1520
1643
                sqlite3_free (table_creation_query);
 
1644
                g_clear_error (error);
1521
1645
 
1522
1646
                table_creation_query = sqlite3_mprintf ("DROP TABLE IF EXISTS %Q", folder_name);
1523
1647
                ret = camel_db_add_to_transaction (cdb, table_creation_query, error);
1524
1648
                sqlite3_free (table_creation_query);
 
1649
                g_clear_error (error);
1525
1650
 
1526
1651
                ret = camel_db_create_message_info_table (cdb, folder_name, error);
1527
1652
                g_clear_error (error);
1678
1803
                                     GError **error)
1679
1804
{
1680
1805
        gint ret, current_version;
 
1806
        gboolean in_transaction = TRUE;
1681
1807
        GError *err = NULL;
1682
1808
 
1683
1809
        /* Make sure we have the table already */
1687
1813
                goto exit;
1688
1814
 
1689
1815
        camel_db_end_transaction (cdb, &err);
 
1816
        in_transaction = FALSE;
1690
1817
 
1691
1818
        /* Migration stage zero: version fetch */
1692
1819
        current_version = camel_db_get_folder_version (cdb, folder_name, &err);
 
1820
        if (err && err->message && strstr (err->message, "no such table") != NULL) {
 
1821
                g_clear_error (&err);
 
1822
                current_version = -1;
 
1823
        }
1693
1824
 
1694
1825
        camel_db_begin_transaction (cdb, &err);
 
1826
        in_transaction = TRUE;
1695
1827
 
1696
1828
        /* Migration stage one: storing the old data if necessary */
1697
1829
        ret = camel_db_migrate_folder_prepare (cdb, folder_name, current_version, &err);
1709
1841
                goto exit;
1710
1842
 
1711
1843
        camel_db_end_transaction (cdb, &err);
 
1844
        in_transaction = FALSE;
1712
1845
 
1713
1846
exit:
1714
 
        if (err && cdb->priv->transaction_is_on)
 
1847
        if (err && in_transaction)
1715
1848
                camel_db_abort_transaction (cdb, NULL);
1716
1849
 
1717
1850
        if (err)
2600
2733
 
2601
2734
        return GPOINTER_TO_INT (value);
2602
2735
}
 
2736
 
 
2737
static gint
 
2738
get_number_cb (gpointer data,
 
2739
               gint argc,
 
2740
               gchar **argv,
 
2741
               gchar **azColName)
 
2742
{
 
2743
        guint64 *pui64 = data;
 
2744
 
 
2745
        if (argc == 1) {
 
2746
                *pui64 = argv[0] ? g_ascii_strtoull (argv[0], NULL, 10) : 0;
 
2747
        } else {
 
2748
                *pui64 = 0;
 
2749
        }
 
2750
 
 
2751
        return 0;
 
2752
}
 
2753
 
 
2754
/**
 
2755
 * camel_db_maybe_run_maintenance:
 
2756
 * @cdb: a #CamelDB instance
 
2757
 * @error: (allow none): a #GError or %NULL
 
2758
 *
 
2759
 * Runs a @cdb maintenance, which includes vacuum, if necessary.
 
2760
 *
 
2761
 * Returns: Whether succeeded.
 
2762
 *
 
2763
 * Since: 3.16
 
2764
 **/
 
2765
gboolean
 
2766
camel_db_maybe_run_maintenance (CamelDB *cdb,
 
2767
                                GError **error)
 
2768
{
 
2769
        GError *local_error = NULL;
 
2770
        guint64 page_count = 0, freelist_count = 0;
 
2771
        gboolean success = FALSE;
 
2772
 
 
2773
        g_return_val_if_fail (cdb != NULL, FALSE);
 
2774
 
 
2775
        cdb_writer_lock (cdb);
 
2776
 
 
2777
        if (cdb_sql_exec (cdb->db, "PRAGMA page_count;", get_number_cb, &page_count, &local_error) == SQLITE_OK &&
 
2778
            cdb_sql_exec (cdb->db, "PRAGMA freelist_count;", get_number_cb, &freelist_count, &local_error) == SQLITE_OK) {
 
2779
                /* Vacuum, if there's more than 5% of the free pages */
 
2780
                success = !page_count || !freelist_count || freelist_count * 1000 / page_count <= 50 ||
 
2781
                    cdb_sql_exec (cdb->db, "vacuum;", NULL, NULL, &local_error) == SQLITE_OK;
 
2782
        }
 
2783
 
 
2784
        cdb_writer_unlock (cdb);
 
2785
 
 
2786
        if (local_error) {
 
2787
                g_propagate_error (error, local_error);
 
2788
                success = FALSE;
 
2789
        }
 
2790
 
 
2791
        return success;
 
2792
}