2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 * Copyright (C) 2014 Cloudius Systems, Ltd.
24 #include <seastar/net/packet.hh>
32 template <typename Offset, typename Tag>
35 static uint64_t& linearizations_ref() {
36 static thread_local uint64_t linearization_count;
37 return linearization_count;
40 std::map<Offset, packet> map;
42 static uint64_t linearizations() {
43 return linearizations_ref();
46 void merge(Offset offset, packet p) {
49 auto end = beg + p.len();
50 // Fisrt, try to merge the packet with existing segment
51 for (auto it = map.begin(); it != map.end();) {
52 auto& seg_pkt = it->second;
53 auto seg_beg = it->first;
54 auto seg_end = seg_beg + seg_pkt.len();
56 if (seg_beg <= beg && end <= seg_end) {
57 // 1) seg_beg beg end seg_end
58 // We already have data in this packet
60 } else if (beg <= seg_beg && seg_end <= end) {
61 // 2) beg seg_beg seg_end end
62 // The new segment contains more data than this old segment
63 // Delete the old one, insert the new one
67 } else if (beg < seg_beg && seg_beg <= end && end <= seg_end) {
68 // 3) beg seg_beg end seg_end
69 // Merge two segments, trim front of old segment
70 auto trim = end - seg_beg;
71 seg_pkt.trim_front(trim);
72 p.append(std::move(seg_pkt));
73 // Delete the old one, insert the new one
77 } else if (seg_beg <= beg && beg <= seg_end && seg_end < end) {
78 // 4) seg_beg beg seg_end end
79 // Merge two segments, trim front of new segment
80 auto trim = seg_end - beg;
82 // Append new data to the old segment, keep the old segment
83 seg_pkt.append(std::move(p));
85 ++linearizations_ref();
89 // 5) beg end < seg_beg seg_end
91 // 6) seg_beg seg_end < beg end
92 // Can not merge with this segment, keep looking
100 ++linearizations_ref();
101 map.emplace(beg, std::move(p));
104 // Second, merge adjacent segments after this packet has been merged,
105 // becasue this packet might fill a "whole" and make two adjacent
107 for (auto it = map.begin(); it != map.end();) {
109 auto& seg_pkt = it->second;
110 auto seg_beg = it->first;
111 auto seg_end = seg_beg + seg_pkt.len();
113 // The second segment
116 if (it_next == map.end()) {
119 auto& p = it_next->second;
120 auto beg = it_next->first;
121 auto end = beg + p.len();
123 // Merge the the second segment into first segment if possible
124 if (seg_beg <= beg && beg <= seg_end && seg_end < end) {
125 // Merge two segments, trim front of second segment
126 auto trim = seg_end - beg;
128 // Append new data to the first segment, keep the first segment
129 seg_pkt.append(std::move(p));
131 // Delete the second segment
134 // Keep merging this first segment with its new next packet
135 // So we do not update the iterator: it
137 } else if (end <= seg_end) {
138 // The first segment has all the data in the second segment
139 // Delete the second segment
142 } else if (seg_end < beg) {
143 // Can not merge first segment with second segment
147 // If we reach here, we have a bug with merge.
148 std::cout << "packet_merger: merge error\n";