int ListMgr_MassUpdate( lmgr_t * p_mgr, const lmgr_filter_t * p_filter, const attr_set_t * p_attr_set ) { char query[4096]; char filter_str_main[2048]; char filter_str_annex[2048]; char filter_str_stripe_info[2048]; char filter_str_stripe_units[2048]; int filter_main = 0; int filter_annex = 0; int filter_stripe_info = 0; int filter_stripe_units = 0; int rc, count; int impact_all = FALSE; int filter_unic = FALSE; char fields[2048]; char tmp_table_name[256]; int tmp_table_created = FALSE; filter_str_main[0] = '\0'; filter_str_annex[0] = '\0'; filter_str_stripe_info[0] = '\0'; filter_str_stripe_units[0] = '\0'; /* /!\ possible cases: * - simplest: the fields of the filter and the attributes to be changed are in the same table * - harder: the fields of the filter are in the same table and attributes are in another different table */ /* 1) check the location of filters */ if ( p_filter ) { filter_main = filter2str( p_mgr, filter_str_main, p_filter, T_MAIN, FALSE, FALSE ); if ( annex_table ) filter_annex = filter2str( p_mgr, filter_str_annex, p_filter, T_ANNEX, FALSE, FALSE ); else filter_annex = 0; filter_stripe_info = filter2str( p_mgr, filter_str_stripe_info, p_filter, T_STRIPE_INFO, FALSE, FALSE ); filter_stripe_units = filter2str( p_mgr, filter_str_stripe_units, p_filter, T_STRIPE_ITEMS,FALSE, FALSE ); if ( filter_main + filter_annex + filter_stripe_info + filter_stripe_units == 0 ) { /* all records */ impact_all = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Empty filter: all records will be affected" ); } else if ( filter_main && !( filter_annex || filter_stripe_info || filter_stripe_units ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " MAIN_TABLE " table" ); } else if ( filter_annex && !( filter_main || filter_stripe_info || filter_stripe_units ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " ANNEX_TABLE " table" ); } else if ( filter_stripe_info && !( filter_main || filter_annex || filter_stripe_units ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " STRIPE_INFO_TABLE " table" ); } else if ( filter_stripe_units && !( filter_main || filter_annex || filter_stripe_info ) ) { filter_unic = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter is only on " STRIPE_ITEMS_TABLE " table" ); } else DisplayLog( LVL_FULL, LISTMGR_TAG, "Filter on several tables: " MAIN_TABLE ":%d, " ANNEX_TABLE ":%d, " STRIPE_INFO_TABLE ":%d, " STRIPE_ITEMS_TABLE ":%d", filter_main, filter_annex, filter_stripe_info, filter_stripe_units ); } else { impact_all = TRUE; DisplayLog( LVL_FULL, LISTMGR_TAG, "Empty filter: all records will be affected" ); } /* 2) check if attributes to be changed are in MAIN table */ /* 3) if filters are in MAIN table too, make a simple update statement */ /* 4) if not, make a compound request: update xxx set xxx WHERE pk in ( select pk from ... where ... ) */ rc = lmgr_begin( p_mgr ); if ( rc ) return rc; /* perform updates on MAIN TABLE */ count = attrset2updatelist( p_mgr, fields, p_attr_set, T_MAIN, FALSE ); if ( count < 0 ) return -count; if ( count > 0 ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Update on " MAIN_TABLE " table" ); if ( impact_all ) { /* all records are impacted */ sprintf( query, "UPDATE " MAIN_TABLE " SET %s", fields ); } else if ( filter_unic && filter_main ) { /* update on the same table as filter */ sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE %s", fields, filter_str_main ); } else if ( filter_unic ) { /* update is on a different table than filter */ if ( filter_annex ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " ANNEX_TABLE " WHERE %s", tmp_table_name, filter_str_annex ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_units ) { if ( !tmp_table_created ) { sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); /* create temp table */ sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_ITEMS_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_units ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_info ) { if ( !tmp_table_created ) { sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); /* create temp table */ sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_INFO_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_info ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } } else { /* @todo mixed filter :-s */ rc = DB_NOT_SUPPORTED; goto rollback; } rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } /* update on annex table ? */ if ( annex_table ) { count = attrset2updatelist( p_mgr, fields, p_attr_set, T_ANNEX, FALSE ); if ( count < 0 ) return -count; if ( count > 0 ) { DisplayLog( LVL_FULL, LISTMGR_TAG, "Update on " ANNEX_TABLE " table" ); if ( impact_all ) { /* all records are impacted */ sprintf( query, "UPDATE " ANNEX_TABLE " SET %s", fields ); } else if ( filter_unic && filter_annex ) { /* update on the same table as filter */ sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE %s", fields, filter_str_annex ); } else if ( filter_unic ) { /* update is on a different table than filter */ if ( filter_main ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " MAIN_TABLE " WHERE %s", tmp_table_name, filter_str_main ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_units ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_ITEMS_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_units ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } else if ( filter_stripe_info ) { if ( !tmp_table_created ) { /* create temp table */ sprintf( tmp_table_name, "TMP_TABLE_%u_%u", ( unsigned int ) getpid( ), ( unsigned int ) pthread_self( ) ); sprintf( query, "CREATE TEMPORARY TABLE %s AS SELECT id FROM " STRIPE_INFO_TABLE " WHERE %s", tmp_table_name, filter_str_stripe_info ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; tmp_table_created = TRUE; } DisplayLog( LVL_MAJOR, LISTMGR_TAG, "WARNING: passing through unoptimized algorithm" ); sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id IN (SELECT id FROM %s)", fields, tmp_table_name ); } } else { /* @todo mixed filter :-s */ rc = DB_NOT_SUPPORTED; goto rollback; } rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } } if ( ATTR_MASK_TEST( p_attr_set, stripe_info ) || ATTR_MASK_TEST( p_attr_set, stripe_items ) ) { /* XXX is there a case where stripe info is to be updated massively ? */ rc = DB_NOT_SUPPORTED; goto rollback; } if ( tmp_table_created ) { sprintf( query, "DROP TABLE %s", tmp_table_name ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } return lmgr_commit( p_mgr ); rollback: lmgr_rollback( p_mgr ); return rc; }
int ListMgr_Update( lmgr_t * p_mgr, const entry_id_t * p_id, const attr_set_t * p_update_set ) { int rc, main_count, annex_count; char query[4096]; char fields[4096]; char annex_fields[4096]; DEF_PK(pk); int nb_tables = 0; /* read only fields in info mask? */ if ( readonly_attr_set & p_update_set->attr_mask ) { DisplayLog( LVL_MAJOR, LISTMGR_TAG, "Error: trying to update read only values: attr_mask=%#x", readonly_attr_set & p_update_set->attr_mask ); return DB_INVALID_ARG; } rc = entry_id2pk( p_mgr, p_id, FALSE, PTR_PK(pk) ); if (rc) return rc; /* check how many tables are to be updated */ if ( main_fields( p_update_set->attr_mask ) ) { main_count = attrset2updatelist( p_mgr, fields, p_update_set, T_MAIN, FALSE ); if ( main_count < 0 ) return -main_count; if ( main_count > 0 ) nb_tables++; } else main_count = 0; if ( annex_table && annex_fields( p_update_set->attr_mask ) ) { annex_count = attrset2updatelist( p_mgr, annex_fields, p_update_set, T_ANNEX, FALSE ); if ( annex_count < 0 ) return -annex_count; if ( annex_count > 0 ) nb_tables++; } else annex_count = 0; if ( stripe_fields( p_update_set->attr_mask ) ) nb_tables += 2; /* if only 1 table is impacted, switch to autocommit mode */ if ( nb_tables > 1 ) { /* @todo in the case of sqlite, we may want to do periodic commit * instead of systematic one. */ rc = lmgr_begin( p_mgr ); if ( rc ) return rc; } /* update main table */ if ( main_count > 0 ) { sprintf( query, "UPDATE " MAIN_TABLE " SET %s WHERE id="DPK, fields, pk ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } /* update annex table (if any) */ if ( annex_count > 0 ) { sprintf( query, "UPDATE " ANNEX_TABLE " SET %s WHERE id="DPK, annex_fields, pk ); rc = db_exec_sql( &p_mgr->conn, query, NULL ); if ( rc ) goto rollback; } /* insert new stripe info if provided (and eventually remove previous values) */ if ( ATTR_MASK_TEST( p_update_set, stripe_info ) ) { rc = insert_stripe_info( p_mgr, pk, VALID(p_id), &ATTR( p_update_set, stripe_info ), ATTR_MASK_TEST( p_update_set, stripe_items ) ? &ATTR( p_update_set, stripe_items ) : NULL, TRUE ); if ( rc ) goto rollback; } if ( nb_tables > 1 ) return lmgr_commit( p_mgr ); else return DB_SUCCESS; rollback: lmgr_rollback( p_mgr ); return rc; }
int listmgr_batch_insert_no_tx(lmgr_t * p_mgr, entry_id_t **p_ids, attr_set_t **p_attrs, unsigned int count, int update_if_exists) { int rc = 0; int i, full_mask; char fields[1024]; /* field list */ pktype *pklist = NULL; var_str query = VAR_STR_NULL; char values[4096] = ""; char *values_curr = NULL; bool first; /* fake attribute struct, to write generic name fields */ attr_set_t fake_attrs = *(p_attrs[0]); full_mask = sum_masks(p_attrs, count, ~0); fake_attrs.attr_mask = full_mask; pklist = (pktype *)MemCalloc(count, sizeof(pktype)); if (pklist == NULL) return DB_NO_MEMORY; for (i = 0; i < count; i++) { /* check attr mask */ if (!lmgr_batch_compat(full_mask, p_attrs[i]->attr_mask)) { DisplayLog(LVL_MAJOR, LISTMGR_TAG, "Incompatible attr mask in batched operation: %#x vs. %#x", p_attrs[i]->attr_mask, full_mask); rc = DB_INVALID_ARG; goto out_free; } /* fill pk array */ entry_id2pk(p_ids[i], PTR_PK(pklist[i])); /* The same for all tables? */ } /* build batch request for main table */ attrmask2fieldlist(fields, full_mask, T_MAIN, TRUE, FALSE, "", ""); var_str_append(&query, "INSERT INTO " MAIN_TABLE "(id"); var_str_append(&query, fields); var_str_append(&query, ") VALUES "); first = true; for (i = 0; i < count; i++) { /* don't set this entry if no attribute is in main table */ if ((p_attrs[i]->attr_mask & main_attr_set) == 0) continue; values_curr = values + sprintf(values, DPK, pklist[i]); attrset2valuelist(p_mgr, values_curr, p_attrs[i], T_MAIN, TRUE); /* add "[,](values)" to query */ var_str_append(&query, first ? "(" : ",("); var_str_append(&query, values); var_str_append(&query, ")"); first = false; } if (update_if_exists) { /* append "on duplicate key ..." */ attrset2updatelist(p_mgr, values, &fake_attrs, T_MAIN, FALSE, TRUE); var_str_append(&query, " ON DUPLICATE KEY UPDATE "); var_str_append(&query, values); } rc = db_exec_sql(&p_mgr->conn, VAR_STR_START(query), NULL); if (rc) goto out_free; var_str_reset(&query); /* allow inserting entries in MAIN_TABLE, without name information */ /* both parent and name are defined */ if ((full_mask & ATTR_MASK_name) && (full_mask & ATTR_MASK_parent_id)) { /* build batch request for names table */ attrmask2fieldlist(fields, full_mask, T_DNAMES, TRUE, FALSE, "", ""); var_str_append(&query, "INSERT INTO " DNAMES_TABLE "(id"); var_str_append(&query, fields); var_str_append(&query, ",pkn) VALUES "); first = true; for (i = 0; i < count; i++) { /* don't set this entry if parent or name is missing */ if (!ATTR_MASK_TEST(p_attrs[i], name) || !ATTR_MASK_TEST(p_attrs[i], parent_id)) { /* warn for create operations without name information */ if (!update_if_exists) no_name_warning(pklist[i], p_attrs[i], 1); continue; } values_curr = values + sprintf(values, DPK, pklist[i]); attrset2valuelist(p_mgr, values_curr, p_attrs[i], T_DNAMES, TRUE); /* add "[,](values,<pk>)" to query */ var_str_append(&query, first ? "(" : ",("); var_str_append(&query, values); var_str_append(&query, ","HNAME_DEF")"); first = false; } values_curr = values + sprintf(values, "id=VALUES(id)"); /* not part of the PK */ attrset2updatelist(p_mgr, values_curr, &fake_attrs, T_DNAMES, TRUE, TRUE); var_str_append(&query, " ON DUPLICATE KEY UPDATE "); var_str_append(&query, values); rc = db_exec_sql(&p_mgr->conn, VAR_STR_START(query), NULL); if (rc) goto out_free; } else if (!update_if_exists) { /* only warn for create operations */ /* if we get here, the name information is missing in all fields. * use entry[0] as example for the warning message. */ no_name_warning(pklist[0], p_attrs[0], count); } var_str_reset(&query); /* insert all info in annex table, if any */ if (annex_table && (full_mask & annex_attr_set)) { /* Create field and values lists. * Do nothing if no fields are to be set. */ if (attrmask2fieldlist(fields, full_mask, T_ANNEX, TRUE, FALSE, "", "") > 0) { var_str_append(&query, "INSERT INTO "ANNEX_TABLE "(id"); var_str_append(&query, fields); var_str_append(&query, ") VALUES "); first = true; for (i = 0; i < count; i++) { char values[4096] = ""; char *values_curr = NULL; /* don't set this entry if no attribute is in annex table */ if ((p_attrs[i]->attr_mask & annex_attr_set) == 0) continue; sprintf(values, DPK, pklist[i]); values_curr = values + strlen(values); attrset2valuelist(p_mgr, values_curr, p_attrs[i], T_ANNEX, TRUE); /* add "[,](values)" to query */ var_str_append(&query, first ? "(" : ",("); var_str_append(&query, values); var_str_append(&query, ")"); first = false; } /* always update as having the entry in the main table * is the reference to know if we knew the entry */ /* append "on duplicate key ..." */ attrset2updatelist(p_mgr, values, &fake_attrs, T_ANNEX, FALSE, TRUE); var_str_append(&query, " ON DUPLICATE KEY UPDATE "); var_str_append(&query, values); rc = db_exec_sql(&p_mgr->conn, VAR_STR_START(query), NULL); if (rc) goto out_free; } } #ifdef _LUSTRE /* batch insert of striping info */ if (ATTR_MASK_TEST(&fake_attrs, stripe_info) || ATTR_MASK_TEST(&fake_attrs, stripe_items)) { /* create validator list */ int *validators = (int*)MemCalloc(count, sizeof(int)); if (!validators) { rc = DB_NO_MEMORY; goto out_free; } for (i = 0; i < count; i++) #ifdef HAVE_LLAPI_FSWAP_LAYOUTS validators[i] = ATTR_MASK_TEST(p_attrs[i], stripe_info)? ATTR(p_attrs[i],stripe_info).validator:VALID_NOSTRIPE; #else validators[i] = VALID(p_ids[i]); #endif rc = batch_insert_stripe_info(p_mgr, pklist, validators, p_attrs, count, TRUE); MemFree(validators); if (rc) goto out_free; } #endif out_free: var_str_free(&query); MemFree(pklist); return rc; }