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.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * file_object.c - enter objects into and load them from the backend
32 * The primary entry points in this layer are object_create(),
33 * object_create_pg(), object_delete(), and object_fill_children(). They each
34 * take an rc_node_t and use the functions in the object_info_t info array for
46 #include "repcache_protocol.h"
48 typedef struct child_info
{
50 backend_tx_t
*ci_tx
; /* only for properties */
51 rc_node_lookup_t ci_base_nl
;
54 typedef struct delete_ent delete_ent_t
;
55 typedef struct delete_stack delete_stack_t
;
56 typedef struct delete_info delete_info_t
;
58 typedef int delete_cb_func(delete_info_t
*, const delete_ent_t
*);
61 delete_cb_func
*de_cb
; /* callback */
64 uint32_t de_gen
; /* only for property groups */
68 struct delete_stack
*ds_next
;
69 uint32_t ds_size
; /* number of elements */
70 uint32_t ds_cur
; /* current offset */
71 delete_ent_t ds_buf
[1]; /* actually ds_size */
73 #define DELETE_STACK_SIZE(x) offsetof(delete_stack_t, ds_buf[(x)])
77 backend_tx_t
*di_np_tx
;
78 delete_stack_t
*di_stack
;
79 delete_stack_t
*di_free
;
82 typedef struct object_info
{
84 enum id_space obj_id_space
;
86 int (*obj_fill_children
)(rc_node_t
*);
87 int (*obj_setup_child_info
)(rc_node_t
*, uint32_t, child_info_t
*);
88 int (*obj_query_child
)(backend_query_t
*, rc_node_lookup_t
*,
90 int (*obj_insert_child
)(backend_tx_t
*, rc_node_lookup_t
*,
92 int (*obj_insert_pg_child
)(backend_tx_t
*, rc_node_lookup_t
*,
93 const char *, const char *, uint32_t, uint32_t);
94 int (*obj_delete_start
)(rc_node_t
*, delete_info_t
*);
98 string_to_id(const char *str
, uint32_t *output
, const char *fieldname
)
100 if (uu_strtouint(str
, output
, sizeof (*output
), 0, 0, 0) == -1)
101 backend_panic("invalid integer \"%s\" in field \"%s\"",
105 #define NUM_NEEDED 50
108 delete_stack_push(delete_info_t
*dip
, uint32_t be
, delete_cb_func
*cb
,
109 uint32_t id
, uint32_t gen
)
111 delete_stack_t
*cur
= dip
->di_stack
;
114 if (cur
== NULL
|| cur
->ds_cur
== cur
->ds_size
) {
115 delete_stack_t
*new = dip
->di_free
;
118 new = uu_zalloc(DELETE_STACK_SIZE(NUM_NEEDED
));
120 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
121 new->ds_size
= NUM_NEEDED
;
124 new->ds_next
= dip
->di_stack
;
128 assert(cur
->ds_cur
< cur
->ds_size
);
129 ent
= &cur
->ds_buf
[cur
->ds_cur
++];
131 ent
->de_backend
= be
;
136 return (REP_PROTOCOL_SUCCESS
);
140 delete_stack_pop(delete_info_t
*dip
, delete_ent_t
*out
)
142 delete_stack_t
*cur
= dip
->di_stack
;
147 assert(cur
->ds_cur
> 0 && cur
->ds_cur
<= cur
->ds_size
);
148 ent
= &cur
->ds_buf
[--cur
->ds_cur
];
149 if (cur
->ds_cur
== 0) {
150 dip
->di_stack
= cur
->ds_next
;
153 if (dip
->di_free
!= NULL
)
154 uu_free(dip
->di_free
);
165 delete_stack_cleanup(delete_info_t
*dip
)
168 while ((cur
= dip
->di_stack
) != NULL
) {
169 dip
->di_stack
= cur
->ds_next
;
174 if ((cur
= dip
->di_free
) != NULL
) {
175 assert(cur
->ds_next
== NULL
); /* should only be one */
181 struct delete_cb_info
{
182 delete_info_t
*dci_dip
;
184 delete_cb_func
*dci_cb
;
190 push_delete_callback(void *data
, int columns
, char **vals
, char **names
)
192 struct delete_cb_info
*info
= data
;
194 const char *id_str
= *vals
++;
195 const char *gen_str
= *vals
++;
200 assert(columns
== 2);
202 string_to_id(id_str
, &id
, "id");
203 string_to_id(gen_str
, &gen
, "gen_id");
205 info
->dci_result
= delete_stack_push(info
->dci_dip
, info
->dci_be
,
206 info
->dci_cb
, id
, gen
);
208 if (info
->dci_result
!= REP_PROTOCOL_SUCCESS
)
209 return (BACKEND_CALLBACK_ABORT
);
210 return (BACKEND_CALLBACK_CONTINUE
);
214 value_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
216 uint32_t be
= ent
->de_backend
;
221 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
224 q
= backend_query_alloc();
227 "SELECT 1 FROM prop_lnk_tbl WHERE (lnk_val_id = %d); "
228 "DELETE FROM value_tbl WHERE (value_id = %d); ",
229 ent
->de_id
, ent
->de_id
);
230 r
= backend_tx_run(tx
, q
, backend_fail_if_seen
, NULL
);
231 backend_query_free(q
);
232 if (r
== REP_PROTOCOL_DONE
)
233 return (REP_PROTOCOL_SUCCESS
); /* still in use */
238 pg_lnk_tbl_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
240 struct delete_cb_info info
;
241 uint32_t be
= ent
->de_backend
;
246 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
250 * For non-persistent backends, we could only have one parent, and
251 * it's already been deleted.
253 * For normal backends, we need to check to see if we're in
254 * a snapshot or are the active generation for the property
255 * group. If we are, there's nothing to be done.
257 if (be
== BACKEND_TYPE_NORMAL
) {
258 q
= backend_query_alloc();
262 "WHERE (pg_id = %d AND pg_gen_id = %d); "
264 "FROM snaplevel_lnk_tbl "
265 "WHERE (snaplvl_pg_id = %d AND snaplvl_gen_id = %d);",
266 ent
->de_id
, ent
->de_gen
,
267 ent
->de_id
, ent
->de_gen
);
268 r
= backend_tx_run(tx
, q
, backend_fail_if_seen
, NULL
);
269 backend_query_free(q
);
271 if (r
== REP_PROTOCOL_DONE
)
272 return (REP_PROTOCOL_SUCCESS
); /* still in use */
277 info
.dci_cb
= &value_delete
;
278 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
280 q
= backend_query_alloc();
282 "SELECT DISTINCT lnk_val_id, 0 FROM prop_lnk_tbl "
284 " (lnk_pg_id = %d AND lnk_gen_id = %d AND lnk_val_id NOTNULL); "
285 "DELETE FROM prop_lnk_tbl "
286 "WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)",
287 ent
->de_id
, ent
->de_gen
, ent
->de_id
, ent
->de_gen
);
289 r
= backend_tx_run(tx
, q
, push_delete_callback
, &info
);
290 backend_query_free(q
);
292 if (r
== REP_PROTOCOL_DONE
) {
293 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
294 return (info
.dci_result
);
300 propertygrp_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
302 uint32_t be
= ent
->de_backend
;
308 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
311 q
= backend_query_alloc();
313 "SELECT pg_gen_id FROM pg_tbl WHERE pg_id = %d; "
314 "DELETE FROM pg_tbl WHERE pg_id = %d",
315 ent
->de_id
, ent
->de_id
);
316 r
= backend_tx_run_single_int(tx
, q
, &gen
);
317 backend_query_free(q
);
319 if (r
!= REP_PROTOCOL_SUCCESS
)
322 return (delete_stack_push(dip
, be
, &pg_lnk_tbl_delete
,
327 snaplevel_lnk_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
329 uint32_t be
= ent
->de_backend
;
331 struct delete_cb_info info
;
335 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
340 info
.dci_cb
= &pg_lnk_tbl_delete
;
341 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
343 q
= backend_query_alloc();
345 "SELECT snaplvl_pg_id, snaplvl_gen_id "
346 " FROM snaplevel_lnk_tbl "
347 " WHERE snaplvl_level_id = %d; "
348 "DELETE FROM snaplevel_lnk_tbl WHERE snaplvl_level_id = %d",
349 ent
->de_id
, ent
->de_id
);
350 r
= backend_tx_run(tx
, q
, push_delete_callback
, &info
);
351 backend_query_free(q
);
353 if (r
== REP_PROTOCOL_DONE
) {
354 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
355 return (info
.dci_result
);
361 snaplevel_tbl_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
363 uint32_t be
= ent
->de_backend
;
364 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
367 struct delete_cb_info info
;
371 assert(be
== BACKEND_TYPE_NORMAL
);
373 q
= backend_query_alloc();
375 "SELECT 1 FROM snapshot_lnk_tbl WHERE lnk_snap_id = %d",
377 r
= backend_tx_run(tx
, q
, backend_fail_if_seen
, NULL
);
378 backend_query_free(q
);
380 if (r
== REP_PROTOCOL_DONE
)
381 return (REP_PROTOCOL_SUCCESS
); /* still in use */
385 info
.dci_cb
= &snaplevel_lnk_delete
;
386 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
388 q
= backend_query_alloc();
390 "SELECT snap_level_id, 0 FROM snaplevel_tbl WHERE snap_id = %d;"
391 "DELETE FROM snaplevel_tbl WHERE snap_id = %d",
392 ent
->de_id
, ent
->de_id
);
393 r
= backend_tx_run(tx
, q
, push_delete_callback
, &info
);
394 backend_query_free(q
);
396 if (r
== REP_PROTOCOL_DONE
) {
397 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
398 return (info
.dci_result
);
404 snapshot_lnk_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
406 uint32_t be
= ent
->de_backend
;
407 backend_tx_t
*tx
= (be
== BACKEND_TYPE_NORMAL
)? dip
->di_tx
:
414 assert(be
== BACKEND_TYPE_NORMAL
);
416 q
= backend_query_alloc();
418 "SELECT lnk_snap_id FROM snapshot_lnk_tbl WHERE lnk_id = %d; "
419 "DELETE FROM snapshot_lnk_tbl WHERE lnk_id = %d",
420 ent
->de_id
, ent
->de_id
);
421 r
= backend_tx_run_single_int(tx
, q
, &snapid
);
422 backend_query_free(q
);
424 if (r
!= REP_PROTOCOL_SUCCESS
)
427 return (delete_stack_push(dip
, be
, &snaplevel_tbl_delete
, snapid
, 0));
431 pgparent_delete_add_pgs(delete_info_t
*dip
, uint32_t parent_id
)
433 struct delete_cb_info info
;
438 info
.dci_be
= BACKEND_TYPE_NORMAL
;
439 info
.dci_cb
= &propertygrp_delete
;
440 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
442 q
= backend_query_alloc();
444 "SELECT pg_id, 0 FROM pg_tbl WHERE pg_parent_id = %d",
447 r
= backend_tx_run(dip
->di_tx
, q
, push_delete_callback
, &info
);
449 if (r
== REP_PROTOCOL_DONE
) {
450 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
451 backend_query_free(q
);
452 return (info
.dci_result
);
454 if (r
!= REP_PROTOCOL_SUCCESS
) {
455 backend_query_free(q
);
459 if (dip
->di_np_tx
!= NULL
) {
460 info
.dci_be
= BACKEND_TYPE_NONPERSIST
;
462 r
= backend_tx_run(dip
->di_np_tx
, q
, push_delete_callback
,
465 if (r
== REP_PROTOCOL_DONE
) {
466 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
467 backend_query_free(q
);
468 return (info
.dci_result
);
470 if (r
!= REP_PROTOCOL_SUCCESS
) {
471 backend_query_free(q
);
475 backend_query_free(q
);
476 return (REP_PROTOCOL_SUCCESS
);
480 service_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
484 r
= backend_tx_run_update_changed(dip
->di_tx
,
485 "DELETE FROM service_tbl WHERE svc_id = %d", ent
->de_id
);
486 if (r
!= REP_PROTOCOL_SUCCESS
)
489 return (pgparent_delete_add_pgs(dip
, ent
->de_id
));
493 instance_delete(delete_info_t
*dip
, const delete_ent_t
*ent
)
495 struct delete_cb_info info
;
499 r
= backend_tx_run_update_changed(dip
->di_tx
,
500 "DELETE FROM instance_tbl WHERE instance_id = %d", ent
->de_id
);
501 if (r
!= REP_PROTOCOL_SUCCESS
)
504 r
= pgparent_delete_add_pgs(dip
, ent
->de_id
);
505 if (r
!= REP_PROTOCOL_SUCCESS
)
509 info
.dci_be
= BACKEND_TYPE_NORMAL
;
510 info
.dci_cb
= &snapshot_lnk_delete
;
511 info
.dci_result
= REP_PROTOCOL_SUCCESS
;
513 q
= backend_query_alloc();
515 "SELECT lnk_id, 0 FROM snapshot_lnk_tbl WHERE lnk_inst_id = %d",
517 r
= backend_tx_run(dip
->di_tx
, q
, push_delete_callback
, &info
);
518 backend_query_free(q
);
520 if (r
== REP_PROTOCOL_DONE
) {
521 assert(info
.dci_result
!= REP_PROTOCOL_SUCCESS
);
522 return (info
.dci_result
);
529 fill_child_callback(void *data
, int columns
, char **vals
, char **names
)
531 child_info_t
*cp
= data
;
536 rc_node_lookup_t
*lp
= &cp
->ci_base_nl
;
538 assert(columns
== 2);
545 string_to_id(cur
, &main_id
, "id");
547 lp
->rl_main_id
= main_id
;
549 if ((np
= rc_node_alloc()) == NULL
)
550 return (BACKEND_CALLBACK_ABORT
);
552 np
= rc_node_setup(np
, lp
, name
, cp
->ci_parent
);
555 return (BACKEND_CALLBACK_CONTINUE
);
560 fill_snapshot_callback(void *data
, int columns
, char **vals
, char **names
)
562 child_info_t
*cp
= data
;
569 rc_node_lookup_t
*lp
= &cp
->ci_base_nl
;
571 assert(columns
== 3);
581 string_to_id(cur
, &main_id
, "lnk_id");
582 string_to_id(snap
, &snap_id
, "lnk_snap_id");
584 lp
->rl_main_id
= main_id
;
586 if ((np
= rc_node_alloc()) == NULL
)
587 return (BACKEND_CALLBACK_ABORT
);
589 np
= rc_node_setup_snapshot(np
, lp
, name
, snap_id
, cp
->ci_parent
);
592 return (BACKEND_CALLBACK_CONTINUE
);
597 fill_pg_callback(void *data
, int columns
, char **vals
, char **names
)
599 child_info_t
*cip
= data
;
607 rc_node_lookup_t
*lp
= &cip
->ci_base_nl
;
608 rc_node_t
*newnode
, *pg
;
610 assert(columns
== 5);
612 name
= *vals
++; /* pg_name */
615 cur
= *vals
++; /* pg_id */
617 string_to_id(cur
, &main_id
, "pg_id");
619 lp
->rl_main_id
= main_id
;
621 cur
= *vals
++; /* pg_gen_id */
623 string_to_id(cur
, &gen_id
, "pg_gen_id");
625 type
= *vals
++; /* pg_type */
628 cur
= *vals
++; /* pg_flags */
630 string_to_id(cur
, &flags
, "pg_flags");
632 if ((newnode
= rc_node_alloc()) == NULL
)
633 return (BACKEND_CALLBACK_ABORT
);
635 pg
= rc_node_setup_pg(newnode
, lp
, name
, type
, flags
, gen_id
,
638 rc_node_destroy(newnode
);
639 return (BACKEND_CALLBACK_ABORT
);
644 return (BACKEND_CALLBACK_CONTINUE
);
647 struct property_value_info
{
656 property_value_size_cb(void *data
, int columns
, char **vals
, char **names
)
658 struct property_value_info
*info
= data
;
659 assert(columns
== 1);
661 info
->pvi_size
+= strlen(vals
[0]) + 1; /* count the '\0' */
663 return (BACKEND_CALLBACK_CONTINUE
);
668 property_value_cb(void *data
, int columns
, char **vals
, char **names
)
670 struct property_value_info
*info
= data
;
671 size_t pos
, left
, len
;
673 assert(columns
== 1);
675 left
= info
->pvi_size
- pos
;
678 left
= info
->pvi_size
- pos
;
680 if ((len
= strlcpy(&info
->pvi_base
[pos
], vals
[0], left
)) >= left
) {
682 * since we preallocated, above, this shouldn't happen
684 backend_panic("unexpected database change");
687 len
+= 1; /* count the '\0' */
689 info
->pvi_pos
+= len
;
692 return (BACKEND_CALLBACK_CONTINUE
);
697 object_free_values(const char *vals
, uint32_t type
, size_t count
, size_t size
)
700 uu_free((void *)vals
);
705 fill_property_callback(void *data
, int columns
, char **vals
, char **names
)
707 child_info_t
*cp
= data
;
708 backend_tx_t
*tx
= cp
->ci_tx
;
712 rep_protocol_value_type_t type
;
713 rc_node_lookup_t
*lp
= &cp
->ci_base_nl
;
714 struct property_value_info info
;
717 assert(columns
== 4);
720 info
.pvi_base
= NULL
;
728 string_to_id(cur
, &main_id
, "lnk_prop_id");
731 assert(('a' <= cur
[0] && 'z' >= cur
[0]) ||
732 ('A' <= cur
[0] && 'Z' >= cur
[0]) &&
733 (cur
[1] == 0 || ('a' <= cur
[1] && 'z' >= cur
[1]) ||
734 ('A' <= cur
[1] && 'Z' >= cur
[1])));
735 type
= cur
[0] | (cur
[1] << 8);
737 lp
->rl_main_id
= main_id
;
740 * fill in the values, if any
742 if ((cur
= *vals
++) != NULL
) {
743 rep_protocol_responseid_t r
;
744 backend_query_t
*q
= backend_query_alloc();
747 * Ensure that select operation is reflective
748 * of repository schema. If the repository has
749 * been upgraded, make use of value ordering
750 * by retrieving values in order using the
751 * value_order column. Otherwise, simply
752 * run the select with no order specified.
753 * The order-insensitive select is necessary
754 * as on first reboot post-upgrade, the repository
755 * contents need to be read before the repository
756 * backend is writable (and upgrade is possible).
758 if (backend_is_upgraded(tx
)) {
760 "SELECT value_value FROM value_tbl "
761 "WHERE (value_id = '%q') ORDER BY value_order",
765 "SELECT value_value FROM value_tbl "
766 "WHERE (value_id = '%q')",
770 switch (r
= backend_tx_run(tx
, q
, property_value_size_cb
,
772 case REP_PROTOCOL_SUCCESS
:
775 case REP_PROTOCOL_FAIL_NO_RESOURCES
:
776 backend_query_free(q
);
777 return (BACKEND_CALLBACK_ABORT
);
779 case REP_PROTOCOL_DONE
:
781 backend_panic("backend_tx_run() returned %d", r
);
783 if (info
.pvi_size
> 0) {
784 info
.pvi_base
= uu_zalloc(info
.pvi_size
);
785 if (info
.pvi_base
== NULL
) {
786 backend_query_free(q
);
787 return (BACKEND_CALLBACK_ABORT
);
789 switch (r
= backend_tx_run(tx
, q
, property_value_cb
,
791 case REP_PROTOCOL_SUCCESS
:
794 case REP_PROTOCOL_FAIL_NO_RESOURCES
:
795 uu_free(info
.pvi_base
);
796 backend_query_free(q
);
797 return (BACKEND_CALLBACK_ABORT
);
799 case REP_PROTOCOL_DONE
:
801 backend_panic("backend_tx_run() returned %d",
805 backend_query_free(q
);
808 rc
= rc_node_create_property(cp
->ci_parent
, lp
, name
, type
,
809 info
.pvi_base
, info
.pvi_count
, info
.pvi_size
);
810 if (rc
!= REP_PROTOCOL_SUCCESS
) {
811 assert(rc
== REP_PROTOCOL_FAIL_NO_RESOURCES
);
812 return (BACKEND_CALLBACK_ABORT
);
815 return (BACKEND_CALLBACK_CONTINUE
);
819 * The *_setup_child_info() functions fill in a child_info_t structure with the
820 * information for the children of np with type type.
823 * _TYPE_MISMATCH - object cannot have children of type type
827 scope_setup_child_info(rc_node_t
*np
, uint32_t type
, child_info_t
*cip
)
829 if (type
!= REP_PROTOCOL_ENTITY_SERVICE
)
830 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
832 bzero(cip
, sizeof (*cip
));
834 cip
->ci_base_nl
.rl_type
= type
;
835 cip
->ci_base_nl
.rl_backend
= np
->rn_id
.rl_backend
;
836 return (REP_PROTOCOL_SUCCESS
);
840 service_setup_child_info(rc_node_t
*np
, uint32_t type
, child_info_t
*cip
)
843 case REP_PROTOCOL_ENTITY_INSTANCE
:
844 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
847 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
850 bzero(cip
, sizeof (*cip
));
852 cip
->ci_base_nl
.rl_type
= type
;
853 cip
->ci_base_nl
.rl_backend
= np
->rn_id
.rl_backend
;
854 cip
->ci_base_nl
.rl_ids
[ID_SERVICE
] = np
->rn_id
.rl_main_id
;
856 return (REP_PROTOCOL_SUCCESS
);
860 instance_setup_child_info(rc_node_t
*np
, uint32_t type
, child_info_t
*cip
)
863 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
864 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
867 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
870 bzero(cip
, sizeof (*cip
));
872 cip
->ci_base_nl
.rl_type
= type
;
873 cip
->ci_base_nl
.rl_backend
= np
->rn_id
.rl_backend
;
874 cip
->ci_base_nl
.rl_ids
[ID_SERVICE
] = np
->rn_id
.rl_ids
[ID_SERVICE
];
875 cip
->ci_base_nl
.rl_ids
[ID_INSTANCE
] = np
->rn_id
.rl_main_id
;
877 return (REP_PROTOCOL_SUCCESS
);
881 snaplevel_setup_child_info(rc_node_t
*np
, uint32_t type
, child_info_t
*cip
)
883 if (type
!= REP_PROTOCOL_ENTITY_PROPERTYGRP
)
884 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
886 bzero(cip
, sizeof (*cip
));
888 cip
->ci_base_nl
.rl_type
= type
;
889 cip
->ci_base_nl
.rl_backend
= np
->rn_id
.rl_backend
;
890 cip
->ci_base_nl
.rl_ids
[ID_SERVICE
] = np
->rn_id
.rl_ids
[ID_SERVICE
];
891 cip
->ci_base_nl
.rl_ids
[ID_INSTANCE
] = np
->rn_id
.rl_ids
[ID_INSTANCE
];
892 cip
->ci_base_nl
.rl_ids
[ID_NAME
] = np
->rn_id
.rl_ids
[ID_NAME
];
893 cip
->ci_base_nl
.rl_ids
[ID_SNAPSHOT
] = np
->rn_id
.rl_ids
[ID_SNAPSHOT
];
894 cip
->ci_base_nl
.rl_ids
[ID_LEVEL
] = np
->rn_id
.rl_main_id
;
896 return (REP_PROTOCOL_SUCCESS
);
900 propertygrp_setup_child_info(rc_node_t
*pg
, uint32_t type
, child_info_t
*cip
)
902 if (type
!= REP_PROTOCOL_ENTITY_PROPERTY
)
903 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
905 bzero(cip
, sizeof (*cip
));
907 cip
->ci_base_nl
.rl_type
= type
;
908 cip
->ci_base_nl
.rl_backend
= pg
->rn_id
.rl_backend
;
909 cip
->ci_base_nl
.rl_ids
[ID_SERVICE
] = pg
->rn_id
.rl_ids
[ID_SERVICE
];
910 cip
->ci_base_nl
.rl_ids
[ID_INSTANCE
] = pg
->rn_id
.rl_ids
[ID_INSTANCE
];
911 cip
->ci_base_nl
.rl_ids
[ID_PG
] = pg
->rn_id
.rl_main_id
;
912 cip
->ci_base_nl
.rl_ids
[ID_GEN
] = pg
->rn_gen_id
;
913 cip
->ci_base_nl
.rl_ids
[ID_NAME
] = pg
->rn_id
.rl_ids
[ID_NAME
];
914 cip
->ci_base_nl
.rl_ids
[ID_SNAPSHOT
] = pg
->rn_id
.rl_ids
[ID_SNAPSHOT
];
915 cip
->ci_base_nl
.rl_ids
[ID_LEVEL
] = pg
->rn_id
.rl_ids
[ID_LEVEL
];
917 return (REP_PROTOCOL_SUCCESS
);
921 * The *_fill_children() functions populate the children of the given rc_node_t
922 * by querying the database and calling rc_node_setup_*() functions (usually
923 * via a fill_*_callback()).
935 scope_fill_children(rc_node_t
*np
)
941 (void) scope_setup_child_info(np
, REP_PROTOCOL_ENTITY_SERVICE
, &ci
);
943 q
= backend_query_alloc();
944 backend_query_append(q
, "SELECT svc_name, svc_id FROM service_tbl");
945 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_child_callback
, &ci
);
946 backend_query_free(q
);
948 if (res
== REP_PROTOCOL_DONE
)
949 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
959 service_fill_children(rc_node_t
*np
)
965 assert(np
->rn_id
.rl_backend
== BACKEND_TYPE_NORMAL
);
967 (void) service_setup_child_info(np
, REP_PROTOCOL_ENTITY_INSTANCE
, &ci
);
969 q
= backend_query_alloc();
971 "SELECT instance_name, instance_id FROM instance_tbl"
972 " WHERE (instance_svc = %d)",
973 np
->rn_id
.rl_main_id
);
974 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_child_callback
, &ci
);
975 backend_query_free(q
);
977 if (res
== REP_PROTOCOL_DONE
)
978 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
979 if (res
!= REP_PROTOCOL_SUCCESS
)
982 (void) service_setup_child_info(np
, REP_PROTOCOL_ENTITY_PROPERTYGRP
,
985 q
= backend_query_alloc();
987 "SELECT pg_name, pg_id, pg_gen_id, pg_type, pg_flags FROM pg_tbl"
988 " WHERE (pg_parent_id = %d)",
989 np
->rn_id
.rl_main_id
);
991 ci
.ci_base_nl
.rl_backend
= BACKEND_TYPE_NORMAL
;
992 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_pg_callback
, &ci
);
993 if (res
== REP_PROTOCOL_SUCCESS
) {
994 ci
.ci_base_nl
.rl_backend
= BACKEND_TYPE_NONPERSIST
;
995 res
= backend_run(BACKEND_TYPE_NONPERSIST
, q
,
996 fill_pg_callback
, &ci
);
997 /* nonpersistant database may not exist */
998 if (res
== REP_PROTOCOL_FAIL_BACKEND_ACCESS
)
999 res
= REP_PROTOCOL_SUCCESS
;
1001 if (res
== REP_PROTOCOL_DONE
)
1002 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1003 backend_query_free(q
);
1014 instance_fill_children(rc_node_t
*np
)
1020 assert(np
->rn_id
.rl_backend
== BACKEND_TYPE_NORMAL
);
1022 /* Get child property groups */
1023 (void) instance_setup_child_info(np
, REP_PROTOCOL_ENTITY_PROPERTYGRP
,
1026 q
= backend_query_alloc();
1027 backend_query_add(q
,
1028 "SELECT pg_name, pg_id, pg_gen_id, pg_type, pg_flags FROM pg_tbl"
1029 " WHERE (pg_parent_id = %d)",
1030 np
->rn_id
.rl_main_id
);
1031 ci
.ci_base_nl
.rl_backend
= BACKEND_TYPE_NORMAL
;
1032 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_pg_callback
, &ci
);
1033 if (res
== REP_PROTOCOL_SUCCESS
) {
1034 ci
.ci_base_nl
.rl_backend
= BACKEND_TYPE_NONPERSIST
;
1035 res
= backend_run(BACKEND_TYPE_NONPERSIST
, q
,
1036 fill_pg_callback
, &ci
);
1037 /* nonpersistant database may not exist */
1038 if (res
== REP_PROTOCOL_FAIL_BACKEND_ACCESS
)
1039 res
= REP_PROTOCOL_SUCCESS
;
1041 if (res
== REP_PROTOCOL_DONE
)
1042 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1043 backend_query_free(q
);
1045 if (res
!= REP_PROTOCOL_SUCCESS
)
1048 /* Get child snapshots */
1049 (void) instance_setup_child_info(np
, REP_PROTOCOL_ENTITY_SNAPSHOT
,
1052 q
= backend_query_alloc();
1053 backend_query_add(q
,
1054 "SELECT lnk_snap_name, lnk_id, lnk_snap_id FROM snapshot_lnk_tbl"
1055 " WHERE (lnk_inst_id = %d)",
1056 np
->rn_id
.rl_main_id
);
1057 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_snapshot_callback
, &ci
);
1058 if (res
== REP_PROTOCOL_DONE
)
1059 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1060 backend_query_free(q
);
1071 snapshot_fill_children(rc_node_t
*np
)
1074 rc_snapshot_t
*sp
, *oldsp
;
1075 rc_snaplevel_t
*lvl
;
1076 rc_node_lookup_t nl
;
1079 /* Get the rc_snapshot_t (& its rc_snaplevel_t's). */
1080 (void) pthread_mutex_lock(&np
->rn_lock
);
1081 sp
= np
->rn_snapshot
;
1082 (void) pthread_mutex_unlock(&np
->rn_lock
);
1084 r
= rc_snapshot_get(np
->rn_snapshot_id
, &sp
);
1085 if (r
!= REP_PROTOCOL_SUCCESS
) {
1086 assert(r
== REP_PROTOCOL_FAIL_NO_RESOURCES
);
1089 (void) pthread_mutex_lock(&np
->rn_lock
);
1090 oldsp
= np
->rn_snapshot
;
1091 assert(oldsp
== NULL
|| oldsp
== sp
);
1092 np
->rn_snapshot
= sp
;
1093 (void) pthread_mutex_unlock(&np
->rn_lock
);
1095 rc_snapshot_rele(oldsp
);
1098 bzero(&nl
, sizeof (nl
));
1099 nl
.rl_type
= REP_PROTOCOL_ENTITY_SNAPLEVEL
;
1100 nl
.rl_backend
= np
->rn_id
.rl_backend
;
1101 nl
.rl_ids
[ID_SERVICE
] = np
->rn_id
.rl_ids
[ID_SERVICE
];
1102 nl
.rl_ids
[ID_INSTANCE
] = np
->rn_id
.rl_ids
[ID_INSTANCE
];
1103 nl
.rl_ids
[ID_NAME
] = np
->rn_id
.rl_main_id
;
1104 nl
.rl_ids
[ID_SNAPSHOT
] = np
->rn_snapshot_id
;
1106 /* Create rc_node_t's for the snapshot's rc_snaplevel_t's. */
1107 for (lvl
= sp
->rs_levels
; lvl
!= NULL
; lvl
= lvl
->rsl_next
) {
1108 nnp
= rc_node_alloc();
1109 assert(nnp
!= NULL
);
1110 nl
.rl_main_id
= lvl
->rsl_level_id
;
1111 nnp
= rc_node_setup_snaplevel(nnp
, &nl
, lvl
, np
);
1115 return (REP_PROTOCOL_SUCCESS
);
1124 snaplevel_fill_children(rc_node_t
*np
)
1126 rc_snaplevel_t
*lvl
= np
->rn_snaplevel
;
1131 (void) snaplevel_setup_child_info(np
, REP_PROTOCOL_ENTITY_PROPERTYGRP
,
1134 q
= backend_query_alloc();
1135 backend_query_add(q
,
1136 "SELECT snaplvl_pg_name, snaplvl_pg_id, snaplvl_gen_id, "
1137 " snaplvl_pg_type, snaplvl_pg_flags "
1138 " FROM snaplevel_lnk_tbl "
1139 " WHERE (snaplvl_level_id = %d)",
1141 res
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_pg_callback
, &ci
);
1142 if (res
== REP_PROTOCOL_DONE
)
1143 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1144 backend_query_free(q
);
1155 propertygrp_fill_children(rc_node_t
*np
)
1162 backend_type_t backend
= np
->rn_id
.rl_backend
;
1164 (void) propertygrp_setup_child_info(np
, REP_PROTOCOL_ENTITY_PROPERTY
,
1167 res
= backend_tx_begin_ro(backend
, &tx
);
1168 if (res
!= REP_PROTOCOL_SUCCESS
) {
1170 * If the backend didn't exist, we wouldn't have got this
1173 assert(res
!= REP_PROTOCOL_FAIL_BACKEND_ACCESS
);
1179 q
= backend_query_alloc();
1180 backend_query_add(q
,
1181 "SELECT lnk_prop_name, lnk_prop_id, lnk_prop_type, lnk_val_id "
1182 "FROM prop_lnk_tbl "
1183 "WHERE (lnk_pg_id = %d AND lnk_gen_id = %d)",
1184 np
->rn_id
.rl_main_id
, np
->rn_gen_id
);
1185 res
= backend_tx_run(tx
, q
, fill_property_callback
, &ci
);
1186 if (res
== REP_PROTOCOL_DONE
)
1187 res
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1188 backend_query_free(q
);
1189 backend_tx_end_ro(tx
);
1196 * _TYPE_MISMATCH - lp is not for a service
1197 * _INVALID_TYPE - lp has invalid type
1198 * _BAD_REQUEST - name is invalid
1201 scope_query_child(backend_query_t
*q
, rc_node_lookup_t
*lp
, const char *name
)
1203 uint32_t type
= lp
->rl_type
;
1206 if (type
!= REP_PROTOCOL_ENTITY_SERVICE
)
1207 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
1209 if ((rc
= rc_check_type_name(type
, name
)) != REP_PROTOCOL_SUCCESS
)
1212 backend_query_add(q
,
1213 "SELECT svc_id FROM service_tbl "
1214 "WHERE svc_name = '%q'",
1217 return (REP_PROTOCOL_SUCCESS
);
1222 * _NO_RESOURCES - out of memory
1225 scope_insert_child(backend_tx_t
*tx
, rc_node_lookup_t
*lp
, const char *name
)
1227 return (backend_tx_run_update(tx
,
1228 "INSERT INTO service_tbl (svc_id, svc_name) "
1229 "VALUES (%d, '%q')",
1230 lp
->rl_main_id
, name
));
1235 * _TYPE_MISMATCH - lp is not for an instance or property group
1236 * _INVALID_TYPE - lp has invalid type
1237 * _BAD_REQUEST - name is invalid
1240 service_query_child(backend_query_t
*q
, rc_node_lookup_t
*lp
, const char *name
)
1242 uint32_t type
= lp
->rl_type
;
1245 if (type
!= REP_PROTOCOL_ENTITY_INSTANCE
&&
1246 type
!= REP_PROTOCOL_ENTITY_PROPERTYGRP
)
1247 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
1249 if ((rc
= rc_check_type_name(type
, name
)) != REP_PROTOCOL_SUCCESS
)
1253 case REP_PROTOCOL_ENTITY_INSTANCE
:
1254 backend_query_add(q
,
1255 "SELECT instance_id FROM instance_tbl "
1256 "WHERE instance_name = '%q' AND instance_svc = %d",
1257 name
, lp
->rl_ids
[ID_SERVICE
]);
1259 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
1260 backend_query_add(q
,
1261 "SELECT pg_id FROM pg_tbl "
1262 " WHERE pg_name = '%q' AND pg_parent_id = %d",
1263 name
, lp
->rl_ids
[ID_SERVICE
]);
1270 return (REP_PROTOCOL_SUCCESS
);
1275 * _NO_RESOURCES - out of memory
1278 service_insert_child(backend_tx_t
*tx
, rc_node_lookup_t
*lp
, const char *name
)
1280 return (backend_tx_run_update(tx
,
1281 "INSERT INTO instance_tbl "
1282 " (instance_id, instance_name, instance_svc) "
1283 "VALUES (%d, '%q', %d)",
1284 lp
->rl_main_id
, name
, lp
->rl_ids
[ID_SERVICE
]));
1289 * _NO_RESOURCES - out of memory
1292 instance_insert_child(backend_tx_t
*tx
, rc_node_lookup_t
*lp
, const char *name
)
1294 return (backend_tx_run_update(tx
,
1295 "INSERT INTO snapshot_lnk_tbl "
1296 " (lnk_id, lnk_inst_id, lnk_snap_name, lnk_snap_id) "
1297 "VALUES (%d, %d, '%q', 0)",
1298 lp
->rl_main_id
, lp
->rl_ids
[ID_INSTANCE
], name
));
1303 * _TYPE_MISMATCH - lp is not for a property group or snapshot
1304 * _INVALID_TYPE - lp has invalid type
1305 * _BAD_REQUEST - name is invalid
1308 instance_query_child(backend_query_t
*q
, rc_node_lookup_t
*lp
, const char *name
)
1310 uint32_t type
= lp
->rl_type
;
1313 if (type
!= REP_PROTOCOL_ENTITY_PROPERTYGRP
&&
1314 type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
)
1315 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
1317 if ((rc
= rc_check_type_name(type
, name
)) != REP_PROTOCOL_SUCCESS
)
1321 case REP_PROTOCOL_ENTITY_PROPERTYGRP
:
1322 backend_query_add(q
,
1323 "SELECT pg_id FROM pg_tbl "
1324 " WHERE pg_name = '%q' AND pg_parent_id = %d",
1325 name
, lp
->rl_ids
[ID_INSTANCE
]);
1327 case REP_PROTOCOL_ENTITY_SNAPSHOT
:
1328 backend_query_add(q
,
1329 "SELECT lnk_id FROM snapshot_lnk_tbl "
1330 " WHERE lnk_snap_name = '%q' AND lnk_inst_id = %d",
1331 name
, lp
->rl_ids
[ID_INSTANCE
]);
1338 return (REP_PROTOCOL_SUCCESS
);
1342 generic_insert_pg_child(backend_tx_t
*tx
, rc_node_lookup_t
*lp
,
1343 const char *name
, const char *pgtype
, uint32_t flags
, uint32_t gen
)
1345 int parent_id
= (lp
->rl_ids
[ID_INSTANCE
] != 0)?
1346 lp
->rl_ids
[ID_INSTANCE
] : lp
->rl_ids
[ID_SERVICE
];
1347 return (backend_tx_run_update(tx
,
1348 "INSERT INTO pg_tbl "
1349 " (pg_id, pg_name, pg_parent_id, pg_type, pg_flags, pg_gen_id) "
1350 "VALUES (%d, '%q', %d, '%q', %d, %d)",
1351 lp
->rl_main_id
, name
, parent_id
, pgtype
, flags
, gen
));
1355 service_delete_start(rc_node_t
*np
, delete_info_t
*dip
)
1358 backend_query_t
*q
= backend_query_alloc();
1361 * Check for child instances, and refuse to delete if they exist.
1363 backend_query_add(q
,
1364 "SELECT 1 FROM instance_tbl WHERE instance_svc = %d",
1365 np
->rn_id
.rl_main_id
);
1367 r
= backend_tx_run(dip
->di_tx
, q
, backend_fail_if_seen
, NULL
);
1368 backend_query_free(q
);
1370 if (r
== REP_PROTOCOL_DONE
)
1371 return (REP_PROTOCOL_FAIL_EXISTS
); /* instances exist */
1373 return (delete_stack_push(dip
, BACKEND_TYPE_NORMAL
, &service_delete
,
1374 np
->rn_id
.rl_main_id
, 0));
1378 instance_delete_start(rc_node_t
*np
, delete_info_t
*dip
)
1380 return (delete_stack_push(dip
, BACKEND_TYPE_NORMAL
, &instance_delete
,
1381 np
->rn_id
.rl_main_id
, 0));
1385 snapshot_delete_start(rc_node_t
*np
, delete_info_t
*dip
)
1387 return (delete_stack_push(dip
, BACKEND_TYPE_NORMAL
,
1388 &snapshot_lnk_delete
, np
->rn_id
.rl_main_id
, 0));
1392 propertygrp_delete_start(rc_node_t
*np
, delete_info_t
*dip
)
1394 return (delete_stack_push(dip
, np
->rn_id
.rl_backend
,
1395 &propertygrp_delete
, np
->rn_id
.rl_main_id
, 0));
1398 static object_info_t info
[] = {
1399 {REP_PROTOCOL_ENTITY_NONE
},
1400 {REP_PROTOCOL_ENTITY_SCOPE
,
1402 scope_fill_children
,
1403 scope_setup_child_info
,
1409 {REP_PROTOCOL_ENTITY_SERVICE
,
1410 BACKEND_ID_SERVICE_INSTANCE
,
1411 service_fill_children
,
1412 service_setup_child_info
,
1413 service_query_child
,
1414 service_insert_child
,
1415 generic_insert_pg_child
,
1416 service_delete_start
,
1418 {REP_PROTOCOL_ENTITY_INSTANCE
,
1419 BACKEND_ID_SERVICE_INSTANCE
,
1420 instance_fill_children
,
1421 instance_setup_child_info
,
1422 instance_query_child
,
1423 instance_insert_child
,
1424 generic_insert_pg_child
,
1425 instance_delete_start
,
1427 {REP_PROTOCOL_ENTITY_SNAPSHOT
,
1428 BACKEND_ID_SNAPNAME
,
1429 snapshot_fill_children
,
1434 snapshot_delete_start
,
1436 {REP_PROTOCOL_ENTITY_SNAPLEVEL
,
1437 BACKEND_ID_SNAPLEVEL
,
1438 snaplevel_fill_children
,
1439 snaplevel_setup_child_info
,
1441 {REP_PROTOCOL_ENTITY_PROPERTYGRP
,
1442 BACKEND_ID_PROPERTYGRP
,
1443 propertygrp_fill_children
,
1448 propertygrp_delete_start
,
1450 {REP_PROTOCOL_ENTITY_PROPERTY
},
1453 #define NUM_INFO (sizeof (info) / sizeof (*info))
1456 * object_fill_children() populates the child list of an rc_node_t by calling
1457 * the appropriate <type>_fill_children() which runs backend queries that
1458 * call an appropriate fill_*_callback() which takes a row of results,
1459 * decodes them, and calls an rc_node_setup*() function in rc_node.c to create
1466 object_fill_children(rc_node_t
*pp
)
1468 uint32_t type
= pp
->rn_id
.rl_type
;
1469 assert(type
> 0 && type
< NUM_INFO
);
1471 return ((*info
[type
].obj_fill_children
)(pp
));
1475 object_delete(rc_node_t
*pp
)
1482 uint32_t type
= pp
->rn_id
.rl_type
;
1483 assert(type
> 0 && type
< NUM_INFO
);
1485 if (info
[type
].obj_delete_start
== NULL
)
1486 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1488 (void) memset(&dip
, '\0', sizeof (dip
));
1489 rc
= backend_tx_begin(BACKEND_TYPE_NORMAL
, &dip
.di_tx
);
1490 if (rc
!= REP_PROTOCOL_SUCCESS
)
1493 rc
= backend_tx_begin(BACKEND_TYPE_NONPERSIST
, &dip
.di_np_tx
);
1494 if (rc
== REP_PROTOCOL_FAIL_BACKEND_ACCESS
||
1495 rc
== REP_PROTOCOL_FAIL_BACKEND_READONLY
)
1496 dip
.di_np_tx
= NULL
;
1497 else if (rc
!= REP_PROTOCOL_SUCCESS
) {
1498 backend_tx_rollback(dip
.di_tx
);
1502 if ((rc
= (*info
[type
].obj_delete_start
)(pp
, &dip
)) !=
1503 REP_PROTOCOL_SUCCESS
) {
1507 while (delete_stack_pop(&dip
, &de
)) {
1508 rc
= (*de
.de_cb
)(&dip
, &de
);
1509 if (rc
!= REP_PROTOCOL_SUCCESS
)
1513 rc
= backend_tx_commit(dip
.di_tx
);
1514 if (rc
!= REP_PROTOCOL_SUCCESS
)
1515 backend_tx_rollback(dip
.di_np_tx
);
1516 else if (dip
.di_np_tx
)
1517 (void) backend_tx_commit(dip
.di_np_tx
);
1519 delete_stack_cleanup(&dip
);
1524 backend_tx_rollback(dip
.di_tx
);
1525 backend_tx_rollback(dip
.di_np_tx
);
1526 delete_stack_cleanup(&dip
);
1531 object_do_create(backend_tx_t
*tx
, child_info_t
*cip
, rc_node_t
*pp
,
1532 uint32_t type
, const char *name
, rc_node_t
**cpp
)
1534 uint32_t ptype
= pp
->rn_id
.rl_type
;
1538 rc_node_t
*np
= NULL
;
1542 rc_node_lookup_t
*lp
= &cip
->ci_base_nl
;
1544 assert(ptype
> 0 && ptype
< NUM_INFO
);
1548 if (type
== REP_PROTOCOL_ENTITY_PROPERTYGRP
)
1549 return (REP_PROTOCOL_FAIL_NOT_APPLICABLE
);
1551 if (ip
->obj_setup_child_info
== NULL
||
1552 ip
->obj_query_child
== NULL
||
1553 ip
->obj_insert_child
== NULL
)
1554 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1556 if ((rc
= (*ip
->obj_setup_child_info
)(pp
, type
, cip
)) !=
1557 REP_PROTOCOL_SUCCESS
)
1560 q
= backend_query_alloc();
1561 if ((rc
= (*ip
->obj_query_child
)(q
, lp
, name
)) !=
1562 REP_PROTOCOL_SUCCESS
) {
1563 assert(rc
== REP_PROTOCOL_FAIL_BAD_REQUEST
);
1564 backend_query_free(q
);
1568 rc
= backend_tx_run_single_int(tx
, q
, &id
);
1569 backend_query_free(q
);
1571 if (rc
== REP_PROTOCOL_SUCCESS
)
1572 return (REP_PROTOCOL_FAIL_EXISTS
);
1573 else if (rc
!= REP_PROTOCOL_FAIL_NOT_FOUND
)
1576 if ((lp
->rl_main_id
= backend_new_id(tx
,
1577 info
[type
].obj_id_space
)) == 0) {
1578 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1581 if ((np
= rc_node_alloc()) == NULL
)
1582 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
1584 if ((rc
= (*ip
->obj_insert_child
)(tx
, lp
, name
)) !=
1585 REP_PROTOCOL_SUCCESS
) {
1586 rc_node_destroy(np
);
1591 return (REP_PROTOCOL_SUCCESS
);
1596 * _NOT_APPLICABLE - type is _PROPERTYGRP
1597 * _BAD_REQUEST - cannot create children for this type of node
1599 * _TYPE_MISMATCH - object cannot have children of type type
1600 * _NO_RESOURCES - out of memory, or could not allocate new id
1603 * _EXISTS - child already exists
1606 object_create(rc_node_t
*pp
, uint32_t type
, const char *name
, rc_node_t
**cpp
)
1609 rc_node_t
*np
= NULL
;
1613 if ((rc
= backend_tx_begin(pp
->rn_id
.rl_backend
, &tx
)) !=
1614 REP_PROTOCOL_SUCCESS
) {
1618 if ((rc
= object_do_create(tx
, &ci
, pp
, type
, name
, &np
)) !=
1619 REP_PROTOCOL_SUCCESS
) {
1620 backend_tx_rollback(tx
);
1624 rc
= backend_tx_commit(tx
);
1625 if (rc
!= REP_PROTOCOL_SUCCESS
) {
1626 rc_node_destroy(np
);
1630 *cpp
= rc_node_setup(np
, &ci
.ci_base_nl
, name
, ci
.ci_parent
);
1632 return (REP_PROTOCOL_SUCCESS
);
1637 object_create_pg(rc_node_t
*pp
, uint32_t type
, const char *name
,
1638 const char *pgtype
, uint32_t flags
, rc_node_t
**cpp
)
1640 uint32_t ptype
= pp
->rn_id
.rl_type
;
1641 backend_tx_t
*tx_ro
, *tx_wr
;
1645 rc_node_t
*np
= NULL
;
1651 int nonpersist
= (flags
& SCF_PG_FLAG_NONPERSISTENT
);
1654 rc_node_lookup_t
*lp
= &ci
.ci_base_nl
;
1656 assert(ptype
> 0 && ptype
< NUM_INFO
);
1658 if (ptype
!= REP_PROTOCOL_ENTITY_SERVICE
&&
1659 ptype
!= REP_PROTOCOL_ENTITY_INSTANCE
)
1660 return (REP_PROTOCOL_FAIL_BAD_REQUEST
);
1664 assert(ip
->obj_setup_child_info
!= NULL
&&
1665 ip
->obj_query_child
!= NULL
&&
1666 ip
->obj_insert_pg_child
!= NULL
);
1668 if ((rc
= (*ip
->obj_setup_child_info
)(pp
, type
, &ci
)) !=
1669 REP_PROTOCOL_SUCCESS
)
1672 q
= backend_query_alloc();
1673 if ((rc
= (*ip
->obj_query_child
)(q
, lp
, name
)) !=
1674 REP_PROTOCOL_SUCCESS
) {
1675 backend_query_free(q
);
1680 lp
->rl_backend
= BACKEND_TYPE_NORMAL
;
1681 rc_wr
= backend_tx_begin(BACKEND_TYPE_NORMAL
, &tx_wr
);
1682 rc_ro
= backend_tx_begin_ro(BACKEND_TYPE_NONPERSIST
, &tx_ro
);
1684 lp
->rl_backend
= BACKEND_TYPE_NONPERSIST
;
1685 rc_ro
= backend_tx_begin_ro(BACKEND_TYPE_NORMAL
, &tx_ro
);
1686 rc_wr
= backend_tx_begin(BACKEND_TYPE_NONPERSIST
, &tx_wr
);
1689 if (rc_wr
!= REP_PROTOCOL_SUCCESS
) {
1693 if (rc_ro
!= REP_PROTOCOL_SUCCESS
&&
1694 rc_ro
!= REP_PROTOCOL_FAIL_BACKEND_ACCESS
) {
1699 if (tx_ro
!= NULL
) {
1700 rc
= backend_tx_run_single_int(tx_ro
, q
, &id
);
1702 if (rc
== REP_PROTOCOL_SUCCESS
) {
1703 backend_query_free(q
);
1704 rc
= REP_PROTOCOL_FAIL_EXISTS
;
1706 } else if (rc
!= REP_PROTOCOL_FAIL_NOT_FOUND
) {
1707 backend_query_free(q
);
1712 rc
= backend_tx_run_single_int(tx_wr
, q
, &id
);
1713 backend_query_free(q
);
1715 if (rc
== REP_PROTOCOL_SUCCESS
) {
1716 rc
= REP_PROTOCOL_FAIL_EXISTS
;
1718 } else if (rc
!= REP_PROTOCOL_FAIL_NOT_FOUND
) {
1723 backend_tx_end_ro(tx_ro
);
1726 if ((lp
->rl_main_id
= backend_new_id(tx_wr
,
1727 info
[type
].obj_id_space
)) == 0) {
1728 rc
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1732 if ((np
= rc_node_alloc()) == NULL
) {
1733 rc
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1737 if ((rc
= (*ip
->obj_insert_pg_child
)(tx_wr
, lp
, name
, pgtype
, flags
,
1738 gen
)) != REP_PROTOCOL_SUCCESS
) {
1739 rc_node_destroy(np
);
1743 rc
= backend_tx_commit(tx_wr
);
1744 if (rc
!= REP_PROTOCOL_SUCCESS
) {
1745 rc_node_destroy(np
);
1749 *cpp
= rc_node_setup_pg(np
, lp
, name
, pgtype
, flags
, gen
, ci
.ci_parent
);
1751 return (REP_PROTOCOL_SUCCESS
);
1755 backend_tx_end_ro(tx_ro
);
1757 backend_tx_rollback(tx_wr
);
1762 * Given a row of snaplevel number, snaplevel id, service id, service name,
1763 * instance id, & instance name, create a rc_snaplevel_t & prepend it onto the
1764 * rs_levels list of the rc_snapshot_t passed in as data.
1765 * Returns _CONTINUE on success or _ABORT if any allocations fail.
1769 fill_snapshot_cb(void *data
, int columns
, char **vals
, char **names
)
1771 rc_snapshot_t
*sp
= data
;
1772 rc_snaplevel_t
*lvl
;
1773 char *num
= vals
[0];
1775 char *service_id
= vals
[2];
1776 char *service
= vals
[3];
1777 char *instance_id
= vals
[4];
1778 char *instance
= vals
[5];
1779 assert(columns
== 6);
1781 lvl
= uu_zalloc(sizeof (*lvl
));
1783 return (BACKEND_CALLBACK_ABORT
);
1784 lvl
->rsl_parent
= sp
;
1785 lvl
->rsl_next
= sp
->rs_levels
;
1786 sp
->rs_levels
= lvl
;
1788 string_to_id(num
, &lvl
->rsl_level_num
, "snap_level_num");
1789 string_to_id(id
, &lvl
->rsl_level_id
, "snap_level_id");
1790 string_to_id(service_id
, &lvl
->rsl_service_id
, "snap_level_service_id");
1791 if (instance_id
!= NULL
)
1792 string_to_id(instance_id
, &lvl
->rsl_instance_id
,
1793 "snap_level_instance_id");
1795 lvl
->rsl_scope
= (const char *)"localhost";
1796 lvl
->rsl_service
= strdup(service
);
1797 if (lvl
->rsl_service
== NULL
) {
1799 return (BACKEND_CALLBACK_ABORT
);
1802 assert(lvl
->rsl_instance_id
!= 0);
1803 lvl
->rsl_instance
= strdup(instance
);
1804 if (lvl
->rsl_instance
== NULL
) {
1805 free((void *)lvl
->rsl_instance
);
1807 return (BACKEND_CALLBACK_ABORT
);
1810 assert(lvl
->rsl_instance_id
== 0);
1813 return (BACKEND_CALLBACK_CONTINUE
);
1817 * Populate sp's rs_levels list from the snaplevel_tbl table.
1822 object_fill_snapshot(rc_snapshot_t
*sp
)
1829 q
= backend_query_alloc();
1830 backend_query_add(q
,
1831 "SELECT snap_level_num, snap_level_id, "
1832 " snap_level_service_id, snap_level_service, "
1833 " snap_level_instance_id, snap_level_instance "
1834 "FROM snaplevel_tbl "
1835 "WHERE snap_id = %d "
1836 "ORDER BY snap_level_id DESC",
1839 result
= backend_run(BACKEND_TYPE_NORMAL
, q
, fill_snapshot_cb
, sp
);
1840 if (result
== REP_PROTOCOL_DONE
)
1841 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
1842 backend_query_free(q
);
1844 if (result
== REP_PROTOCOL_SUCCESS
) {
1846 for (sl
= sp
->rs_levels
; sl
!= NULL
; sl
= sl
->rsl_next
) {
1847 if (sl
->rsl_level_num
!= ++i
) {
1848 backend_panic("snaplevels corrupt; expected "
1849 "level %d, got %d", i
, sl
->rsl_level_num
);
1857 * This represents a property group in a snapshot.
1859 typedef struct check_snapshot_elem
{
1860 uint32_t cse_parent
;
1862 uint32_t cse_pg_gen
;
1864 } check_snapshot_elem_t
;
1866 #define CSI_MAX_PARENTS COMPOSITION_DEPTH
1867 typedef struct check_snapshot_info
{
1869 size_t csi_array_size
;
1870 check_snapshot_elem_t
*csi_array
;
1871 size_t csi_nparents
;
1872 uint32_t csi_parent_ids
[CSI_MAX_PARENTS
];
1873 } check_snapshot_info_t
;
1877 check_snapshot_fill_cb(void *data
, int columns
, char **vals
, char **names
)
1879 check_snapshot_info_t
*csip
= data
;
1880 check_snapshot_elem_t
*cur
;
1883 const char *pg_gen_id
;
1888 if (csip
->csi_nparents
>= CSI_MAX_PARENTS
)
1889 backend_panic("snaplevel table has too many elements");
1891 target
= &csip
->csi_parent_ids
[csip
->csi_nparents
++];
1892 string_to_id(vals
[0], target
, "snap_level_*_id");
1894 return (BACKEND_CALLBACK_CONTINUE
);
1897 assert(columns
== 3);
1901 pg_gen_id
= vals
[2];
1903 if (csip
->csi_count
== csip
->csi_array_size
) {
1904 size_t newsz
= (csip
->csi_array_size
> 0) ?
1905 csip
->csi_array_size
* 2 : 8;
1906 check_snapshot_elem_t
*new = uu_zalloc(newsz
* sizeof (*new));
1909 return (BACKEND_CALLBACK_ABORT
);
1911 (void) memcpy(new, csip
->csi_array
,
1912 sizeof (*new) * csip
->csi_array_size
);
1913 uu_free(csip
->csi_array
);
1914 csip
->csi_array
= new;
1915 csip
->csi_array_size
= newsz
;
1918 cur
= &csip
->csi_array
[csip
->csi_count
++];
1920 string_to_id(parent
, &cur
->cse_parent
, "snap_level_*_id");
1921 string_to_id(pg_id
, &cur
->cse_pg_id
, "snaplvl_pg_id");
1922 string_to_id(pg_gen_id
, &cur
->cse_pg_gen
, "snaplvl_gen_id");
1925 return (BACKEND_CALLBACK_CONTINUE
);
1929 check_snapshot_elem_cmp(const void *lhs_arg
, const void *rhs_arg
)
1931 const check_snapshot_elem_t
*lhs
= lhs_arg
;
1932 const check_snapshot_elem_t
*rhs
= rhs_arg
;
1934 if (lhs
->cse_parent
< rhs
->cse_parent
)
1936 if (lhs
->cse_parent
> rhs
->cse_parent
)
1939 if (lhs
->cse_pg_id
< rhs
->cse_pg_id
)
1941 if (lhs
->cse_pg_id
> rhs
->cse_pg_id
)
1944 if (lhs
->cse_pg_gen
< rhs
->cse_pg_gen
)
1946 if (lhs
->cse_pg_gen
> rhs
->cse_pg_gen
)
1954 check_snapshot_check_cb(void *data
, int columns
, char **vals
, char **names
)
1956 check_snapshot_info_t
*csip
= data
;
1957 check_snapshot_elem_t elem
;
1958 check_snapshot_elem_t
*cur
;
1960 const char *parent
= vals
[0];
1961 const char *pg_id
= vals
[1];
1962 const char *pg_gen_id
= vals
[2];
1964 assert(columns
== 3);
1966 string_to_id(parent
, &elem
.cse_parent
, "snap_level_*_id");
1967 string_to_id(pg_id
, &elem
.cse_pg_id
, "snaplvl_pg_id");
1968 string_to_id(pg_gen_id
, &elem
.cse_pg_gen
, "snaplvl_gen_id");
1970 if ((cur
= bsearch(&elem
, csip
->csi_array
, csip
->csi_count
,
1971 sizeof (*csip
->csi_array
), check_snapshot_elem_cmp
)) == NULL
)
1972 return (BACKEND_CALLBACK_ABORT
);
1975 backend_panic("duplicate property group reported");
1977 return (BACKEND_CALLBACK_CONTINUE
);
1981 * Check that a snapshot matches up with the latest in the repository.
1983 * REP_PROTOCOL_SUCCESS if it is up-to-date,
1984 * REP_PROTOCOL_DONE if it is out-of-date, or
1985 * REP_PROTOCOL_FAIL_NO_RESOURCES if we ran out of memory.
1988 object_check_snapshot(uint32_t snap_id
)
1990 check_snapshot_info_t csi
;
1995 /* if the snapshot has never been taken, it must be out of date. */
1997 return (REP_PROTOCOL_DONE
);
1999 (void) memset(&csi
, '\0', sizeof (csi
));
2001 q
= backend_query_alloc();
2002 backend_query_add(q
,
2004 " CASE snap_level_instance_id\n"
2005 " WHEN 0 THEN snap_level_service_id\n"
2006 " ELSE snap_level_instance_id\n"
2008 "FROM snaplevel_tbl\n"
2009 "WHERE snap_id = %d;\n"
2012 " CASE snap_level_instance_id\n"
2013 " WHEN 0 THEN snap_level_service_id\n"
2014 " ELSE snap_level_instance_id\n"
2018 "FROM snaplevel_tbl, snaplevel_lnk_tbl\n"
2020 " (snaplvl_level_id = snap_level_id AND\n"
2024 result
= backend_run(BACKEND_TYPE_NORMAL
, q
, check_snapshot_fill_cb
,
2026 if (result
== REP_PROTOCOL_DONE
)
2027 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
2028 backend_query_free(q
);
2030 if (result
!= REP_PROTOCOL_SUCCESS
)
2033 if (csi
.csi_count
> 0) {
2034 qsort(csi
.csi_array
, csi
.csi_count
, sizeof (*csi
.csi_array
),
2035 check_snapshot_elem_cmp
);
2038 #if COMPOSITION_DEPTH == 2
2039 if (csi
.csi_nparents
!= COMPOSITION_DEPTH
) {
2040 result
= REP_PROTOCOL_DONE
;
2044 q
= backend_query_alloc();
2045 backend_query_add(q
,
2047 " pg_parent_id, pg_id, pg_gen_id "
2050 "WHERE (pg_parent_id = %d OR pg_parent_id = %d)",
2051 csi
.csi_parent_ids
[0], csi
.csi_parent_ids
[1]);
2053 result
= backend_run(BACKEND_TYPE_NORMAL
, q
, check_snapshot_check_cb
,
2056 #error This code must be updated
2059 * To succeed, the callback must not have aborted, and we must have
2060 * found all of the items.
2062 if (result
== REP_PROTOCOL_SUCCESS
) {
2063 for (idx
= 0; idx
< csi
.csi_count
; idx
++) {
2064 if (csi
.csi_array
[idx
].cse_seen
== 0) {
2065 result
= REP_PROTOCOL_DONE
;
2072 uu_free(csi
.csi_array
);
2078 object_copy_string(void *data_arg
, int columns
, char **vals
, char **names
)
2080 char **data
= data_arg
;
2082 assert(columns
== 1);
2088 if (vals
[0] != NULL
) {
2089 if ((*data
= strdup(vals
[0])) == NULL
)
2090 return (BACKEND_CALLBACK_ABORT
);
2093 return (BACKEND_CALLBACK_CONTINUE
);
2096 struct snaplevel_add_info
{
2097 backend_query_t
*sai_q
;
2098 uint32_t sai_level_id
;
2099 int sai_used
; /* sai_q has been used */
2104 object_snaplevel_process_pg(void *data_arg
, int columns
, char **vals
,
2107 struct snaplevel_add_info
*data
= data_arg
;
2109 assert(columns
== 5);
2111 backend_query_add(data
->sai_q
,
2112 "INSERT INTO snaplevel_lnk_tbl "
2113 " (snaplvl_level_id, snaplvl_pg_id, snaplvl_pg_name, "
2114 " snaplvl_pg_type, snaplvl_pg_flags, snaplvl_gen_id)"
2115 "VALUES (%d, %s, '%q', '%q', %s, %s);",
2116 data
->sai_level_id
, vals
[0], vals
[1], vals
[2], vals
[3], vals
[4]);
2120 return (BACKEND_CALLBACK_CONTINUE
);
2125 object_snapshot_add_level(backend_tx_t
*tx
, uint32_t snap_id
,
2126 uint32_t snap_level_num
, uint32_t svc_id
, const char *svc_name
,
2127 uint32_t inst_id
, const char *inst_name
)
2129 struct snaplevel_add_info data
;
2133 assert((snap_level_num
== 1 && inst_name
!= NULL
) ||
2134 snap_level_num
== 2 && inst_name
== NULL
);
2136 data
.sai_level_id
= backend_new_id(tx
, BACKEND_ID_SNAPLEVEL
);
2137 if (data
.sai_level_id
== 0) {
2138 return (REP_PROTOCOL_FAIL_NO_RESOURCES
);
2141 result
= backend_tx_run_update(tx
,
2142 "INSERT INTO snaplevel_tbl "
2143 " (snap_id, snap_level_num, snap_level_id, "
2144 " snap_level_service_id, snap_level_service, "
2145 " snap_level_instance_id, snap_level_instance) "
2146 "VALUES (%d, %d, %d, %d, %Q, %d, %Q);",
2147 snap_id
, snap_level_num
, data
.sai_level_id
, svc_id
, svc_name
,
2148 inst_id
, inst_name
);
2150 q
= backend_query_alloc();
2151 backend_query_add(q
,
2152 "SELECT pg_id, pg_name, pg_type, pg_flags, pg_gen_id FROM pg_tbl "
2153 "WHERE (pg_parent_id = %d);",
2154 (inst_name
!= NULL
)? inst_id
: svc_id
);
2156 data
.sai_q
= backend_query_alloc();
2158 result
= backend_tx_run(tx
, q
, object_snaplevel_process_pg
,
2160 backend_query_free(q
);
2162 if (result
== REP_PROTOCOL_SUCCESS
&& data
.sai_used
!= 0)
2163 result
= backend_tx_run(tx
, data
.sai_q
, NULL
, NULL
);
2164 backend_query_free(data
.sai_q
);
2171 * _NO_RESOURCES - no new id or out of disk space
2172 * _BACKEND_READONLY - persistent backend is read-only
2175 object_snapshot_do_take(uint32_t instid
, const char *inst_name
,
2176 uint32_t svcid
, const char *svc_name
,
2177 backend_tx_t
**tx_out
, uint32_t *snapid_out
)
2183 char *svc_name_alloc
= NULL
;
2184 char *inst_name_alloc
= NULL
;
2187 result
= backend_tx_begin(BACKEND_TYPE_NORMAL
, &tx
);
2188 if (result
!= REP_PROTOCOL_SUCCESS
)
2191 snapid
= backend_new_id(tx
, BACKEND_ID_SNAPSHOT
);
2193 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
2197 if (svc_name
== NULL
) {
2198 q
= backend_query_alloc();
2199 backend_query_add(q
,
2200 "SELECT svc_name FROM service_tbl "
2201 "WHERE (svc_id = %d)", svcid
);
2202 result
= backend_tx_run(tx
, q
, object_copy_string
,
2204 backend_query_free(q
);
2206 svc_name
= svc_name_alloc
;
2208 if (result
== REP_PROTOCOL_DONE
) {
2209 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
2212 if (result
== REP_PROTOCOL_SUCCESS
&& svc_name
== NULL
)
2213 backend_panic("unable to find name for svc id %d\n",
2216 if (result
!= REP_PROTOCOL_SUCCESS
)
2220 if (inst_name
== NULL
) {
2221 q
= backend_query_alloc();
2222 backend_query_add(q
,
2223 "SELECT instance_name FROM instance_tbl "
2224 "WHERE (instance_id = %d)", instid
);
2225 result
= backend_tx_run(tx
, q
, object_copy_string
,
2227 backend_query_free(q
);
2229 inst_name
= inst_name_alloc
;
2231 if (result
== REP_PROTOCOL_DONE
) {
2232 result
= REP_PROTOCOL_FAIL_NO_RESOURCES
;
2236 if (result
== REP_PROTOCOL_SUCCESS
&& inst_name
== NULL
)
2238 "unable to find name for instance id %d\n", instid
);
2240 if (result
!= REP_PROTOCOL_SUCCESS
)
2244 result
= object_snapshot_add_level(tx
, snapid
, 1,
2245 svcid
, svc_name
, instid
, inst_name
);
2247 if (result
!= REP_PROTOCOL_SUCCESS
)
2250 result
= object_snapshot_add_level(tx
, snapid
, 2,
2251 svcid
, svc_name
, 0, NULL
);
2253 if (result
!= REP_PROTOCOL_SUCCESS
)
2256 *snapid_out
= snapid
;
2259 free(svc_name_alloc
);
2260 free(inst_name_alloc
);
2262 return (REP_PROTOCOL_SUCCESS
);
2265 backend_tx_rollback(tx
);
2266 free(svc_name_alloc
);
2267 free(inst_name_alloc
);
2273 * _TYPE_MISMATCH - pp is not an instance
2274 * _NO_RESOURCES - no new id or out of disk space
2275 * _BACKEND_READONLY - persistent backend is read-only
2278 object_snapshot_take_new(rc_node_t
*pp
,
2279 const char *svc_name
, const char *inst_name
,
2280 const char *name
, rc_node_t
**outp
)
2282 rc_node_lookup_t
*insti
= &pp
->rn_id
;
2284 uint32_t instid
= insti
->rl_main_id
;
2285 uint32_t svcid
= insti
->rl_ids
[ID_SERVICE
];
2286 uint32_t snapid
= 0;
2287 backend_tx_t
*tx
= NULL
;
2292 if (insti
->rl_type
!= REP_PROTOCOL_ENTITY_INSTANCE
)
2293 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
2295 result
= object_snapshot_do_take(instid
, inst_name
, svcid
, svc_name
,
2297 if (result
!= REP_PROTOCOL_SUCCESS
)
2300 if ((result
= object_do_create(tx
, &ci
, pp
,
2301 REP_PROTOCOL_ENTITY_SNAPSHOT
, name
, &np
)) != REP_PROTOCOL_SUCCESS
) {
2302 backend_tx_rollback(tx
);
2307 * link the new object to the new snapshot.
2309 np
->rn_snapshot_id
= snapid
;
2311 result
= backend_tx_run_update(tx
,
2312 "UPDATE snapshot_lnk_tbl SET lnk_snap_id = %d WHERE lnk_id = %d;",
2313 snapid
, ci
.ci_base_nl
.rl_main_id
);
2314 if (result
!= REP_PROTOCOL_SUCCESS
) {
2315 backend_tx_rollback(tx
);
2316 rc_node_destroy(np
);
2319 result
= backend_tx_commit(tx
);
2320 if (result
!= REP_PROTOCOL_SUCCESS
) {
2321 rc_node_destroy(np
);
2325 *outp
= rc_node_setup(np
, &ci
.ci_base_nl
, name
, ci
.ci_parent
);
2326 return (REP_PROTOCOL_SUCCESS
);
2331 * _TYPE_MISMATCH - pp is not an instance
2332 * _NO_RESOURCES - no new id or out of disk space
2333 * _BACKEND_READONLY - persistent backend is read-only
2336 object_snapshot_attach(rc_node_lookup_t
*snapi
, uint32_t *snapid_ptr
,
2339 uint32_t svcid
= snapi
->rl_ids
[ID_SERVICE
];
2340 uint32_t instid
= snapi
->rl_ids
[ID_INSTANCE
];
2341 uint32_t snapid
= *snapid_ptr
;
2342 uint32_t oldsnapid
= 0;
2343 backend_tx_t
*tx
= NULL
;
2350 if (snapi
->rl_type
!= REP_PROTOCOL_ENTITY_SNAPSHOT
)
2351 return (REP_PROTOCOL_FAIL_TYPE_MISMATCH
);
2354 /* first, check that we're actually out of date */
2355 if (object_check_snapshot(snapid
) == REP_PROTOCOL_SUCCESS
)
2356 return (REP_PROTOCOL_SUCCESS
);
2358 result
= object_snapshot_do_take(instid
, NULL
,
2359 svcid
, NULL
, &tx
, &snapid
);
2360 if (result
!= REP_PROTOCOL_SUCCESS
)
2363 result
= backend_tx_begin(BACKEND_TYPE_NORMAL
, &tx
);
2364 if (result
!= REP_PROTOCOL_SUCCESS
)
2368 q
= backend_query_alloc();
2369 backend_query_add(q
,
2370 "SELECT lnk_snap_id FROM snapshot_lnk_tbl WHERE lnk_id = %d; "
2371 "UPDATE snapshot_lnk_tbl SET lnk_snap_id = %d WHERE lnk_id = %d;",
2372 snapi
->rl_main_id
, snapid
, snapi
->rl_main_id
);
2373 result
= backend_tx_run_single_int(tx
, q
, &oldsnapid
);
2374 backend_query_free(q
);
2376 if (result
== REP_PROTOCOL_FAIL_NOT_FOUND
) {
2377 backend_tx_rollback(tx
);
2378 backend_panic("unable to find snapshot id %d",
2381 if (result
!= REP_PROTOCOL_SUCCESS
)
2385 * Now we use the delete stack to handle the possible unreferencing
2388 (void) memset(&dip
, 0, sizeof (dip
));
2390 dip
.di_np_tx
= NULL
; /* no need for non-persistant backend */
2392 if ((result
= delete_stack_push(&dip
, BACKEND_TYPE_NORMAL
,
2393 &snaplevel_tbl_delete
, oldsnapid
, 0)) != REP_PROTOCOL_SUCCESS
)
2396 while (delete_stack_pop(&dip
, &de
)) {
2397 result
= (*de
.de_cb
)(&dip
, &de
);
2398 if (result
!= REP_PROTOCOL_SUCCESS
)
2402 result
= backend_tx_commit(tx
);
2403 if (result
!= REP_PROTOCOL_SUCCESS
)
2406 delete_stack_cleanup(&dip
);
2407 *snapid_ptr
= snapid
;
2408 return (REP_PROTOCOL_SUCCESS
);
2411 backend_tx_rollback(tx
);
2412 delete_stack_cleanup(&dip
);