cachelib/common/piecewise/GenericPieces.h (113 lines of code) (raw):

/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <folly/dynamic.h> #include <folly/io/IOBuf.h> #include <folly/logging/xlog.h> #include <memory> #include <string> #include <unordered_map> #include "cachelib/common/piecewise/RequestRange.h" namespace facebook { namespace cachelib { const std::string kCacheGroupSeparator = "|@|"; const std::string kCachePieceSeparator = "|#|"; /** * A content can be split and stored in multiple pieces in cache. The class * provides the utility to map content object to pieces. * */ class GenericPieces { public: /** * @param baseKey: base key of the request. we will generate piece key from * the base key. * @param pieceSize: byte size for each cache piece. * @param piecesPerGroup: # of pieces we put into a single group. we may want * to put each group onto a separate machine, depending on application. * @param fullBodyLen: the length of the full content (without the response * header), in regardless of the range. * @param range: define the range request. */ GenericPieces(const std::string& baseKey, uint64_t pieceSize, uint64_t piecesPerGroup, uint64_t fullBodyLen, const RequestRange* range); void resetFromRequestRange(const RequestRange& range); /** * We fetch one piece at a time and keep track of that piece * number here. */ uint64_t getCurFetchingPieceIndex() const { return curFetchingPieceIndex_; } bool morePiecesToFetch() const { return curFetchingPieceIndex_ < endPieceIndex_; } /** * Indicates we finished fetching a piece and are ready to fetch the * next one. */ void updateFetchIndex() { curFetchingPieceIndex_ += 1; } void setFetchIndex(uint64_t pieceIndex) { curFetchingPieceIndex_ = pieceIndex; } uint64_t getFirstByteOffsetOfCurPiece() const { return curFetchingPieceIndex_ * getPieceSize(); } uint64_t getLastByteOffsetOfLastPiece() const { return std::min((endPieceIndex_ + 1) * pieceSize_ - 1, fullBodyLen_ - 1); } uint64_t getRemainingBytes() const { if (curFetchingPieceIndex_ > endPieceIndex_) { return 0; } return getLastByteOffsetOfLastPiece() - getFirstByteOffsetOfCurPiece() + 1; } uint64_t getPieceSize() const { return pieceSize_; } uint64_t getPiecesPerGroup() const { return numPiecesPerGroup_; } bool isPieceWithinBound(uint64_t pieceIndex) const { return pieceIndex <= endPieceIndex_; } uint64_t getSizeOfAPiece(uint64_t pieceIndex) const { // The size is full piece size when it's not the last piece if (pieceIndex < endPieceIndex_) { return pieceSize_; } else { return getLastByteOffsetOfLastPiece() % pieceSize_ + 1; } } // Return the byte size of all pieces uint64_t getTotalSize() const { return getLastByteOffsetOfLastPiece() - startPieceIndex_ * getPieceSize() + 1; } uint64_t getRequestedSizeOfAPiece(uint64_t pieceIndex) const { if (startPieceIndex_ == endPieceIndex_) { XDCHECK_EQ(pieceIndex, startPieceIndex_); return requestedEndByte_ - requestedStartByte_ + 1; } if (pieceIndex == startPieceIndex_) { // For the first piece, trim bytes before requestedStartByte_ return pieceSize_ - requestedStartByte_ % pieceSize_; } else if (pieceIndex == endPieceIndex_) { // For the last piece, trim bytes after requestedEndByte_ return requestedEndByte_ % pieceSize_ + 1; } else { return pieceSize_; } } uint64_t getBytesToTrimAtStart() const { return requestedStartByte_ - startPieceIndex_ * pieceSize_; } uint64_t getBytesToTrimAtEnd() const { return getLastByteOffsetOfLastPiece() - requestedEndByte_; } uint64_t getRequestedSize() const { return (requestedEndByte_ - requestedStartByte_ + 1); } /** * Returns the body-length of the *full* blob (e.g. if there is a * 1000000-byte blob and 6400 bytes are requested in a range request, this * will still return 1000000) */ uint64_t getFullBodyLength() const { return fullBodyLen_; } uint64_t getStartPieceIndex() const { return startPieceIndex_; } uint64_t getEndPieceIndex() const { return endPieceIndex_; } uint64_t getNumPiecesTotal() const { return numPiecesTotal_; } uint64_t getRequestedStartByte() const { return requestedStartByte_; } uint64_t getRequestedEndByte() const { return requestedEndByte_; } uint64_t getFirstByteOffsetToFetch() const { return firstByteOffsetToFetch_; } /** * Get the number of pieces we need to fetch (excluding the header piece) */ uint64_t getTargetNumPieces() const; /** * We use "|#|" as the separator between the actual cachekey and meta * key information (Is it a header? Is it a piece? Which piece?) So * we want to make sure this separator is escaped in the main key. Do this * by doubling it whenever we see it. If we ever see the single separator * string by itself, we know it's actually the separator. */ static std::string escapeCacheKey(const std::string& key); /** * Get the basekey from the given pieceKey (full key). The returned value * shares the same lifetime as the passed in pieceKey. */ static folly::StringPiece getBaseKey(folly::StringPiece pieceKey); /** * @param versionID: unique identifer of the content's version, e.g., * hash of the content. */ static std::string createPieceHeaderKey(const std::string& baseKey, uint64_t versionID = 0); /** * Keys used to store each piece of the response. We include the pieceSize * in the key in case we change pieceSize at some point, so we can * distinguish between the different values. */ static std::string createPieceKey(const std::string& baseKey, size_t pieceNum, uint64_t piecesPerGroup, uint64_t versionID = 0); static uint64_t calculateNumPiecesTotal(const uint64_t fullBodyLen, const uint64_t pieceSize) { return ((fullBodyLen - 1) / pieceSize) + 1; } protected: std::string baseKey_; uint64_t pieceSize_; uint64_t numPiecesPerGroup_; uint64_t fullBodyLen_; uint64_t curFetchingPieceIndex_; // Calculated values // Total number of pieces for the full content uint64_t numPiecesTotal_; // Start byte of the request content (or range) uint64_t requestedStartByte_; // End byte of the request content (or range) uint64_t requestedEndByte_; // Start piece index of he request content (or range) uint64_t startPieceIndex_; // End piece index of he request content (or range) uint64_t endPieceIndex_; // Starting byte offset of the first piece uint64_t firstByteOffsetToFetch_; }; } // namespace cachelib } // namespace facebook