GError * meta0_backend_reset(struct meta0_backend_s *m0, gboolean flag_local) { EXTRA_ASSERT(m0 != NULL); GError *err = NULL; struct sqlx_sqlite3_s *sq3 = NULL; struct sqlx_repctx_s *repctx = NULL; err = _open_and_lock(m0, flag_local ? M0V2_OPENBASE_LOCAL : M0V2_OPENBASE_MASTERONLY, &sq3); if (err) return err; if (!(err = sqlx_transaction_begin (sq3, &repctx))) { gint rc; sqlite3_stmt *stmt = NULL; sqlite3_prepare_debug (rc, sq3->db, "DELETE FROM meta1", -1, &stmt, NULL); if (rc != SQLITE_OK && rc != SQLITE_DONE) err = SQLITE_GERROR(sq3->db, rc); else { sqlite3_step_debug_until_end (rc, stmt); if (rc != SQLITE_OK && rc != SQLITE_DONE) err = SQLITE_GERROR(sq3->db, rc); else sqlx_transaction_notify_huge_changes (repctx); sqlite3_finalize_debug (rc, stmt); } err = sqlx_transaction_end (repctx, err); } _unlock_and_close (sq3); return NULL; }
GError* meta0_backend_assign(struct meta0_backend_s *m0, const GPtrArray *new_assign_prefixes, const GPtrArray *new_assign_meta1ref, const gboolean init) { GError *err; struct sqlx_sqlite3_s *sq3 = NULL; struct sqlx_repctx_s *repctx = NULL; EXTRA_ASSERT(m0 != NULL); EXTRA_ASSERT(new_assign_prefixes != NULL); EXTRA_ASSERT(new_assign_meta1ref != NULL); err = _open_and_lock(m0, M0V2_OPENBASE_MASTERONLY, &sq3); if (NULL != err) return err; err = sqlx_transaction_begin(sq3, &repctx); if (NULL == err) { err = _assign_prefixes(sq3->db, new_assign_prefixes,init); if (!err) err = _record_meta1ref(sq3->db, new_assign_meta1ref); err = sqlx_transaction_end(repctx, err); } _unlock_and_close(sq3); return err; }
GError * meta1_backend_services_link (struct meta1_backend_s *m1, struct oio_url_s *url, const char *srvtype, gboolean dryrun, gboolean autocreate, gchar ***result) { struct sqlx_sqlite3_s *sq3 = NULL; GError *err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERONLY, &sq3); if (err) return err; struct sqlx_repctx_s *repctx = NULL; if (!(err = sqlx_transaction_begin(sq3, &repctx))) { gboolean renewed = FALSE; if (!(err = __info_user(sq3, url, autocreate, NULL))) { enum m1v2_getsrv_e mode = dryrun ? M1V2_GETSRV_DRYRUN : M1V2_GETSRV_REUSE; err = __get_container_service(sq3, url, srvtype, m1, mode, result, &renewed); if (NULL != err) g_prefix_error(&err, "Query error: "); } if (!(err = sqlx_transaction_end(repctx, err))) { if (renewed) __notify_services_by_cid(m1, sq3, url); } } sqlx_repository_unlock_and_close_noerror(sq3); return err; }
GError* meta1_backend_services_set(struct meta1_backend_s *m1, struct oio_url_s *url, const char *packedurl, gboolean autocreate, gboolean force) { struct meta1_service_url_s *m1url; if (!(m1url = meta1_unpack_url(packedurl))) return NEWERROR(CODE_BAD_REQUEST, "Invalid URL"); struct sqlx_sqlite3_s *sq3 = NULL; GError *err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERONLY, &sq3); if (err) { g_free(m1url); return err; } struct sqlx_repctx_s *repctx = NULL; if (!(err = sqlx_transaction_begin(sq3, &repctx))) { if (!(err = __info_user(sq3, url, autocreate, NULL))) err = __save_service(sq3, url, m1url, force); if (!(err = sqlx_transaction_end(repctx, err))) __notify_services_by_cid(m1, sq3, url); } sqlx_repository_unlock_and_close_noerror(sq3); g_free(m1url); /* XXX JFS: ugly quirk until we find a pretty way to distinguish the * commit errors (e.g. it can fail because of a replication error or * a constraint violation) */ if (err && NULL != strstr(err->message, "UNIQUE")) err->code = CODE_SRV_ALREADY; return err; }
GError * meta1_backend_services_all(struct meta1_backend_s *m1, struct oio_url_s *url, gchar ***result) { struct sqlx_sqlite3_s *sq3 = NULL; GError *err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERSLAVE, &sq3); if (err) return err; struct sqlx_repctx_s *repctx = NULL; if (!(err = sqlx_transaction_begin(sq3, &repctx))) { struct meta1_service_url_s **used = NULL; if (NULL != (err = __get_all_services(sq3, &used))) g_prefix_error(&err, "Query error: "); else { struct meta1_service_url_s **expanded = expand_urlv(used); *result = pack_urlv(expanded); meta1_service_url_cleanv(expanded); meta1_service_url_cleanv(used); } err = sqlx_transaction_end(repctx, err); } sqlx_repository_unlock_and_close_noerror(sq3); return err; }
GError * meta1_backend_services_list(struct meta1_backend_s *m1, struct oio_url_s *url, const char *srvtype, gchar ***result) { struct sqlx_sqlite3_s *sq3 = NULL; GError *err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERSLAVE, &sq3); if (err) return err; struct sqlx_repctx_s *repctx = NULL; if (!(err = sqlx_transaction_begin(sq3, &repctx))) { if (!(err = __info_user(sq3, url, FALSE, NULL))) { struct meta1_service_url_s **uv = NULL; err = __get_container_all_services(sq3, url, srvtype, &uv); if (NULL != err) g_prefix_error(&err, "Query error: "); else { struct meta1_service_url_s **expanded; expanded = expand_urlv(uv); *result = pack_urlv(expanded); meta1_service_url_cleanv(expanded); meta1_service_url_cleanv(uv); } } err = sqlx_transaction_end(repctx, err); } sqlx_repository_unlock_and_close_noerror(sq3); return err; }
GError* meta1_backend_services_config(struct meta1_backend_s *m1, struct oio_url_s *url, const char *packedurl) { struct meta1_service_url_s *m1url; if (!(m1url = meta1_unpack_url(packedurl))) return NEWERROR(CODE_BAD_REQUEST, "Invalid URL"); GRID_DEBUG("About to reconfigure [%s] [%"G_GINT64_FORMAT"] [%s] [%s]", m1url->srvtype, m1url->seq, m1url->host, m1url->args); struct sqlx_sqlite3_s *sq3 = NULL; GError *err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERONLY, &sq3); if (err) { g_free(m1url); return err; } struct sqlx_repctx_s *repctx = NULL; if (!(err = sqlx_transaction_begin(sq3, &repctx))) { if (!(err = __info_user(sq3, url, FALSE, NULL))) err = __configure_service(sq3, url, m1url); if (!(err = sqlx_transaction_end(repctx, err))) __notify_services_by_cid(m1, sq3, url); } sqlx_repository_unlock_and_close_noerror(sq3); g_free(m1url); return err; }
GError * meta1_backend_set_container_properties(struct meta1_backend_s *m1, struct oio_url_s *url, gchar **props, gboolean flush) { EXTRA_ASSERT(props != NULL); GError *err; if (NULL != (err = __check_property_format(props))) { g_prefix_error(&err, "Malformed properties: "); return err; } struct sqlx_sqlite3_s *sq3 = NULL; err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERONLY, &sq3); if (err) return err; struct sqlx_repctx_s *repctx = NULL; if (!(err = sqlx_transaction_begin(sq3, &repctx))) { if (!(err = __info_user(sq3, url, FALSE, NULL))) { if (flush) { err = __del_container_properties(sq3, url, NULL); if (err) g_prefix_error(&err, "Flush error: "); } if (!err) { err = __set_container_properties(sq3, url, props); if (err) g_prefix_error(&err, "Set error: "); } } err = sqlx_transaction_end(repctx, err); } sqlx_repository_unlock_and_close_noerror(sq3); return err; }
GError* meta1_backend_services_unlink(struct meta1_backend_s *m1, struct oio_url_s *url, const char *srvtype, gchar **urlv) { GError *err = __check_backend_events (m1); if (err) return err; EXTRA_ASSERT(srvtype != NULL); struct sqlx_sqlite3_s *sq3 = NULL; err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERONLY, &sq3); if (err) return err; struct sqlx_repctx_s *repctx = NULL; if (!(err = sqlx_transaction_begin(sq3, &repctx))) { if (!(err = __info_user(sq3, url, FALSE, NULL))) { err = __del_container_services(sq3, url, srvtype, urlv); if (NULL != err) g_prefix_error(&err, "Query error: "); } if (!(err = sqlx_transaction_end(repctx, err))) __notify_services_by_cid(m1, sq3, url); } sqlx_repository_unlock_and_close_noerror(sq3); return err; }
static GError * _create_container_init_phase(struct sqlx_sqlite3_s *sq3, struct oio_url_s *url, struct m2v2_create_params_s *params) { GError *err = NULL; struct sqlx_repctx_s *repctx = NULL; if (!params->local && (err = _transaction_begin(sq3, url, &repctx))) return err; if (!err && params->storage_policy) err = m2db_set_storage_policy(sq3, params->storage_policy, 0); if (!err && params->version_policy) { gint64 max = g_ascii_strtoll(params->version_policy, NULL, 10); m2db_set_max_versions(sq3, max); } if (!err) { m2db_set_ctime (sq3, oio_ext_real_time()); sqlx_admin_init_i64(sq3, META2_INIT_FLAG, 1); } if (!err && params->properties) { for (gchar **p=params->properties; *p && *(p+1) ;p+=2) sqlx_admin_set_str (sq3, *p, *(p+1)); } if (!params->local) err = sqlx_transaction_end(repctx, err); return err; }
static GError* _update_container_quota(struct meta1_backend_s *m1, struct container_info_s *cinfo) { GError *e0 = NULL; gint rc; sqlite3_stmt *stmt = NULL; struct sqlx_sqlite3_s *sq3 = NULL; struct sqlx_repctx_s *repctx = NULL; e0 = meta1_backend_open_base(m1, cinfo->id, M1V2_OPENBASE_MASTERONLY, &sq3); if (NULL != e0) return e0; e0 = sqlx_transaction_begin(sq3, &repctx); if (NULL != e0) { sqlx_repository_unlock_and_close_noerror(sq3); return e0; } sqlite3_prepare_debug(rc, sq3->db, "UPDATE properties SET" " value = ?" " WHERE cid = ?" " AND name = 'meta2.quota'", -1, &stmt, NULL); (void) sqlite3_bind_int64(stmt, 1, cinfo->size); (void) sqlite3_bind_blob(stmt, 2, cinfo->id, sizeof(container_id_t), NULL); for (rc=SQLITE_ROW; rc == SQLITE_ROW ;) rc = sqlite3_step(stmt); if (rc != SQLITE_OK && rc != SQLITE_DONE) e0 = SQLITE_GERROR(sq3->db, rc); sqlite3_finalize_debug(rc, stmt); if (!e0 && sqlite3_changes(sq3->db) <= 0) { sqlite3_prepare_debug(rc, sq3->db, "INSERT INTO properties (cid,name,value)" " VALUES (?,?,?)", -1, &stmt, NULL); (void) sqlite3_bind_blob(stmt, 1, cinfo->id, sizeof(container_id_t), NULL); (void) sqlite3_bind_text(stmt, 2, "meta2.quota", sizeof("meta2.quota")-1, NULL); (void) sqlite3_bind_int64(stmt, 3, cinfo->size); for (rc=SQLITE_ROW; rc == SQLITE_ROW ;) rc = sqlite3_step(stmt); if (rc != SQLITE_OK && rc != SQLITE_DONE) e0 = SQLITE_GERROR(sq3->db, rc); sqlite3_finalize_debug(rc, stmt); } /* Commit then close the container's base */ e0 = sqlx_transaction_end(repctx, e0); sqlx_repository_unlock_and_close_noerror(sq3); return e0; }
GError* meta0_backend_destroy_meta1_ref(struct meta0_backend_s *m0, gchar *meta1) { GError *err = NULL; struct sqlx_sqlite3_s *sq3 = NULL; struct sqlx_repctx_s *repctx = NULL; GPtrArray *result; gchar *v, *addr, *ref, *nb; guint i, max, cmpaddr, cmpstate; EXTRA_ASSERT(m0 != NULL); EXTRA_ASSERT(meta1 != NULL); /* check if meta1 is disable */ if (NULL != (err = _reload(m0, TRUE))) { g_prefix_error(&err, "Reload error: "); return err; } g_rw_lock_reader_lock(&(m0->rwlock)); EXTRA_ASSERT(m0->array_meta1_ref != NULL); result = meta0_utils_array_meta1ref_dup(m0->array_meta1_ref); g_rw_lock_reader_unlock(&(m0->rwlock)); for (i=0,max=result->len; i<max ;i++) { if (!(v = result->pdata[i])) continue; meta0_utils_unpack_meta1ref(v,&addr,&ref,&nb); cmpaddr = g_ascii_strcasecmp(addr,meta1); cmpstate = g_ascii_strcasecmp(ref,"0"); g_free(addr); g_free(ref); g_free(nb); if ( cmpaddr == 0) { if (cmpstate != 0) return NEWERROR(EINVAL, "meta1 always available to prefix allocation"); err = _open_and_lock(m0, M0V2_OPENBASE_MASTERONLY, &sq3); if (NULL != err) return err; err = sqlx_transaction_begin(sq3, &repctx); if (NULL == err) { err = _delete_meta1_ref(sq3->db, meta1); err = sqlx_transaction_end(repctx, err); } _unlock_and_close(sq3); return err; } } return NEWERROR(EINVAL, "UNKNOWN meta1"); }
GError* __destroy_container(struct sqlx_sqlite3_s *sq3, struct hc_url_s *url, gboolean force, gboolean *done) { GError *err = NULL; gint count_actions = 0; struct sqlx_repctx_s *repctx = NULL; EXTRA_ASSERT(sq3 != NULL); EXTRA_ASSERT(sq3->db != NULL); err = sqlx_transaction_begin(sq3, &repctx); if (NULL != err) return err; if (force) { __exec_cid (sq3->db, "DELETE FROM services WHERE cid = ?", hc_url_get_id (url)); count_actions += sqlite3_changes(sq3->db); __exec_cid (sq3->db, "DELETE FROM properties WHERE cid = ?", hc_url_get_id (url)); count_actions += sqlite3_changes(sq3->db); } else { guint count_services = 0, count_properties = 0; /* No forced op, we count the services belonging to the container. */ err = __count_FK(sq3, url, "services", &count_services); if (!err) err = __count_FK(sq3, url, "properties", &count_properties); /* If any service is found, this is an error. */ if (!err && count_services > 0) err = NEWERROR(CODE_USER_INUSE, "User still linked to services"); if (!err && count_properties > 0) err = NEWERROR(CODE_USER_INUSE, "User still has properties"); } if (!err) { __exec_cid(sq3->db, "DELETE FROM users WHERE cid = ?", hc_url_get_id (url)); count_actions += sqlite3_changes(sq3->db); } *done = !err && (count_actions > 0); if (!err && !*done) err = NEWERROR(CODE_USER_NOTFOUND, "User not found"); return sqlx_transaction_end(repctx, err); }
static GError* _fill(struct sqlx_sqlite3_s *sq3,guint replicas, gchar **m1urls) { struct sqlx_repctx_s *repctx = NULL; GError *err = NULL; guint max; max = m1urls ? g_strv_length(m1urls) : 0; EXTRA_ASSERT(max > 0 && max < 65536); err = sqlx_transaction_begin(sq3, &repctx); if (NULL != err) return err; while (replicas--) { err = __fill(sq3->db, m1urls, max, replicas); if (err) break; } return sqlx_transaction_end(repctx, err); }
GError * meta1_backend_get_container_properties(struct meta1_backend_s *m1, struct oio_url_s *url, gchar **names, gchar ***result) { EXTRA_ASSERT(result != NULL); struct sqlx_sqlite3_s *sq3 = NULL; GError *err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERSLAVE, &sq3); if (err) return err; struct sqlx_repctx_s *repctx = NULL; if (!(err = sqlx_transaction_begin(sq3, &repctx))) { if (!(err = __info_user(sq3, url, FALSE, NULL))) { err = __get_container_properties(sq3, url, names, result); if (err) g_prefix_error(&err, "Lookup error: "); } err = sqlx_transaction_end(repctx, err); } sqlx_repository_unlock_and_close_noerror(sq3); return err; }
GError* meta1_backend_services_relink(struct meta1_backend_s *m1, struct oio_url_s *url, const char *kept, const char *replaced, gboolean dryrun, gchar ***out) { GError *err = NULL; struct meta1_service_url_s **ukept = NULL, **urepl = NULL; /* fields to be prefetched */ struct grid_lb_iterator_s *iterator = NULL; struct compound_type_s ct; memset (&ct, 0, sizeof(ct)); ukept = __parse_and_expand (kept); urepl = __parse_and_expand (replaced); /* Sanity checks: we must receive at least one service */ if ((!ukept || !*ukept) && (!urepl || !*urepl)) { err = NEWERROR (CODE_BAD_REQUEST, "Missing URL set"); goto out; } /* Sanity check : all the services must have the same <seq,type> */ struct meta1_service_url_s *ref = ukept && *ukept ? *ukept : *urepl; for (struct meta1_service_url_s **p = ukept; p && *p ; ++p) { if (0 != _sorter(p, &ref)) { err = NEWERROR(CODE_BAD_REQUEST, "Mismatch in URL set (%s)", "kept"); goto out; } } for (struct meta1_service_url_s **p = urepl; p && *p ; ++p) { if (0 != _sorter(p, &ref)) { err = NEWERROR(CODE_BAD_REQUEST, "Mismatch in URL set (%s)", "kept"); goto out; } } /* prefetch some fields from the backend: the compound type (so it is * parsed only once), the iterator (so we can already poll services, out * of the sqlite3 transaction) */ if (NULL != (err = compound_type_parse(&ct, ref->srvtype))) { err = NEWERROR(CODE_BAD_REQUEST, "Invalid service type"); goto out; } if (NULL != (err = _get_iterator (m1, &ct, &iterator))) { err = NEWERROR(CODE_BAD_REQUEST, "Service type not managed"); goto out; } /* Call the backend logic now */ struct sqlx_sqlite3_s *sq3 = NULL; struct sqlx_repctx_s *repctx = NULL; if (!(err = _open_and_lock(m1, url, M1V2_OPENBASE_MASTERONLY, &sq3))) { if (!(err = sqlx_transaction_begin(sq3, &repctx))) { if (!(err = __info_user(sq3, url, FALSE, NULL))) { struct m1v2_relink_input_s in = { .m1 = m1, .sq3 = sq3, .url = url, .iterator = iterator, .ct = &ct, .kept = ukept, .replaced = urepl, .dryrun = dryrun }; err = __relink_container_services(&in, out); } if (!(err = sqlx_transaction_end(repctx, err))) { if (!dryrun) __notify_services_by_cid(m1, sq3, url); } } sqlx_repository_unlock_and_close_noerror(sq3); } out: meta1_service_url_cleanv (ukept); meta1_service_url_cleanv (urepl); grid_lb_iterator_clean (iterator); compound_type_clean (&ct); return err; }