2
* Copyright 2008, 2009 Alexandros Frantzis, Michael Iatrou
4
* This file is part of libbls.
6
* libbls is free software: you can redistribute it and/or modify it under the
7
* terms of the GNU Lesser General Public License as published by the Free Software
8
* Foundation, either version 3 of the License, or (at your option) any later
11
* libbls is distributed in the hope that it will be useful, but WITHOUT ANY
12
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16
* You should have received a copy of the GNU General Public License along with
17
* libbls. If not, see <http://www.gnu.org/licenses/>.
23
* List implementation of segcol_t
29
#include "segcol_internal.h"
30
#include "segcol_list.h"
31
#include "type_limits.h"
35
struct segment_entry {
40
struct segcol_list_iter_impl {
41
struct list_node *node;
45
struct segcol_list_impl {
47
struct list_node *cached_node;
51
/* Forward declarations */
53
/* internal convenience functions */
54
static int find_seg_entry(segcol_t *segcol,
55
struct segment_entry **snode, off_t *mapping, off_t offset);
56
static int segcol_list_clear_cache(struct segcol_list_impl *impl);
57
static int segcol_list_set_cache(struct segcol_list_impl *impl,
58
struct list_node *node, off_t mapping);
60
/* segcol API implementation functions */
61
int segcol_list_new(segcol_t **segcol);
62
static int segcol_list_free(segcol_t *segcol);
63
static int segcol_list_append(segcol_t *segcol, segment_t *seg);
64
static int segcol_list_insert(segcol_t *segcol, off_t offset, segment_t *seg);
65
static int segcol_list_delete(segcol_t *segcol, segcol_t **deleted, off_t offset, off_t length);
66
static int segcol_list_find(segcol_t *segcol, segcol_iter_t **iter, off_t offset);
67
static int segcol_list_iter_new(segcol_t *segcol, void **iter);
68
static int segcol_list_iter_next(segcol_iter_t *iter);
69
static int segcol_list_iter_is_valid(segcol_iter_t *iter, int *valid);
70
static int segcol_list_iter_get_segment(segcol_iter_t *iter, segment_t **seg);
71
static int segcol_list_iter_get_mapping(segcol_iter_t *iter, off_t *mapping);
72
static int segcol_list_iter_free(segcol_iter_t *iter);
74
/* Function pointers for the list implementation of segcol_t */
75
static struct segcol_funcs segcol_list_funcs = {
76
.free = segcol_list_free,
77
.append = segcol_list_append,
78
.insert = segcol_list_insert,
79
.delete = segcol_list_delete,
80
.find = segcol_list_find,
81
.iter_new = segcol_list_iter_new,
82
.iter_next = segcol_list_iter_next,
83
.iter_is_valid = segcol_list_iter_is_valid,
84
.iter_get_segment = segcol_list_iter_get_segment,
85
.iter_get_mapping = segcol_list_iter_get_mapping,
86
.iter_free = segcol_list_iter_free
90
* Finds the segment entry in the segcol_list that contains a logical offset.
92
* @param segcol the segcol_t to search
93
* @param[out] entry the found entry (or NULL if not found)
94
* @param[out] mapping the mapping of the found node
95
* @param offset the offset to look for
97
* @return the operation error code
99
static int find_seg_entry(segcol_t *segcol,
100
struct segment_entry **entry, off_t *mapping, off_t offset)
102
segcol_iter_t *iter = NULL;
103
int err = segcol_find(segcol, &iter, offset);
109
if (segcol_iter_is_valid(iter, &valid) || !valid) {
112
struct segcol_list_iter_impl *iter_impl = segcol_iter_get_impl(iter);
113
*entry = list_entry(iter_impl->node, struct segment_entry, ln);
114
*mapping = iter_impl->mapping;
117
segcol_iter_free(iter);
123
* Clears the search cache of a segcol_list_impl.
125
* @param impl the segcol_list_impl
127
* @return the operation error code
129
static int segcol_list_clear_cache(struct segcol_list_impl *impl)
132
return_error(EINVAL);
134
impl->cached_node = NULL;
135
impl->cached_mapping = 0;
141
* Sets the search cache of a segcol_list_impl.
143
* @param impl the segcol_list_impl
144
* @param node the cached list node
145
* @param mapping the logical mapping of the cached node in the segcol_list
147
* @return the operation error code
149
static int segcol_list_set_cache(struct segcol_list_impl *impl,
150
struct list_node *node, off_t mapping)
152
if (impl == NULL || node == NULL)
153
return_error(EINVAL);
155
impl->cached_node = node;
156
impl->cached_mapping = mapping;
162
* Gets the closest known node/mapping pair to an offset.
164
* @param impl the segcol_list_impl
165
* @param node the closest known list node
166
* @param mapping the mapping of the closest known node in the segcol_list
167
* @param offset the offset to look for
169
* @return the operation error code
171
static int segcol_list_get_closest_node(segcol_t *segcol,
172
struct list_node **node, off_t *mapping, off_t offset)
175
segcol_get_size(segcol, &segcol_size);
177
struct segcol_list_impl *impl =
178
(struct segcol_list_impl *) segcol_get_impl(segcol);
181
* Calculate the distance of the head, tail and cached nodes to the offset.
182
* The distance metric is the byte distance of the offset to the
183
* afforementioned nodes' mappings. However, our search algorithm is
184
* O(#segments) not O(#byte_diff), so this metric may not lead to good
185
* results in some cases.
187
* Eg if the distance metric from the head is 10000 with 1000 intervening
188
* segment nodes and the metric from the tail is 100000 with 1 intervening
189
* segment node we will incorrectly choose head as the closest node.
191
off_t dist_from_cache = __MAX(off_t);
192
if (impl->cached_node != NULL) {
193
*node = impl->cached_node;
194
*mapping = impl->cached_mapping;
195
if (offset > *mapping)
196
dist_from_cache = offset - *mapping;
198
dist_from_cache = *mapping - offset;
201
off_t dist_from_head = offset;
202
off_t dist_from_tail = segcol_size - offset;
205
* Decide which is the closest node to the offset:
206
* head, cached or tail.
208
off_t cur_min = dist_from_cache;
210
if (dist_from_head < cur_min) {
211
*node = list_head(impl->list)->next;
213
cur_min = dist_from_head;
216
if (dist_from_tail < cur_min) {
217
*node = list_tail(impl->list)->prev;
219
struct segment_entry *snode =
220
list_entry(*node, struct segment_entry, ln);
222
segment_get_size(snode->segment, &seg_size);
224
*mapping = segcol_size - seg_size;
235
* Creates a new segcol_t using a linked list implementation.
237
* @param[out] segcol the created segcol_t
239
* @return the operation error code
241
int segcol_list_new(segcol_t **segcol)
244
return_error(EINVAL);
246
/* Allocate memory for implementation */
247
struct segcol_list_impl *impl = malloc(sizeof(struct segcol_list_impl));
250
return_error(EINVAL);
252
/* Create head and tail nodes */
253
int err = list_new(&impl->list, struct segment_entry, ln);
257
segcol_list_clear_cache(impl);
259
/* Create segcol_t */
260
err = segcol_create_impl(segcol, impl, &segcol_list_funcs);
263
list_free(impl->list);
271
static int segcol_list_free(segcol_t *segcol)
274
return_error(EINVAL);
276
struct segcol_list_impl *impl =
277
(struct segcol_list_impl *) segcol_get_impl(segcol);
279
struct list_node *node;
280
struct list_node *tmp;
283
list_for_each_safe(list_head(impl->list)->next, node, tmp) {
284
struct segment_entry *snode = list_entry(node, struct segment_entry, ln);
285
if (snode->segment != NULL)
286
segment_free(snode->segment);
290
list_free(impl->list);
297
static int segcol_list_append(segcol_t *segcol, segment_t *seg)
299
if (segcol == NULL || seg == NULL)
300
return_error(EINVAL);
303
* If the segment size is 0, return successfully without adding
304
* anything. Free the segment as we will not be using it.
307
segment_get_size(seg, &seg_size);
313
struct segcol_list_impl *impl =
314
(struct segcol_list_impl *) segcol_get_impl(segcol);
316
struct segment_entry *new_entry;
317
new_entry = malloc(sizeof(struct segment_entry));
318
if (new_entry == NULL)
319
return_error(ENOMEM);
321
new_entry->segment = seg;
323
/* Append at the end */
324
list_insert_before(list_tail(impl->list), &new_entry->ln);
326
/* Set the cache at the appended node */
328
segcol_get_size(segcol, &segcol_size);
329
segcol_list_set_cache(impl, &new_entry->ln, segcol_size);
334
static int segcol_list_insert(segcol_t *segcol, off_t offset, segment_t *seg)
336
if (segcol == NULL || seg == NULL || offset < 0)
337
return_error(EINVAL);
339
struct segcol_list_impl *impl =
340
(struct segcol_list_impl *) segcol_get_impl(segcol);
342
/* find the segment that 'offset' is mapped to */
344
int err = segcol_list_find(segcol, &iter, offset);
349
* If the segment size is 0, return successfully without adding
350
* anything. Free the segment as we will not be using it.
351
* This check is placed after the first find_seg_entry() so that the
352
* validity of offset (if it is in range) is checked first.
355
segment_get_size(seg, &seg_size);
358
segcol_iter_free(iter);
362
segcol_list_clear_cache(impl);
365
segcol_list_iter_get_segment(iter, &pseg);
368
segcol_list_iter_get_mapping(iter, &mapping);
370
struct segcol_list_iter_impl *iter_impl =
371
(struct segcol_list_iter_impl *) segcol_iter_get_impl(iter);
373
struct segment_entry *pentry =
374
list_entry(iter_impl->node, struct segment_entry, ln);
376
segcol_iter_free(iter);
378
/* create a list node containing the new segment */
379
struct segment_entry *qentry;
380
qentry = malloc(sizeof(struct segment_entry));
382
return_error(ENOMEM);
384
qentry->segment = seg;
387
* split the existing segment and insert the new segment
390
/* where to split the existing segment */
391
off_t split_index = offset - mapping;
393
/* check if a split is actually needed or we just have to prepend
395
if (split_index == 0)
396
list_insert_before(&pentry->ln, &qentry->ln);
399
err = segment_split(pseg, &rseg, split_index);
403
struct segment_entry *rentry;
404
rentry = malloc(sizeof(struct segment_entry));
405
if (rentry == NULL) {
406
segment_merge(pseg, rseg);
408
return_error(ENOMEM);
410
rentry->segment = rseg;
412
list_insert_after(&pentry->ln, &qentry->ln);
413
list_insert_after(&qentry->ln, &rentry->ln);
416
/* Set the cache at the inserted node */
417
segcol_list_set_cache(impl, &qentry->ln, offset);
423
* The algorithm first deletes from the segcol list the entry chain that is
424
* defined by first_entry and last_entry (the nodes that contain the start and
425
* end of the range, respectively). This possibly deletes more than it should
426
* because we completely delete the first and last segment, when perhaps only a
427
* part of them should be deleted (F, L). We fix this later on by reinserting
428
* a and b. Some of the comments below will refer to the following diagram:
430
* P: first_entry_prev a: entry_a F: first_entry
431
* N: last_entry_next b: entry_b L: last_entry
433
* -[P]-[a|F]-[]-[]-[L|b]-[N]- => -[]-[P]-[N]-[]- => -[P]-[a]-[b]-[N]-
435
* offset offset + length
437
static int segcol_list_delete(segcol_t *segcol, segcol_t **deleted, off_t
438
offset, off_t length)
440
if (segcol == NULL || offset < 0 || length < 0)
441
return_error(EINVAL);
443
/* Check range for overflow */
444
if (__MAX(off_t) - offset < length - 1 * (length != 0))
445
return_error(EOVERFLOW);
447
struct segcol_list_impl *impl =
448
(struct segcol_list_impl *) segcol_get_impl(segcol);
450
struct segment_entry *first_entry = NULL;
451
struct segment_entry *last_entry = NULL;
452
off_t first_mapping = -1;
453
off_t last_mapping = -1;
455
/* Find the first and last list nodes that contain the range */
456
int err = find_seg_entry(segcol, &first_entry, &first_mapping, offset);
461
* If the length is 0 return successfully without doing anything.
462
* This check is placed after the first find_seg_entry() so that the
463
* validity of offset (if it is in range) is checked first.
466
/* Return an empty deleted segcol if the caller wants one */
467
if (deleted != NULL) {
468
err = segcol_list_new(deleted);
475
err = find_seg_entry(segcol, &last_entry, &last_mapping,
476
offset + length - 1 * (length != 0));
481
if (first_entry == NULL || last_entry == NULL
482
|| first_entry->segment == NULL || last_entry->segment == NULL)
483
return_error(EINVAL);
485
segcol_list_clear_cache(impl);
488
* entry_a will hold the part of the first segment that we must
489
* put back into the segcol.
490
* entry_b will hold the part of the last segment that we must
491
* put back into the segcol.
493
struct segment_entry *entry_a;
494
struct segment_entry *entry_b;
496
entry_a = malloc(sizeof(struct segment_entry));
497
if (entry_a == NULL) {
499
goto_error(err, on_error_mem_entry_a);
501
entry_b = malloc(sizeof(struct segment_entry));
502
if (entry_b == NULL) {
504
goto_error(err, on_error_mem_entry_b);
508
* The nodes that should go before and after entry_a and entry_b, respectively
509
* when and if we should insert them back in.
511
struct segment_entry *entry_a_prev =
512
list_entry(first_entry->ln.prev, struct segment_entry, ln);
514
struct segment_entry *entry_b_next =
515
list_entry(last_entry->ln.next, struct segment_entry, ln);
517
/* Delete the chain */
518
list_delete_chain(&first_entry->ln, &last_entry->ln);
520
/* Calculate new size, after having deleted the chain */
522
segcol_get_size(segcol, &new_size);
525
segment_get_size(last_entry->segment, &last_seg_size);
527
new_size -= last_mapping + last_seg_size - first_mapping;
530
* Handle first node: Split first segment so that the first node contains
531
* only segment F (and store the remaining in entry_a). We only have to do
532
* something if the range to delete starts after the beginning of the first
533
* segment. Otherwise the whole segment should be deleted which has
534
* already been done by list_delete_chain.
536
if (first_mapping < offset) {
538
err = segment_split(first_entry->segment, &tmp_seg, offset - first_mapping);
540
goto_error(err, on_error_first_entry);
542
entry_a->segment = first_entry->segment;
543
first_entry->segment = tmp_seg;
550
* Handle last node: Split last segment so that the last node contains only
551
* segment L (and store the remaining in entry_b). We only have to do
552
* something if the range to delete ends after the end of the last segment.
553
* Otherwise the whole segment should be deleted which has already been
554
* done by list_delete_chain.
556
if (last_mapping + last_seg_size > offset + length) {
558
* If the first and last nodes are the same the segment that is
559
* contained in them may have been decreased by 'offset - mapping' due
560
* to the split in the handling of the first node. Take this into
561
* account to correctly calculate the index for the second split.
563
int last_seg_dec = 0;
565
if (first_entry == last_entry)
566
last_seg_dec = offset - first_mapping;
569
err = segment_split(last_entry->segment, &tmp_seg,
570
offset + length - last_mapping - last_seg_dec);
572
goto_error(err, on_error_last_entry);
574
entry_b->segment = tmp_seg;
581
* Insert incorrectly deleted parts of the segments back into segcol
585
list_insert_after(&entry_a_prev->ln, &entry_a->ln);
588
list_insert_before(&entry_b_next->ln, &entry_b->ln);
590
/* Create a new segcol_t and put in the deleted segments */
591
segcol_t *deleted_tmp;
592
err = segcol_list_new(&deleted_tmp);
594
goto_error(err, on_error_segcol_new);
596
struct segcol_list_impl *deleted_impl =
597
(struct segcol_list_impl *) segcol_get_impl(deleted_tmp);
599
list_insert_chain_after(list_head(deleted_impl->list), &first_entry->ln,
602
/* Either return the deleted segments or free them */
604
*deleted = deleted_tmp;
606
segcol_free(deleted_tmp);
608
/* Set the cache at the node after the deleted range */
610
segcol_list_set_cache(impl, &entry_b->ln, offset);
611
else if (entry_b_next->ln.next != &entry_b_next->ln)
612
segcol_list_set_cache(impl, &entry_b_next->ln, offset);
616
* Handle failures so that the segcol is in its expected state
617
* after a failure and there are no memory leaks.
621
list_delete_chain(&entry_b->ln, &entry_b->ln);
624
list_delete_chain(&entry_a->ln, &entry_a->ln);
626
if (entry_b != NULL) {
627
segment_merge(last_entry->segment, entry_b->segment);
628
free(entry_b->segment);
631
if (entry_a != NULL) {
632
segment_merge(entry_a->segment, first_entry->segment);
633
free(first_entry->segment);
634
first_entry->segment = entry_a->segment;
636
on_error_first_entry:
637
list_insert_before(&entry_b_next->ln, &last_entry->ln);
638
list_insert_after(&entry_a_prev->ln, &first_entry->ln);
639
if (entry_b != NULL) free(entry_b);
640
on_error_mem_entry_b:
641
if (entry_a != NULL) free(entry_a);
642
on_error_mem_entry_a:
646
static int segcol_list_find(segcol_t *segcol, segcol_iter_t **iter, off_t offset)
648
if (segcol == NULL || iter == NULL || offset < 0)
649
return_error(EINVAL);
653
/* Make sure offset is in range */
655
segcol_get_size(segcol, &segcol_size);
657
if (offset >= segcol_size)
658
return_error(EINVAL);
660
struct segcol_list_impl *impl =
661
(struct segcol_list_impl *) segcol_get_impl(segcol);
664
* Find the closest known node/mapping pair to the offset
665
* and start the search from there.
667
struct list_node *cur_node = NULL;
668
off_t cur_mapping = -1;
670
segcol_list_get_closest_node(segcol, &cur_node, &cur_mapping, offset);
674
/* linear search of list nodes */
675
while (cur_node != cur_node->next && cur_node != cur_node->prev) {
676
struct segment_entry *snode =
677
list_entry(cur_node, struct segment_entry, ln);
679
segment_t *seg = snode->segment;
681
err = segment_get_size(seg, &seg_size);
684
* When we move backwards in the list the new mapping is the
685
* cur_mapping - prev_seg->size. In order to avoid getting the
686
* size twice we just set a flag to indicate that we should fix
690
cur_mapping -= seg_size;
692
/* We have found the node! */
693
if (offset >= cur_mapping && offset < cur_mapping + seg_size) {
694
segcol_list_set_cache(impl, cur_node, cur_mapping);
699
* Move forwards or backwards in the list depending on where
700
* is the offset relative to the current node.
702
if (offset < cur_mapping) {
703
cur_node = cur_node->prev;
705
* Fix the mapping in the next iteration. Otherwise we would have
706
* to get the size here, which is a waste since we are doing
707
* that at the start of the loop.
711
else if (offset >= cur_mapping + seg_size) {
712
cur_node = cur_node->next;
714
cur_mapping += seg_size;
718
/* Create iterator to return search results */
719
err = segcol_iter_new(segcol, iter);
723
struct segcol_list_iter_impl *iter_impl =
724
(struct segcol_list_iter_impl *) segcol_iter_get_impl(*iter);
726
iter_impl->node = cur_node;
727
iter_impl->mapping = cur_mapping;
732
static int segcol_list_iter_new(segcol_t *segcol, void **iter_impl)
734
if (segcol == NULL || iter_impl == NULL)
735
return_error(EINVAL);
737
struct segcol_list_impl *impl =
738
(struct segcol_list_impl *) segcol_get_impl(segcol);
739
struct segcol_list_iter_impl **iter_impl1 =
740
(struct segcol_list_iter_impl **)iter_impl;
742
*iter_impl1 = malloc(sizeof(struct segcol_list_iter_impl));
744
(*iter_impl1)->node = list_head(impl->list)->next;
745
(*iter_impl1)->mapping = 0;
751
static int segcol_list_iter_next(segcol_iter_t *iter)
754
return_error(EINVAL);
756
struct segcol_list_iter_impl *iter_impl = segcol_iter_get_impl(iter);
758
if (iter_impl->node != iter_impl->node->next) {
761
struct segment_entry *snode =
762
list_entry(iter_impl->node, struct segment_entry, ln);
764
segment_get_size(snode->segment, &node_size);
765
iter_impl->node = iter_impl->node->next;
766
iter_impl->mapping = iter_impl->mapping + node_size;
772
static int segcol_list_iter_get_segment(segcol_iter_t *iter, segment_t **seg)
774
if (iter == NULL || seg == NULL)
775
return_error(EINVAL);
777
struct segcol_list_iter_impl *iter_impl = segcol_iter_get_impl(iter);
779
*seg = list_entry(iter_impl->node, struct segment_entry, ln)->segment;
784
static int segcol_list_iter_get_mapping(segcol_iter_t *iter, off_t *mapping)
786
if (iter == NULL || mapping == NULL)
787
return_error(EINVAL);
789
struct segcol_list_iter_impl *iter_impl = segcol_iter_get_impl(iter);
791
*mapping = iter_impl->mapping;
796
static int segcol_list_iter_is_valid(segcol_iter_t *iter, int *valid)
798
if (iter == NULL || valid == NULL)
799
return_error(EINVAL);
801
struct segcol_list_iter_impl *iter_impl = segcol_iter_get_impl(iter);
803
/* Iterator is valid if it is not NULL and its node its not the head
805
*valid = (iter_impl != NULL) && (iter_impl->node != iter_impl->node->next)
806
&& (iter_impl->node != iter_impl->node->prev);
811
static int segcol_list_iter_free(segcol_iter_t *iter)
814
return_error(EINVAL);
816
free(segcol_iter_get_impl(iter));