void meta0_backend_migrate(struct meta0_backend_s *m0) { GError *err = NULL; struct sqlx_sqlite3_s *handle=NULL; struct sqlx_sqlite3_s *oldhandle=NULL; struct sqlx_name_s n; n.base = m0->ns; n.type = NAME_SRVTYPE_META0; n.ns = m0->ns; err = sqlx_repository_open_and_lock(m0->repository, &n, SQLX_OPEN_LOCAL, &handle, NULL); if ( err ) { // check if the erreur message is the ENOENT message ; DB doesn't exist if ( (strstr(err->message, strerror(ENOENT)) != NULL) ) { g_clear_error(&err); err = NULL; err = sqlx_repository_open_and_lock(m0->repository, &n, SQLX_OPEN_LOCAL|SQLX_OPEN_CREATE,&handle, NULL); if( !err ) { // Migration (1.7 -> 1.8) from old meta0 database n.base = m0->id; err = sqlx_repository_open_and_lock(m0->repository, &n, SQLX_OPEN_LOCAL, &oldhandle,NULL); if ( ! err ) { GRID_INFO("Start Migrate meta0 database"); err = sqlx_repository_backup_base(oldhandle,handle); if ( err ) { GRID_ERROR("Failed to migrate meta0 database : (%d) %s",err->code,err->message); } else { sqlx_repository_unlock_and_close_noerror(oldhandle); // APPLY schema gint rc; char *errmsg = NULL; rc = sqlite3_exec(handle->db, META0_SCHEMA, NULL, NULL, &errmsg); if (rc != SQLITE_OK && rc != SQLITE_DONE) { GRID_WARN("Failed to apply schema (%d) %s %s",rc,sqlite3_errmsg(handle->db), errmsg); } if(errmsg != NULL) g_free(errmsg); // set table version GRID_INFO("Update version in database"); sqlx_admin_inc_all_versions(handle, 2); } } else { // database 1.7 doesn't existe ; new grid g_clear_error(&err); err = NULL; } } else { GRID_ERROR("Failed to create meta0 database :(%d) %s",err->code,err->message); } } } if ( handle) sqlx_repository_unlock_and_close_noerror(handle); }
static GError* _open_and_lock(struct meta0_backend_s *m0, enum m0v2_open_type_e how, struct sqlx_sqlite3_s **handle) { GError *err = NULL; EXTRA_ASSERT(m0 != NULL); EXTRA_ASSERT(handle != NULL); /* Now open/lock the base in a way suitable for our op */ guint flag = m0_to_sqlx(how); struct sqlx_name_s n = {.base=m0->ns, .type=NAME_SRVTYPE_META0, .ns=m0->ns}; err = sqlx_repository_open_and_lock(m0->repository, &n, flag, handle, NULL); if (err != NULL) { if (!CODE_IS_REDIRECT(err->code)) g_prefix_error(&err, "Open/Lock error: "); return err; } EXTRA_ASSERT(*handle != NULL); GRID_TRACE("Opened and locked [%s/%s]", m0->id, NAME_SRVTYPE_META0); return NULL; } static void _unlock_and_close(struct sqlx_sqlite3_s *sq3) { EXTRA_ASSERT(sq3 != NULL); sqlx_admin_save_lazy (sq3); sqlx_repository_unlock_and_close_noerror(sq3); }
static void _round_open_close (void) { sqlx_repository_t *repo = NULL; GError *err; err = sqlx_repository_init("/tmp", NULL, &repo); g_assert_no_error (err); g_assert_true (sqlx_repository_running (repo)); err = sqlx_repository_configure_type(repo, type, SCHEMA); g_assert_no_error (err); sqlx_repository_set_locator (repo, _locator, NULL); for (int i=0; i<5 ;i++) { struct sqlx_sqlite3_s *sq3 = NULL; struct sqlx_name_s n = { .base = name, .type = type, .ns = nsname, }; err = sqlx_repository_open_and_lock(repo, &n, SQLX_OPEN_LOCAL, &sq3, NULL); g_assert_no_error (err); g_assert_nonnull (sq3); err = sqlx_repository_unlock_and_close(sq3); g_assert_no_error (err); } sqlx_repository_clean(repo); }
GError* _open_and_lock(struct meta1_backend_s *m1, struct oio_url_s *url, enum m1v2_open_type_e how, struct sqlx_sqlite3_s **handle) { EXTRA_ASSERT(m1 != NULL); EXTRA_ASSERT(url != NULL); EXTRA_ASSERT(handle != NULL); GRID_TRACE2("%s(%p,%p,%d,%p)", __FUNCTION__, (void*)m1, oio_url_get (url, OIOURL_HEXID), how, (void*)handle); if (!oio_url_has (url, OIOURL_HEXID)) return NEWERROR (CODE_BAD_REQUEST, "Partial URL (missing HEXID)"); if (!m1b_check_ns_url (m1, url)) return NEWERROR(CODE_NAMESPACE_NOTMANAGED, "Invalid NS"); gchar base[5]; const guint8 *cid = oio_url_get_id(url); g_snprintf(base, sizeof(base), "%02X%02X", cid[0], cid[1]); if (!meta1_prefixes_is_managed(m1->prefixes, cid)) return NEWERROR(CODE_RANGE_NOTFOUND, "prefix [%s] not managed", base); /* Now open/lock the base in a way suitable for our op */ struct sqlx_name_s n = {.base=base, .type=NAME_SRVTYPE_META1, .ns=m1->ns_name}; GError *err = sqlx_repository_open_and_lock(m1->repo, &n, m1_to_sqlx(how), handle, NULL); if (err != NULL) { if (!CODE_IS_REDIRECT(err->code)) g_prefix_error(&err, "Open/Lock error: "); return err; } EXTRA_ASSERT(*handle != NULL); GRID_TRACE("Opened and locked [%s][%s] -> [%s][%s]", base, NAME_SRVTYPE_META1, (*handle)->name.base, (*handle)->name.type); return NULL; } GError* __create_user(struct sqlx_sqlite3_s *sq3, struct oio_url_s *url) { if (!oio_url_has_fq_container (url)) return NEWERROR(CODE_BAD_REQUEST, "Partial URL"); static const gchar *sql = "INSERT INTO users ('cid','account','user') VALUES (?,?,?)"; GError *err = NULL; sqlite3_stmt *stmt = NULL; int rc; EXTRA_ASSERT(sq3 != NULL); EXTRA_ASSERT(sq3->db != NULL); /* Prepare the statement */ sqlite3_prepare_debug(rc, sq3->db, sql, -1, &stmt, NULL); if (rc != SQLITE_OK) err = M1_SQLITE_GERROR(sq3->db, rc); else { sqlite3_bind_blob(stmt, 1, oio_url_get_id(url), oio_url_get_id_size(url), NULL); sqlite3_bind_text(stmt, 2, oio_url_get(url, OIOURL_ACCOUNT), -1, NULL); sqlite3_bind_text(stmt, 3, oio_url_get(url, OIOURL_USER), -1, NULL); /* Run the results */ do { rc = sqlite3_step(stmt); } while (rc == SQLITE_ROW); if (rc != SQLITE_OK && rc != SQLITE_DONE) { err = M1_SQLITE_GERROR(sq3->db, rc); if (rc == SQLITE_CONSTRAINT) { g_prefix_error(&err, "Already created? "); err->code = CODE_CONTAINER_EXISTS; } } sqlite3_finalize_debug(rc, stmt); } if (err) GRID_DEBUG("User creation failed : (%d) %s", err->code, err->message); return err; } GError* __info_user(struct sqlx_sqlite3_s *sq3, struct oio_url_s *url, gboolean ac, struct oio_url_s ***result) { GError *err = NULL; sqlite3_stmt *stmt = NULL; GPtrArray *gpa; int rc; gboolean found; EXTRA_ASSERT(sq3 != NULL); EXTRA_ASSERT(sq3->db != NULL); EXTRA_ASSERT(url != NULL); retry: /* Prepare the statement */ sqlite3_prepare_debug(rc, sq3->db, "SELECT account,user FROM users WHERE cid = ?", -1, &stmt, NULL); if (rc != SQLITE_OK) return M1_SQLITE_GERROR(sq3->db, rc); (void) sqlite3_bind_blob(stmt, 1, oio_url_get_id (url), oio_url_get_id_size (url), NULL); /* Run the results */ found = FALSE; gpa = result ? g_ptr_array_new() : NULL; do { if (SQLITE_ROW == (rc = sqlite3_step(stmt))) { found = TRUE; if (!gpa) continue; struct oio_url_s *u = oio_url_empty (); oio_url_set (u, OIOURL_NS, oio_url_get (url, OIOURL_NS)); oio_url_set (u, OIOURL_ACCOUNT, (char*)sqlite3_column_text(stmt, 0)); oio_url_set (u, OIOURL_USER, (char*)sqlite3_column_text(stmt, 1)); oio_url_set (u, OIOURL_HEXID, oio_url_get (url, OIOURL_HEXID)); g_ptr_array_add(gpa, u); } } while (rc == SQLITE_ROW); if (rc != SQLITE_DONE && rc != SQLITE_OK) { err = M1_SQLITE_GERROR(sq3->db, rc); g_prefix_error(&err, "DB error: "); } sqlite3_finalize_debug(rc,stmt); stmt = NULL; if (err) { if (gpa) { g_ptr_array_set_free_func (gpa, (GDestroyNotify)oio_url_clean); g_ptr_array_free (gpa, TRUE); } return err; } if (!found) { if (gpa) g_ptr_array_free (gpa, TRUE); if (ac) { ac = FALSE; /* do not retry */ err = __create_user (sq3, url); if (!err) goto retry; } return NEWERROR(CODE_USER_NOTFOUND, "no such container"); } if (gpa) *result = (struct oio_url_s**) metautils_gpa_to_array(gpa, TRUE); return NULL; }
static GError * m2b_open(struct meta2_backend_s *m2, struct oio_url_s *url, enum m2v2_open_type_e how, struct sqlx_sqlite3_s **result) { GError *err = NULL; struct sqlx_sqlite3_s *sq3 = NULL; EXTRA_ASSERT(url != NULL); EXTRA_ASSERT(result != NULL); EXTRA_ASSERT(m2 != NULL); EXTRA_ASSERT(m2->backend.repo != NULL); /* TODO */ gboolean no_peers = FALSE; if (no_peers) { how &= ~M2V2_OPEN_REPLIMODE; how |= M2V2_OPEN_LOCAL|M2V2_OPEN_NOREFCHECK; } struct sqlx_name_mutable_s n; sqlx_name_fill (&n, url, NAME_SRVTYPE_META2, 1); err = sqlx_repository_open_and_lock(m2->backend.repo, sqlx_name_mutable_to_const(&n), m2_to_sqlx(how), &sq3, NULL); sqlx_name_clean (&n); if (NULL != err) { if (err->code == CODE_CONTAINER_NOTFOUND) err->domain = GQ(); return err; } sq3->no_peers = how & (M2V2_OPEN_LOCAL|M2V2_OPEN_NOREFCHECK); // XXX If the container is being deleted, this is sad ... // This MIGHT happen if a cache is present (and this is the // common case for m2v2), because the deletion will happen // when the base exit the cache. // In facts this SHOULD NOT happend because a base being deleted // is closed with an instruction to exit the cache immediately. // TODO FIXME this is maybe a good place for an assert(). if (sq3->deleted) { err = NEWERROR(CODE_CONTAINER_FROZEN, "destruction pending"); m2b_close(sq3); return err; } // Complete URL with full VNS and container name void set(gchar *k, int f) { if (oio_url_has(url, f)) return; gchar *s = sqlx_admin_get_str (sq3, k); if (s) { oio_url_set (url, f, s); g_free (s); } } set (SQLX_ADMIN_NAMESPACE, OIOURL_NS); set (SQLX_ADMIN_ACCOUNT, OIOURL_ACCOUNT); set (SQLX_ADMIN_USERNAME, OIOURL_USER); set (SQLX_ADMIN_USERTYPE, OIOURL_TYPE); *result = sq3; return NULL; }