| // Copyright 2024 The Bazel Authors. All rights reserved. | |
| // | |
| // 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. | |
| edition = "2023"; | |
| package devtools.skyframe; | |
| option java_multiple_files = true; | |
| option java_package = "com.google.devtools.build.lib.skyframe.serialization.proto"; | |
| // This message contains sufficient information to invalidate Bazel file | |
| // dependencies against repository diffs. | |
| // | |
| // The goal is for this data to represent | |
| // `com.google.devtools.build.lib.vfs.FileStateKey.argument` values. However, | |
| // these values are represented within a structure defined by the | |
| // `com.google.devtools.build.lib.skyframe.FileFunction`, meaning that whenever | |
| // a `FileStateKey.argument` is encountered, it implies that its parent | |
| // directory will be present. Therefore, there's going to be significant | |
| // redundancy in the path information. | |
| // | |
| // This redundancy can be exploited for compactness, resulting in this implicit | |
| // representation. | |
| // | |
| // This value is always used in the context of a key-value store (e.g. | |
| // Memcached), where the key is defined as follows. Let E be some | |
| // Memcached-friendly encoding function, (e.g. Base64) and `:` be a delimiter in | |
| // the following (`:` does not occur in Base64, making it a good delimiter). Let | |
| // MTSV be the maximum transitive source version, a version number that is the | |
| // maximum version over all the transitive source files affecting an entry. In | |
| // the case of a file, this includes all source versions of all parent | |
| // directories and any symlinks needed to resolve it. The MTSV is a canonical | |
| // version for the file. | |
| // | |
| // KEY = E(MTSV) : <FileValue.Key.argument path> | |
| // | |
| // Logically, the key consists of the FileValue's MTSV and unresolved path. | |
| // Note, in particular, the path data present in the key does not need to be | |
| // repeated in the value. The parent directory of this key is already the | |
| // `FileValue.Key.argument` path of its parent directory, so that doesn't need | |
| // to be repeated either. The only additional data needed to identify the | |
| // `FileInvalidationData` of its parent is the parent's MTSV, which is included | |
| // as `parent_mtsv`. | |
| // | |
| // In the common case, `FileInvalidationData` only contains `parent_mtsv` and | |
| // that's sufficient information to derive all the paths, assuming that the | |
| // parent lookups are transitively performed. The `FileStateKey.argument` | |
| // matches the path present in the key. | |
| // | |
| // In the presence of symlinks, special logic applies to produce the resolved | |
| // paths. A `symlinks` entry will be present. To unpack the symlink entry, we | |
| // first resolve the parent path as usual. Then, we concatenate the symlink's | |
| // contents to the resolved parent path and syntactically normalize it | |
| // (interpreting things like `..`, `.` using string manipulation). This | |
| // establishes a new path to be recursively resolved. `Symlink` contains another | |
| // `parent_mtsv` for this purpose. The resulting resolved path is another | |
| // implicit `FileStateKey.argument` value. If this path is itself a symlink, the | |
| // process is repeated. | |
| // | |
| // Note that this is only suitable for persisting information about a successful | |
| // build so it ignores symlink cycles. | |
| message FileInvalidationData { | |
| // The following field is populated when the key needs to be abbreviated to | |
| // its fingerprint due to Memcached's key length restriction. This field can | |
| // be used to verify that no fingerprint collision has occurred. | |
| string overflow_key = 1; | |
| // The MTSV used to resolve the parent directory. | |
| // | |
| // Resolution means creating a key from this MTSV and the parent directory of | |
| // the key of this entry, looking up the value and interpreting it. | |
| // | |
| // Optional. Only unset when the path has no parent, i.e. contains no '/' | |
| // separators. | |
| int64 parent_mtsv = 2; | |
| // This field is repeated, with one entry for each symbolic link encountered | |
| // while resolving the path. | |
| repeated Symlink symlinks = 3; | |
| // Type of the fully resolved entry. | |
| // | |
| // Symbolic links are not included in the DirentType enum below. They are | |
| // exclusively represented using the symlinks field. | |
| enum DirentType { | |
| // Required by internal best practices. | |
| // Not expected to occur. | |
| UNDEFINED = 0; | |
| // A regular file. | |
| FILE = 1; | |
| // A directory. | |
| DIRECTORY = 2; | |
| // Explicit marker for a non-existing file. | |
| // | |
| // Nonexistence of specific files is meaningful to Bazel, (e.g., BUILD | |
| // files). | |
| NON_EXISTENT = 3; | |
| } | |
| // Type of the final resolved file. | |
| // | |
| // Required. | |
| DirentType type = 4; | |
| } | |
| // Invalidation information for a | |
| // `com.google.devtools.build.lib.skyframe.DirectoryListingValue`. Note | |
| // that this is designed for certain repository deltas have no directory | |
| // awareness. This means when a file within the directory changes, there's no | |
| // change notification to the directory itself. The consumer is responsible for | |
| // invalidating this entry when its children change in ways that would affect | |
| // the directory listing, like adding and deleting files or a change in their | |
| // type. | |
| // | |
| // This behaves very similarly to `FileInvalidationData`. The KEY is same except | |
| // that it uses a different delimiter, `;`. | |
| // | |
| // This induces a `FileInvalidationData` at the same path as in the key. The | |
| // resolved path of the `FileInvalidationData` is the real path of this | |
| // directory. NB: this is slightly different from `FileInvalidationData` | |
| // behavior which induces a `FileInvalidationData` entry of its parent. | |
| message DirectoryListingInvalidationData { | |
| // The following field is populated when the key needs to be abbreviated to | |
| // its fingerprint due to Memcached's key length restriction. This field can | |
| // be used to verify that no fingerprint collision has occurred. | |
| string overflow_key = 1; | |
| // MTSV required to resolve the real directory path. | |
| int64 file_mtsv = 2; | |
| } | |
| // Representation of symlinks in `FileInvalidationData`. | |
| message Symlink { | |
| // The contents of the symlink. | |
| // | |
| // This field only stores the path specified within the symlink itself. The | |
| // resolved path of the symlink's parent directory is determined based on its | |
| // position within the `symlinks` field in the `FileInvalidationData` message. | |
| // | |
| // * For the first `Symlink` entry in the list, the parent directory is the | |
| // same as the parent directory of the original file path being resolved. | |
| // * For subsequent `Symlink` entries, the parent directory is the directory | |
| // of the resolved target path of the preceding `Symlink` entry. | |
| // | |
| // Given the resolved parent directory, `contents` appended to that parent | |
| // directory and then syntactically normalized, resulting in a new path. | |
| // | |
| // Required. | |
| string contents = 1; | |
| // The MTSV of the resolved parent directory of this symlink. | |
| // | |
| // This field is optional. It is only set if the resolved path formed by | |
| // combining the `contents` with the parent directory results in a *different* | |
| // parent directory than the one used to resolve the symlink itself. | |
| // | |
| // Optional. | |
| int64 parent_mtsv = 2; | |
| } |