17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55b7f77adStw21770 * Common Development and Distribution License (the "License"). 65b7f77adStw21770 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 215b7f77adStw21770 227c478bd9Sstevel@tonic-gate /* 235b7f77adStw21770 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * This file only contains the transaction commit logic. 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #include <assert.h> 347c478bd9Sstevel@tonic-gate #include <alloca.h> 357c478bd9Sstevel@tonic-gate #include <errno.h> 367c478bd9Sstevel@tonic-gate #include <stdio.h> 377c478bd9Sstevel@tonic-gate #include <stdlib.h> 387c478bd9Sstevel@tonic-gate #include <strings.h> 397c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 407c478bd9Sstevel@tonic-gate #include "configd.h" 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate #define INVALID_OBJ_ID ((uint32_t)-1) 437c478bd9Sstevel@tonic-gate #define INVALID_TYPE ((uint32_t)-1) 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate struct tx_cmd { 467c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *tx_cmd; 477c478bd9Sstevel@tonic-gate const char *tx_prop; 487c478bd9Sstevel@tonic-gate uint32_t *tx_values; 497c478bd9Sstevel@tonic-gate uint32_t tx_nvalues; 507c478bd9Sstevel@tonic-gate uint32_t tx_orig_value_id; 517c478bd9Sstevel@tonic-gate char tx_found; 527c478bd9Sstevel@tonic-gate char tx_processed; 537c478bd9Sstevel@tonic-gate char tx_bad; 547c478bd9Sstevel@tonic-gate }; 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate static int 577c478bd9Sstevel@tonic-gate tx_cmd_compare(const void *key, const void *elem_arg) 587c478bd9Sstevel@tonic-gate { 597c478bd9Sstevel@tonic-gate const struct tx_cmd *elem = elem_arg; 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate return (strcmp((const char *)key, elem->tx_prop)); 627c478bd9Sstevel@tonic-gate } 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate struct tx_commit_data { 657c478bd9Sstevel@tonic-gate uint32_t txc_pg_id; 667c478bd9Sstevel@tonic-gate uint32_t txc_gen; 677c478bd9Sstevel@tonic-gate uint32_t txc_oldgen; 687c478bd9Sstevel@tonic-gate short txc_backend; 697c478bd9Sstevel@tonic-gate backend_tx_t *txc_tx; 707c478bd9Sstevel@tonic-gate backend_query_t *txc_inserts; 717c478bd9Sstevel@tonic-gate size_t txc_count; 727c478bd9Sstevel@tonic-gate rep_protocol_responseid_t txc_result; 737c478bd9Sstevel@tonic-gate struct tx_cmd txc_cmds[1]; /* actually txc_count */ 747c478bd9Sstevel@tonic-gate }; 757c478bd9Sstevel@tonic-gate #define TX_COMMIT_DATA_SIZE(count) \ 767c478bd9Sstevel@tonic-gate offsetof(struct tx_commit_data, txc_cmds[count]) 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 797c478bd9Sstevel@tonic-gate static int 807c478bd9Sstevel@tonic-gate tx_check_genid(void *data_arg, int columns, char **vals, char **names) 817c478bd9Sstevel@tonic-gate { 825b7f77adStw21770 tx_commit_data_t *data = data_arg; 837c478bd9Sstevel@tonic-gate assert(columns == 1); 847c478bd9Sstevel@tonic-gate if (atoi(vals[0]) != data->txc_oldgen) 857c478bd9Sstevel@tonic-gate data->txc_result = REP_PROTOCOL_FAIL_NOT_LATEST; 867c478bd9Sstevel@tonic-gate else 877c478bd9Sstevel@tonic-gate data->txc_result = REP_PROTOCOL_SUCCESS; 887c478bd9Sstevel@tonic-gate return (BACKEND_CALLBACK_CONTINUE); 897c478bd9Sstevel@tonic-gate } 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate /* 927c478bd9Sstevel@tonic-gate * tx_process_property() is called once for each property in current 937c478bd9Sstevel@tonic-gate * property group generation. Its purpose is threefold: 947c478bd9Sstevel@tonic-gate * 957c478bd9Sstevel@tonic-gate * 1. copy properties not mentioned in the transaction over unchanged. 967c478bd9Sstevel@tonic-gate * 2. mark DELETEd properties as seen (they will be left out of the new 977c478bd9Sstevel@tonic-gate * generation). 987c478bd9Sstevel@tonic-gate * 3. consistancy-check NEW, CLEAR, and REPLACE commands. 997c478bd9Sstevel@tonic-gate * 1007c478bd9Sstevel@tonic-gate * Any consistancy problems set tx_bad, and seen properties are marked 1017c478bd9Sstevel@tonic-gate * tx_found. These is used later, in tx_process_cmds(). 1027c478bd9Sstevel@tonic-gate */ 1037c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1047c478bd9Sstevel@tonic-gate static int 1057c478bd9Sstevel@tonic-gate tx_process_property(void *data_arg, int columns, char **vals, char **names) 1067c478bd9Sstevel@tonic-gate { 1075b7f77adStw21770 tx_commit_data_t *data = data_arg; 1087c478bd9Sstevel@tonic-gate struct tx_cmd *elem; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate const char *prop_name = vals[0]; 1117c478bd9Sstevel@tonic-gate const char *prop_type = vals[1]; 1127c478bd9Sstevel@tonic-gate const char *lnk_val_id = vals[2]; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate char *endptr; 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate assert(columns == 3); 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate elem = bsearch(prop_name, data->txc_cmds, data->txc_count, 1197c478bd9Sstevel@tonic-gate sizeof (*data->txc_cmds), tx_cmd_compare); 1207c478bd9Sstevel@tonic-gate 1217c478bd9Sstevel@tonic-gate if (elem == NULL) { 1227c478bd9Sstevel@tonic-gate backend_query_add(data->txc_inserts, 1237c478bd9Sstevel@tonic-gate "INSERT INTO prop_lnk_tbl" 1247c478bd9Sstevel@tonic-gate " (lnk_pg_id, lnk_gen_id, lnk_prop_name, lnk_prop_type," 1257c478bd9Sstevel@tonic-gate " lnk_val_id) " 1267c478bd9Sstevel@tonic-gate "VALUES ( %d, %d, '%q', '%q', %Q );", 1277c478bd9Sstevel@tonic-gate data->txc_pg_id, data->txc_gen, prop_name, prop_type, 1287c478bd9Sstevel@tonic-gate lnk_val_id); 1297c478bd9Sstevel@tonic-gate } else { 1307c478bd9Sstevel@tonic-gate assert(!elem->tx_found); 1317c478bd9Sstevel@tonic-gate elem->tx_found = 1; 1327c478bd9Sstevel@tonic-gate 1337c478bd9Sstevel@tonic-gate if (lnk_val_id != NULL) { 1347c478bd9Sstevel@tonic-gate errno = 0; 1357c478bd9Sstevel@tonic-gate elem->tx_orig_value_id = 1367c478bd9Sstevel@tonic-gate strtoul(lnk_val_id, &endptr, 10); 1377c478bd9Sstevel@tonic-gate if (elem->tx_orig_value_id == 0 || *endptr != 0 || 1387c478bd9Sstevel@tonic-gate errno != 0) { 1397c478bd9Sstevel@tonic-gate return (BACKEND_CALLBACK_ABORT); 1407c478bd9Sstevel@tonic-gate } 1417c478bd9Sstevel@tonic-gate } else { 1427c478bd9Sstevel@tonic-gate elem->tx_orig_value_id = 0; 1437c478bd9Sstevel@tonic-gate } 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate switch (elem->tx_cmd->rptc_action) { 1467c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_NEW: 1477c478bd9Sstevel@tonic-gate elem->tx_bad = 1; 1487c478bd9Sstevel@tonic-gate data->txc_result = REP_PROTOCOL_FAIL_EXISTS; 1497c478bd9Sstevel@tonic-gate break; 1507c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_CLEAR: 1517c478bd9Sstevel@tonic-gate if (REP_PROTOCOL_BASE_TYPE(elem->tx_cmd->rptc_type) != 1527c478bd9Sstevel@tonic-gate prop_type[0] && 1537c478bd9Sstevel@tonic-gate REP_PROTOCOL_SUBTYPE(elem->tx_cmd->rptc_type) != 1547c478bd9Sstevel@tonic-gate prop_type[1]) { 1557c478bd9Sstevel@tonic-gate elem->tx_bad = 1; 1567c478bd9Sstevel@tonic-gate data->txc_result = 1577c478bd9Sstevel@tonic-gate REP_PROTOCOL_FAIL_TYPE_MISMATCH; 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate break; 1607c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_REPLACE: 1617c478bd9Sstevel@tonic-gate break; 1627c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_DELETE: 1637c478bd9Sstevel@tonic-gate elem->tx_processed = 1; 1647c478bd9Sstevel@tonic-gate break; 1657c478bd9Sstevel@tonic-gate default: 1667c478bd9Sstevel@tonic-gate assert(0); 1677c478bd9Sstevel@tonic-gate break; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate } 1707c478bd9Sstevel@tonic-gate return (BACKEND_CALLBACK_CONTINUE); 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * tx_process_cmds() finishes the job tx_process_property() started: 1757c478bd9Sstevel@tonic-gate * 1767c478bd9Sstevel@tonic-gate * 1. if tx_process_property() marked a command as bad, we skip it. 1777c478bd9Sstevel@tonic-gate * 2. if a DELETE, REPLACE, or CLEAR operated on a non-existant property, 1787c478bd9Sstevel@tonic-gate * we mark it as bad. 1797c478bd9Sstevel@tonic-gate * 3. we complete the work of NEW, REPLACE, and CLEAR, by inserting the 1807c478bd9Sstevel@tonic-gate * appropriate values into the database. 1817c478bd9Sstevel@tonic-gate * 4. we delete all replaced data, if it is no longer referenced. 1827c478bd9Sstevel@tonic-gate * 1837c478bd9Sstevel@tonic-gate * Finally, we check all of the commands, and fail if anything was marked bad. 1847c478bd9Sstevel@tonic-gate */ 1857c478bd9Sstevel@tonic-gate static int 1865b7f77adStw21770 tx_process_cmds(tx_commit_data_t *data) 1877c478bd9Sstevel@tonic-gate { 1887c478bd9Sstevel@tonic-gate int idx; 1897c478bd9Sstevel@tonic-gate int r; 1907c478bd9Sstevel@tonic-gate int count = data->txc_count; 1917c478bd9Sstevel@tonic-gate struct tx_cmd *elem; 1927c478bd9Sstevel@tonic-gate uint32_t val_id = 0; 1937c478bd9Sstevel@tonic-gate uint8_t type[3]; 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate backend_query_t *q; 1967c478bd9Sstevel@tonic-gate int do_delete; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * For persistent pgs, we use backend_fail_if_seen to abort the 2007c478bd9Sstevel@tonic-gate * deletion if there is a snapshot using our current state. 2017c478bd9Sstevel@tonic-gate * 2027c478bd9Sstevel@tonic-gate * All of the deletions in this function are safe, since 2037c478bd9Sstevel@tonic-gate * rc_tx_commit() guarantees that all the data is in-cache. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate q = backend_query_alloc(); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate if (data->txc_backend != BACKEND_TYPE_NONPERSIST) { 2087c478bd9Sstevel@tonic-gate backend_query_add(q, 2097c478bd9Sstevel@tonic-gate "SELECT 1 FROM snaplevel_lnk_tbl " 2107c478bd9Sstevel@tonic-gate " WHERE (snaplvl_pg_id = %d AND snaplvl_gen_id = %d); ", 2117c478bd9Sstevel@tonic-gate data->txc_pg_id, data->txc_oldgen); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate backend_query_add(q, 2147c478bd9Sstevel@tonic-gate "DELETE FROM prop_lnk_tbl" 2157c478bd9Sstevel@tonic-gate " WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)", 2167c478bd9Sstevel@tonic-gate data->txc_pg_id, data->txc_oldgen); 2177c478bd9Sstevel@tonic-gate r = backend_tx_run(data->txc_tx, q, backend_fail_if_seen, NULL); 2187c478bd9Sstevel@tonic-gate backend_query_free(q); 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate if (r == REP_PROTOCOL_SUCCESS) 2217c478bd9Sstevel@tonic-gate do_delete = 1; 2227c478bd9Sstevel@tonic-gate else if (r == REP_PROTOCOL_DONE) 2237c478bd9Sstevel@tonic-gate do_delete = 0; /* old gen_id is in use */ 2247c478bd9Sstevel@tonic-gate else 2257c478bd9Sstevel@tonic-gate return (r); 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate for (idx = 0; idx < count; idx++) { 2287c478bd9Sstevel@tonic-gate elem = &data->txc_cmds[idx]; 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate if (elem->tx_bad) 2317c478bd9Sstevel@tonic-gate continue; 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate switch (elem->tx_cmd->rptc_action) { 2347c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_DELETE: 2357c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_REPLACE: 2367c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_CLEAR: 2377c478bd9Sstevel@tonic-gate if (!elem->tx_found) { 2387c478bd9Sstevel@tonic-gate elem->tx_bad = 1; 2397c478bd9Sstevel@tonic-gate continue; 2407c478bd9Sstevel@tonic-gate } 2417c478bd9Sstevel@tonic-gate break; 2427c478bd9Sstevel@tonic-gate case REP_PROTOCOL_TX_ENTRY_NEW: 2437c478bd9Sstevel@tonic-gate break; 2447c478bd9Sstevel@tonic-gate default: 2457c478bd9Sstevel@tonic-gate assert(0); 2467c478bd9Sstevel@tonic-gate break; 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate if (do_delete && 2507c478bd9Sstevel@tonic-gate elem->tx_cmd->rptc_action != REP_PROTOCOL_TX_ENTRY_NEW && 2517c478bd9Sstevel@tonic-gate elem->tx_orig_value_id != 0) { 2527c478bd9Sstevel@tonic-gate /* 2537c478bd9Sstevel@tonic-gate * delete the old values, if they are not in use 2547c478bd9Sstevel@tonic-gate */ 2557c478bd9Sstevel@tonic-gate q = backend_query_alloc(); 2567c478bd9Sstevel@tonic-gate backend_query_add(q, 2577c478bd9Sstevel@tonic-gate "SELECT 1 FROM prop_lnk_tbl " 2587c478bd9Sstevel@tonic-gate " WHERE (lnk_val_id = %d); " 2597c478bd9Sstevel@tonic-gate "DELETE FROM value_tbl" 2607c478bd9Sstevel@tonic-gate " WHERE (value_id = %d)", 2617c478bd9Sstevel@tonic-gate elem->tx_orig_value_id, elem->tx_orig_value_id); 2627c478bd9Sstevel@tonic-gate r = backend_tx_run(data->txc_tx, q, 2637c478bd9Sstevel@tonic-gate backend_fail_if_seen, NULL); 2647c478bd9Sstevel@tonic-gate backend_query_free(q); 2657c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS && r != REP_PROTOCOL_DONE) 2667c478bd9Sstevel@tonic-gate return (r); 2677c478bd9Sstevel@tonic-gate } 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate if (elem->tx_cmd->rptc_action == REP_PROTOCOL_TX_ENTRY_DELETE) 2707c478bd9Sstevel@tonic-gate continue; /* no further work to do */ 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate type[0] = REP_PROTOCOL_BASE_TYPE(elem->tx_cmd->rptc_type); 2737c478bd9Sstevel@tonic-gate type[1] = REP_PROTOCOL_SUBTYPE(elem->tx_cmd->rptc_type); 2747c478bd9Sstevel@tonic-gate type[2] = 0; 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate if (elem->tx_nvalues == 0) { 2777c478bd9Sstevel@tonic-gate r = backend_tx_run_update(data->txc_tx, 2787c478bd9Sstevel@tonic-gate "INSERT INTO prop_lnk_tbl" 2797c478bd9Sstevel@tonic-gate " (lnk_pg_id, lnk_gen_id, " 2807c478bd9Sstevel@tonic-gate " lnk_prop_name, lnk_prop_type, lnk_val_id) " 2817c478bd9Sstevel@tonic-gate "VALUES ( %d, %d, '%q', '%q', NULL );", 2827c478bd9Sstevel@tonic-gate data->txc_pg_id, data->txc_gen, elem->tx_prop, 2837c478bd9Sstevel@tonic-gate type); 2847c478bd9Sstevel@tonic-gate } else { 285*6e1d2b42Samaguire uint32_t *v, i = 0; 2867c478bd9Sstevel@tonic-gate const char *str; 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate val_id = backend_new_id(data->txc_tx, BACKEND_ID_VALUE); 2897c478bd9Sstevel@tonic-gate if (val_id == 0) 2907c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 2917c478bd9Sstevel@tonic-gate r = backend_tx_run_update(data->txc_tx, 2927c478bd9Sstevel@tonic-gate "INSERT INTO prop_lnk_tbl " 2937c478bd9Sstevel@tonic-gate " (lnk_pg_id, lnk_gen_id, " 2947c478bd9Sstevel@tonic-gate " lnk_prop_name, lnk_prop_type, lnk_val_id) " 2957c478bd9Sstevel@tonic-gate "VALUES ( %d, %d, '%q', '%q', %d );", 2967c478bd9Sstevel@tonic-gate data->txc_pg_id, data->txc_gen, elem->tx_prop, 2977c478bd9Sstevel@tonic-gate type, val_id); 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate v = elem->tx_values; 3007c478bd9Sstevel@tonic-gate 301*6e1d2b42Samaguire for (i = 0; i < elem->tx_nvalues; i++) { 3027c478bd9Sstevel@tonic-gate str = (const char *)&v[1]; 3037c478bd9Sstevel@tonic-gate 304*6e1d2b42Samaguire /* 305*6e1d2b42Samaguire * Update values in backend, imposing 306*6e1d2b42Samaguire * ordering via the value_order column. 307*6e1d2b42Samaguire * This ordering is then used in subseqent 308*6e1d2b42Samaguire * value retrieval operations. We can 309*6e1d2b42Samaguire * safely assume that the repository schema 310*6e1d2b42Samaguire * has been upgraded (and hence has the 311*6e1d2b42Samaguire * value_order column in value_tbl), since 312*6e1d2b42Samaguire * it is upgraded as soon as the repository 313*6e1d2b42Samaguire * is writable. 314*6e1d2b42Samaguire */ 3157c478bd9Sstevel@tonic-gate r = backend_tx_run_update(data->txc_tx, 316*6e1d2b42Samaguire "INSERT INTO value_tbl (value_id, " 317*6e1d2b42Samaguire "value_type, value_value, " 318*6e1d2b42Samaguire "value_order) VALUES (%d, '%c', " 319*6e1d2b42Samaguire "'%q', '%d');\n", 320*6e1d2b42Samaguire val_id, elem->tx_cmd->rptc_type, 321*6e1d2b42Samaguire str, i); 322*6e1d2b42Samaguire if (r != REP_PROTOCOL_SUCCESS) 323*6e1d2b42Samaguire break; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /*LINTED alignment*/ 3267c478bd9Sstevel@tonic-gate v = (uint32_t *)((caddr_t)str + TX_SIZE(*v)); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS) 3307c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_UNKNOWN); 3317c478bd9Sstevel@tonic-gate elem->tx_processed = 1; 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate 3347c478bd9Sstevel@tonic-gate for (idx = 0; idx < count; idx++) { 3357c478bd9Sstevel@tonic-gate elem = &data->txc_cmds[idx]; 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate if (elem->tx_bad) 3387c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_TX); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate static boolean_t 3447c478bd9Sstevel@tonic-gate check_string(uintptr_t loc, uint32_t len, uint32_t sz) 3457c478bd9Sstevel@tonic-gate { 3467c478bd9Sstevel@tonic-gate const char *ptr = (const char *)loc; 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate if (len == 0 || len > sz || ptr[len - 1] != 0 || strlen(ptr) != len - 1) 3497c478bd9Sstevel@tonic-gate return (0); 3507c478bd9Sstevel@tonic-gate return (1); 3517c478bd9Sstevel@tonic-gate } 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate static int 3545b7f77adStw21770 tx_check_and_setup(tx_commit_data_t *data, const void *cmds_arg, 3557c478bd9Sstevel@tonic-gate uint32_t count) 3567c478bd9Sstevel@tonic-gate { 3577c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmds; 3587c478bd9Sstevel@tonic-gate struct tx_cmd *cur; 3597c478bd9Sstevel@tonic-gate struct tx_cmd *prev = NULL; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate uintptr_t loc; 3627c478bd9Sstevel@tonic-gate uint32_t sz, len; 3637c478bd9Sstevel@tonic-gate int idx; 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate loc = (uintptr_t)cmds_arg; 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate for (idx = 0; idx < count; idx++) { 3687c478bd9Sstevel@tonic-gate cur = &data->txc_cmds[idx]; 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate cmds = (struct rep_protocol_transaction_cmd *)loc; 3717c478bd9Sstevel@tonic-gate cur->tx_cmd = cmds; 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate sz = cmds->rptc_size; 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate loc += REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE; 3767c478bd9Sstevel@tonic-gate sz -= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate len = cmds->rptc_name_len; 3797c478bd9Sstevel@tonic-gate if (len <= 1 || !check_string(loc, len, sz)) { 3807c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate cur->tx_prop = (const char *)loc; 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate len = TX_SIZE(len); 3857c478bd9Sstevel@tonic-gate loc += len; 3867c478bd9Sstevel@tonic-gate sz -= len; 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate cur->tx_nvalues = 0; 3897c478bd9Sstevel@tonic-gate cur->tx_values = (uint32_t *)loc; 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate while (sz > 0) { 3927c478bd9Sstevel@tonic-gate if (sz < sizeof (uint32_t)) 3937c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 3947c478bd9Sstevel@tonic-gate 3957c478bd9Sstevel@tonic-gate cur->tx_nvalues++; 3967c478bd9Sstevel@tonic-gate 3977c478bd9Sstevel@tonic-gate len = *(uint32_t *)loc; 3987c478bd9Sstevel@tonic-gate loc += sizeof (uint32_t); 3997c478bd9Sstevel@tonic-gate sz -= sizeof (uint32_t); 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate if (!check_string(loc, len, sz)) 4027c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate /* 4057c478bd9Sstevel@tonic-gate * XXX here, we should be checking that the values 4067c478bd9Sstevel@tonic-gate * match the purported type 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate len = TX_SIZE(len); 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (len > sz) 4127c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate loc += len; 4157c478bd9Sstevel@tonic-gate sz -= len; 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate if (prev != NULL && strcmp(prev->tx_prop, cur->tx_prop) >= 0) 4197c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate prev = cur; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_SUCCESS); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4265b7f77adStw21770 /* 4275b7f77adStw21770 * Free the memory associated with a tx_commit_data structure. 4285b7f77adStw21770 */ 4295b7f77adStw21770 void 4305b7f77adStw21770 tx_commit_data_free(tx_commit_data_t *tx_data) 4315b7f77adStw21770 { 4325b7f77adStw21770 uu_free(tx_data); 4335b7f77adStw21770 } 4345b7f77adStw21770 4355b7f77adStw21770 /* 4365b7f77adStw21770 * Parse the data of a REP_PROTOCOL_PROPERTYGRP_TX_COMMIT message into a 4375b7f77adStw21770 * more useful form. The data in the message will be represented by a 4385b7f77adStw21770 * tx_commit_data_t structure which is allocated by this function. The 4395b7f77adStw21770 * address of the allocated structure is returned to *tx_data and must be 4405b7f77adStw21770 * freed by calling tx_commit_data_free(). 4415b7f77adStw21770 * 4425b7f77adStw21770 * Parameters: 4435b7f77adStw21770 * cmds_arg Address of the commands in the 4445b7f77adStw21770 * REP_PROTOCOL_PROPERTYGRP_TX_COMMIT message. 4455b7f77adStw21770 * 4465b7f77adStw21770 * cmds_sz Number of message bytes at cmds_arg. 4475b7f77adStw21770 * 4485b7f77adStw21770 * tx_data Points to the place to receive the address of the 4495b7f77adStw21770 * allocated memory. 4505b7f77adStw21770 * 4515b7f77adStw21770 * Fails with 4525b7f77adStw21770 * _BAD_REQUEST 4535b7f77adStw21770 * _NO_RESOURCES 4545b7f77adStw21770 */ 4557c478bd9Sstevel@tonic-gate int 4565b7f77adStw21770 tx_commit_data_new(const void *cmds_arg, size_t cmds_sz, 4575b7f77adStw21770 tx_commit_data_t **tx_data) 4587c478bd9Sstevel@tonic-gate { 4597c478bd9Sstevel@tonic-gate const struct rep_protocol_transaction_cmd *cmds; 4605b7f77adStw21770 tx_commit_data_t *data; 4617c478bd9Sstevel@tonic-gate uintptr_t loc; 4625b7f77adStw21770 uint32_t count; 4635b7f77adStw21770 uint32_t sz; 4647c478bd9Sstevel@tonic-gate int ret; 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate /* 4677c478bd9Sstevel@tonic-gate * First, verify that the reported sizes make sense, and count 4687c478bd9Sstevel@tonic-gate * the number of commands. 4697c478bd9Sstevel@tonic-gate */ 4707c478bd9Sstevel@tonic-gate count = 0; 4717c478bd9Sstevel@tonic-gate loc = (uintptr_t)cmds_arg; 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate while (cmds_sz > 0) { 4747c478bd9Sstevel@tonic-gate cmds = (struct rep_protocol_transaction_cmd *)loc; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate if (cmds_sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE) 4777c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate sz = cmds->rptc_size; 4807c478bd9Sstevel@tonic-gate if (sz <= REP_PROTOCOL_TRANSACTION_CMD_MIN_SIZE) 4817c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate sz = TX_SIZE(sz); 4847c478bd9Sstevel@tonic-gate if (sz > cmds_sz) 4857c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_BAD_REQUEST); 4867c478bd9Sstevel@tonic-gate 4877c478bd9Sstevel@tonic-gate loc += sz; 4887c478bd9Sstevel@tonic-gate cmds_sz -= sz; 4897c478bd9Sstevel@tonic-gate count++; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 4925b7f77adStw21770 data = uu_zalloc(TX_COMMIT_DATA_SIZE(count)); 4935b7f77adStw21770 if (data == NULL) 4945b7f77adStw21770 return (REP_PROTOCOL_FAIL_NO_RESOURCES); 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * verify that everything looks okay, and set up our command 4987c478bd9Sstevel@tonic-gate * datastructures. 4997c478bd9Sstevel@tonic-gate */ 5005b7f77adStw21770 data->txc_count = count; 5017c478bd9Sstevel@tonic-gate ret = tx_check_and_setup(data, cmds_arg, count); 5025b7f77adStw21770 if (ret == REP_PROTOCOL_SUCCESS) { 5035b7f77adStw21770 *tx_data = data; 5045b7f77adStw21770 } else { 5055b7f77adStw21770 *tx_data = NULL; 5065b7f77adStw21770 uu_free(data); 5075b7f77adStw21770 } 5087c478bd9Sstevel@tonic-gate return (ret); 5095b7f77adStw21770 } 5105b7f77adStw21770 5115b7f77adStw21770 /* 5125b7f77adStw21770 * The following are a set of accessor functions to retrieve data from a 5135b7f77adStw21770 * tx_commit_data_t that has been allocated by tx_commit_data_new(). 5145b7f77adStw21770 */ 5155b7f77adStw21770 5165b7f77adStw21770 /* 5175b7f77adStw21770 * Return the action of the transaction command whose command number is 5185b7f77adStw21770 * cmd_no. The action is placed at *action. 5195b7f77adStw21770 * 5205b7f77adStw21770 * Returns: 5215b7f77adStw21770 * _FAIL_BAD_REQUEST cmd_no is out of range. 5225b7f77adStw21770 */ 5235b7f77adStw21770 int 5245b7f77adStw21770 tx_cmd_action(tx_commit_data_t *tx_data, size_t cmd_no, 5255b7f77adStw21770 enum rep_protocol_transaction_action *action) 5265b7f77adStw21770 { 5275b7f77adStw21770 struct tx_cmd *cur; 5285b7f77adStw21770 5295b7f77adStw21770 assert(cmd_no < tx_data->txc_count); 5305b7f77adStw21770 if (cmd_no >= tx_data->txc_count) 5315b7f77adStw21770 return (REP_PROTOCOL_FAIL_BAD_REQUEST); 5325b7f77adStw21770 5335b7f77adStw21770 cur = &tx_data->txc_cmds[cmd_no]; 5345b7f77adStw21770 *action = cur->tx_cmd->rptc_action; 5355b7f77adStw21770 return (REP_PROTOCOL_SUCCESS); 5365b7f77adStw21770 } 5375b7f77adStw21770 5385b7f77adStw21770 /* 5395b7f77adStw21770 * Return the number of transaction commands held in tx_data. 5405b7f77adStw21770 */ 5415b7f77adStw21770 size_t 5425b7f77adStw21770 tx_cmd_count(tx_commit_data_t *tx_data) 5435b7f77adStw21770 { 5445b7f77adStw21770 return (tx_data->txc_count); 5455b7f77adStw21770 } 5465b7f77adStw21770 5475b7f77adStw21770 /* 5485b7f77adStw21770 * Return the number of property values that are associated with the 5495b7f77adStw21770 * transaction command whose number is cmd_no. The number of values is 5505b7f77adStw21770 * returned to *nvalues. 5515b7f77adStw21770 * 5525b7f77adStw21770 * Returns: 5535b7f77adStw21770 * _FAIL_BAD_REQUEST cmd_no is out of range. 5545b7f77adStw21770 */ 5555b7f77adStw21770 int 5565b7f77adStw21770 tx_cmd_nvalues(tx_commit_data_t *tx_data, size_t cmd_no, uint32_t *nvalues) 5575b7f77adStw21770 { 5585b7f77adStw21770 struct tx_cmd *cur; 5595b7f77adStw21770 5605b7f77adStw21770 assert(cmd_no < tx_data->txc_count); 5615b7f77adStw21770 if (cmd_no >= tx_data->txc_count) 5625b7f77adStw21770 return (REP_PROTOCOL_FAIL_BAD_REQUEST); 5635b7f77adStw21770 5645b7f77adStw21770 cur = &tx_data->txc_cmds[cmd_no]; 5655b7f77adStw21770 *nvalues = cur->tx_nvalues; 5665b7f77adStw21770 return (REP_PROTOCOL_SUCCESS); 5675b7f77adStw21770 } 5685b7f77adStw21770 5695b7f77adStw21770 /* 5705b7f77adStw21770 * Return a pointer to the property name of the command whose number is 5715b7f77adStw21770 * cmd_no. The property name pointer is returned to *pname. 5725b7f77adStw21770 * 5735b7f77adStw21770 * Returns: 5745b7f77adStw21770 * _FAIL_BAD_REQUEST cmd_no is out of range. 5755b7f77adStw21770 */ 5765b7f77adStw21770 int 5775b7f77adStw21770 tx_cmd_prop(tx_commit_data_t *tx_data, size_t cmd_no, const char **pname) 5785b7f77adStw21770 { 5795b7f77adStw21770 struct tx_cmd *cur; 5805b7f77adStw21770 5815b7f77adStw21770 assert(cmd_no < tx_data->txc_count); 5825b7f77adStw21770 if (cmd_no >= tx_data->txc_count) 5835b7f77adStw21770 return (REP_PROTOCOL_FAIL_BAD_REQUEST); 5845b7f77adStw21770 5855b7f77adStw21770 cur = &tx_data->txc_cmds[cmd_no]; 5865b7f77adStw21770 *pname = cur->tx_prop; 5875b7f77adStw21770 return (REP_PROTOCOL_SUCCESS); 5885b7f77adStw21770 } 5895b7f77adStw21770 5905b7f77adStw21770 /* 5915b7f77adStw21770 * Return the property type of the property whose command number is 5925b7f77adStw21770 * cmd_no. The property type is returned to *ptype. 5935b7f77adStw21770 * 5945b7f77adStw21770 * Returns: 5955b7f77adStw21770 * _FAIL_BAD_REQUEST cmd_no is out of range. 5965b7f77adStw21770 */ 5975b7f77adStw21770 int 5985b7f77adStw21770 tx_cmd_prop_type(tx_commit_data_t *tx_data, size_t cmd_no, uint32_t *ptype) 5995b7f77adStw21770 { 6005b7f77adStw21770 struct tx_cmd *cur; 6015b7f77adStw21770 6025b7f77adStw21770 assert(cmd_no < tx_data->txc_count); 6035b7f77adStw21770 if (cmd_no >= tx_data->txc_count) 6045b7f77adStw21770 return (REP_PROTOCOL_FAIL_BAD_REQUEST); 6055b7f77adStw21770 6065b7f77adStw21770 cur = &tx_data->txc_cmds[cmd_no]; 6075b7f77adStw21770 *ptype = cur->tx_cmd->rptc_type; 6085b7f77adStw21770 return (REP_PROTOCOL_SUCCESS); 6095b7f77adStw21770 } 6105b7f77adStw21770 6115b7f77adStw21770 /* 6125b7f77adStw21770 * This function is used to retrieve a property value from the transaction 6135b7f77adStw21770 * data. val_no specifies which value is to be retrieved from the 6145b7f77adStw21770 * transaction command whose number is cmd_no. A pointer to the specified 6155b7f77adStw21770 * value is placed in *val. 6165b7f77adStw21770 * 6175b7f77adStw21770 * Returns: 6185b7f77adStw21770 * _FAIL_BAD_REQUEST cmd_no or val_no is out of range. 6195b7f77adStw21770 */ 6205b7f77adStw21770 int 6215b7f77adStw21770 tx_cmd_value(tx_commit_data_t *tx_data, size_t cmd_no, uint32_t val_no, 6225b7f77adStw21770 const char **val) 6235b7f77adStw21770 { 6245b7f77adStw21770 const char *bp; 6255b7f77adStw21770 struct tx_cmd *cur; 6265b7f77adStw21770 uint32_t i; 6275b7f77adStw21770 uint32_t value_len; 6285b7f77adStw21770 6295b7f77adStw21770 assert(cmd_no < tx_data->txc_count); 6305b7f77adStw21770 if (cmd_no >= tx_data->txc_count) 6315b7f77adStw21770 return (REP_PROTOCOL_FAIL_BAD_REQUEST); 6325b7f77adStw21770 6335b7f77adStw21770 cur = &tx_data->txc_cmds[cmd_no]; 6345b7f77adStw21770 assert(val_no < cur->tx_nvalues); 6355b7f77adStw21770 if (val_no >= cur->tx_nvalues) 6365b7f77adStw21770 return (REP_PROTOCOL_FAIL_BAD_REQUEST); 6375b7f77adStw21770 6385b7f77adStw21770 /* Find the correct value */ 6395b7f77adStw21770 bp = (char *)cur->tx_values; 6405b7f77adStw21770 for (i = 0; i < val_no; i++) { 6415b7f77adStw21770 /* LINTED alignment */ 6425b7f77adStw21770 value_len = *(uint32_t *)bp; 6435b7f77adStw21770 bp += sizeof (uint32_t) + TX_SIZE(value_len); 6445b7f77adStw21770 } 6455b7f77adStw21770 6465b7f77adStw21770 /* Bypass the count & return pointer to value. */ 6475b7f77adStw21770 bp += sizeof (uint32_t); 6485b7f77adStw21770 *val = bp; 6495b7f77adStw21770 return (REP_PROTOCOL_SUCCESS); 6505b7f77adStw21770 } 6515b7f77adStw21770 6525b7f77adStw21770 int 6535b7f77adStw21770 object_tx_commit(rc_node_lookup_t *lp, tx_commit_data_t *data, uint32_t *gen) 6545b7f77adStw21770 { 6555b7f77adStw21770 uint32_t new_gen; 6565b7f77adStw21770 int ret; 6575b7f77adStw21770 rep_protocol_responseid_t r; 6585b7f77adStw21770 backend_tx_t *tx; 6595b7f77adStw21770 backend_query_t *q; 6605b7f77adStw21770 int backend = lp->rl_backend; 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate ret = backend_tx_begin(backend, &tx); 6637c478bd9Sstevel@tonic-gate if (ret != REP_PROTOCOL_SUCCESS) 6647c478bd9Sstevel@tonic-gate return (ret); 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate /* Make sure the pg is up-to-date. */ 6677c478bd9Sstevel@tonic-gate data->txc_oldgen = *gen; 6687c478bd9Sstevel@tonic-gate data->txc_backend = backend; 6697c478bd9Sstevel@tonic-gate data->txc_result = REP_PROTOCOL_FAIL_NOT_FOUND; 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate q = backend_query_alloc(); 6727c478bd9Sstevel@tonic-gate backend_query_add(q, "SELECT pg_gen_id FROM pg_tbl WHERE (pg_id = %d);", 6737c478bd9Sstevel@tonic-gate lp->rl_main_id); 6747c478bd9Sstevel@tonic-gate r = backend_tx_run(tx, q, tx_check_genid, data); 6757c478bd9Sstevel@tonic-gate backend_query_free(q); 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS || 6787c478bd9Sstevel@tonic-gate (r = data->txc_result) != REP_PROTOCOL_SUCCESS) { 6797c478bd9Sstevel@tonic-gate backend_tx_rollback(tx); 6807c478bd9Sstevel@tonic-gate goto end; 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate /* If the transaction is empty, cut out early. */ 6845b7f77adStw21770 if (data->txc_count == 0) { 6857c478bd9Sstevel@tonic-gate backend_tx_rollback(tx); 6867c478bd9Sstevel@tonic-gate r = REP_PROTOCOL_DONE; 6877c478bd9Sstevel@tonic-gate goto end; 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate new_gen = backend_new_id(tx, BACKEND_ID_GENERATION); 6917c478bd9Sstevel@tonic-gate if (new_gen == 0) { 6927c478bd9Sstevel@tonic-gate backend_tx_rollback(tx); 6937c478bd9Sstevel@tonic-gate return (REP_PROTOCOL_FAIL_NO_RESOURCES); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate data->txc_pg_id = lp->rl_main_id; 6977c478bd9Sstevel@tonic-gate data->txc_gen = new_gen; 6987c478bd9Sstevel@tonic-gate data->txc_tx = tx; 6997c478bd9Sstevel@tonic-gate 7007c478bd9Sstevel@tonic-gate r = backend_tx_run_update(tx, 7017c478bd9Sstevel@tonic-gate "UPDATE pg_tbl SET pg_gen_id = %d " 7027c478bd9Sstevel@tonic-gate " WHERE (pg_id = %d AND pg_gen_id = %d);", 7037c478bd9Sstevel@tonic-gate new_gen, lp->rl_main_id, *gen); 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS) { 7067c478bd9Sstevel@tonic-gate backend_tx_rollback(tx); 7077c478bd9Sstevel@tonic-gate goto end; 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate q = backend_query_alloc(); 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate backend_query_add(q, 7137c478bd9Sstevel@tonic-gate "SELECT lnk_prop_name, lnk_prop_type, lnk_val_id " 7147c478bd9Sstevel@tonic-gate "FROM prop_lnk_tbl " 7157c478bd9Sstevel@tonic-gate "WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)", 7167c478bd9Sstevel@tonic-gate lp->rl_main_id, *gen); 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate data->txc_inserts = backend_query_alloc(); 7197c478bd9Sstevel@tonic-gate r = backend_tx_run(tx, q, tx_process_property, data); 7207c478bd9Sstevel@tonic-gate backend_query_free(q); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate if (r == REP_PROTOCOL_DONE) 7237c478bd9Sstevel@tonic-gate r = REP_PROTOCOL_FAIL_UNKNOWN; /* corruption */ 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS || 7267c478bd9Sstevel@tonic-gate (r = data->txc_result) != REP_PROTOCOL_SUCCESS) { 7277c478bd9Sstevel@tonic-gate backend_query_free(data->txc_inserts); 7287c478bd9Sstevel@tonic-gate backend_tx_rollback(tx); 7297c478bd9Sstevel@tonic-gate goto end; 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate r = backend_tx_run(tx, data->txc_inserts, NULL, NULL); 7337c478bd9Sstevel@tonic-gate backend_query_free(data->txc_inserts); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS) { 7367c478bd9Sstevel@tonic-gate backend_tx_rollback(tx); 7377c478bd9Sstevel@tonic-gate goto end; 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate r = tx_process_cmds(data); 7417c478bd9Sstevel@tonic-gate if (r != REP_PROTOCOL_SUCCESS) { 7427c478bd9Sstevel@tonic-gate backend_tx_rollback(tx); 7437c478bd9Sstevel@tonic-gate goto end; 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate r = backend_tx_commit(tx); 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate if (r == REP_PROTOCOL_SUCCESS) 7487c478bd9Sstevel@tonic-gate *gen = new_gen; 7497c478bd9Sstevel@tonic-gate end: 7507c478bd9Sstevel@tonic-gate return (r); 7517c478bd9Sstevel@tonic-gate } 752