4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
28 * file_object.c - enter objects into and load them from the backend
30 * The primary entry points in this layer are object_create(),
31 * object_create_pg(), object_delete(), and object_fill_children(). They each
32 * take an rc_node_t and use the functions in the object_info_t info array for
44 #include "repcache_protocol.h"
46 typedef struct child_info
{
48 backend_tx_t
*ci_tx
; /* only for properties */
49 rc_node_lookup_t ci_base_nl
;
52 typedef struct delete_ent delete_ent_t
;
53 typedef struct delete_stack delete_stack_t
;
54 typedef struct delete_info delete_info_t
;
56 typedef int delete_cb_func(delete_info_t
*, const delete_ent_t
*);
59 delete_cb_func
*de_cb
; /* callback */
62 uint32_t de_gen
; /* only for property groups */
66 struct delete_stack
*ds_next
;
67 uint32_t ds_size
; /* number of elements */
68 uint32_t ds_cur
; /* current offset */
69 delete_ent_t ds_buf
[1]; /* actually ds_size */
71 #define DELETE_STACK_SIZE(x) offsetof(delete_stack_t, ds_buf[(x)])
75 backend_tx_t
*di_np_tx
;
76 delete_stack_t
*di_stack
;
77 delete_stack_t
*di_free
;
80 typedef struct object_info
{
82 enum id_space obj_id_space
;
84 int (*obj_fill_children
)(rc_node_t
*);
85 int (*obj_setup_child_info
)(rc_node_t
*, uint32_t, child_info_t
*);
86 int (*obj_query_child
)(backend_query_t
*, rc_node_lookup_t
*,
88 int (*obj_insert_child
)(backend_tx_t
*, rc_node_lookup_t
*,
90 int (*obj_insert_pg_child
)(backend_tx_t
*, rc_node_lookup_t
*,
91 const char *, const char *, uint32_t, uint32_t);
92 int (*obj_delete_start
)(rc_node_t
*, delete_info_t
*);
96 string_to_id(const char *str
, uint32_t *output
, const char *fieldname
)
98 if (uu_strtouint(str
, output
, sizeof (*output
), 0, 0, 0) == -1)
99 backend_panic("invalid integer \"%s\" in field \"%s\"",
103 #define NUM_NEEDED 50
106 delete_stack_push(delete_info_t
*dip
, uint32_t be
, delete_cb_func
*cb
,
107 uint32_t id
, uint32_t gen
)
109 delete_stack_t
*cur
= dip
->di_stack
;
112 if (cur
== NULL
|| cur
->ds_cur
== cur
->ds_size
) {
113 delete_stack_t
*new = dip
->di_free
;
116 new = uu_zalloc(DELETE_STACK_SIZE(NUM_NEEDED
));
118 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
119 new->ds_size
= NUM_NEEDED
;
122 new->ds_next
= dip
->di_stack
;
126 assert(cur
->ds_cur
< cur
->ds_size
);
127 ent
= &cur
->ds_buf
[cur
->ds_cur
++];
129 ent
->de_backend
= be
;
134 return (REP_PROTOCOL_SUCCESS
);
138 delete_stack_pop(delete_info_t
*dip
, delete_ent_t
*out
)
140 delete_stack_t
*cur
= dip
->di_stack
;
145 assert(cur
->ds_cur
> 0 && cur
->ds_cur
<= cur
->ds_size
);
146 ent
= &cur
->ds_buf
[--cur
->ds_cur
];
147 if (cur
->ds_cur
== 0) {
148 dip
->di_stack
= cur
->ds_next
;
151 if (dip
->di_free
!= NULL
)
152 uu_free(dip
->di_free
);
163 delete_stack_cleanup(delete_info_t
*dip
)
166 while ((cur
= dip
->di_stack
) != NULL
) {
167 dip
->di_stack
= cur
->ds_next
;
172 if ((cur
= dip
->di_free
) != NULL
) {
173 assert(cur
->ds_next
== NULL
); /* should only be one */
179 struct delete_cb_info
{
180 delete_info_t
*dci_dip
;
182 delete_cb_func
*dci_cb
;
188 push_delete_callback(void *data
, int columns
, char **vals
, char **names
)
190 struct delete_cb_info
*info
= data
;
192 const char *id_str
= *vals
++;
193 const char *gen_str
= *vals
++;
198 assert(columns
== 2);
200 string_to_id(id_str
, &id
, "id");
201 string_to_id(gen_str
, &gen
, "gen_id");
203 info
->dci_result
= delete_stack_push(info
->dci_dip
, info
->dci_be
,
204 info
->dci_cb
, id
, gen
);
206 if (info
->dci_result
!= REP_PROTOCOL_SUCCESS
)
207 return (BACKEND_CALLBACK_ABORT
);
208 return (BACKEND_CALLBACK_CONTINUE
);
212 value_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
214 uint32_t be
= ent
->de_backend
;
219 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
222 q
= backend_query_alloc();
225 "SELECT 1 FROM prop_lnk_tbl WHERE (lnk_val_id = %d); "
226 "DELETE FROM value_tbl WHERE (value_id = %d); ",
227 ent
->de_id
, ent
->de_id
);
228 r
= backend_tx_run(tx
, q
, backend_fail_if_seen
, NULL
);
229 backend_query_free(q
);
230 if (r
== REP_PROTOCOL_DONE
)
231 return (REP_PROTOCOL_SUCCESS
); /* still in use */
236 pg_lnk_tbl_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
238 struct delete_cb_info info
;
239 uint32_t be
= ent
->de_backend
;
244 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
248 * For non-persistent backends, we could only have one parent, and
249 * it's already been deleted.
251 * For normal backends, we need to check to see if we're in
252 * a snapshot or are the active generation for the property
253 * group. If we are, there's nothing to be done.
255 if (be
== BACKEND_TYPE_NORMAL
) {
256 q
= backend_query_alloc();
260 "WHERE (pg_id = %d AND pg_gen_id = %d); "
262 "FROM snaplevel_lnk_tbl "
263 "WHERE (snaplvl_pg_id = %d AND snaplvl_gen_id = %d);",
264 ent
->de_id
, ent
->de_gen
,
265 ent
->de_id
, ent
->de_gen
);
266 r
= backend_tx_run(tx
, q
, backend_fail_if_seen
, NULL
);
267 backend_query_free(q
);
269 if (r
== REP_PROTOCOL_DONE
)
270 return (REP_PROTOCOL_SUCCESS
); /* still in use */
275 info
.dci_cb
= &value_delete
;
276 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
278 q
= backend_query_alloc();
280 "SELECT DISTINCT lnk_val_id, 0 FROM prop_lnk_tbl "
282 " (lnk_pg_id = %d AND lnk_gen_id = %d AND lnk_val_id NOTNULL); "
283 "DELETE FROM prop_lnk_tbl "
284 "WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)",
285 ent
->de_id
, ent
->de_gen
, ent
->de_id
, ent
->de_gen
);
287 r
= backend_tx_run(tx
, q
, push_delete_callback
, &info
);
288 backend_query_free(q
);
290 if (r
== REP_PROTOCOL_DONE
) {
291 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
292 return (info
.dci_result
);
298 propertygrp_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
300 uint32_t be
= ent
->de_backend
;
306 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
309 q
= backend_query_alloc();
311 "SELECT pg_gen_id FROM pg_tbl WHERE pg_id = %d; "
312 "DELETE FROM pg_tbl WHERE pg_id = %d",
313 ent
->de_id
, ent
->de_id
);
314 r
= backend_tx_run_single_int(tx
, q
, &gen
);
315 backend_query_free(q
);
317 if (r
!= REP_PROTOCOL_SUCCESS
)
320 return (delete_stack_push(dip
, be
, &pg_lnk_tbl_delete
,
325 snaplevel_lnk_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
327 uint32_t be
= ent
->de_backend
;
329 struct delete_cb_info info
;
333 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
338 info
.dci_cb
= &pg_lnk_tbl_delete
;
339 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
341 q
= backend_query_alloc();
343 "SELECT snaplvl_pg_id, snaplvl_gen_id "
344 " FROM snaplevel_lnk_tbl "
345 " WHERE snaplvl_level_id = %d; "
346 "DELETE FROM snaplevel_lnk_tbl WHERE snaplvl_level_id = %d",
347 ent
->de_id
, ent
->de_id
);
348 r
= backend_tx_run(tx
, q
, push_delete_callback
, &info
);
349 backend_query_free(q
);
351 if (r
== REP_PROTOCOL_DONE
) {
352 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
353 return (info
.dci_result
);
359 snaplevel_tbl_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
361 uint32_t be
= ent
->de_backend
;
362 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
365 struct delete_cb_info info
;
369 assert(be
== BACKEND_TYPE_NORMAL
);
371 q
= backend_query_alloc();
373 "SELECT 1 FROM snapshot_lnk_tbl WHERE lnk_snap_id = %d",
375 r
= backend_tx_run(tx
, q
, backend_fail_if_seen
, NULL
);
376 backend_query_free(q
);
378 if (r
== REP_PROTOCOL_DONE
)
379 return (REP_PROTOCOL_SUCCESS
); /* still in use */
383 info
.dci_cb
= &snaplevel_lnk_delete
;
384 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
386 q
= backend_query_alloc();
388 "SELECT snap_level_id, 0 FROM snaplevel_tbl WHERE snap_id = %d;"
389 "DELETE FROM snaplevel_tbl WHERE snap_id = %d",
390 ent
->de_id
, ent
->de_id
);
391 r
= backend_tx_run(tx
, q
, push_delete_callback
, &info
);
392 backend_query_free(q
);
394 if (r
== REP_PROTOCOL_DONE
) {
395 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
396 return (info
.dci_result
);
402 snapshot_lnk_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
404 uint32_t be
= ent
->de_backend
;
405 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
412 assert(be
== BACKEND_TYPE_NORMAL
);
414 q
= backend_query_alloc();
416 "SELECT lnk_snap_id FROM snapshot_lnk_tbl WHERE lnk_id = %d; "
417 "DELETE FROM snapshot_lnk_tbl WHERE lnk_id = %d",
418 ent
->de_id
, ent
->de_id
);
419 r
= backend_tx_run_single_int(tx
, q
, &snapid
);
420 backend_query_free(q
);
422 if (r
!= REP_PROTOCOL_SUCCESS
)
425 return (delete_stack_push(dip
, be
, &snaplevel_tbl_delete
, snapid
, 0));
429 pgparent_delete_add_pgs(delete_info_t
*dip
, uint32_t parent_id
)
431 struct delete_cb_info info
;
436 info
.dci_be
= BACKEND_TYPE_NORMAL
;
437 info
.dci_cb
= &propertygrp_delete
;
438 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
440 q
= backend_query_alloc();
442 "SELECT pg_id, 0 FROM pg_tbl WHERE pg_parent_id = %d",
445 r
= backend_tx_run(dip
->di_tx
, q
, push_delete_callback
, &info
);
447 if (r
== REP_PROTOCOL_DONE
) {
448 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
449 backend_query_free(q
);
450 return (info
.dci_result
);
452 if (r
!= REP_PROTOCOL_SUCCESS
) {
453 backend_query_free(q
);
457 if (dip
->di_np_tx
!= NULL
) {
458 info
.dci_be
= BACKEND_TYPE_NONPERSIST
;
460 r
= backend_tx_run(dip
->di_np_tx
, q
, push_delete_callback
,
463 if (r
== REP_PROTOCOL_DONE
) {
464 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
465 backend_query_free(q
);
466 return (info
.dci_result
);
468 if (r
!= REP_PROTOCOL_SUCCESS
) {
469 backend_query_free(q
);
473 backend_query_free(q
);
474 return (REP_PROTOCOL_SUCCESS
);
478 service_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
482 r
= backend_tx_run_update_changed(dip
->di_tx
,
483 "DELETE FROM service_tbl WHERE svc_id = %d", ent
->de_id
);
484 if (r
!= REP_PROTOCOL_SUCCESS
)
487 return (pgparent_delete_add_pgs(dip
, ent
->de_id
));
491 instance_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
493 struct delete_cb_info info
;
497 r
= backend_tx_run_update_changed(dip
->di_tx
,
498 "DELETE FROM instance_tbl WHERE instance_id = %d", ent
->de_id
);
499 if (r
!= REP_PROTOCOL_SUCCESS
)
502 r
= pgparent_delete_add_pgs(dip
, ent
->de_id
);
503 if (r
!= REP_PROTOCOL_SUCCESS
)
507 info
.dci_be
= BACKEND_TYPE_NORMAL
;
508 info
.dci_cb
= &snapshot_lnk_delete
;
509 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
511 q
= backend_query_alloc();
513 "SELECT lnk_id, 0 FROM snapshot_lnk_tbl WHERE lnk_inst_id = %d",
515 r
= backend_tx_run(dip
->di_tx
, q
, push_delete_callback
, &info
);
516 backend_query_free(q
);
518 if (r
== REP_PROTOCOL_DONE
) {
519 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
520 return (info
.dci_result
);
527 fill_child_callback(void *data
, int columns
, char **vals
, char **names
)
529 child_info_t
*cp
= data
;
534 rc_node_lookup_t
*lp
= &cp
->ci_base_nl
;
536 assert(columns
== 2);
543 string_to_id(cur
, &main_id
, "id");
545 lp
->rl_main_id
= main_id
;
547 if ((np
= rc_node_alloc()) == NULL
)
548 return (BACKEND_CALLBACK_ABORT
);
550 np
= rc_node_setup(np
, lp
, name
, cp
->ci_parent
);
553 return (BACKEND_CALLBACK_CONTINUE
);
558 fill_snapshot_callback(void *data
, int columns
, char **vals
, char **names
)
560 child_info_t
*cp
= data
;
567 rc_node_lookup_t
*lp
= &cp
->ci_base_nl
;
569 assert(columns
== 3);
579 string_to_id(cur
, &main_id
, "lnk_id");
580 string_to_id(snap
, &snap_id
, "lnk_snap_id");
582 lp
->rl_main_id
= main_id
;
584 if ((np
= rc_node_alloc()) == NULL
)
585 return (BACKEND_CALLBACK_ABORT
);
587 np
= rc_node_setup_snapshot(np
, lp
, name
, snap_id
, cp
->ci_parent
);
590 return (BACKEND_CALLBACK_CONTINUE
);
595 fill_pg_callback(void *data
, int columns
, char **vals
, char **names
)
597 child_info_t
*cip
= data
;
605 rc_node_lookup_t
*lp
= &cip
->ci_base_nl
;
606 rc_node_t
*newnode
, *pg
;
608 assert(columns
== 5);
610 name
= *vals
++; /* pg_name */
613 cur
= *vals
++; /* pg_id */
615 string_to_id(cur
, &main_id
, "pg_id");
617 lp
->rl_main_id
= main_id
;
619 cur
= *vals
++; /* pg_gen_id */
621 string_to_id(cur
, &gen_id
, "pg_gen_id");
623 type
= *vals
++; /* pg_type */
626 cur
= *vals
++; /* pg_flags */
628 string_to_id(cur
, &flags
, "pg_flags");
630 if ((newnode
= rc_node_alloc()) == NULL
)
631 return (BACKEND_CALLBACK_ABORT
);
633 pg
= rc_node_setup_pg(newnode
, lp
, name
, type
, flags
, gen_id
,
636 rc_node_destroy(newnode
);
637 return (BACKEND_CALLBACK_ABORT
);
642 return (BACKEND_CALLBACK_CONTINUE
);
645 struct property_value_info
{
654 property_value_size_cb(void *data
, int columns
, char **vals
, char **names
)
656 struct property_value_info
*info
= data
;
657 assert(columns
== 1);
659 info
->pvi_size
+= strlen(vals
[0]) + 1; /* count the '\0' */
661 return (BACKEND_CALLBACK_CONTINUE
);
666 property_value_cb(void *data
, int columns
, char **vals
, char **names
)
668 struct property_value_info
*info
= data
;
669 size_t pos
, left
, len
;
671 assert(columns
== 1);
673 left
= info
->pvi_size
- pos
;
676 left
= info
->pvi_size
- pos
;
678 if ((len
= strlcpy(&info
->pvi_base
[pos
], vals
[0], left
)) >= left
) {
680 * since we preallocated, above, this shouldn't happen
682 backend_panic("unexpected database change");
685 len
+= 1; /* count the '\0' */
687 info
->pvi_pos
+= len
;
690 return (BACKEND_CALLBACK_CONTINUE
);
695 object_free_values(const char *vals
, uint32_t type
, size_t count
, size_t size
)
698 uu_free((void *)vals
);
703 fill_property_callback(void *data
, int columns
, char **vals
, char **names
)
705 child_info_t
*cp
= data
;
706 backend_tx_t
*tx
= cp
->ci_tx
;
710 rep_protocol_value_type_t type
;
711 rc_node_lookup_t
*lp
= &cp
->ci_base_nl
;
712 struct property_value_info info
;
715 assert(columns
== 4);
718 info
.pvi_base
= NULL
;
726 string_to_id(cur
, &main_id
, "lnk_prop_id");
729 assert(('a' <= cur
[0] && 'z' >= cur
[0]) ||
730 ('A' <= cur
[0] && 'Z' >= cur
[0]) &&
731 (cur
[1] == 0 || ('a' <= cur
[1] && 'z' >= cur
[1]) ||
732 ('A' <= cur
[1] && 'Z' >= cur
[1])));
733 type
= cur
[0] | (cur
[1] << 8);
735 lp
->rl_main_id
= main_id
;
738 * fill in the values, if any
740 if ((cur
= *vals
++) != NULL
) {
741 rep_protocol_responseid_t r
;
742 backend_query_t
*q
= backend_query_alloc();
745 * Ensure that select operation is reflective
746 * of repository schema. If the repository has
747 * been upgraded, make use of value ordering
748 * by retrieving values in order using the
749 * value_order column. Otherwise, simply
750 * run the select with no order specified.
751 * The order-insensitive select is necessary
752 * as on first reboot post-upgrade, the repository
753 * contents need to be read before the repository
754 * backend is writable (and upgrade is possible).
756 if (backend_is_upgraded(tx
)) {
758 "SELECT value_value FROM value_tbl "
759 "WHERE (value_id = '%q') ORDER BY value_order",
763 "SELECT value_value FROM value_tbl "
764 "WHERE (value_id = '%q')",
768 switch (r
= backend_tx_run(tx
, q
, property_value_size_cb
,
770 case REP_PROTOCOL_SUCCESS
:
773 case REP_PROTOCOL_FAIL_NO_RESOURCES
:
774 backend_query_free(q
);
775 return (BACKEND_CALLBACK_ABORT
);
777 case REP_PROTOCOL_DONE
:
779 backend_panic("backend_tx_run() returned %d", r
);
781 if (info
.pvi_size
> 0) {
782 info
.pvi_base
= uu_zalloc(info
.pvi_size
);
783 if (info
.pvi_base
== NULL
) {
784 backend_query_free(q
);
785 return (BACKEND_CALLBACK_ABORT
);
787 switch (r
= backend_tx_run(tx
, q
, property_value_cb
,
789 case REP_PROTOCOL_SUCCESS
:
792 case REP_PROTOCOL_FAIL_NO_RESOURCES
:
793 uu_free(info
.pvi_base
);
794 backend_query_free(q
);
795 return (BACKEND_CALLBACK_ABORT
);
797 case REP_PROTOCOL_DONE
:
799 backend_panic("backend_tx_run() returned %d",
803 backend_query_free(q
);
806 rc
= rc_node_create_property(cp
->ci_parent
, lp
, name
, type
,
807 info
.pvi_base
, info
.pvi_count
, info
.pvi_size
);
808 if (rc
!= REP_PROTOCOL_SUCCESS
) {
809 assert(rc
== REP_PROTOCOL_FAIL_NO_RESOURCES
);
810 return (BACKEND_CALLBACK_ABORT
);
813 return (BACKEND_CALLBACK_CONTINUE
);
817 * The *_setup_child_info() functions fill in a child_info_t structure with the
818 * information for the children of np with type type.
821 * _TYPE_MISMATCH - object cannot have children of type type
825 scope_setup_child_info(rc_node_t
*np
, uint32_t type
, child_info_t
*cip
)
827 if (type
!= REP_PROTOCOL_ENTITY_SERVICE
)
828 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
830 bzero(cip
, sizeof (*cip
));
832 cip
->ci_base_nl
.rl_type
= type
;
833 cip
->ci_base_nl
.rl_backend
= np
->rn_id
.rl_backend
;
834 return (REP_PROTOCOL_SUCCESS
);
838 service_setup_child_info(rc_node_t
*np
, uint32_t type
, child_info_t
*cip
)
841 case REP_PROTOCOL_ENTITY_INSTANCE
:
842 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
845 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
848 bzero(cip
, sizeof (*cip
));
850 cip
->ci_base_nl
.rl_type
= type
;
851 cip
->ci_base_nl
.rl_backend
= np
->rn_id
.rl_backend
;
852 cip
->ci_base_nl
.rl_ids
[ID_SERVICE
] = np
->rn_id
.rl_main_id
;
854 return (REP_PROTOCOL_SUCCESS
);
858 instance_setup_child_info(rc_node_t
*np
, uint32_t type
, child_info_t
*cip
)
861 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
862 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
865 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
868 bzero(cip
, sizeof (*cip
));
870 cip
->ci_base_nl
.rl_type
= type
;
871 cip
->ci_base_nl
.rl_backend
= np
->rn_id
.rl_backend
;
872 cip
->ci_base_nl
.rl_ids
[ID_SERVICE
] = np
->rn_id
.rl_ids
[ID_SERVICE
];
873 cip
->ci_base_nl
.rl_ids
[ID_INSTANCE
] = np
->rn_id
.rl_main_id
;
875 return (REP_PROTOCOL_SUCCESS
);
879 snaplevel_setup_child_info(rc_node_t
*np
, uint32_t type
, child_info_t
*cip
)
881 if (type
!= REP_PROTOCOL_ENTITY_PROPERTYGRP
)
882 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
884 bzero(cip
, sizeof (*cip
));
886 cip
->ci_base_nl
.rl_type
= type
;
887 cip
->ci_base_nl
.rl_backend
= np
->rn_id
.rl_backend
;
888 cip
->ci_base_nl
.rl_ids
[ID_SERVICE
] = np
->rn_id
.rl_ids
[ID_SERVICE
];
889 cip
->ci_base_nl
.rl_ids
[ID_INSTANCE
] = np
->rn_id
.rl_ids
[ID_INSTANCE
];
890 cip
->ci_base_nl
.rl_ids
[ID_NAME
] = np
->rn_id
.rl_ids
[ID_NAME
];
891 cip
->ci_base_nl
.rl_ids
[ID_SNAPSHOT
] = np
->rn_id
.rl_ids
[ID_SNAPSHOT
];
892 cip
->ci_base_nl
.rl_ids
[ID_LEVEL
] = np
->rn_id
.rl_main_id
;
894 return (REP_PROTOCOL_SUCCESS
);
898 propertygrp_setup_child_info(rc_node_t
*pg
, uint32_t type
, child_info_t
*cip
)
900 if (type
!= REP_PROTOCOL_ENTITY_PROPERTY
)
901 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
903 bzero(cip
, sizeof (*cip
));
905 cip
->ci_base_nl
.rl_type
= type
;
906 cip
->ci_base_nl
.rl_backend
= pg
->rn_id
.rl_backend
;
907 cip
->ci_base_nl
.rl_ids
[ID_SERVICE
] = pg
->rn_id
.rl_ids
[ID_SERVICE
];
908 cip
->ci_base_nl
.rl_ids
[ID_INSTANCE
] = pg
->rn_id
.rl_ids
[ID_INSTANCE
];
909 cip
->ci_base_nl
.rl_ids
[ID_PG
] = pg
->rn_id
.rl_main_id
;
910 cip
->ci_base_nl
.rl_ids
[ID_GEN
] = pg
->rn_gen_id
;
911 cip
->ci_base_nl
.rl_ids
[ID_NAME
] = pg
->rn_id
.rl_ids
[ID_NAME
];
912 cip
->ci_base_nl
.rl_ids
[ID_SNAPSHOT
] = pg
->rn_id
.rl_ids
[ID_SNAPSHOT
];
913 cip
->ci_base_nl
.rl_ids
[ID_LEVEL
] = pg
->rn_id
.rl_ids
[ID_LEVEL
];
915 return (REP_PROTOCOL_SUCCESS
);
919 * The *_fill_children() functions populate the children of the given rc_node_t
920 * by querying the database and calling rc_node_setup_*() functions (usually
921 * via a fill_*_callback()).
933 scope_fill_children(rc_node_t
*np
)
939 (void) scope_setup_child_info(np
, REP_PROTOCOL_ENTITY_SERVICE
, &ci
);
941 q
= backend_query_alloc();
942 backend_query_append(q
, "SELECT svc_name, svc_id FROM service_tbl");
943 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_child_callback
, &ci
);
944 backend_query_free(q
);
946 if (res
== REP_PROTOCOL_DONE
)
947 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
957 service_fill_children(rc_node_t
*np
)
963 assert(np
->rn_id
.rl_backend
== BACKEND_TYPE_NORMAL
);
965 (void) service_setup_child_info(np
, REP_PROTOCOL_ENTITY_INSTANCE
, &ci
);
967 q
= backend_query_alloc();
969 "SELECT instance_name, instance_id FROM instance_tbl"
970 " WHERE (instance_svc = %d)",
971 np
->rn_id
.rl_main_id
);
972 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_child_callback
, &ci
);
973 backend_query_free(q
);
975 if (res
== REP_PROTOCOL_DONE
)
976 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
977 if (res
!= REP_PROTOCOL_SUCCESS
)
980 (void) service_setup_child_info(np
, REP_PROTOCOL_ENTITY_PROPERTYGRP
,
983 q
= backend_query_alloc();
985 "SELECT pg_name, pg_id, pg_gen_id, pg_type, pg_flags FROM pg_tbl"
986 " WHERE (pg_parent_id = %d)",
987 np
->rn_id
.rl_main_id
);
989 ci
.ci_base_nl
.rl_backend
= BACKEND_TYPE_NORMAL
;
990 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_pg_callback
, &ci
);
991 if (res
== REP_PROTOCOL_SUCCESS
) {
992 ci
.ci_base_nl
.rl_backend
= BACKEND_TYPE_NONPERSIST
;
993 res
= backend_run(BACKEND_TYPE_NONPERSIST
, q
,
994 fill_pg_callback
, &ci
);
995 /* nonpersistant database may not exist */
996 if (res
== REP_PROTOCOL_FAIL_BACKEND_ACCESS
)
997 res
= REP_PROTOCOL_SUCCESS
;
999 if (res
== REP_PROTOCOL_DONE
)
1000 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1001 backend_query_free(q
);
1012 instance_fill_children(rc_node_t
*np
)
1018 assert(np
->rn_id
.rl_backend
== BACKEND_TYPE_NORMAL
);
1020 /* Get child property groups */
1021 (void) instance_setup_child_info(np
, REP_PROTOCOL_ENTITY_PROPERTYGRP
,
1024 q
= backend_query_alloc();
1025 backend_query_add(q
,
1026 "SELECT pg_name, pg_id, pg_gen_id, pg_type, pg_flags FROM pg_tbl"
1027 " WHERE (pg_parent_id = %d)",
1028 np
->rn_id
.rl_main_id
);
1029 ci
.ci_base_nl
.rl_backend
= BACKEND_TYPE_NORMAL
;
1030 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_pg_callback
, &ci
);
1031 if (res
== REP_PROTOCOL_SUCCESS
) {
1032 ci
.ci_base_nl
.rl_backend
= BACKEND_TYPE_NONPERSIST
;
1033 res
= backend_run(BACKEND_TYPE_NONPERSIST
, q
,
1034 fill_pg_callback
, &ci
);
1035 /* nonpersistant database may not exist */
1036 if (res
== REP_PROTOCOL_FAIL_BACKEND_ACCESS
)
1037 res
= REP_PROTOCOL_SUCCESS
;
1039 if (res
== REP_PROTOCOL_DONE
)
1040 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1041 backend_query_free(q
);
1043 if (res
!= REP_PROTOCOL_SUCCESS
)
1046 /* Get child snapshots */
1047 (void) instance_setup_child_info(np
, REP_PROTOCOL_ENTITY_SNAPSHOT
,
1050 q
= backend_query_alloc();
1051 backend_query_add(q
,
1052 "SELECT lnk_snap_name, lnk_id, lnk_snap_id FROM snapshot_lnk_tbl"
1053 " WHERE (lnk_inst_id = %d)",
1054 np
->rn_id
.rl_main_id
);
1055 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_snapshot_callback
, &ci
);
1056 if (res
== REP_PROTOCOL_DONE
)
1057 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1058 backend_query_free(q
);
1069 snapshot_fill_children(rc_node_t
*np
)
1072 rc_snapshot_t
*sp
, *oldsp
;
1073 rc_snaplevel_t
*lvl
;
1074 rc_node_lookup_t nl
;
1077 /* Get the rc_snapshot_t (& its rc_snaplevel_t's). */
1078 (void) pthread_mutex_lock(&np
->rn_lock
);
1079 sp
= np
->rn_snapshot
;
1080 (void) pthread_mutex_unlock(&np
->rn_lock
);
1082 r
= rc_snapshot_get(np
->rn_snapshot_id
, &sp
);
1083 if (r
!= REP_PROTOCOL_SUCCESS
) {
1084 assert(r
== REP_PROTOCOL_FAIL_NO_RESOURCES
);
1087 (void) pthread_mutex_lock(&np
->rn_lock
);
1088 oldsp
= np
->rn_snapshot
;
1089 assert(oldsp
== NULL
|| oldsp
== sp
);
1090 np
->rn_snapshot
= sp
;
1091 (void) pthread_mutex_unlock(&np
->rn_lock
);
1093 rc_snapshot_rele(oldsp
);
1096 bzero(&nl
, sizeof (nl
));
1097 nl
.rl_type
= REP_PROTOCOL_ENTITY_SNAPLEVEL
;
1098 nl
.rl_backend
= np
->rn_id
.rl_backend
;
1099 nl
.rl_ids
[ID_SERVICE
] = np
->rn_id
.rl_ids
[ID_SERVICE
];
1100 nl
.rl_ids
[ID_INSTANCE
] = np
->rn_id
.rl_ids
[ID_INSTANCE
];
1101 nl
.rl_ids
[ID_NAME
] = np
->rn_id
.rl_main_id
;
1102 nl
.rl_ids
[ID_SNAPSHOT
] = np
->rn_snapshot_id
;
1104 /* Create rc_node_t's for the snapshot's rc_snaplevel_t's. */
1105 for (lvl
= sp
->rs_levels
; lvl
!= NULL
; lvl
= lvl
->rsl_next
) {
1106 nnp
= rc_node_alloc();
1107 assert(nnp
!= NULL
);
1108 nl
.rl_main_id
= lvl
->rsl_level_id
;
1109 nnp
= rc_node_setup_snaplevel(nnp
, &nl
, lvl
, np
);
1113 return (REP_PROTOCOL_SUCCESS
);
1122 snaplevel_fill_children(rc_node_t
*np
)
1124 rc_snaplevel_t
*lvl
= np
->rn_snaplevel
;
1129 (void) snaplevel_setup_child_info(np
, REP_PROTOCOL_ENTITY_PROPERTYGRP
,
1132 q
= backend_query_alloc();
1133 backend_query_add(q
,
1134 "SELECT snaplvl_pg_name, snaplvl_pg_id, snaplvl_gen_id, "
1135 " snaplvl_pg_type, snaplvl_pg_flags "
1136 " FROM snaplevel_lnk_tbl "
1137 " WHERE (snaplvl_level_id = %d)",
1139 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_pg_callback
, &ci
);
1140 if (res
== REP_PROTOCOL_DONE
)
1141 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1142 backend_query_free(q
);
1153 propertygrp_fill_children(rc_node_t
*np
)
1160 backend_type_t backend
= np
->rn_id
.rl_backend
;
1162 (void) propertygrp_setup_child_info(np
, REP_PROTOCOL_ENTITY_PROPERTY
,
1165 res
= backend_tx_begin_ro(backend
, &tx
);
1166 if (res
!= REP_PROTOCOL_SUCCESS
) {
1168 * If the backend didn't exist, we wouldn't have got this
1171 assert(res
!= REP_PROTOCOL_FAIL_BACKEND_ACCESS
);
1177 q
= backend_query_alloc();
1178 backend_query_add(q
,
1179 "SELECT lnk_prop_name, lnk_prop_id, lnk_prop_type, lnk_val_id "
1180 "FROM prop_lnk_tbl "
1181 "WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)",
1182 np
->rn_id
.rl_main_id
, np
->rn_gen_id
);
1183 res
= backend_tx_run(tx
, q
, fill_property_callback
, &ci
);
1184 if (res
== REP_PROTOCOL_DONE
)
1185 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1186 backend_query_free(q
);
1187 backend_tx_end_ro(tx
);
1194 * _TYPE_MISMATCH - lp is not for a service
1195 * _INVALID_TYPE - lp has invalid type
1196 * _BAD_REQUEST - name is invalid
1199 scope_query_child(backend_query_t
*q
, rc_node_lookup_t
*lp
, const char *name
)
1201 uint32_t type
= lp
->rl_type
;
1204 if (type
!= REP_PROTOCOL_ENTITY_SERVICE
)
1205 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
1207 if ((rc
= rc_check_type_name(type
, name
)) != REP_PROTOCOL_SUCCESS
)
1210 backend_query_add(q
,
1211 "SELECT svc_id FROM service_tbl "
1212 "WHERE svc_name = '%q'",
1215 return (REP_PROTOCOL_SUCCESS
);
1220 * _NO_RESOURCES - out of memory
1223 scope_insert_child(backend_tx_t
*tx
, rc_node_lookup_t
*lp
, const char *name
)
1225 return (backend_tx_run_update(tx
,
1226 "INSERT INTO service_tbl (svc_id, svc_name) "
1227 "VALUES (%d, '%q')",
1228 lp
->rl_main_id
, name
));
1233 * _TYPE_MISMATCH - lp is not for an instance or property group
1234 * _INVALID_TYPE - lp has invalid type
1235 * _BAD_REQUEST - name is invalid
1238 service_query_child(backend_query_t
*q
, rc_node_lookup_t
*lp
, const char *name
)
1240 uint32_t type
= lp
->rl_type
;
1243 if (type
!= REP_PROTOCOL_ENTITY_INSTANCE
&&
1244 type
!= REP_PROTOCOL_ENTITY_PROPERTYGRP
)
1245 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
1247 if ((rc
= rc_check_type_name(type
, name
)) != REP_PROTOCOL_SUCCESS
)
1251 case REP_PROTOCOL_ENTITY_INSTANCE
:
1252 backend_query_add(q
,
1253 "SELECT instance_id FROM instance_tbl "
1254 "WHERE instance_name = '%q' AND instance_svc = %d",
1255 name
, lp
->rl_ids
[ID_SERVICE
]);
1257 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
1258 backend_query_add(q
,
1259 "SELECT pg_id FROM pg_tbl "
1260 " WHERE pg_name = '%q' AND pg_parent_id = %d",
1261 name
, lp
->rl_ids
[ID_SERVICE
]);
1268 return (REP_PROTOCOL_SUCCESS
);
1273 * _NO_RESOURCES - out of memory
1276 service_insert_child(backend_tx_t
*tx
, rc_node_lookup_t
*lp
, const char *name
)
1278 return (backend_tx_run_update(tx
,
1279 "INSERT INTO instance_tbl "
1280 " (instance_id, instance_name, instance_svc) "
1281 "VALUES (%d, '%q', %d)",
1282 lp
->rl_main_id
, name
, lp
->rl_ids
[ID_SERVICE
]));
1287 * _NO_RESOURCES - out of memory
1290 instance_insert_child(backend_tx_t
*tx
, rc_node_lookup_t
*lp
, const char *name
)
1292 return (backend_tx_run_update(tx
,
1293 "INSERT INTO snapshot_lnk_tbl "
1294 " (lnk_id, lnk_inst_id, lnk_snap_name, lnk_snap_id) "
1295 "VALUES (%d, %d, '%q', 0)",
1296 lp
->rl_main_id
, lp
->rl_ids
[ID_INSTANCE
], name
));
1301 * _TYPE_MISMATCH - lp is not for a property group or snapshot
1302 * _INVALID_TYPE - lp has invalid type
1303 * _BAD_REQUEST - name is invalid
1306 instance_query_child(backend_query_t
*q
, rc_node_lookup_t
*lp
, const char *name
)
1308 uint32_t type
= lp
->rl_type
;
1311 if (type
!= REP_PROTOCOL_ENTITY_PROPERTYGRP
&&
1312 type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
)
1313 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
1315 if ((rc
= rc_check_type_name(type
, name
)) != REP_PROTOCOL_SUCCESS
)
1319 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
1320 backend_query_add(q
,
1321 "SELECT pg_id FROM pg_tbl "
1322 " WHERE pg_name = '%q' AND pg_parent_id = %d",
1323 name
, lp
->rl_ids
[ID_INSTANCE
]);
1325 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1326 backend_query_add(q
,
1327 "SELECT lnk_id FROM snapshot_lnk_tbl "
1328 " WHERE lnk_snap_name = '%q' AND lnk_inst_id = %d",
1329 name
, lp
->rl_ids
[ID_INSTANCE
]);
1336 return (REP_PROTOCOL_SUCCESS
);
1340 generic_insert_pg_child(backend_tx_t
*tx
, rc_node_lookup_t
*lp
,
1341 const char *name
, const char *pgtype
, uint32_t flags
, uint32_t gen
)
1343 int parent_id
= (lp
->rl_ids
[ID_INSTANCE
] != 0)?
1344 lp
->rl_ids
[ID_INSTANCE
] : lp
->rl_ids
[ID_SERVICE
];
1345 return (backend_tx_run_update(tx
,
1346 "INSERT INTO pg_tbl "
1347 " (pg_id, pg_name, pg_parent_id, pg_type, pg_flags, pg_gen_id) "
1348 "VALUES (%d, '%q', %d, '%q', %d, %d)",
1349 lp
->rl_main_id
, name
, parent_id
, pgtype
, flags
, gen
));
1353 service_delete_start(rc_node_t
*np
, delete_info_t
*dip
)
1356 backend_query_t
*q
= backend_query_alloc();
1359 * Check for child instances, and refuse to delete if they exist.
1361 backend_query_add(q
,
1362 "SELECT 1 FROM instance_tbl WHERE instance_svc = %d",
1363 np
->rn_id
.rl_main_id
);
1365 r
= backend_tx_run(dip
->di_tx
, q
, backend_fail_if_seen
, NULL
);
1366 backend_query_free(q
);
1368 if (r
== REP_PROTOCOL_DONE
)
1369 return (REP_PROTOCOL_FAIL_EXISTS
); /* instances exist */
1371 return (delete_stack_push(dip
, BACKEND_TYPE_NORMAL
, &service_delete
,
1372 np
->rn_id
.rl_main_id
, 0));
1376 instance_delete_start(rc_node_t
*np
, delete_info_t
*dip
)
1378 return (delete_stack_push(dip
, BACKEND_TYPE_NORMAL
, &instance_delete
,
1379 np
->rn_id
.rl_main_id
, 0));
1383 snapshot_delete_start(rc_node_t
*np
, delete_info_t
*dip
)
1385 return (delete_stack_push(dip
, BACKEND_TYPE_NORMAL
,
1386 &snapshot_lnk_delete
, np
->rn_id
.rl_main_id
, 0));
1390 propertygrp_delete_start(rc_node_t
*np
, delete_info_t
*dip
)
1392 return (delete_stack_push(dip
, np
->rn_id
.rl_backend
,
1393 &propertygrp_delete
, np
->rn_id
.rl_main_id
, 0));
1396 static object_info_t info
[] = {
1397 {REP_PROTOCOL_ENTITY_NONE
},
1398 {REP_PROTOCOL_ENTITY_SCOPE
,
1400 scope_fill_children
,
1401 scope_setup_child_info
,
1407 {REP_PROTOCOL_ENTITY_SERVICE
,
1408 BACKEND_ID_SERVICE_INSTANCE
,
1409 service_fill_children
,
1410 service_setup_child_info
,
1411 service_query_child
,
1412 service_insert_child
,
1413 generic_insert_pg_child
,
1414 service_delete_start
,
1416 {REP_PROTOCOL_ENTITY_INSTANCE
,
1417 BACKEND_ID_SERVICE_INSTANCE
,
1418 instance_fill_children
,
1419 instance_setup_child_info
,
1420 instance_query_child
,
1421 instance_insert_child
,
1422 generic_insert_pg_child
,
1423 instance_delete_start
,
1425 {REP_PROTOCOL_ENTITY_SNAPSHOT
,
1426 BACKEND_ID_SNAPNAME
,
1427 snapshot_fill_children
,
1432 snapshot_delete_start
,
1434 {REP_PROTOCOL_ENTITY_SNAPLEVEL
,
1435 BACKEND_ID_SNAPLEVEL
,
1436 snaplevel_fill_children
,
1437 snaplevel_setup_child_info
,
1439 {REP_PROTOCOL_ENTITY_PROPERTYGRP
,
1440 BACKEND_ID_PROPERTYGRP
,
1441 propertygrp_fill_children
,
1446 propertygrp_delete_start
,
1448 {REP_PROTOCOL_ENTITY_PROPERTY
},
1451 #define NUM_INFO (sizeof (info) / sizeof (*info))
1454 * object_fill_children() populates the child list of an rc_node_t by calling
1455 * the appropriate <type>_fill_children() which runs backend queries that
1456 * call an appropriate fill_*_callback() which takes a row of results,
1457 * decodes them, and calls an rc_node_setup*() function in rc_node.c to create
1464 object_fill_children(rc_node_t
*pp
)
1466 uint32_t type
= pp
->rn_id
.rl_type
;
1467 assert(type
> 0 && type
< NUM_INFO
);
1469 return ((*info
[type
].obj_fill_children
)(pp
));
1473 object_delete(rc_node_t
*pp
)
1480 uint32_t type
= pp
->rn_id
.rl_type
;
1481 assert(type
> 0 && type
< NUM_INFO
);
1483 if (info
[type
].obj_delete_start
== NULL
)
1484 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1486 (void) memset(&dip
, '\0', sizeof (dip
));
1487 rc
= backend_tx_begin(BACKEND_TYPE_NORMAL
, &dip
.di_tx
);
1488 if (rc
!= REP_PROTOCOL_SUCCESS
)
1491 rc
= backend_tx_begin(BACKEND_TYPE_NONPERSIST
, &dip
.di_np_tx
);
1492 if (rc
== REP_PROTOCOL_FAIL_BACKEND_ACCESS
||
1493 rc
== REP_PROTOCOL_FAIL_BACKEND_READONLY
)
1494 dip
.di_np_tx
= NULL
;
1495 else if (rc
!= REP_PROTOCOL_SUCCESS
) {
1496 backend_tx_rollback(dip
.di_tx
);
1500 if ((rc
= (*info
[type
].obj_delete_start
)(pp
, &dip
)) !=
1501 REP_PROTOCOL_SUCCESS
) {
1505 while (delete_stack_pop(&dip
, &de
)) {
1506 rc
= (*de
.de_cb
)(&dip
, &de
);
1507 if (rc
!= REP_PROTOCOL_SUCCESS
)
1511 rc
= backend_tx_commit(dip
.di_tx
);
1512 if (rc
!= REP_PROTOCOL_SUCCESS
)
1513 backend_tx_rollback(dip
.di_np_tx
);
1514 else if (dip
.di_np_tx
)
1515 (void) backend_tx_commit(dip
.di_np_tx
);
1517 delete_stack_cleanup(&dip
);
1522 backend_tx_rollback(dip
.di_tx
);
1523 backend_tx_rollback(dip
.di_np_tx
);
1524 delete_stack_cleanup(&dip
);
1529 object_do_create(backend_tx_t
*tx
, child_info_t
*cip
, rc_node_t
*pp
,
1530 uint32_t type
, const char *name
, rc_node_t
**cpp
)
1532 uint32_t ptype
= pp
->rn_id
.rl_type
;
1536 rc_node_t
*np
= NULL
;
1540 rc_node_lookup_t
*lp
= &cip
->ci_base_nl
;
1542 assert(ptype
> 0 && ptype
< NUM_INFO
);
1546 if (type
== REP_PROTOCOL_ENTITY_PROPERTYGRP
)
1547 return (REP_PROTOCOL_FAIL_NOT_APPLICABLE
);
1549 if (ip
->obj_setup_child_info
== NULL
||
1550 ip
->obj_query_child
== NULL
||
1551 ip
->obj_insert_child
== NULL
)
1552 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1554 if ((rc
= (*ip
->obj_setup_child_info
)(pp
, type
, cip
)) !=
1555 REP_PROTOCOL_SUCCESS
)
1558 q
= backend_query_alloc();
1559 if ((rc
= (*ip
->obj_query_child
)(q
, lp
, name
)) !=
1560 REP_PROTOCOL_SUCCESS
) {
1561 assert(rc
== REP_PROTOCOL_FAIL_BAD_REQUEST
);
1562 backend_query_free(q
);
1566 rc
= backend_tx_run_single_int(tx
, q
, &id
);
1567 backend_query_free(q
);
1569 if (rc
== REP_PROTOCOL_SUCCESS
)
1570 return (REP_PROTOCOL_FAIL_EXISTS
);
1571 else if (rc
!= REP_PROTOCOL_FAIL_NOT_FOUND
)
1574 if ((lp
->rl_main_id
= backend_new_id(tx
,
1575 info
[type
].obj_id_space
)) == 0) {
1576 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1579 if ((np
= rc_node_alloc()) == NULL
)
1580 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1582 if ((rc
= (*ip
->obj_insert_child
)(tx
, lp
, name
)) !=
1583 REP_PROTOCOL_SUCCESS
) {
1584 rc_node_destroy(np
);
1589 return (REP_PROTOCOL_SUCCESS
);
1594 * _NOT_APPLICABLE - type is _PROPERTYGRP
1595 * _BAD_REQUEST - cannot create children for this type of node
1597 * _TYPE_MISMATCH - object cannot have children of type type
1598 * _NO_RESOURCES - out of memory, or could not allocate new id
1601 * _EXISTS - child already exists
1604 object_create(rc_node_t
*pp
, uint32_t type
, const char *name
, rc_node_t
**cpp
)
1607 rc_node_t
*np
= NULL
;
1611 if ((rc
= backend_tx_begin(pp
->rn_id
.rl_backend
, &tx
)) !=
1612 REP_PROTOCOL_SUCCESS
) {
1616 if ((rc
= object_do_create(tx
, &ci
, pp
, type
, name
, &np
)) !=
1617 REP_PROTOCOL_SUCCESS
) {
1618 backend_tx_rollback(tx
);
1622 rc
= backend_tx_commit(tx
);
1623 if (rc
!= REP_PROTOCOL_SUCCESS
) {
1624 rc_node_destroy(np
);
1628 *cpp
= rc_node_setup(np
, &ci
.ci_base_nl
, name
, ci
.ci_parent
);
1630 return (REP_PROTOCOL_SUCCESS
);
1635 object_create_pg(rc_node_t
*pp
, uint32_t type
, const char *name
,
1636 const char *pgtype
, uint32_t flags
, rc_node_t
**cpp
)
1638 uint32_t ptype
= pp
->rn_id
.rl_type
;
1639 backend_tx_t
*tx_ro
, *tx_wr
;
1643 rc_node_t
*np
= NULL
;
1649 int nonpersist
= (flags
& SCF_PG_FLAG_NONPERSISTENT
);
1652 rc_node_lookup_t
*lp
= &ci
.ci_base_nl
;
1654 assert(ptype
> 0 && ptype
< NUM_INFO
);
1656 if (ptype
!= REP_PROTOCOL_ENTITY_SERVICE
&&
1657 ptype
!= REP_PROTOCOL_ENTITY_INSTANCE
)
1658 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1662 assert(ip
->obj_setup_child_info
!= NULL
&&
1663 ip
->obj_query_child
!= NULL
&&
1664 ip
->obj_insert_pg_child
!= NULL
);
1666 if ((rc
= (*ip
->obj_setup_child_info
)(pp
, type
, &ci
)) !=
1667 REP_PROTOCOL_SUCCESS
)
1670 q
= backend_query_alloc();
1671 if ((rc
= (*ip
->obj_query_child
)(q
, lp
, name
)) !=
1672 REP_PROTOCOL_SUCCESS
) {
1673 backend_query_free(q
);
1678 lp
->rl_backend
= BACKEND_TYPE_NORMAL
;
1679 rc_wr
= backend_tx_begin(BACKEND_TYPE_NORMAL
, &tx_wr
);
1680 rc_ro
= backend_tx_begin_ro(BACKEND_TYPE_NONPERSIST
, &tx_ro
);
1682 lp
->rl_backend
= BACKEND_TYPE_NONPERSIST
;
1683 rc_ro
= backend_tx_begin_ro(BACKEND_TYPE_NORMAL
, &tx_ro
);
1684 rc_wr
= backend_tx_begin(BACKEND_TYPE_NONPERSIST
, &tx_wr
);
1687 if (rc_wr
!= REP_PROTOCOL_SUCCESS
) {
1691 if (rc_ro
!= REP_PROTOCOL_SUCCESS
&&
1692 rc_ro
!= REP_PROTOCOL_FAIL_BACKEND_ACCESS
) {
1697 if (tx_ro
!= NULL
) {
1698 rc
= backend_tx_run_single_int(tx_ro
, q
, &id
);
1700 if (rc
== REP_PROTOCOL_SUCCESS
) {
1701 backend_query_free(q
);
1702 rc
= REP_PROTOCOL_FAIL_EXISTS
;
1704 } else if (rc
!= REP_PROTOCOL_FAIL_NOT_FOUND
) {
1705 backend_query_free(q
);
1710 rc
= backend_tx_run_single_int(tx_wr
, q
, &id
);
1711 backend_query_free(q
);
1713 if (rc
== REP_PROTOCOL_SUCCESS
) {
1714 rc
= REP_PROTOCOL_FAIL_EXISTS
;
1716 } else if (rc
!= REP_PROTOCOL_FAIL_NOT_FOUND
) {
1721 backend_tx_end_ro(tx_ro
);
1724 if ((lp
->rl_main_id
= backend_new_id(tx_wr
,
1725 info
[type
].obj_id_space
)) == 0) {
1726 rc
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1730 if ((np
= rc_node_alloc()) == NULL
) {
1731 rc
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1735 if ((rc
= (*ip
->obj_insert_pg_child
)(tx_wr
, lp
, name
, pgtype
, flags
,
1736 gen
)) != REP_PROTOCOL_SUCCESS
) {
1737 rc_node_destroy(np
);
1741 rc
= backend_tx_commit(tx_wr
);
1742 if (rc
!= REP_PROTOCOL_SUCCESS
) {
1743 rc_node_destroy(np
);
1747 *cpp
= rc_node_setup_pg(np
, lp
, name
, pgtype
, flags
, gen
, ci
.ci_parent
);
1749 return (REP_PROTOCOL_SUCCESS
);
1753 backend_tx_end_ro(tx_ro
);
1755 backend_tx_rollback(tx_wr
);
1760 * Given a row of snaplevel number, snaplevel id, service id, service name,
1761 * instance id, & instance name, create a rc_snaplevel_t & prepend it onto the
1762 * rs_levels list of the rc_snapshot_t passed in as data.
1763 * Returns _CONTINUE on success or _ABORT if any allocations fail.
1767 fill_snapshot_cb(void *data
, int columns
, char **vals
, char **names
)
1769 rc_snapshot_t
*sp
= data
;
1770 rc_snaplevel_t
*lvl
;
1771 char *num
= vals
[0];
1773 char *service_id
= vals
[2];
1774 char *service
= vals
[3];
1775 char *instance_id
= vals
[4];
1776 char *instance
= vals
[5];
1777 assert(columns
== 6);
1779 lvl
= uu_zalloc(sizeof (*lvl
));
1781 return (BACKEND_CALLBACK_ABORT
);
1782 lvl
->rsl_parent
= sp
;
1783 lvl
->rsl_next
= sp
->rs_levels
;
1784 sp
->rs_levels
= lvl
;
1786 string_to_id(num
, &lvl
->rsl_level_num
, "snap_level_num");
1787 string_to_id(id
, &lvl
->rsl_level_id
, "snap_level_id");
1788 string_to_id(service_id
, &lvl
->rsl_service_id
, "snap_level_service_id");
1789 if (instance_id
!= NULL
)
1790 string_to_id(instance_id
, &lvl
->rsl_instance_id
,
1791 "snap_level_instance_id");
1793 lvl
->rsl_scope
= (const char *)"localhost";
1794 lvl
->rsl_service
= strdup(service
);
1795 if (lvl
->rsl_service
== NULL
) {
1797 return (BACKEND_CALLBACK_ABORT
);
1800 assert(lvl
->rsl_instance_id
!= 0);
1801 lvl
->rsl_instance
= strdup(instance
);
1802 if (lvl
->rsl_instance
== NULL
) {
1803 free((void *)lvl
->rsl_instance
);
1805 return (BACKEND_CALLBACK_ABORT
);
1808 assert(lvl
->rsl_instance_id
== 0);
1811 return (BACKEND_CALLBACK_CONTINUE
);
1815 * Populate sp's rs_levels list from the snaplevel_tbl table.
1820 object_fill_snapshot(rc_snapshot_t
*sp
)
1827 q
= backend_query_alloc();
1828 backend_query_add(q
,
1829 "SELECT snap_level_num, snap_level_id, "
1830 " snap_level_service_id, snap_level_service, "
1831 " snap_level_instance_id, snap_level_instance "
1832 "FROM snaplevel_tbl "
1833 "WHERE snap_id = %d "
1834 "ORDER BY snap_level_id DESC",
1837 result
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_snapshot_cb
, sp
);
1838 if (result
== REP_PROTOCOL_DONE
)
1839 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1840 backend_query_free(q
);
1842 if (result
== REP_PROTOCOL_SUCCESS
) {
1844 for (sl
= sp
->rs_levels
; sl
!= NULL
; sl
= sl
->rsl_next
) {
1845 if (sl
->rsl_level_num
!= ++i
) {
1846 backend_panic("snaplevels corrupt; expected "
1847 "level %d, got %d", i
, sl
->rsl_level_num
);
1855 * This represents a property group in a snapshot.
1857 typedef struct check_snapshot_elem
{
1858 uint32_t cse_parent
;
1860 uint32_t cse_pg_gen
;
1862 } check_snapshot_elem_t
;
1864 #define CSI_MAX_PARENTS COMPOSITION_DEPTH
1865 typedef struct check_snapshot_info
{
1867 size_t csi_array_size
;
1868 check_snapshot_elem_t
*csi_array
;
1869 size_t csi_nparents
;
1870 uint32_t csi_parent_ids
[CSI_MAX_PARENTS
];
1871 } check_snapshot_info_t
;
1875 check_snapshot_fill_cb(void *data
, int columns
, char **vals
, char **names
)
1877 check_snapshot_info_t
*csip
= data
;
1878 check_snapshot_elem_t
*cur
;
1881 const char *pg_gen_id
;
1886 if (csip
->csi_nparents
>= CSI_MAX_PARENTS
)
1887 backend_panic("snaplevel table has too many elements");
1889 target
= &csip
->csi_parent_ids
[csip
->csi_nparents
++];
1890 string_to_id(vals
[0], target
, "snap_level_*_id");
1892 return (BACKEND_CALLBACK_CONTINUE
);
1895 assert(columns
== 3);
1899 pg_gen_id
= vals
[2];
1901 if (csip
->csi_count
== csip
->csi_array_size
) {
1902 size_t newsz
= (csip
->csi_array_size
> 0) ?
1903 csip
->csi_array_size
* 2 : 8;
1904 check_snapshot_elem_t
*new = uu_zalloc(newsz
* sizeof (*new));
1907 return (BACKEND_CALLBACK_ABORT
);
1909 (void) memcpy(new, csip
->csi_array
,
1910 sizeof (*new) * csip
->csi_array_size
);
1911 uu_free(csip
->csi_array
);
1912 csip
->csi_array
= new;
1913 csip
->csi_array_size
= newsz
;
1916 cur
= &csip
->csi_array
[csip
->csi_count
++];
1918 string_to_id(parent
, &cur
->cse_parent
, "snap_level_*_id");
1919 string_to_id(pg_id
, &cur
->cse_pg_id
, "snaplvl_pg_id");
1920 string_to_id(pg_gen_id
, &cur
->cse_pg_gen
, "snaplvl_gen_id");
1923 return (BACKEND_CALLBACK_CONTINUE
);
1927 check_snapshot_elem_cmp(const void *lhs_arg
, const void *rhs_arg
)
1929 const check_snapshot_elem_t
*lhs
= lhs_arg
;
1930 const check_snapshot_elem_t
*rhs
= rhs_arg
;
1932 if (lhs
->cse_parent
< rhs
->cse_parent
)
1934 if (lhs
->cse_parent
> rhs
->cse_parent
)
1937 if (lhs
->cse_pg_id
< rhs
->cse_pg_id
)
1939 if (lhs
->cse_pg_id
> rhs
->cse_pg_id
)
1942 if (lhs
->cse_pg_gen
< rhs
->cse_pg_gen
)
1944 if (lhs
->cse_pg_gen
> rhs
->cse_pg_gen
)
1952 check_snapshot_check_cb(void *data
, int columns
, char **vals
, char **names
)
1954 check_snapshot_info_t
*csip
= data
;
1955 check_snapshot_elem_t elem
;
1956 check_snapshot_elem_t
*cur
;
1958 const char *parent
= vals
[0];
1959 const char *pg_id
= vals
[1];
1960 const char *pg_gen_id
= vals
[2];
1962 assert(columns
== 3);
1964 string_to_id(parent
, &elem
.cse_parent
, "snap_level_*_id");
1965 string_to_id(pg_id
, &elem
.cse_pg_id
, "snaplvl_pg_id");
1966 string_to_id(pg_gen_id
, &elem
.cse_pg_gen
, "snaplvl_gen_id");
1968 if ((cur
= bsearch(&elem
, csip
->csi_array
, csip
->csi_count
,
1969 sizeof (*csip
->csi_array
), check_snapshot_elem_cmp
)) == NULL
)
1970 return (BACKEND_CALLBACK_ABORT
);
1973 backend_panic("duplicate property group reported");
1975 return (BACKEND_CALLBACK_CONTINUE
);
1979 * Check that a snapshot matches up with the latest in the repository.
1981 * REP_PROTOCOL_SUCCESS if it is up-to-date,
1982 * REP_PROTOCOL_DONE if it is out-of-date, or
1983 * REP_PROTOCOL_FAIL_NO_RESOURCES if we ran out of memory.
1986 object_check_snapshot(uint32_t snap_id
)
1988 check_snapshot_info_t csi
;
1993 /* if the snapshot has never been taken, it must be out of date. */
1995 return (REP_PROTOCOL_DONE
);
1997 (void) memset(&csi
, '\0', sizeof (csi
));
1999 q
= backend_query_alloc();
2000 backend_query_add(q
,
2002 " CASE snap_level_instance_id\n"
2003 " WHEN 0 THEN snap_level_service_id\n"
2004 " ELSE snap_level_instance_id\n"
2006 "FROM snaplevel_tbl\n"
2007 "WHERE snap_id = %d;\n"
2010 " CASE snap_level_instance_id\n"
2011 " WHEN 0 THEN snap_level_service_id\n"
2012 " ELSE snap_level_instance_id\n"
2016 "FROM snaplevel_tbl, snaplevel_lnk_tbl\n"
2018 " (snaplvl_level_id = snap_level_id AND\n"
2022 result
= backend_run(BACKEND_TYPE_NORMAL
, q
, check_snapshot_fill_cb
,
2024 if (result
== REP_PROTOCOL_DONE
)
2025 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
2026 backend_query_free(q
);
2028 if (result
!= REP_PROTOCOL_SUCCESS
)
2031 if (csi
.csi_count
> 0) {
2032 qsort(csi
.csi_array
, csi
.csi_count
, sizeof (*csi
.csi_array
),
2033 check_snapshot_elem_cmp
);
2036 #if COMPOSITION_DEPTH == 2
2037 if (csi
.csi_nparents
!= COMPOSITION_DEPTH
) {
2038 result
= REP_PROTOCOL_DONE
;
2042 q
= backend_query_alloc();
2043 backend_query_add(q
,
2045 " pg_parent_id, pg_id, pg_gen_id "
2048 "WHERE (pg_parent_id = %d OR pg_parent_id = %d)",
2049 csi
.csi_parent_ids
[0], csi
.csi_parent_ids
[1]);
2051 result
= backend_run(BACKEND_TYPE_NORMAL
, q
, check_snapshot_check_cb
,
2054 #error This code must be updated
2057 * To succeed, the callback must not have aborted, and we must have
2058 * found all of the items.
2060 if (result
== REP_PROTOCOL_SUCCESS
) {
2061 for (idx
= 0; idx
< csi
.csi_count
; idx
++) {
2062 if (csi
.csi_array
[idx
].cse_seen
== 0) {
2063 result
= REP_PROTOCOL_DONE
;
2070 uu_free(csi
.csi_array
);
2076 object_copy_string(void *data_arg
, int columns
, char **vals
, char **names
)
2078 char **data
= data_arg
;
2080 assert(columns
== 1);
2085 if (vals
[0] != NULL
) {
2086 if ((*data
= strdup(vals
[0])) == NULL
)
2087 return (BACKEND_CALLBACK_ABORT
);
2090 return (BACKEND_CALLBACK_CONTINUE
);
2093 struct snaplevel_add_info
{
2094 backend_query_t
*sai_q
;
2095 uint32_t sai_level_id
;
2096 int sai_used
; /* sai_q has been used */
2101 object_snaplevel_process_pg(void *data_arg
, int columns
, char **vals
,
2104 struct snaplevel_add_info
*data
= data_arg
;
2106 assert(columns
== 5);
2108 backend_query_add(data
->sai_q
,
2109 "INSERT INTO snaplevel_lnk_tbl "
2110 " (snaplvl_level_id, snaplvl_pg_id, snaplvl_pg_name, "
2111 " snaplvl_pg_type, snaplvl_pg_flags, snaplvl_gen_id)"
2112 "VALUES (%d, %s, '%q', '%q', %s, %s);",
2113 data
->sai_level_id
, vals
[0], vals
[1], vals
[2], vals
[3], vals
[4]);
2117 return (BACKEND_CALLBACK_CONTINUE
);
2122 object_snapshot_add_level(backend_tx_t
*tx
, uint32_t snap_id
,
2123 uint32_t snap_level_num
, uint32_t svc_id
, const char *svc_name
,
2124 uint32_t inst_id
, const char *inst_name
)
2126 struct snaplevel_add_info data
;
2130 assert((snap_level_num
== 1 && inst_name
!= NULL
) ||
2131 snap_level_num
== 2 && inst_name
== NULL
);
2133 data
.sai_level_id
= backend_new_id(tx
, BACKEND_ID_SNAPLEVEL
);
2134 if (data
.sai_level_id
== 0) {
2135 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
2138 result
= backend_tx_run_update(tx
,
2139 "INSERT INTO snaplevel_tbl "
2140 " (snap_id, snap_level_num, snap_level_id, "
2141 " snap_level_service_id, snap_level_service, "
2142 " snap_level_instance_id, snap_level_instance) "
2143 "VALUES (%d, %d, %d, %d, %Q, %d, %Q);",
2144 snap_id
, snap_level_num
, data
.sai_level_id
, svc_id
, svc_name
,
2145 inst_id
, inst_name
);
2147 q
= backend_query_alloc();
2148 backend_query_add(q
,
2149 "SELECT pg_id, pg_name, pg_type, pg_flags, pg_gen_id FROM pg_tbl "
2150 "WHERE (pg_parent_id = %d);",
2151 (inst_name
!= NULL
)? inst_id
: svc_id
);
2153 data
.sai_q
= backend_query_alloc();
2155 result
= backend_tx_run(tx
, q
, object_snaplevel_process_pg
,
2157 backend_query_free(q
);
2159 if (result
== REP_PROTOCOL_SUCCESS
&& data
.sai_used
!= 0)
2160 result
= backend_tx_run(tx
, data
.sai_q
, NULL
, NULL
);
2161 backend_query_free(data
.sai_q
);
2168 * _NO_RESOURCES - no new id or out of disk space
2169 * _BACKEND_READONLY - persistent backend is read-only
2172 object_snapshot_do_take(uint32_t instid
, const char *inst_name
,
2173 uint32_t svcid
, const char *svc_name
,
2174 backend_tx_t
**tx_out
, uint32_t *snapid_out
)
2180 char *svc_name_alloc
= NULL
;
2181 char *inst_name_alloc
= NULL
;
2184 result
= backend_tx_begin(BACKEND_TYPE_NORMAL
, &tx
);
2185 if (result
!= REP_PROTOCOL_SUCCESS
)
2188 snapid
= backend_new_id(tx
, BACKEND_ID_SNAPSHOT
);
2190 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
2194 if (svc_name
== NULL
) {
2195 q
= backend_query_alloc();
2196 backend_query_add(q
,
2197 "SELECT svc_name FROM service_tbl "
2198 "WHERE (svc_id = %d)", svcid
);
2199 result
= backend_tx_run(tx
, q
, object_copy_string
,
2201 backend_query_free(q
);
2203 svc_name
= svc_name_alloc
;
2205 if (result
== REP_PROTOCOL_DONE
) {
2206 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
2209 if (result
== REP_PROTOCOL_SUCCESS
&& svc_name
== NULL
)
2210 backend_panic("unable to find name for svc id %d\n",
2213 if (result
!= REP_PROTOCOL_SUCCESS
)
2217 if (inst_name
== NULL
) {
2218 q
= backend_query_alloc();
2219 backend_query_add(q
,
2220 "SELECT instance_name FROM instance_tbl "
2221 "WHERE (instance_id = %d)", instid
);
2222 result
= backend_tx_run(tx
, q
, object_copy_string
,
2224 backend_query_free(q
);
2226 inst_name
= inst_name_alloc
;
2228 if (result
== REP_PROTOCOL_DONE
) {
2229 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
2233 if (result
== REP_PROTOCOL_SUCCESS
&& inst_name
== NULL
)
2235 "unable to find name for instance id %d\n", instid
);
2237 if (result
!= REP_PROTOCOL_SUCCESS
)
2241 result
= object_snapshot_add_level(tx
, snapid
, 1,
2242 svcid
, svc_name
, instid
, inst_name
);
2244 if (result
!= REP_PROTOCOL_SUCCESS
)
2247 result
= object_snapshot_add_level(tx
, snapid
, 2,
2248 svcid
, svc_name
, 0, NULL
);
2250 if (result
!= REP_PROTOCOL_SUCCESS
)
2253 *snapid_out
= snapid
;
2256 free(svc_name_alloc
);
2257 free(inst_name_alloc
);
2259 return (REP_PROTOCOL_SUCCESS
);
2262 backend_tx_rollback(tx
);
2263 free(svc_name_alloc
);
2264 free(inst_name_alloc
);
2270 * _TYPE_MISMATCH - pp is not an instance
2271 * _NO_RESOURCES - no new id or out of disk space
2272 * _BACKEND_READONLY - persistent backend is read-only
2275 object_snapshot_take_new(rc_node_t
*pp
,
2276 const char *svc_name
, const char *inst_name
,
2277 const char *name
, rc_node_t
**outp
)
2279 rc_node_lookup_t
*insti
= &pp
->rn_id
;
2281 uint32_t instid
= insti
->rl_main_id
;
2282 uint32_t svcid
= insti
->rl_ids
[ID_SERVICE
];
2283 uint32_t snapid
= 0;
2284 backend_tx_t
*tx
= NULL
;
2289 if (insti
->rl_type
!= REP_PROTOCOL_ENTITY_INSTANCE
)
2290 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
2292 result
= object_snapshot_do_take(instid
, inst_name
, svcid
, svc_name
,
2294 if (result
!= REP_PROTOCOL_SUCCESS
)
2297 if ((result
= object_do_create(tx
, &ci
, pp
,
2298 REP_PROTOCOL_ENTITY_SNAPSHOT
, name
, &np
)) != REP_PROTOCOL_SUCCESS
) {
2299 backend_tx_rollback(tx
);
2304 * link the new object to the new snapshot.
2306 np
->rn_snapshot_id
= snapid
;
2308 result
= backend_tx_run_update(tx
,
2309 "UPDATE snapshot_lnk_tbl SET lnk_snap_id = %d WHERE lnk_id = %d;",
2310 snapid
, ci
.ci_base_nl
.rl_main_id
);
2311 if (result
!= REP_PROTOCOL_SUCCESS
) {
2312 backend_tx_rollback(tx
);
2313 rc_node_destroy(np
);
2316 result
= backend_tx_commit(tx
);
2317 if (result
!= REP_PROTOCOL_SUCCESS
) {
2318 rc_node_destroy(np
);
2322 *outp
= rc_node_setup(np
, &ci
.ci_base_nl
, name
, ci
.ci_parent
);
2323 return (REP_PROTOCOL_SUCCESS
);
2328 * _TYPE_MISMATCH - pp is not an instance
2329 * _NO_RESOURCES - no new id or out of disk space
2330 * _BACKEND_READONLY - persistent backend is read-only
2333 object_snapshot_attach(rc_node_lookup_t
*snapi
, uint32_t *snapid_ptr
,
2336 uint32_t svcid
= snapi
->rl_ids
[ID_SERVICE
];
2337 uint32_t instid
= snapi
->rl_ids
[ID_INSTANCE
];
2338 uint32_t snapid
= *snapid_ptr
;
2339 uint32_t oldsnapid
= 0;
2340 backend_tx_t
*tx
= NULL
;
2347 if (snapi
->rl_type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
)
2348 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
2351 /* first, check that we're actually out of date */
2352 if (object_check_snapshot(snapid
) == REP_PROTOCOL_SUCCESS
)
2353 return (REP_PROTOCOL_SUCCESS
);
2355 result
= object_snapshot_do_take(instid
, NULL
,
2356 svcid
, NULL
, &tx
, &snapid
);
2357 if (result
!= REP_PROTOCOL_SUCCESS
)
2360 result
= backend_tx_begin(BACKEND_TYPE_NORMAL
, &tx
);
2361 if (result
!= REP_PROTOCOL_SUCCESS
)
2365 q
= backend_query_alloc();
2366 backend_query_add(q
,
2367 "SELECT lnk_snap_id FROM snapshot_lnk_tbl WHERE lnk_id = %d; "
2368 "UPDATE snapshot_lnk_tbl SET lnk_snap_id = %d WHERE lnk_id = %d;",
2369 snapi
->rl_main_id
, snapid
, snapi
->rl_main_id
);
2370 result
= backend_tx_run_single_int(tx
, q
, &oldsnapid
);
2371 backend_query_free(q
);
2373 if (result
== REP_PROTOCOL_FAIL_NOT_FOUND
) {
2374 backend_tx_rollback(tx
);
2375 backend_panic("unable to find snapshot id %d",
2378 if (result
!= REP_PROTOCOL_SUCCESS
)
2382 * Now we use the delete stack to handle the possible unreferencing
2385 (void) memset(&dip
, 0, sizeof (dip
));
2387 dip
.di_np_tx
= NULL
; /* no need for non-persistant backend */
2389 if ((result
= delete_stack_push(&dip
, BACKEND_TYPE_NORMAL
,
2390 &snaplevel_tbl_delete
, oldsnapid
, 0)) != REP_PROTOCOL_SUCCESS
)
2393 while (delete_stack_pop(&dip
, &de
)) {
2394 result
= (*de
.de_cb
)(&dip
, &de
);
2395 if (result
!= REP_PROTOCOL_SUCCESS
)
2399 result
= backend_tx_commit(tx
);
2400 if (result
!= REP_PROTOCOL_SUCCESS
)
2403 delete_stack_cleanup(&dip
);
2404 *snapid_ptr
= snapid
;
2405 return (REP_PROTOCOL_SUCCESS
);
2408 backend_tx_rollback(tx
);
2409 delete_stack_cleanup(&dip
);