]> git.proxmox.com Git - ceph.git/blob - ceph/src/msg/async/dpdk/PacketUtil.h
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / msg / async / dpdk / PacketUtil.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 /*
3 * This file is open source software, licensed to you under the terms
4 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
5 * distributed with this work for additional information regarding copyright
6 * ownership. You may not use this file except in compliance with the License.
7 *
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 /*
20 * Copyright (C) 2014 Cloudius Systems, Ltd.
21 */
22 /*
23 * Ceph - scalable distributed file system
24 *
25 * Copyright (C) 2015 XSky <haomai@xsky.com>
26 *
27 * Author: Haomai Wang <haomaiwang@gmail.com>
28 *
29 * This is free software; you can redistribute it and/or
30 * modify it under the terms of the GNU Lesser General Public
31 * License version 2.1, as published by the Free Software
32 * Foundation. See file COPYING.
33 *
34 */
35
36 #ifndef CEPH_MSG_PACKET_UTIL_H_
37 #define CEPH_MSG_PACKET_UTIL_H_
38
39 #include <map>
40 #include <iostream>
41
42 #include "Packet.h"
43
44 template <typename Offset, typename Tag>
45 class packet_merger {
46 private:
47 static uint64_t& linearizations_ref() {
48 static thread_local uint64_t linearization_count;
49 return linearization_count;
50 }
51 public:
52 std::map<Offset, Packet> map;
53
54 static uint64_t linearizations() {
55 return linearizations_ref();
56 }
57
58 void merge(Offset offset, Packet p) {
59 bool insert = true;
60 auto beg = offset;
61 auto end = beg + p.len();
62 // Fisrt, try to merge the packet with existing segment
63 for (auto it = map.begin(); it != map.end();) {
64 auto& seg_pkt = it->second;
65 auto seg_beg = it->first;
66 auto seg_end = seg_beg + seg_pkt.len();
67 // There are 6 cases:
68 if (seg_beg <= beg && end <= seg_end) {
69 // 1) seg_beg beg end seg_end
70 // We already have data in this packet
71 return;
72 } else if (beg <= seg_beg && seg_end <= end) {
73 // 2) beg seg_beg seg_end end
74 // The new segment contains more data than this old segment
75 // Delete the old one, insert the new one
76 it = map.erase(it);
77 insert = true;
78 break;
79 } else if (beg < seg_beg && seg_beg <= end && end <= seg_end) {
80 // 3) beg seg_beg end seg_end
81 // Merge two segments, trim front of old segment
82 auto trim = end - seg_beg;
83 seg_pkt.trim_front(trim);
84 p.append(std::move(seg_pkt));
85 // Delete the old one, insert the new one
86 it = map.erase(it);
87 insert = true;
88 break;
89 } else if (seg_beg <= beg && beg <= seg_end && seg_end < end) {
90 // 4) seg_beg beg seg_end end
91 // Merge two segments, trim front of new segment
92 auto trim = seg_end - beg;
93 p.trim_front(trim);
94 // Append new data to the old segment, keep the old segment
95 seg_pkt.append(std::move(p));
96 seg_pkt.linearize();
97 ++linearizations_ref();
98 insert = false;
99 break;
100 } else {
101 // 5) beg end < seg_beg seg_end
102 // or
103 // 6) seg_beg seg_end < beg end
104 // Can not merge with this segment, keep looking
105 it++;
106 insert = true;
107 }
108 }
109
110 if (insert) {
111 p.linearize();
112 ++linearizations_ref();
113 map.emplace(beg, std::move(p));
114 }
115
116 // Second, merge adjacent segments after this packet has been merged,
117 // becasue this packet might fill a "whole" and make two adjacent
118 // segments mergable
119 for (auto it = map.begin(); it != map.end();) {
120 // The first segment
121 auto& seg_pkt = it->second;
122 auto seg_beg = it->first;
123 auto seg_end = seg_beg + seg_pkt.len();
124
125 // The second segment
126 auto it_next = it;
127 it_next++;
128 if (it_next == map.end()) {
129 break;
130 }
131 auto& p = it_next->second;
132 auto beg = it_next->first;
133 auto end = beg + p.len();
134
135 // Merge the the second segment into first segment if possible
136 if (seg_beg <= beg && beg <= seg_end && seg_end < end) {
137 // Merge two segments, trim front of second segment
138 auto trim = seg_end - beg;
139 p.trim_front(trim);
140 // Append new data to the first segment, keep the first segment
141 seg_pkt.append(std::move(p));
142
143 // Delete the second segment
144 map.erase(it_next);
145
146 // Keep merging this first segment with its new next packet
147 // So we do not update the iterator: it
148 continue;
149 } else if (end <= seg_end) {
150 // The first segment has all the data in the second segment
151 // Delete the second segment
152 map.erase(it_next);
153 continue;
154 } else if (seg_end < beg) {
155 // Can not merge first segment with second segment
156 it = it_next;
157 continue;
158 } else {
159 // If we reach here, we have a bug with merge.
160 std::cout << "packet_merger: merge error\n";
161 abort();
162 break;
163 }
164 }
165 }
166 };
167
168 #endif