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