• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (C) 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "icing/file/version-util.h"
16 
17 #include <cstdint>
18 #include <string>
19 #include <utility>
20 
21 #include "icing/text_classifier/lib3/utils/base/status.h"
22 #include "icing/text_classifier/lib3/utils/base/statusor.h"
23 #include "icing/absl_ports/canonical_errors.h"
24 #include "icing/file/filesystem.h"
25 #include "icing/index/index.h"
26 
27 namespace icing {
28 namespace lib {
29 
30 namespace version_util {
31 
ReadVersion(const Filesystem & filesystem,const std::string & version_file_path,const std::string & index_base_dir)32 libtextclassifier3::StatusOr<VersionInfo> ReadVersion(
33     const Filesystem& filesystem, const std::string& version_file_path,
34     const std::string& index_base_dir) {
35   // 1. Read the version info.
36   VersionInfo existing_version_info(-1, -1);
37   if (filesystem.FileExists(version_file_path.c_str()) &&
38       !filesystem.PRead(version_file_path.c_str(), &existing_version_info,
39                         sizeof(VersionInfo), /*offset=*/0)) {
40     return absl_ports::InternalError("Fail to read version");
41   }
42 
43   // 2. Check the Index magic to see if we're actually on version 0.
44   libtextclassifier3::StatusOr<int> existing_flash_index_magic_or =
45       Index::ReadFlashIndexMagic(&filesystem, index_base_dir);
46   if (!existing_flash_index_magic_or.ok()) {
47     if (absl_ports::IsNotFound(existing_flash_index_magic_or.status())) {
48       // Flash index magic doesn't exist. In this case, we're unable to
49       // determine the version change state correctly (regardless of the
50       // existence of the version file), so invalidate VersionInfo by setting
51       // version to -1, but still keep the max_version value read in step 1.
52       existing_version_info.version = -1;
53       return existing_version_info;
54     }
55     // Real error.
56     return std::move(existing_flash_index_magic_or).status();
57   }
58   if (existing_flash_index_magic_or.ValueOrDie() ==
59       kVersionZeroFlashIndexMagic) {
60     existing_version_info.version = 0;
61     if (existing_version_info.max_version == -1) {
62       existing_version_info.max_version = 0;
63     }
64   }
65 
66   return existing_version_info;
67 }
68 
WriteVersion(const Filesystem & filesystem,const std::string & version_file_path,const VersionInfo & version_info)69 libtextclassifier3::Status WriteVersion(const Filesystem& filesystem,
70                                         const std::string& version_file_path,
71                                         const VersionInfo& version_info) {
72   ScopedFd scoped_fd(filesystem.OpenForWrite(version_file_path.c_str()));
73   if (!scoped_fd.is_valid() ||
74       !filesystem.PWrite(scoped_fd.get(), /*offset=*/0, &version_info,
75                          sizeof(VersionInfo)) ||
76       !filesystem.DataSync(scoped_fd.get())) {
77     return absl_ports::InternalError("Fail to write version");
78   }
79   return libtextclassifier3::Status::OK;
80 }
81 
GetVersionStateChange(const VersionInfo & existing_version_info,int32_t curr_version)82 StateChange GetVersionStateChange(const VersionInfo& existing_version_info,
83                                   int32_t curr_version) {
84   if (!existing_version_info.IsValid()) {
85     return StateChange::kUndetermined;
86   }
87 
88   if (existing_version_info.version == 0) {
89     return (existing_version_info.max_version == existing_version_info.version)
90                ? StateChange::kVersionZeroUpgrade
91                : StateChange::kVersionZeroRollForward;
92   }
93 
94   if (existing_version_info.version == curr_version) {
95     return StateChange::kCompatible;
96   } else if (existing_version_info.version > curr_version) {
97     return StateChange::kRollBack;
98   } else {  // existing_version_info.version < curr_version
99     return (existing_version_info.max_version == existing_version_info.version)
100                ? StateChange::kUpgrade
101                : StateChange::kRollForward;
102   }
103 }
104 
105 }  // namespace version_util
106 
107 }  // namespace lib
108 }  // namespace icing
109