New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
os/bluestore: space efficient int encoding #9728
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
ed0dd72
include/small_encoding: small encode/decode helpers
liewegas 3fcb8ac
os/bluestore: varint or lba encode pextent, lextent, ref_map, onode
liewegas 3f7c068
os/bluestore: use varint for pextent count
liewegas 4d84cfe
os/bluestore: fsck: print intervals in hex
liewegas be6d887
os/bluestore: use FLAG_CSUM to indicate if checksums are present
liewegas dc245ae
os/bluestore: make blob csum info encoding conditional
liewegas 049309c
os/bluestore/bluestore_types: delta encode for ref_map offsets
liewegas File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,277 @@ | ||
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- | ||
// vim: ts=8 sw=2 smarttab | ||
#ifndef CEPH_SMALL_ENCODING_H | ||
#define CEPH_SMALL_ENCODING_H | ||
|
||
#include "include/buffer.h" | ||
#include "include/int_types.h" | ||
|
||
// varint encoding | ||
// | ||
// high bit of every byte indicates whether another byte follows. | ||
template<typename T> | ||
inline void small_encode_varint(T v, bufferlist& bl) { | ||
uint8_t byte = v & 0x7f; | ||
v >>= 7; | ||
while (v) { | ||
byte |= 0x80; | ||
::encode(byte, bl); | ||
byte = (v & 0x7f); | ||
v >>= 7; | ||
} | ||
::encode(byte, bl); | ||
} | ||
|
||
template<typename T> | ||
inline void small_decode_varint(T& v, bufferlist::iterator& p) | ||
{ | ||
uint8_t byte; | ||
::decode(byte, p); | ||
v = byte & 0x7f; | ||
int shift = 7; | ||
while (byte & 0x80) { | ||
::decode(byte, p); | ||
v |= (T)(byte & 0x7f) << shift; | ||
shift += 7; | ||
} | ||
} | ||
|
||
// signed varint encoding | ||
// | ||
// low bit = 1 = negative, 0 = positive | ||
// high bit of every byte indicates whether another byte follows. | ||
template<typename T> | ||
inline void small_encode_signed_varint(T v, bufferlist& bl) { | ||
uint8_t byte = 0; | ||
if (v < 0) { | ||
v = -v; | ||
byte = 1; | ||
} | ||
byte |= (v & 0x3f) << 1; | ||
v >>= 6; | ||
while (v) { | ||
byte |= 0x80; | ||
::encode(byte, bl); | ||
byte = (v & 0x7f); | ||
v >>= 7; | ||
} | ||
::encode(byte, bl); | ||
} | ||
|
||
template<typename T> | ||
inline void small_decode_signed_varint(T& v, bufferlist::iterator& p) | ||
{ | ||
uint8_t byte; | ||
::decode(byte, p); | ||
bool negative = byte & 1; | ||
v = (byte & 0x7e) >> 1; | ||
int shift = 6; | ||
while (byte & 0x80) { | ||
::decode(byte, p); | ||
v |= (T)(byte & 0x7f) << shift; | ||
shift += 7; | ||
} | ||
if (negative) { | ||
v = -v; | ||
} | ||
} | ||
|
||
// varint + lowz encoding | ||
// | ||
// first(low) 2 bits = how many low zero bits (nibbles) | ||
// high bit of each byte = another byte follows | ||
// (so, 5 bits data in first byte, 7 bits data thereafter) | ||
template<typename T> | ||
inline void small_encode_varint_lowz(T v, bufferlist& bl) { | ||
int lowz = v ? (ctz(v) / 4) : 0; | ||
uint8_t byte = std::min(lowz, 3); | ||
v >>= byte * 4; | ||
byte |= (((uint8_t)v << 2) & 0x7c); | ||
v >>= 5; | ||
while (v) { | ||
byte |= 0x80; | ||
::encode(byte, bl); | ||
byte = (v & 0x7f); | ||
v >>= 7; | ||
} | ||
::encode(byte, bl); | ||
} | ||
|
||
template<typename T> | ||
inline void small_decode_varint_lowz(T& v, bufferlist::iterator& p) | ||
{ | ||
uint8_t byte; | ||
::decode(byte, p); | ||
int shift = (byte & 3) * 4; | ||
v = ((byte >> 2) & 0x1f) << shift; | ||
shift += 5; | ||
while (byte & 0x80) { | ||
::decode(byte, p); | ||
v |= (T)(byte & 0x7f) << shift; | ||
shift += 7; | ||
} | ||
} | ||
|
||
// signed varint + lowz encoding | ||
// | ||
// first low bit = 1 for negative, 0 for positive | ||
// next 2 bits = how many low zero bits (nibbles) | ||
// high bit of each byte = another byte follows | ||
// (so, 4 bits data in first byte, 7 bits data thereafter) | ||
template<typename T> | ||
inline void small_encode_signed_varint_lowz(T v, bufferlist& bl) { | ||
uint8_t byte = 0; | ||
if (v < 0) { | ||
v = -v; | ||
byte = 1; | ||
} | ||
int lowz = v ? (ctz(v) / 4) : 0; | ||
lowz = std::min(lowz, 3); | ||
byte |= lowz << 1; | ||
v >>= lowz * 4; | ||
byte |= (((uint8_t)v << 3) & 0x78); | ||
v >>= 4; | ||
while (v) { | ||
byte |= 0x80; | ||
::encode(byte, bl); | ||
byte = (v & 0x7f); | ||
v >>= 7; | ||
} | ||
::encode(byte, bl); | ||
} | ||
|
||
template<typename T> | ||
inline void small_decode_signed_varint_lowz(T& v, bufferlist::iterator& p) | ||
{ | ||
uint8_t byte; | ||
::decode(byte, p); | ||
bool negative = byte & 1; | ||
int shift = (byte & 6) * 2; | ||
v = ((byte >> 3) & 0xf) << shift; | ||
shift += 4; | ||
while (byte & 0x80) { | ||
::decode(byte, p); | ||
v |= (T)(byte & 0x7f) << shift; | ||
shift += 7; | ||
} | ||
if (negative) { | ||
v = -v; | ||
} | ||
} | ||
|
||
|
||
// LBA | ||
// | ||
// first 1-3 bits = how many low zero bits | ||
// *0 = 12 (common 4 K alignment case) | ||
// *01 = 16 | ||
// *011 = 20 | ||
// *111 = byte | ||
// then 28-30 bits of data | ||
// then last bit = another byte follows | ||
// high bit of each subsequent byte = another byte follows | ||
inline void small_encode_lba(uint64_t v, bufferlist& bl) { | ||
int low_zero_nibbles = v ? (int)(ctz(v) / 4) : 0; | ||
int pos; | ||
uint32_t word; | ||
int t = low_zero_nibbles - 3; | ||
if (t < 0) { | ||
pos = 3; | ||
word = 0x7; | ||
} else if (t < 3) { | ||
v >>= (low_zero_nibbles * 4); | ||
pos = t + 1; | ||
word = (1 << t) - 1; | ||
} else { | ||
pos = 3; | ||
word = 0x3; | ||
} | ||
word |= (v << pos) & 0x7fffffff; | ||
v >>= 31 - pos; | ||
if (!v) { | ||
::encode(word, bl); | ||
return; | ||
} | ||
word |= 0x80000000; | ||
::encode(word, bl); | ||
uint8_t byte = v & 0x7f; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use small_encode_varint for the rest? |
||
v >>= 7; | ||
while (v) { | ||
byte |= 0x80; | ||
::encode(byte, bl); | ||
byte = (v & 0x7f); | ||
v >>= 7; | ||
} | ||
::encode(byte, bl); | ||
} | ||
|
||
inline void small_decode_lba(uint64_t& v, bufferlist::iterator& p) { | ||
uint32_t word; | ||
::decode(word, p); | ||
int shift; | ||
switch (word & 7) { | ||
case 0: | ||
case 2: | ||
case 4: | ||
case 6: | ||
v = (uint64_t)(word & 0x7ffffffe) << (12 - 1); | ||
shift = 12 + 30; | ||
break; | ||
case 1: | ||
case 5: | ||
v = (uint64_t)(word & 0x7ffffffc) << (16 - 2); | ||
shift = 16 + 29; | ||
break; | ||
case 3: | ||
v = (uint64_t)(word & 0x7ffffff8) << (20 - 3); | ||
shift = 20 + 28; | ||
break; | ||
case 7: | ||
v = (uint64_t)(word & 0x7ffffff8) >> 3; | ||
shift = 28; | ||
} | ||
uint8_t byte = word >> 24; | ||
while (byte & 0x80) { | ||
::decode(byte, p); | ||
v |= (uint64_t)(byte & 0x7f) << shift; | ||
shift += 7; | ||
} | ||
} | ||
|
||
|
||
// short bufferptrs, bufferlists, strings | ||
template<typename T> | ||
inline void small_encode_buf_lowz(const T& bp, bufferlist& bl) { | ||
size_t l = bp.length(); | ||
small_encode_varint_lowz(l, bl); | ||
bl.append(bp); | ||
} | ||
template<typename T> | ||
inline void small_decode_buf_lowz(T& bp, bufferlist::iterator& p) { | ||
size_t l; | ||
small_decode_varint_lowz(l, p); | ||
p.copy(l, bp); | ||
} | ||
|
||
// STL containers | ||
|
||
template<typename T> | ||
inline void small_encode_obj(const std::vector<T>& v, bufferlist& bl) { | ||
size_t n = v.size(); | ||
small_encode_varint(n, bl); | ||
for (auto p = v.cbegin(); p != v.cend(); ++p) { | ||
p->encode(bl); | ||
} | ||
} | ||
template<typename T> | ||
inline void small_decode_obj(std::vector<T>& v, bufferlist::iterator& p) { | ||
size_t n; | ||
small_decode_varint(n, p); | ||
v.clear(); | ||
while (n--) { | ||
v.push_back(T()); | ||
v.back().decode(p); | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could also make 00 = no low zeros, 01 = 6 low zeros, 02 = 10 low zeros, 03 = 14 low zeros, or something like that if we think the <6 or even <12 low zero bits is less common to optimize for. Remember block_size is 4096 = 12 bits.