• 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 #ifndef ICING_FILE_VERSION_UTIL_H_
16 #define ICING_FILE_VERSION_UTIL_H_
17 
18 #include <cstdint>
19 #include <memory>
20 #include <string>
21 #include <string_view>
22 
23 #include "icing/text_classifier/lib3/utils/base/status.h"
24 #include "icing/text_classifier/lib3/utils/base/statusor.h"
25 #include "icing/absl_ports/str_cat.h"
26 #include "icing/file/derived-file-util.h"
27 #include "icing/file/filesystem.h"
28 #include "icing/proto/initialize.pb.h"
29 
30 namespace icing {
31 namespace lib {
32 
33 namespace version_util {
34 
35 // - Version 0: Android T base. Can be identified only by flash index magic.
36 // - Version 1: Android U base and M-2023-08.
37 // - Version 2: M-2023-09, M-2023-11, M-2024-01. Schema is compatible with v1.
38 //   (There were no M-2023-10, M-2023-12).
39 // - Version 3: M-2024-02. Schema is compatible with v1 and v2.
40 // - Version 4: Android V base. Schema is compatible with v1, v2 and v3.
41 // - Version 5: M-2025-02. Schema is compatible with v1, v2, v3 and v4.
42 inline static constexpr int32_t kVersion = 7;
43 inline static constexpr int32_t kVersionOne = 1;
44 inline static constexpr int32_t kVersionTwo = 2;
45 inline static constexpr int32_t kVersionThree = 3;
46 inline static constexpr int32_t kVersionFour = 4;
47 inline static constexpr int32_t kVersionFive = 5;
48 
49 // Version at which v2 version file is introduced.
50 inline static constexpr int32_t kFirstV2Version = kVersionFour;
51 
52 // Version at which the database field is introduced to the schema proto.
53 inline static constexpr int32_t kSchemaDatabaseVersion = kVersionFive;
54 
55 inline static constexpr int kVersionZeroFlashIndexMagic = 0x6dfba6ae;
56 
57 inline static constexpr std::string_view kVersionFilenameV1 = "version";
58 inline static constexpr std::string_view kVersionFilenameV2 = "version2";
59 
60 struct VersionInfo {
61   int32_t version;
62   int32_t max_version;
63 
VersionInfoVersionInfo64   explicit VersionInfo(int32_t version_in, int32_t max_version_in)
65       : version(version_in), max_version(max_version_in) {}
66 
IsValidVersionInfo67   bool IsValid() const { return version >= 0 && max_version >= 0; }
68 
69   bool operator==(const VersionInfo& other) const {
70     return version == other.version && max_version == other.max_version;
71   }
72 } __attribute__((packed));
73 static_assert(sizeof(VersionInfo) == 8, "");
74 
75 enum class StateChange {
76   kUndetermined,
77   kCompatible,
78   kRollForward,
79   kRollBack,
80   kUpgrade,
81   kVersionZeroUpgrade,
82   kVersionZeroRollForward,
83 };
84 
85 // There are two icing version files:
86 // 1. V1 version file contains version and max_version info of the existing
87 //    data.
88 // 2. V2 version file writes the version information using
89 //    FileBackedProto<IcingSearchEngineVersionProto>. This contains information
90 //    about the version's enabled trunk stable features in addition to the
91 //    version numbers written for V1.
92 //
93 // Both version files must be written to maintain backwards compatibility.
MakeVersionFilePath(std::string_view version_file_dir,std::string_view version_file_name)94 inline std::string MakeVersionFilePath(std::string_view version_file_dir,
95                                        std::string_view version_file_name) {
96   return absl_ports::StrCat(version_file_dir, "/", version_file_name);
97 }
98 
99 // Returns a VersionInfo from a given IcingSearchEngineVersionProto.
GetVersionInfoFromProto(const IcingSearchEngineVersionProto & version_proto)100 inline VersionInfo GetVersionInfoFromProto(
101     const IcingSearchEngineVersionProto& version_proto) {
102   return VersionInfo(version_proto.version(), version_proto.max_version());
103 }
104 
105 // Reads the IcingSearchEngineVersionProto from the version files of the
106 // existing data.
107 //
108 // This method reads both the v1 and v2 version files, and returns the v1
109 // version numbers in the absence of the v2 version file. If there is a mismatch
110 // between the v1 and v2 version numbers, or if the state is invalid (e.g. flash
111 // index header file is missing), then an invalid VersionInfo is returned.
112 //
113 // RETURNS:
114 //   - Existing data's IcingSearchEngineVersionProto on success
115 //   - INTERNAL_ERROR on I/O errors
116 libtextclassifier3::StatusOr<IcingSearchEngineVersionProto> ReadVersion(
117     const Filesystem& filesystem, const std::string& version_file_dir,
118     const std::string& index_base_dir);
119 
120 // Writes the v1 version file. V1 version file is written for all versions and
121 // contains only Icing's VersionInfo (version number and max_version)
122 //
123 // RETURNS:
124 //   - OK on success
125 //   - INTERNAL_ERROR on I/O errors
126 libtextclassifier3::Status WriteV1Version(const Filesystem& filesystem,
127                                           const std::string& version_file_dir,
128                                           const VersionInfo& version_info);
129 
130 // Writes the v2 version file. V2 version file writes the version information
131 // using FileBackedProto<IcingSearchEngineVersionProto>.
132 //
133 // REQUIRES: version_proto.version >= kFirstV2Version. We implement v2 version
134 // checking in kFirstV2Version, so callers will always use a version # greater
135 // than this.
136 //
137 // RETURNS:
138 //   - OK on success
139 //   - INTERNAL_ERROR on I/O errors
140 libtextclassifier3::Status WriteV2Version(
141     const Filesystem& filesystem, const std::string& version_file_dir,
142     std::unique_ptr<IcingSearchEngineVersionProto> version_proto);
143 
144 // Deletes Icing's version files from version_file_dir.
145 //
146 // Returns:
147 //   - OK on success
148 //   - INTERNAL_ERROR on I/O error
149 libtextclassifier3::Status DiscardVersionFiles(
150     const Filesystem& filesystem, std::string_view version_file_dir);
151 
152 // Determines the change state between the existing data version and the current
153 // code version.
154 //
155 // REQUIRES: curr_version > 0. We implement version checking in version 1, so
156 //   the callers (except unit tests) will always use a version # greater than 0.
157 //
158 // RETURNS: StateChange
159 StateChange GetVersionStateChange(const VersionInfo& existing_version_info,
160                                   int32_t curr_version = kVersion);
161 
162 // Determines the derived files that need to be rebuilt between Icing's existing
163 // data based on previous data version and enabled features, and the current
164 // code version and enabled features.
165 //
166 // REQUIRES: curr_version >= kFirstV2Version. We implement v2 version checking
167 // in kFirstV2Version, so callers will always use a version # greater than this.
168 //
169 // RETURNS: derived_file_util::DerivedFilesRebuildInfo
170 derived_file_util::DerivedFilesRebuildInfo CalculateRequiredDerivedFilesRebuild(
171     const IcingSearchEngineVersionProto& prev_version_proto,
172     const IcingSearchEngineVersionProto& curr_version_proto);
173 
174 // Determines whether Icing should rebuild all derived files.
175 // Sometimes it is not required to rebuild derived files when
176 // roll-forward/upgrading. This function "encodes" upgrade paths and checks if
177 // the roll-forward/upgrading requires derived files to be rebuilt or not.
178 //
179 // REQUIRES: curr_version > 0. We implement version checking in version 1, so
180 //   the callers (except unit tests) will always use a version # greater than 0.
181 bool ShouldRebuildDerivedFiles(const VersionInfo& existing_version_info,
182                                int32_t curr_version = kVersion);
183 
184 // Returns whether the schema database migration is required.
185 //
186 // This is true if the previous version is less than the version at which the
187 // database field is introduced, or if the schema database feature was
188 // not enabled in the previous version.
189 bool SchemaDatabaseMigrationRequired(
190     const IcingSearchEngineVersionProto& prev_version_proto);
191 
192 // Returns the derived files rebuilds required for a given feature.
193 derived_file_util::DerivedFilesRebuildInfo GetFeatureDerivedFilesRebuildInfo(
194     IcingSearchEngineFeatureInfoProto::FlaggedFeatureType feature);
195 
196 // Constructs the IcingSearchEngineFeatureInfoProto for a given feature.
197 IcingSearchEngineFeatureInfoProto GetFeatureInfoProto(
198     IcingSearchEngineFeatureInfoProto::FlaggedFeatureType feature);
199 
200 // Populates the enabled_features field for an IcingSearchEngineFeatureInfoProto
201 // based on icing's initialization flag options.
202 //
203 // All enabled features are converted into an IcingSearchEngineFeatureInfoProto
204 // and returned in IcingSearchEngineVersionProto::enabled_features. A conversion
205 // should be added for each trunk stable feature flag defined in
206 // IcingSearchEngineOptions.
207 void AddEnabledFeatures(const IcingSearchEngineOptions& options,
208                         IcingSearchEngineVersionProto* version_proto);
209 
210 }  // namespace version_util
211 
212 }  // namespace lib
213 }  // namespace icing
214 
215 #endif  // ICING_FILE_VERSION_UTIL_H_
216