Branch data Line data Source code
1 : : /* Copyright (C) 2016 Hewlett Packard Enterprise Development LP
2 : : * Copyright (C) 2016, IBM
3 : : * All Rights Reserved.
4 : : *
5 : : * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 : : * not use this file except in compliance with the License. You may obtain
7 : : * a copy of the License at
8 : : *
9 : : * http://www.apache.org/licenses/LICENSE-2.0
10 : : *
11 : : * Unless required by applicable law or agreed to in writing, software
12 : : * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 : : * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 : : * License for the specific language governing permissions and limitations
15 : : * under the License.
16 : : */
17 : :
18 : : #include <config.h>
19 : : #include "ovsdb-set-op.h"
20 : : #include "util.h"
21 : :
22 : : /* Set Operation: a Partial Set Update */
23 : : struct set_op {
24 : : struct hmap_node node;
25 : : struct ovsdb_datum *datum;
26 : : enum set_op_type type;
27 : : };
28 : :
29 : : /* List of Set Operations */
30 : : struct set_op_list {
31 : : struct hmap hmap;
32 : : };
33 : :
34 : : static void set_op_destroy_datum(struct set_op *, const struct ovsdb_type *);
35 : : static struct set_op *set_op_list_find(struct set_op_list *, struct set_op *,
36 : : const struct ovsdb_type *, size_t);
37 : :
38 : : struct set_op*
39 : 60 : set_op_create(struct ovsdb_datum *datum, enum set_op_type type)
40 : : {
41 : 60 : struct set_op *set_op = xmalloc(sizeof *set_op);
42 : 60 : set_op->node.hash = 0;
43 : 60 : set_op->node.next = HMAP_NODE_NULL;
44 : 60 : set_op->datum = datum;
45 : 60 : set_op->type = type;
46 : 60 : return set_op;
47 : : }
48 : :
49 : : static void
50 : 60 : set_op_destroy_datum(struct set_op *set_op, const struct ovsdb_type *type)
51 : : {
52 [ + + ]: 60 : if (set_op->type == SET_OP_DELETE){
53 : 20 : struct ovsdb_type type_ = *type;
54 : 20 : type_.value.type = OVSDB_TYPE_VOID;
55 : 20 : ovsdb_datum_destroy(set_op->datum, &type_);
56 : : } else {
57 : 40 : ovsdb_datum_destroy(set_op->datum, type);
58 : : }
59 : 60 : free(set_op->datum);
60 : 60 : set_op->datum = NULL;
61 : 60 : }
62 : :
63 : : void
64 : 60 : set_op_destroy(struct set_op *set_op, const struct ovsdb_type *type)
65 : : {
66 : 60 : set_op_destroy_datum(set_op, type);
67 : 60 : free(set_op);
68 : 60 : }
69 : :
70 : : struct ovsdb_datum*
71 : 79 : set_op_datum(const struct set_op *set_op)
72 : : {
73 : 79 : return set_op->datum;
74 : : }
75 : :
76 : : enum set_op_type
77 : 60 : set_op_type(const struct set_op *set_op)
78 : : {
79 : 60 : return set_op->type;
80 : : }
81 : :
82 : : struct set_op_list*
83 : 54 : set_op_list_create(void)
84 : : {
85 : 54 : struct set_op_list *list = xmalloc(sizeof *list);
86 : 54 : hmap_init(&list->hmap);
87 : 54 : return list;
88 : : }
89 : :
90 : : void
91 : 54 : set_op_list_destroy(struct set_op_list *list, const struct ovsdb_type *type)
92 : : {
93 : : struct set_op *set_op, *next;
94 [ + + ][ - + ]: 114 : HMAP_FOR_EACH_SAFE (set_op, next, node, &list->hmap) {
[ + + ]
95 : 60 : set_op_destroy(set_op, type);
96 : : }
97 : 54 : hmap_destroy(&list->hmap);
98 : 54 : free(list);
99 : 54 : }
100 : :
101 : : static struct set_op*
102 : 60 : set_op_list_find(struct set_op_list *list, struct set_op *set_op,
103 : : const struct ovsdb_type *type, size_t hash)
104 : : {
105 : 60 : struct set_op *found = NULL;
106 : : struct set_op *old;
107 [ - + ][ - + ]: 60 : HMAP_FOR_EACH_WITH_HASH(old, node, hash, &list->hmap) {
108 [ # # ]: 0 : if (ovsdb_atom_equals(&old->datum->keys[0], &set_op->datum->keys[0],
109 : : type->key.type)) {
110 : 0 : found = old;
111 : 0 : break;
112 : : }
113 : : }
114 : 60 : return found;
115 : : }
116 : :
117 : : /* Inserts 'set_op' into 'list'. Makes sure that any conflict with a previous
118 : : * set operation is resolved, so only one set operation is possible on each key
119 : : * per transactions. 'type' must be the type of the column over which the set
120 : : * operation will be applied. */
121 : : void
122 : 60 : set_op_list_add(struct set_op_list *list, struct set_op *set_op,
123 : : const struct ovsdb_type *type)
124 : : {
125 : : /* Check if there is a previous update with the same key. */
126 : : size_t hash;
127 : : struct set_op *prev_set_op;
128 : :
129 : 60 : hash = ovsdb_atom_hash(&set_op->datum->keys[0], type->key.type, 0);
130 : 60 : prev_set_op = set_op_list_find(list, set_op, type, hash);
131 [ + - ]: 60 : if (prev_set_op == NULL){
132 : 60 : hmap_insert(&list->hmap, &set_op->node, hash);
133 : : } else {
134 [ # # ][ # # ]: 0 : if (prev_set_op->type == SET_OP_INSERT &&
135 : 0 : set_op->type == SET_OP_DELETE) {
136 : : /* These operations cancel each other out. */
137 : 0 : hmap_remove(&list->hmap, &prev_set_op->node);
138 : 0 : set_op_destroy(prev_set_op, type);
139 : 0 : set_op_destroy(set_op, type);
140 : : } else {
141 : : /* For any other case, the new update operation replaces
142 : : * the previous update operation. */
143 : 0 : set_op_destroy_datum(prev_set_op, type);
144 : 0 : prev_set_op->type = set_op->type;
145 : 0 : prev_set_op->datum = set_op->datum;
146 : 0 : free(set_op);
147 : : }
148 : : }
149 : 60 : }
150 : :
151 : : struct set_op*
152 : 54 : set_op_list_first(struct set_op_list *list)
153 : : {
154 : 54 : struct hmap_node *node = hmap_first(&list->hmap);
155 [ - + ]: 54 : if (node == NULL) {
156 : 0 : return NULL;
157 : : }
158 : 54 : struct set_op *set_op = CONTAINER_OF(node, struct set_op, node);
159 : 54 : return set_op;
160 : : }
161 : :
162 : : struct set_op*
163 : 60 : set_op_list_next(struct set_op_list *list, struct set_op *set_op)
164 : : {
165 : 60 : struct hmap_node *node = hmap_next(&list->hmap, &set_op->node);
166 [ + + ]: 60 : if (node == NULL) {
167 : 54 : return NULL;
168 : : }
169 : 6 : struct set_op *next = CONTAINER_OF(node, struct set_op, node);
170 : 6 : return next;
171 : : }
|