]> source.dussan.org Git - sonarqube.git/blob
198f3ae8373afcb8d9ed88cd4649b8db8960529c
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 package org.sonar.server.platform.web.requestid;
21
22 import java.util.Base64;
23 import java.util.concurrent.atomic.AtomicLong;
24 import java.util.concurrent.atomic.AtomicReference;
25 import org.sonar.core.util.UuidGenerator;
26
27 /**
28  * This implementation of {@link RequestIdGenerator} creates unique identifiers for HTTP requests leveraging
29  * {@link UuidGenerator.WithFixedBase#generate(int)} and a counter of HTTP requests.
30  * <p>
31  * To work around the limit of unique values produced by {@link UuidGenerator.WithFixedBase#generate(int)}, the
32  * {@link UuidGenerator.WithFixedBase} instance will be renewed every
33  * {@link RequestIdConfiguration#getUidGeneratorRenewalCount() RequestIdConfiguration#uidGeneratorRenewalCount}
34  * HTTP requests.
35  * </p>
36  * <p>
37  * This implementation is Thread safe.
38  * </p>
39  */
40 public class RequestIdGeneratorImpl implements RequestIdGenerator {
41   /**
42    * The value to which the HTTP request count will be compared to (using a modulo operator,
43    * see {@link #mustRenewUuidGenerator(long)}).
44    *
45    * <p>
46    * This value can't be the last value before {@link UuidGenerator.WithFixedBase#generate(int)} returns a non unique
47    * value, ie. 2^23-1 because there is no guarantee the renewal will happen before any other thread calls
48    * {@link UuidGenerator.WithFixedBase#generate(int)} method of the deplated {@link UuidGenerator.WithFixedBase} instance.
49    * </p>
50    *
51    * <p>
52    * To keep a comfortable margin of error, 2^22 will be used.
53    * </p>
54    */
55   public static final long UUID_GENERATOR_RENEWAL_COUNT = 4_194_304;
56
57   private final AtomicLong counter = new AtomicLong();
58   private final RequestIdGeneratorBase requestIdGeneratorBase;
59   private final RequestIdConfiguration requestIdConfiguration;
60   private final AtomicReference<UuidGenerator.WithFixedBase> uuidGenerator;
61
62   public RequestIdGeneratorImpl(RequestIdGeneratorBase requestIdGeneratorBase, RequestIdConfiguration requestIdConfiguration) {
63     this.requestIdGeneratorBase = requestIdGeneratorBase;
64     this.uuidGenerator  = new AtomicReference<>(requestIdGeneratorBase.createNew());
65     this.requestIdConfiguration = requestIdConfiguration;
66   }
67
68   @Override
69   public String generate() {
70     UuidGenerator.WithFixedBase currentUuidGenerator = this.uuidGenerator.get();
71     long counterValue = counter.getAndIncrement();
72     if (counterValue != 0 && mustRenewUuidGenerator(counterValue)) {
73       UuidGenerator.WithFixedBase newUuidGenerator = requestIdGeneratorBase.createNew();
74       uuidGenerator.set(newUuidGenerator);
75       return generate(newUuidGenerator, counterValue);
76     }
77     return generate(currentUuidGenerator, counterValue);
78   }
79
80   /**
81    * Since renewal of {@link UuidGenerator.WithFixedBase} instance is based on the HTTP request counter, only a single
82    * thread can get the right value which will make this method return true. So, this is thread-safe by design, therefor
83    * this method doesn't need external synchronization.
84    * <p>
85    * The value to which the counter is compared should however be chosen with caution: see {@link #UUID_GENERATOR_RENEWAL_COUNT}.
86    * </p>
87    */
88   private boolean mustRenewUuidGenerator(long counter) {
89     return counter % requestIdConfiguration.getUidGeneratorRenewalCount() == 0;
90   }
91
92   private static String generate(UuidGenerator.WithFixedBase uuidGenerator, long increment) {
93     return Base64.getEncoder().encodeToString(uuidGenerator.generate((int) increment));
94   }
95
96 }