Branch data Line data Source code
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 "openvswitch/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 : 5 : map_op_create(struct ovsdb_datum *datum, enum map_op_type type)
41 : : {
42 : 5 : struct map_op *map_op = xmalloc(sizeof *map_op);
43 : 5 : map_op->node.hash = 0;
44 : 5 : map_op->node.next = HMAP_NODE_NULL;
45 : 5 : map_op->datum = datum;
46 : 5 : map_op->type = type;
47 : 5 : return map_op;
48 : : }
49 : :
50 : : static void
51 : 5 : map_op_destroy_datum(struct map_op *map_op, const struct ovsdb_type *type)
52 : : {
53 [ + + ]: 5 : if (map_op->type == MAP_OP_DELETE){
54 : 2 : struct ovsdb_type type_ = *type;
55 : 2 : type_.value.type = OVSDB_TYPE_VOID;
56 : 2 : ovsdb_datum_destroy(map_op->datum, &type_);
57 : : } else {
58 : 3 : ovsdb_datum_destroy(map_op->datum, type);
59 : : }
60 : 5 : free(map_op->datum);
61 : 5 : map_op->datum = NULL;
62 : 5 : }
63 : :
64 : : void
65 : 5 : map_op_destroy(struct map_op *map_op, const struct ovsdb_type *type)
66 : : {
67 : 5 : map_op_destroy_datum(map_op, type);
68 : 5 : free(map_op);
69 : 5 : }
70 : :
71 : : struct ovsdb_datum*
72 : 10 : map_op_datum(const struct map_op *map_op)
73 : : {
74 : 10 : return map_op->datum;
75 : : }
76 : :
77 : : enum map_op_type
78 : 14 : map_op_type(const struct map_op *map_op)
79 : : {
80 : 14 : return map_op->type;
81 : : }
82 : :
83 : : struct map_op_list*
84 : 5 : map_op_list_create(void)
85 : : {
86 : 5 : struct map_op_list *list = xmalloc(sizeof *list);
87 : 5 : hmap_init(&list->hmap);
88 : 5 : return list;
89 : : }
90 : :
91 : : void
92 : 5 : map_op_list_destroy(struct map_op_list *list, const struct ovsdb_type *type)
93 : : {
94 : : struct map_op *map_op, *next;
95 [ + + ][ - + ]: 10 : HMAP_FOR_EACH_SAFE (map_op, next, node, &list->hmap) {
[ + + ]
96 : 5 : map_op_destroy(map_op, type);
97 : : }
98 : 5 : hmap_destroy(&list->hmap);
99 : 5 : free(list);
100 : 5 : }
101 : :
102 : : static struct map_op*
103 : 5 : 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 : 5 : struct map_op *found = NULL;
107 : : struct map_op *old;
108 [ - + ][ - + ]: 5 : HMAP_FOR_EACH_WITH_HASH(old, node, hash, &list->hmap) {
109 [ # # ]: 0 : if (ovsdb_atom_equals(&old->datum->keys[0], &map_op->datum->keys[0],
110 : : type->key.type)) {
111 : 0 : found = old;
112 : 0 : break;
113 : : }
114 : : }
115 : 5 : 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 : 5 : 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 : 5 : hash = ovsdb_atom_hash(&map_op->datum->keys[0], type->key.type, 0);
131 : 5 : prev_map_op = map_op_list_find(list, map_op, type, hash);
132 [ + - ]: 5 : if (prev_map_op == NULL){
133 : 5 : hmap_insert(&list->hmap, &map_op->node, hash);
134 : : } else {
135 [ # # ][ # # ]: 0 : if (prev_map_op->type == MAP_OP_INSERT &&
136 : 0 : map_op->type == MAP_OP_DELETE) {
137 : : /* These operations cancel each other out. */
138 : 0 : hmap_remove(&list->hmap, &prev_map_op->node);
139 : 0 : map_op_destroy(prev_map_op, type);
140 : 0 : map_op_destroy(map_op, type);
141 : : } else {
142 : : /* For any other case, the new update operation replaces
143 : : * the previous update operation. */
144 : 0 : map_op_destroy_datum(prev_map_op, type);
145 : 0 : prev_map_op->type = map_op->type;
146 : 0 : prev_map_op->datum = map_op->datum;
147 : 0 : free(map_op);
148 : : }
149 : : }
150 : 5 : }
151 : :
152 : : struct map_op*
153 : 5 : map_op_list_first(struct map_op_list *list)
154 : : {
155 : 5 : struct hmap_node *node = hmap_first(&list->hmap);
156 [ - + ]: 5 : if (node == NULL) {
157 : 0 : return NULL;
158 : : }
159 : 5 : struct map_op *map_op = CONTAINER_OF(node, struct map_op, node);
160 : 5 : return map_op;
161 : : }
162 : :
163 : : struct map_op*
164 : 5 : map_op_list_next(struct map_op_list *list, struct map_op *map_op)
165 : : {
166 : 5 : struct hmap_node *node = hmap_next(&list->hmap, &map_op->node);
167 [ + - ]: 5 : if (node == NULL) {
168 : 5 : return NULL;
169 : : }
170 : 0 : struct map_op *next = CONTAINER_OF(node, struct map_op, node);
171 : 0 : return next;
172 : : }
|