]>
Commit | Line | Data |
---|---|---|
98e88b5b RM |
1 | /* Copyright (C) 2016 Hewlett Packard Enterprise Development LP |
2 | * Copyright (C) 2016, IBM | |
f1ab6e06 RM |
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 | set_op_create(struct ovsdb_datum *datum, enum set_op_type type) | |
40 | { | |
41 | struct set_op *set_op = xmalloc(sizeof *set_op); | |
42 | set_op->node.hash = 0; | |
43 | set_op->node.next = HMAP_NODE_NULL; | |
44 | set_op->datum = datum; | |
45 | set_op->type = type; | |
46 | return set_op; | |
47 | } | |
48 | ||
49 | static void | |
50 | set_op_destroy_datum(struct set_op *set_op, const struct ovsdb_type *type) | |
51 | { | |
52 | if (set_op->type == SET_OP_DELETE){ | |
53 | struct ovsdb_type type_ = *type; | |
54 | type_.value.type = OVSDB_TYPE_VOID; | |
55 | ovsdb_datum_destroy(set_op->datum, &type_); | |
56 | } else { | |
57 | ovsdb_datum_destroy(set_op->datum, type); | |
58 | } | |
59 | free(set_op->datum); | |
60 | set_op->datum = NULL; | |
61 | } | |
62 | ||
63 | void | |
64 | set_op_destroy(struct set_op *set_op, const struct ovsdb_type *type) | |
65 | { | |
66 | set_op_destroy_datum(set_op, type); | |
67 | free(set_op); | |
68 | } | |
69 | ||
70 | struct ovsdb_datum* | |
71 | set_op_datum(const struct set_op *set_op) | |
72 | { | |
73 | return set_op->datum; | |
74 | } | |
75 | ||
76 | enum set_op_type | |
77 | set_op_type(const struct set_op *set_op) | |
78 | { | |
79 | return set_op->type; | |
80 | } | |
81 | ||
82 | struct set_op_list* | |
83 | set_op_list_create(void) | |
84 | { | |
85 | struct set_op_list *list = xmalloc(sizeof *list); | |
86 | hmap_init(&list->hmap); | |
87 | return list; | |
88 | } | |
89 | ||
90 | void | |
91 | set_op_list_destroy(struct set_op_list *list, const struct ovsdb_type *type) | |
92 | { | |
93 | struct set_op *set_op, *next; | |
94 | HMAP_FOR_EACH_SAFE (set_op, next, node, &list->hmap) { | |
95 | set_op_destroy(set_op, type); | |
96 | } | |
97 | hmap_destroy(&list->hmap); | |
98 | free(list); | |
99 | } | |
100 | ||
101 | static struct set_op* | |
102 | 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 | struct set_op *found = NULL; | |
106 | struct set_op *old; | |
107 | HMAP_FOR_EACH_WITH_HASH(old, node, hash, &list->hmap) { | |
108 | if (ovsdb_atom_equals(&old->datum->keys[0], &set_op->datum->keys[0], | |
109 | type->key.type)) { | |
110 | found = old; | |
111 | break; | |
112 | } | |
113 | } | |
114 | 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 | 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 | hash = ovsdb_atom_hash(&set_op->datum->keys[0], type->key.type, 0); | |
130 | prev_set_op = set_op_list_find(list, set_op, type, hash); | |
131 | if (prev_set_op == NULL){ | |
132 | hmap_insert(&list->hmap, &set_op->node, hash); | |
133 | } else { | |
134 | if (prev_set_op->type == SET_OP_INSERT && | |
135 | set_op->type == SET_OP_DELETE) { | |
136 | /* These operations cancel each other out. */ | |
137 | hmap_remove(&list->hmap, &prev_set_op->node); | |
138 | set_op_destroy(prev_set_op, type); | |
139 | set_op_destroy(set_op, type); | |
140 | } else { | |
141 | /* For any other case, the new update operation replaces | |
142 | * the previous update operation. */ | |
143 | set_op_destroy_datum(prev_set_op, type); | |
144 | prev_set_op->type = set_op->type; | |
145 | prev_set_op->datum = set_op->datum; | |
146 | free(set_op); | |
147 | } | |
148 | } | |
149 | } | |
150 | ||
151 | struct set_op* | |
152 | set_op_list_first(struct set_op_list *list) | |
153 | { | |
154 | struct hmap_node *node = hmap_first(&list->hmap); | |
155 | if (node == NULL) { | |
156 | return NULL; | |
157 | } | |
158 | struct set_op *set_op = CONTAINER_OF(node, struct set_op, node); | |
159 | return set_op; | |
160 | } | |
161 | ||
162 | struct set_op* | |
163 | set_op_list_next(struct set_op_list *list, struct set_op *set_op) | |
164 | { | |
165 | struct hmap_node *node = hmap_next(&list->hmap, &set_op->node); | |
166 | if (node == NULL) { | |
167 | return NULL; | |
168 | } | |
169 | struct set_op *next = CONTAINER_OF(node, struct set_op, node); | |
170 | return next; | |
171 | } |