33
33
import com .google .devtools .build .lib .skyframe .TreeArtifactValue ;
34
34
import com .google .devtools .build .lib .util .Fingerprint ;
35
35
import com .google .devtools .build .lib .vfs .DigestUtils ;
36
+ import com .google .devtools .build .lib .vfs .OutputPermissions ;
36
37
import com .google .devtools .build .lib .vfs .PathFragment ;
37
38
import java .io .IOException ;
38
39
import java .io .PrintStream ;
@@ -84,9 +85,11 @@ public interface ActionCache {
84
85
* will continue to return same result regardless of internal data transformations).
85
86
*/
86
87
final class Entry {
88
+ private static final byte [] EMPTY_CLIENT_ENV_DIGEST = new byte [0 ];
89
+
87
90
/** Unique instance to represent a corrupted cache entry. */
88
91
public static final ActionCache .Entry CORRUPTED =
89
- new ActionCache .Entry (null , ImmutableMap .of (), false );
92
+ new ActionCache .Entry (null , ImmutableMap .of (), false , OutputPermissions . READONLY );
90
93
91
94
private final String actionKey ;
92
95
@ Nullable
@@ -95,7 +98,7 @@ final class Entry {
95
98
// If null, digest is non-null and the entry is immutable.
96
99
private Map <String , FileArtifactValue > mdMap ;
97
100
private byte [] digest ;
98
- private final byte [] usedClientEnvDigest ;
101
+ private final byte [] actionPropertiesDigest ;
99
102
private final Map <String , RemoteFileArtifactValue > outputFileMetadata ;
100
103
private final Map <String , SerializableTreeArtifactValue > outputTreeMetadata ;
101
104
@@ -160,9 +163,13 @@ public static Optional<SerializableTreeArtifactValue> createSerializable(
160
163
public abstract Optional <PathFragment > materializationExecPath ();
161
164
}
162
165
163
- public Entry (String key , Map <String , String > usedClientEnv , boolean discoversInputs ) {
166
+ public Entry (
167
+ String key ,
168
+ Map <String , String > usedClientEnv ,
169
+ boolean discoversInputs ,
170
+ OutputPermissions outputPermissions ) {
164
171
actionKey = key ;
165
- this .usedClientEnvDigest = digestClientEnv (usedClientEnv );
172
+ this .actionPropertiesDigest = digestActionProperties (usedClientEnv , outputPermissions );
166
173
files = discoversInputs ? new ArrayList <>() : null ;
167
174
mdMap = new HashMap <>();
168
175
outputFileMetadata = new HashMap <>();
@@ -171,39 +178,46 @@ public Entry(String key, Map<String, String> usedClientEnv, boolean discoversInp
171
178
172
179
public Entry (
173
180
String key ,
174
- byte [] usedClientEnvDigest ,
181
+ byte [] actionPropertiesDigest ,
175
182
@ Nullable List <String > files ,
176
183
byte [] digest ,
177
184
Map <String , RemoteFileArtifactValue > outputFileMetadata ,
178
185
Map <String , SerializableTreeArtifactValue > outputTreeMetadata ) {
179
186
actionKey = key ;
180
- this .usedClientEnvDigest = usedClientEnvDigest ;
187
+ this .actionPropertiesDigest = actionPropertiesDigest ;
181
188
this .files = files ;
182
189
this .digest = digest ;
183
190
mdMap = null ;
184
191
this .outputFileMetadata = outputFileMetadata ;
185
192
this .outputTreeMetadata = outputTreeMetadata ;
186
193
}
187
194
188
- private static final byte [] EMPTY_CLIENT_ENV_DIGEST = new byte [0 ];
189
-
190
195
/**
191
- * Computes an order-independent digest of a map of environment variables.
196
+ * Computes an order-independent digest of action properties. This includes a map of client
197
+ * environment variables and the non-default permissions for output artifacts of the action.
192
198
*
193
199
* <p>Note that as discussed in https://github.com/bazelbuild/bazel/issues/15660, using {@link
194
200
* DigestUtils#xor} to achieve order-independence is questionable in case it is possible that
195
201
* multiple string keys map to the same bytes when passed through {@link Fingerprint#addString}
196
202
* (due to lossy conversion from UTF-16 to UTF-8). We could instead use a sorted map, however
197
203
* changing the digest function would cause action cache misses across bazel versions.
198
204
*/
199
- private static byte [] digestClientEnv (Map <String , String > clientEnv ) {
205
+ private static byte [] digestActionProperties (
206
+ Map <String , String > clientEnv , OutputPermissions outputPermissions ) {
200
207
byte [] result = EMPTY_CLIENT_ENV_DIGEST ;
201
208
Fingerprint fp = new Fingerprint ();
202
209
for (Map .Entry <String , String > entry : clientEnv .entrySet ()) {
203
210
fp .addString (entry .getKey ());
204
211
fp .addString (entry .getValue ());
205
212
result = DigestUtils .xor (result , fp .digestAndReset ());
206
213
}
214
+ // Add the permissions mode to the digest if it differs from the default.
215
+ // This is a bit of a hack to save memory on entries which have the default permissions mode
216
+ // and no client env.
217
+ if (outputPermissions != OutputPermissions .READONLY ) {
218
+ fp .addInt (outputPermissions .getPermissionsMode ());
219
+ result = DigestUtils .xor (result , fp .digestAndReset ());
220
+ }
207
221
return result ;
208
222
}
209
223
@@ -288,14 +302,16 @@ public String getActionKey() {
288
302
return actionKey ;
289
303
}
290
304
291
- /** @return the effectively used client environment */
292
- public byte [] getUsedClientEnvDigest () {
293
- return usedClientEnvDigest ;
305
+ /** Returns the effectively used client environment. */
306
+ public byte [] getActionPropertiesDigest () {
307
+ return actionPropertiesDigest ;
294
308
}
295
309
296
- /** Determines whether this entry used the same client environment as the one given. */
297
- public boolean usedSameClientEnv (Map <String , String > clientEnv ) {
298
- return Arrays .equals (digestClientEnv (clientEnv ), usedClientEnvDigest );
310
+ /** Determines whether this entry has the same action properties as the one given. */
311
+ public boolean sameActionProperties (
312
+ Map <String , String > clientEnv , OutputPermissions outputPermissions ) {
313
+ return Arrays .equals (
314
+ digestActionProperties (clientEnv , outputPermissions ), actionPropertiesDigest );
299
315
}
300
316
301
317
/**
@@ -343,7 +359,7 @@ public String toString() {
343
359
builder .append (" actionKey = " ).append (actionKey ).append ("\n " );
344
360
builder
345
361
.append (" usedClientEnvKey = " )
346
- .append (formatDigest (usedClientEnvDigest ))
362
+ .append (formatDigest (actionPropertiesDigest ))
347
363
.append ("\n " );
348
364
builder .append (" digestKey = " );
349
365
if (digest == null ) {
0 commit comments