You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

storage_manager.cc 5.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /**
  2. * Copyright 2019 Huawei Technologies Co., Ltd
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "dataset/util/storage_manager.h"
  17. #include <iomanip>
  18. #include <sstream>
  19. #include <stdexcept>
  20. #include <utility>
  21. #include "common/utils.h"
  22. #include "dataset/util/path.h"
  23. #include "dataset/util/services.h"
  24. #include "utils/log_adapter.h"
  25. namespace mindspore {
  26. namespace dataset {
  27. std::string StorageManager::GetBaseName(const std::string &prefix, int32_t file_id) {
  28. std::ostringstream oss;
  29. oss << prefix << std::setfill('0') << std::setw(5) << file_id;
  30. return oss.str();
  31. }
  32. std::string StorageManager::ConstructFileName(const std::string &prefix, int32_t file_id, const std::string &suffix) {
  33. std::string base_name = GetBaseName(prefix, file_id);
  34. return (base_name + "." + suffix);
  35. }
  36. Status StorageManager::AddOneContainer() {
  37. const std::string kPrefix = "IMG";
  38. const std::string kSuffix = "LB";
  39. Path container_name = root_ / ConstructFileName(kPrefix, file_id_, kSuffix);
  40. std::shared_ptr<StorageContainer> sc;
  41. RETURN_IF_NOT_OK(StorageContainer::CreateStorageContainer(&sc, container_name.toString()));
  42. containers_.push_back(sc);
  43. file_id_++;
  44. return Status::OK();
  45. }
  46. Status StorageManager::DoServiceStart() {
  47. containers_.reserve(1000);
  48. if (root_.IsDirectory()) {
  49. RETURN_IF_NOT_OK(AddOneContainer());
  50. } else {
  51. RETURN_STATUS_UNEXPECTED("Not a directory");
  52. }
  53. return Status::OK();
  54. }
  55. Status StorageManager::Write(key_type *key, const std::vector<ReadableSlice> &buf) {
  56. RETURN_UNEXPECTED_IF_NULL(key);
  57. size_t sz = 0;
  58. for (auto &v : buf) {
  59. sz += v.GetSize();
  60. }
  61. if (sz == 0) {
  62. RETURN_STATUS_UNEXPECTED("Unexpected 0 length");
  63. }
  64. std::shared_ptr<StorageContainer> cont;
  65. key_type out_key;
  66. value_type out_value;
  67. bool create_new_container = false;
  68. do {
  69. SharedLock lock_s(&rw_lock_);
  70. size_t num_containers = containers_.size();
  71. if (create_new_container) {
  72. // Upgrade to exclusvie lock.
  73. lock_s.Upgrade();
  74. create_new_container = false;
  75. // Check again if someone has already added a
  76. // new container after we got the x lock
  77. if (containers_.size() == num_containers) {
  78. RETURN_IF_NOT_OK(AddOneContainer());
  79. }
  80. // Refresh how many containers there are.
  81. num_containers = containers_.size();
  82. // Downgrade back to shared lock
  83. lock_s.Downgrade();
  84. }
  85. if (num_containers == 0) {
  86. RETURN_STATUS_UNEXPECTED("num_containers is zero");
  87. }
  88. // Go to the last container to insert.
  89. cont = containers_.at(num_containers - 1);
  90. off64_t offset;
  91. Status rc = cont->Insert(buf, &offset);
  92. if (rc.IsNoSpace()) {
  93. create_new_container = true;
  94. } else if (rc.IsOk()) {
  95. out_value = std::make_pair(num_containers - 1, std::make_pair(offset, sz));
  96. RETURN_IF_NOT_OK(index_.insert(out_value, &out_key));
  97. *key = out_key;
  98. break;
  99. } else {
  100. return rc;
  101. }
  102. } while (true);
  103. return Status::OK();
  104. }
  105. Status StorageManager::Read(StorageManager::key_type key, WritableSlice *dest, size_t *bytesRead) const {
  106. RETURN_UNEXPECTED_IF_NULL(dest);
  107. auto r = index_.Search(key);
  108. if (r.second) {
  109. auto &it = r.first;
  110. value_type v = *it;
  111. int container_inx = v.first;
  112. off_t offset = v.second.first;
  113. size_t sz = v.second.second;
  114. if (dest->GetSize() < sz) {
  115. std::string errMsg = "Destination buffer too small. Expect at least " + std::to_string(sz) +
  116. " but length = " + std::to_string(dest->GetSize());
  117. RETURN_STATUS_UNEXPECTED(errMsg);
  118. }
  119. if (bytesRead != nullptr) {
  120. *bytesRead = sz;
  121. }
  122. auto cont = containers_.at(container_inx);
  123. RETURN_IF_NOT_OK(cont->Read(dest, offset));
  124. } else {
  125. RETURN_STATUS_UNEXPECTED("Key not found");
  126. }
  127. return Status::OK();
  128. }
  129. Status StorageManager::DoServiceStop() noexcept {
  130. Status rc;
  131. Status rc1;
  132. for (auto const &p : containers_) {
  133. // The destructor of StorageContainer is not called automatically until the use
  134. // count drops to 0. But it is not always the case. We will do it ourselves.
  135. rc = p.get()->Truncate();
  136. if (rc.IsError()) {
  137. rc1 = rc;
  138. }
  139. }
  140. containers_.clear();
  141. file_id_ = 0;
  142. return rc1;
  143. }
  144. StorageManager::StorageManager(const Path &root) : root_(root), file_id_(0), index_() {}
  145. StorageManager::~StorageManager() { (void)StorageManager::DoServiceStop(); }
  146. std::ostream &operator<<(std::ostream &os, const StorageManager &s) {
  147. os << "Dumping all containers ..."
  148. << "\n";
  149. for (auto const &p : s.containers_) {
  150. os << *(p.get());
  151. }
  152. return os;
  153. }
  154. } // namespace dataset
  155. } // namespace mindspore