1 /* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
21 #include "condition.h"
23 #include "openvswitch/json.h"
25 #include "ovsdb-data.h"
26 #include "ovsdb-error.h"
27 #include "ovsdb-parser.h"
35 #include "transaction.h"
37 struct ovsdb_execution
{
39 const struct ovsdb_session
*session
;
40 struct ovsdb_txn
*txn
;
41 struct ovsdb_symbol_table
*symtab
;
47 long long int elapsed_msec
;
48 long long int timeout_msec
;
51 typedef struct ovsdb_error
*ovsdb_operation_executor(struct ovsdb_execution
*,
52 struct ovsdb_parser
*,
55 static ovsdb_operation_executor ovsdb_execute_insert
;
56 static ovsdb_operation_executor ovsdb_execute_select
;
57 static ovsdb_operation_executor ovsdb_execute_update
;
58 static ovsdb_operation_executor ovsdb_execute_mutate
;
59 static ovsdb_operation_executor ovsdb_execute_delete
;
60 static ovsdb_operation_executor ovsdb_execute_wait
;
61 static ovsdb_operation_executor ovsdb_execute_commit
;
62 static ovsdb_operation_executor ovsdb_execute_abort
;
63 static ovsdb_operation_executor ovsdb_execute_comment
;
64 static ovsdb_operation_executor ovsdb_execute_assert
;
66 static ovsdb_operation_executor
*
67 lookup_executor(const char *name
, bool *read_only
)
69 struct ovsdb_operation
{
72 ovsdb_operation_executor
*executor
;
75 static const struct ovsdb_operation operations
[] = {
76 { "insert", false, ovsdb_execute_insert
},
77 { "select", true, ovsdb_execute_select
},
78 { "update", false, ovsdb_execute_update
},
79 { "mutate", false, ovsdb_execute_mutate
},
80 { "delete", false, ovsdb_execute_delete
},
81 { "wait", true, ovsdb_execute_wait
},
82 { "commit", false, ovsdb_execute_commit
},
83 { "abort", true, ovsdb_execute_abort
},
84 { "comment", true, ovsdb_execute_comment
},
85 { "assert", true, ovsdb_execute_assert
},
90 for (i
= 0; i
< ARRAY_SIZE(operations
); i
++) {
91 const struct ovsdb_operation
*c
= &operations
[i
];
92 if (!strcmp(c
->name
, name
)) {
93 *read_only
= c
->read_only
;
101 ovsdb_execute(struct ovsdb
*db
, const struct ovsdb_session
*session
,
102 const struct json
*params
, bool read_only
,
103 const char *role
, const char *id
,
104 long long int elapsed_msec
, long long int *timeout_msec
)
106 struct ovsdb_execution x
;
107 struct ovsdb_error
*error
;
108 struct json
*results
;
112 if (params
->type
!= JSON_ARRAY
113 || !params
->u
.array
.n
114 || params
->u
.array
.elems
[0]->type
!= JSON_STRING
115 || strcmp(params
->u
.array
.elems
[0]->u
.string
, db
->schema
->name
)) {
116 if (params
->type
!= JSON_ARRAY
) {
117 error
= ovsdb_syntax_error(params
, NULL
, "array expected");
119 error
= ovsdb_syntax_error(params
, NULL
, "database name expected "
120 "as first parameter");
123 results
= ovsdb_error_to_json(error
);
124 ovsdb_error_destroy(error
);
130 x
.txn
= ovsdb_txn_create(db
);
131 x
.symtab
= ovsdb_symbol_table_create();
135 x
.elapsed_msec
= elapsed_msec
;
136 x
.timeout_msec
= LLONG_MAX
;
139 results
= json_array_create_empty();
140 n_operations
= params
->u
.array
.n
- 1;
142 for (i
= 1; i
<= n_operations
; i
++) {
143 struct json
*operation
= params
->u
.array
.elems
[i
];
144 struct ovsdb_error
*parse_error
;
145 struct ovsdb_parser parser
;
147 const struct json
*op
;
148 const char *op_name
= NULL
;
151 /* Parse and execute operation. */
152 ovsdb_parser_init(&parser
, operation
,
153 "ovsdb operation %"PRIuSIZE
" of %"PRIuSIZE
, i
,
155 op
= ovsdb_parser_member(&parser
, "op", OP_ID
);
156 result
= json_object_create();
158 op_name
= json_string(op
);
159 ovsdb_operation_executor
*executor
= lookup_executor(op_name
, &ro
);
161 error
= executor(&x
, &parser
, result
);
163 ovsdb_parser_raise_error(&parser
, "No operation \"%s\"",
167 ovs_assert(ovsdb_parser_has_error(&parser
));
170 /* A parse error overrides any other error.
171 * An error overrides any other result. */
172 parse_error
= ovsdb_parser_finish(&parser
);
174 ovsdb_error_destroy(error
);
177 /* Create read-only violation error if there is one. */
178 if (!error
&& read_only
&& !ro
) {
179 error
= ovsdb_error("not allowed",
180 "%s operation not allowed when "
181 "database server is in read only mode",
185 json_destroy(result
);
186 result
= ovsdb_error_to_json(error
);
188 if (error
&& !strcmp(ovsdb_error_get_tag(error
), "not supported")
190 ovsdb_txn_abort(x
.txn
);
191 *timeout_msec
= x
.timeout_msec
;
193 json_destroy(result
);
194 json_destroy(results
);
199 /* Add result to array. */
200 json_array_add(results
, result
);
207 error
= ovsdb_txn_commit(x
.txn
, x
.durable
);
209 json_array_add(results
, ovsdb_error_to_json(error
));
212 ovsdb_txn_abort(x
.txn
);
215 while (json_array(results
)->n
< n_operations
) {
216 json_array_add(results
, json_null_create());
220 ovsdb_error_destroy(error
);
221 ovsdb_symbol_table_destroy(x
.symtab
);
226 static struct ovsdb_error
*
227 ovsdb_execute_commit(struct ovsdb_execution
*x
, struct ovsdb_parser
*parser
,
228 struct json
*result OVS_UNUSED
)
230 const struct json
*durable
;
232 durable
= ovsdb_parser_member(parser
, "durable", OP_BOOLEAN
);
233 if (durable
&& json_boolean(durable
)) {
239 static struct ovsdb_error
*
240 ovsdb_execute_abort(struct ovsdb_execution
*x OVS_UNUSED
,
241 struct ovsdb_parser
*parser OVS_UNUSED
,
242 struct json
*result OVS_UNUSED
)
244 return ovsdb_error("aborted", "aborted by request");
247 static struct ovsdb_table
*
248 parse_table(struct ovsdb_execution
*x
,
249 struct ovsdb_parser
*parser
, const char *member
)
251 struct ovsdb_table
*table
;
252 const char *table_name
;
253 const struct json
*json
;
255 json
= ovsdb_parser_member(parser
, member
, OP_ID
);
259 table_name
= json_string(json
);
261 table
= shash_find_data(&x
->db
->tables
, table_name
);
263 ovsdb_parser_raise_error(parser
, "No table named %s.", table_name
);
268 static OVS_WARN_UNUSED_RESULT
struct ovsdb_error
*
269 parse_row(const struct json
*json
, const struct ovsdb_table
*table
,
270 struct ovsdb_symbol_table
*symtab
,
271 struct ovsdb_row
**rowp
, struct ovsdb_column_set
*columns
)
273 struct ovsdb_error
*error
;
274 struct ovsdb_row
*row
;
279 return OVSDB_BUG("null table");
282 return OVSDB_BUG("null row");
285 row
= ovsdb_row_create(table
);
286 error
= ovsdb_row_from_json(row
, json
, symtab
, columns
);
288 ovsdb_row_destroy(row
);
296 static struct ovsdb_error
*
297 ovsdb_execute_insert(struct ovsdb_execution
*x
, struct ovsdb_parser
*parser
,
300 struct ovsdb_table
*table
;
301 struct ovsdb_row
*row
= NULL
;
302 const struct json
*uuid_name
, *row_json
;
303 struct ovsdb_error
*error
;
304 struct uuid row_uuid
;
306 table
= parse_table(x
, parser
, "table");
307 uuid_name
= ovsdb_parser_member(parser
, "uuid-name", OP_ID
| OP_OPTIONAL
);
308 row_json
= ovsdb_parser_member(parser
, "row", OP_OBJECT
);
309 error
= ovsdb_parser_get_error(parser
);
315 struct ovsdb_symbol
*symbol
;
317 symbol
= ovsdb_symbol_table_insert(x
->symtab
, json_string(uuid_name
));
318 if (symbol
->created
) {
319 return ovsdb_syntax_error(uuid_name
, "duplicate uuid-name",
320 "This \"uuid-name\" appeared on an "
321 "earlier \"insert\" operation.");
323 row_uuid
= symbol
->uuid
;
324 symbol
->created
= true;
326 uuid_generate(&row_uuid
);
330 error
= parse_row(row_json
, table
, x
->symtab
, &row
, NULL
);
333 /* Check constraints for columns not included in "row", in case the
334 * default values do not satisfy the constraints. We could check only
335 * the columns that have their default values by supplying an
336 * ovsdb_column_set to parse_row() above, but I suspect that this is
338 const struct shash_node
*node
;
340 SHASH_FOR_EACH (node
, &table
->schema
->columns
) {
341 const struct ovsdb_column
*column
= node
->data
;
342 const struct ovsdb_datum
*datum
= &row
->fields
[column
->index
];
344 /* If there are 0 keys or pairs, there's nothing to check.
345 * If there is 1, it might be a default value.
346 * If there are more, it can't be a default value, so the value has
347 * already been checked. */
349 error
= ovsdb_datum_check_constraints(datum
, &column
->type
);
357 if (!error
&& !ovsdb_rbac_insert(x
->db
, table
, row
, x
->role
, x
->id
)) {
358 error
= ovsdb_perm_error("RBAC rules for client \"%s\" role \"%s\" "
359 "prohibit row insertion into table \"%s\".",
360 x
->id
, x
->role
, table
->schema
->name
);
364 *ovsdb_row_get_uuid_rw(row
) = row_uuid
;
365 ovsdb_txn_row_insert(x
->txn
, row
);
366 json_object_put(result
, "uuid",
367 ovsdb_datum_to_json(&row
->fields
[OVSDB_COL_UUID
],
370 ovsdb_row_destroy(row
);
375 static struct ovsdb_error
*
376 ovsdb_execute_select(struct ovsdb_execution
*x
, struct ovsdb_parser
*parser
,
379 struct ovsdb_table
*table
;
380 const struct json
*where
, *columns_json
, *sort_json
;
381 struct ovsdb_condition condition
= OVSDB_CONDITION_INITIALIZER(&condition
);
382 struct ovsdb_column_set columns
= OVSDB_COLUMN_SET_INITIALIZER
;
383 struct ovsdb_column_set sort
= OVSDB_COLUMN_SET_INITIALIZER
;
384 struct ovsdb_error
*error
;
386 table
= parse_table(x
, parser
, "table");
387 where
= ovsdb_parser_member(parser
, "where", OP_ARRAY
);
388 columns_json
= ovsdb_parser_member(parser
, "columns",
389 OP_ARRAY
| OP_OPTIONAL
);
390 sort_json
= ovsdb_parser_member(parser
, "sort", OP_ARRAY
| OP_OPTIONAL
);
392 error
= ovsdb_parser_get_error(parser
);
394 error
= ovsdb_condition_from_json(table
->schema
, where
, x
->symtab
,
398 error
= ovsdb_column_set_from_json(columns_json
, table
->schema
,
402 error
= ovsdb_column_set_from_json(sort_json
, table
->schema
, &sort
);
405 struct ovsdb_row_set rows
= OVSDB_ROW_SET_INITIALIZER
;
407 ovsdb_query_distinct(table
, &condition
, &columns
, &rows
);
408 ovsdb_row_set_sort(&rows
, &sort
);
409 json_object_put(result
, "rows",
410 ovsdb_row_set_to_json(&rows
, &columns
));
412 ovsdb_row_set_destroy(&rows
);
415 ovsdb_column_set_destroy(&columns
);
416 ovsdb_column_set_destroy(&sort
);
417 ovsdb_condition_destroy(&condition
);
422 struct update_row_cbdata
{
424 struct ovsdb_txn
*txn
;
425 const struct ovsdb_row
*row
;
426 const struct ovsdb_column_set
*columns
;
432 update_row_cb(const struct ovsdb_row
*row
, void *ur_
)
434 struct update_row_cbdata
*ur
= ur_
;
437 if (!ovsdb_row_equal_columns(row
, ur
->row
, ur
->columns
)) {
438 ovsdb_row_update_columns(ovsdb_txn_row_modify(ur
->txn
, row
),
439 ur
->row
, ur
->columns
);
445 static struct ovsdb_error
*
446 ovsdb_execute_update(struct ovsdb_execution
*x
, struct ovsdb_parser
*parser
,
449 struct ovsdb_table
*table
;
450 const struct json
*where
, *row_json
;
451 struct ovsdb_condition condition
= OVSDB_CONDITION_INITIALIZER(&condition
);
452 struct ovsdb_column_set columns
= OVSDB_COLUMN_SET_INITIALIZER
;
453 struct ovsdb_row
*row
= NULL
;
454 struct update_row_cbdata ur
;
455 struct ovsdb_error
*error
;
457 table
= parse_table(x
, parser
, "table");
458 where
= ovsdb_parser_member(parser
, "where", OP_ARRAY
);
459 row_json
= ovsdb_parser_member(parser
, "row", OP_OBJECT
);
460 error
= ovsdb_parser_get_error(parser
);
462 error
= parse_row(row_json
, table
, x
->symtab
, &row
, &columns
);
467 for (i
= 0; i
< columns
.n_columns
; i
++) {
468 const struct ovsdb_column
*column
= columns
.columns
[i
];
470 if (!column
->mutable) {
471 error
= ovsdb_syntax_error(parser
->json
,
472 "constraint violation",
473 "Cannot update immutable column %s "
475 column
->name
, table
->schema
->name
);
481 error
= ovsdb_condition_from_json(table
->schema
, where
, x
->symtab
,
488 ur
.columns
= &columns
;
489 if (ovsdb_rbac_update(x
->db
, table
, &columns
, &condition
, x
->role
,
491 ovsdb_query(table
, &condition
, update_row_cb
, &ur
);
493 error
= ovsdb_perm_error("RBAC rules for client \"%s\" role "
494 "\"%s\" prohibit modification of "
496 x
->id
, x
->role
, table
->schema
->name
);
498 json_object_put(result
, "count", json_integer_create(ur
.n_matches
));
501 ovsdb_row_destroy(row
);
502 ovsdb_column_set_destroy(&columns
);
503 ovsdb_condition_destroy(&condition
);
508 struct mutate_row_cbdata
{
510 struct ovsdb_txn
*txn
;
511 const struct ovsdb_mutation_set
*mutations
;
512 struct ovsdb_error
**error
;
516 mutate_row_cb(const struct ovsdb_row
*row
, void *mr_
)
518 struct mutate_row_cbdata
*mr
= mr_
;
521 *mr
->error
= ovsdb_mutation_set_execute(ovsdb_txn_row_modify(mr
->txn
, row
),
523 return *mr
->error
== NULL
;
526 static struct ovsdb_error
*
527 ovsdb_execute_mutate(struct ovsdb_execution
*x
, struct ovsdb_parser
*parser
,
530 struct ovsdb_table
*table
;
531 const struct json
*where
;
532 const struct json
*mutations_json
;
533 struct ovsdb_condition condition
= OVSDB_CONDITION_INITIALIZER(&condition
);
534 struct ovsdb_mutation_set mutations
= OVSDB_MUTATION_SET_INITIALIZER
;
535 struct ovsdb_row
*row
= NULL
;
536 struct mutate_row_cbdata mr
;
537 struct ovsdb_error
*error
;
539 table
= parse_table(x
, parser
, "table");
540 where
= ovsdb_parser_member(parser
, "where", OP_ARRAY
);
541 mutations_json
= ovsdb_parser_member(parser
, "mutations", OP_ARRAY
);
542 error
= ovsdb_parser_get_error(parser
);
544 error
= ovsdb_mutation_set_from_json(table
->schema
, mutations_json
,
545 x
->symtab
, &mutations
);
548 error
= ovsdb_condition_from_json(table
->schema
, where
, x
->symtab
,
554 mr
.mutations
= &mutations
;
556 if (ovsdb_rbac_mutate(x
->db
, table
, &mutations
, &condition
, x
->role
,
558 ovsdb_query(table
, &condition
, mutate_row_cb
, &mr
);
560 error
= ovsdb_perm_error("RBAC rules for client \"%s\" role "
561 "\"%s\" prohibit mutate operation on "
563 x
->id
, x
->role
, table
->schema
->name
);
565 json_object_put(result
, "count", json_integer_create(mr
.n_matches
));
568 ovsdb_row_destroy(row
);
569 ovsdb_mutation_set_destroy(&mutations
);
570 ovsdb_condition_destroy(&condition
);
575 struct delete_row_cbdata
{
577 const struct ovsdb_table
*table
;
578 struct ovsdb_txn
*txn
;
582 delete_row_cb(const struct ovsdb_row
*row
, void *dr_
)
584 struct delete_row_cbdata
*dr
= dr_
;
587 ovsdb_txn_row_delete(dr
->txn
, row
);
592 static struct ovsdb_error
*
593 ovsdb_execute_delete(struct ovsdb_execution
*x
, struct ovsdb_parser
*parser
,
596 struct ovsdb_table
*table
;
597 const struct json
*where
;
598 struct ovsdb_condition condition
= OVSDB_CONDITION_INITIALIZER(&condition
);
599 struct ovsdb_error
*error
;
601 where
= ovsdb_parser_member(parser
, "where", OP_ARRAY
);
602 table
= parse_table(x
, parser
, "table");
603 error
= ovsdb_parser_get_error(parser
);
605 error
= ovsdb_condition_from_json(table
->schema
, where
, x
->symtab
,
609 struct delete_row_cbdata dr
;
615 if (ovsdb_rbac_delete(x
->db
, table
, &condition
, x
->role
, x
->id
)) {
616 ovsdb_query(table
, &condition
, delete_row_cb
, &dr
);
618 error
= ovsdb_perm_error("RBAC rules for client \"%s\" role "
619 "\"%s\" prohibit row deletion from "
621 x
->id
, x
->role
, table
->schema
->name
);
623 json_object_put(result
, "count", json_integer_create(dr
.n_matches
));
626 ovsdb_condition_destroy(&condition
);
631 struct wait_auxdata
{
632 struct ovsdb_row_hash
*actual
;
633 struct ovsdb_row_hash
*expected
;
638 ovsdb_execute_wait_query_cb(const struct ovsdb_row
*row
, void *aux_
)
640 struct wait_auxdata
*aux
= aux_
;
642 if (ovsdb_row_hash_contains(aux
->expected
, row
)) {
643 ovsdb_row_hash_insert(aux
->actual
, row
);
646 /* The query row isn't in the expected result set, so the actual and
647 * expected results sets definitely differ and we can short-circuit the
648 * rest of the query. */
654 static struct ovsdb_error
*
655 ovsdb_execute_wait(struct ovsdb_execution
*x
, struct ovsdb_parser
*parser
,
656 struct json
*result OVS_UNUSED
)
658 struct ovsdb_table
*table
;
659 const struct json
*timeout
, *where
, *columns_json
, *until
, *rows
;
660 struct ovsdb_condition condition
= OVSDB_CONDITION_INITIALIZER(&condition
);
661 struct ovsdb_column_set columns
= OVSDB_COLUMN_SET_INITIALIZER
;
662 struct ovsdb_row_hash expected
= OVSDB_ROW_HASH_INITIALIZER(expected
);
663 struct ovsdb_row_hash actual
= OVSDB_ROW_HASH_INITIALIZER(actual
);
664 struct ovsdb_error
*error
;
665 struct wait_auxdata aux
;
666 long long int timeout_msec
= 0;
669 timeout
= ovsdb_parser_member(parser
, "timeout", OP_NUMBER
| OP_OPTIONAL
);
670 where
= ovsdb_parser_member(parser
, "where", OP_ARRAY
);
671 columns_json
= ovsdb_parser_member(parser
, "columns",
672 OP_ARRAY
| OP_OPTIONAL
);
673 until
= ovsdb_parser_member(parser
, "until", OP_STRING
);
674 rows
= ovsdb_parser_member(parser
, "rows", OP_ARRAY
);
675 table
= parse_table(x
, parser
, "table");
676 error
= ovsdb_parser_get_error(parser
);
678 error
= ovsdb_condition_from_json(table
->schema
, where
, x
->symtab
,
682 error
= ovsdb_column_set_from_json(columns_json
, table
->schema
,
687 timeout_msec
= MIN(LLONG_MAX
, json_real(timeout
));
688 if (timeout_msec
< 0) {
689 error
= ovsdb_syntax_error(timeout
, NULL
,
690 "timeout must be nonnegative");
691 } else if (timeout_msec
< x
->timeout_msec
) {
692 x
->timeout_msec
= timeout_msec
;
695 timeout_msec
= LLONG_MAX
;
699 if (strcmp(json_string(until
), "==")
700 && strcmp(json_string(until
), "!=")) {
701 error
= ovsdb_syntax_error(until
, NULL
,
702 "\"until\" must be \"==\" or \"!=\"");
706 /* Parse "rows" into 'expected'. */
707 ovsdb_row_hash_init(&expected
, &columns
);
708 for (i
= 0; i
< rows
->u
.array
.n
; i
++) {
709 struct ovsdb_row
*row
;
711 row
= ovsdb_row_create(table
);
712 error
= ovsdb_row_from_json(row
, rows
->u
.array
.elems
[i
], x
->symtab
,
715 ovsdb_row_destroy(row
);
719 if (!ovsdb_row_hash_insert(&expected
, row
)) {
720 /* XXX Perhaps we should abort with an error or log a
722 ovsdb_row_destroy(row
);
729 ovsdb_row_hash_init(&actual
, &columns
);
730 aux
.actual
= &actual
;
731 aux
.expected
= &expected
;
733 ovsdb_query(table
, &condition
, ovsdb_execute_wait_query_cb
, &aux
);
735 /* We know that every row in 'actual' is also in 'expected'. We
736 * also know that all of the rows in 'actual' are distinct and that
737 * all of the rows in 'expected' are distinct. Therefore, if
738 * 'actual' and 'expected' have the same number of rows, then they
739 * have the same content. */
740 size_t n_actual
= ovsdb_row_hash_count(&actual
);
741 size_t n_expected
= ovsdb_row_hash_count(&expected
);
742 equal
= n_actual
== n_expected
;
744 if (!strcmp(json_string(until
), "==") != equal
) {
745 if (timeout
&& x
->elapsed_msec
>= timeout_msec
) {
746 if (x
->elapsed_msec
) {
747 error
= ovsdb_error("timed out",
748 "\"wait\" timed out after %lld ms",
751 error
= ovsdb_error("timed out",
752 "\"where\" clause test failed");
755 /* ovsdb_execute() will change this, if triggers really are
757 error
= ovsdb_error("not supported", "triggers not supported");
763 ovsdb_row_hash_destroy(&expected
, true);
764 ovsdb_row_hash_destroy(&actual
, false);
765 ovsdb_column_set_destroy(&columns
);
766 ovsdb_condition_destroy(&condition
);
771 static struct ovsdb_error
*
772 ovsdb_execute_comment(struct ovsdb_execution
*x
, struct ovsdb_parser
*parser
,
773 struct json
*result OVS_UNUSED
)
775 const struct json
*comment
;
777 comment
= ovsdb_parser_member(parser
, "comment", OP_STRING
);
781 ovsdb_txn_add_comment(x
->txn
, json_string(comment
));
786 static struct ovsdb_error
*
787 ovsdb_execute_assert(struct ovsdb_execution
*x
, struct ovsdb_parser
*parser
,
788 struct json
*result OVS_UNUSED
)
790 const struct json
*lock_name
;
792 lock_name
= ovsdb_parser_member(parser
, "lock", OP_ID
);
798 const struct ovsdb_lock_waiter
*waiter
;
800 waiter
= ovsdb_session_get_lock_waiter(x
->session
,
801 json_string(lock_name
));
802 if (waiter
&& ovsdb_lock_waiter_is_owner(waiter
)) {
807 return ovsdb_error("not owner", "Asserted lock %s not held.",
808 json_string(lock_name
));