~mhr3/unity-lens-applications/fix-858056

« back to all changes in this revision

Viewing changes to src/unity-ratings-db.c

  • Committer: Mikkel Kamstrup Erlandsen
  • Date: 2011-09-23 12:52:49 UTC
  • mfrom: (232.1.21 ratings-query)
  • Revision ID: mikkel.kamstrup@gmail.com-20110923125249-s1a37i06uerthbw0
MergeĀ lp:~kamstrup/unity-lens-applications/ratings-query

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2011 Canonical Ltd
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License version 3 as
 
6
 * published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
 * GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by Mikkel Kamstrup Erlandsen <mikkel.kamstrup@canonical.com>
 
17
 *
 
18
 */
 
19
 
 
20
#include "unity-ratings-db.h"
 
21
#include <string.h>
 
22
#include <db.h>
 
23
 
 
24
/* Hacky check, but we *really* need to have the same libdb version as the
 
25
 * software-center is using to avoid a cascade of fail */
 
26
#if DB_VERSION_MAJOR != 4 || DB_VERSION_MINOR != 8
 
27
  #error "unity-lens-applications only compiles and works against libdb-4.8. Please install the package libdb4.8-dev"
 
28
#endif
 
29
 
 
30
struct _UnityRatingsDatabase {
 
31
  DB_ENV  *env;
 
32
  DB      *db;
 
33
};
 
34
 
 
35
/* IMPLEMENTATION NOTE: It is paramount that we create our BDB environment
 
36
 *                      in "concurrent" mode. This makes the database
 
37
 *                      single-writer-multiple-reader safe. Hence allowing
 
38
 *                      us to read the DB while S-C is updating it.
 
39
 */
 
40
 
 
41
 
 
42
#define UNITY_RATINGS_DB_PATH "software-center/reviews.ubuntu.com_reviews_api_1.0_review-stats-pkgnames.p__4.8.db"
 
43
#define UNITY_RATINGS_DB_ENV_PATH UNITY_RATINGS_DB_PATH".dbenv"
 
44
 
 
45
UnityRatingsDatabase*
 
46
unity_ratings_database_new (GError                **error)
 
47
{
 
48
  UnityRatingsDatabase *self;
 
49
  DB_ENV *env;
 
50
  DB     *db;
 
51
  int     error_code;
 
52
  gchar  *path;
 
53
  
 
54
  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
55
  
 
56
  /* Create a database environment in concurrent mode,
 
57
   * enabling single-writer-multiple-reader support */
 
58
  path = g_build_filename (g_get_user_cache_dir (),
 
59
                           UNITY_RATINGS_DB_ENV_PATH,
 
60
                           NULL);
 
61
  db_env_create (&env, 0);
 
62
  error_code = env->open (env,
 
63
                          path,                        /* db env home dir */
 
64
                          DB_INIT_CDB | DB_INIT_MPOOL, /* use concurrent mode */
 
65
                          0600 /* access mode (user-rw only) */);
 
66
  
 
67
  if (error_code)
 
68
    {
 
69
      g_set_error (error, G_FILE_ERROR, error_code,
 
70
                   "Unable to open ratings database environment '%s': %s",
 
71
                   path, db_strerror (error_code)); // FIXME: Leak db_strerror() return?
 
72
      env->close (env, 0);
 
73
      g_free (path);
 
74
      return NULL;
 
75
    }
 
76
  
 
77
  g_free (path);
 
78
  
 
79
  /* Create a db handle in our environment */
 
80
  path = g_build_filename (g_get_user_cache_dir (),
 
81
                           UNITY_RATINGS_DB_PATH,
 
82
                           NULL);
 
83
  db_create (&db, env, 0);
 
84
  error_code = db->open (db,
 
85
                         NULL,       /* transaction context */
 
86
                         path,       /* file name */
 
87
                         NULL,       /* db name */
 
88
                         DB_HASH,    /* db type */
 
89
                         DB_RDONLY,  /* flags - read-only */
 
90
                         0600        /* access mode (user-rw only) */);
 
91
  
 
92
  if (error_code)
 
93
    {
 
94
      g_set_error (error, G_FILE_ERROR, error_code,
 
95
                   "Unable to open ratings database '%s': %s",
 
96
                   path, db_strerror (error_code)); // FIXME: Leak db_strerror() return?
 
97
      g_free (path);
 
98
      db->close (db, 0);
 
99
      env->close (env, 0);
 
100
      return NULL;
 
101
    }
 
102
  
 
103
  g_free (path);
 
104
  
 
105
  self = g_new0 (UnityRatingsDatabase, 1);
 
106
  self->env = env;
 
107
  self->db = db;
 
108
  
 
109
  return self;
 
110
}
 
111
 
 
112
void
 
113
unity_ratings_database_free (UnityRatingsDatabase   *self)
 
114
{
 
115
  g_return_if_fail (self != NULL);
 
116
  
 
117
  self->db->close (self->db, 0);
 
118
  self->env->close (self->env, 0);
 
119
  
 
120
  g_free (self);
 
121
}
 
122
 
 
123
gboolean
 
124
unity_ratings_database_query (UnityRatingsDatabase   *self,
 
125
                              const gchar            *pkgname,
 
126
                              UnityRatingsResult     *out_result)
 
127
{
 
128
  DBT     key = { 0 }, data = { 0 };
 
129
  gint    error_code;
 
130
  
 
131
  
 
132
  g_return_val_if_fail (self != NULL, FALSE);
 
133
  g_return_val_if_fail (pkgname != NULL, FALSE);
 
134
  g_return_val_if_fail (out_result != NULL, FALSE);
 
135
  
 
136
  /* Make sure the DBTs are zeroed. Otherwise libdb throws a fit */
 
137
  key.data = (gchar*)pkgname;
 
138
  key.size = strlen (pkgname);
 
139
  key.ulen = key.size;
 
140
  key.dlen = 0;
 
141
  key.doff = 0;
 
142
  key.flags = DB_DBT_USERMEM;
 
143
  data.data = out_result;
 
144
  data.size = 0;
 
145
  data.ulen = sizeof (UnityRatingsResult);
 
146
  data.dlen = 0;
 
147
  data.doff = 0;
 
148
  data.flags= DB_DBT_USERMEM;
 
149
  
 
150
  error_code = self->db->get (self->db,
 
151
                              NULL,
 
152
                              &key,
 
153
                              &data,
 
154
                              0);
 
155
  
 
156
  /* error_code == 0 means success, everything else is bad */
 
157
  if (error_code == DB_NOTFOUND)
 
158
    {
 
159
      goto not_found;
 
160
    }
 
161
  else if (error_code)
 
162
    {
 
163
      g_warning ("Error looking up ratings for '%s': %s",
 
164
                 pkgname, db_strerror (error_code)); // FIXME : leak strerror?
 
165
      goto not_found;
 
166
    }
 
167
  
 
168
  if (data.size != 3*sizeof (gint32))
 
169
    {
 
170
      g_critical ("Unexpected datum size from ratings database %i bytes. "
 
171
                  "Expected %i bytes", data.size, 3*sizeof (gint32));
 
172
      goto not_found;
 
173
    }
 
174
  
 
175
  return TRUE;
 
176
  
 
177
  not_found:
 
178
    out_result->average_rating = 0;
 
179
    out_result->total_rating = 0;
 
180
    out_result->dampened_rating = 0;
 
181
    return FALSE;
 
182
}
 
183