@@ -29,6 +29,7 @@ import (
2929 "github.com/cockroachdb/cockroach/pkg/settings"
3030 "github.com/cockroachdb/cockroach/pkg/settings/cluster"
3131 "github.com/cockroachdb/cockroach/pkg/util/ioctx"
32+ "github.com/cockroachdb/cockroach/pkg/util/syncutil"
3233 "github.com/cockroachdb/cockroach/pkg/util/timeutil"
3334 "github.com/cockroachdb/cockroach/pkg/util/tracing"
3435 "github.com/cockroachdb/errors"
@@ -55,6 +56,13 @@ var tryTimeout = settings.RegisterDurationSetting(
5556 "the timeout for individual retry attempts in Azure operations" ,
5657 60 * time .Second )
5758
59+ var reuseSession = settings .RegisterBoolSetting (
60+ settings .ApplicationLevel ,
61+ "cloudstorage.azure.session_reuse.enabled" ,
62+ "persist the last opened azure client and re-use it when opening a new client with the same argument (some settings may take 2mins to take effect)" ,
63+ false ,
64+ )
65+
5866// A note on Azure authentication:
5967//
6068// The standardized way to authenticate a third-party identity to the Azure
@@ -214,6 +222,14 @@ type azureStorage struct {
214222 settings * cluster.Settings
215223}
216224
225+ var azClientCache struct {
226+ syncutil.Mutex
227+ // TODO(dt): make this an >1 item cache e.g. add a FIFO ring.
228+ key cloudpb.ExternalStorage_Azure
229+ set time.Time
230+ client * service.Client
231+ }
232+
217233var _ cloud.ExternalStorage = & azureStorage {}
218234
219235func makeAzureStorage (
@@ -224,6 +240,7 @@ func makeAzureStorage(
224240 if conf == nil {
225241 return nil , errors .Errorf ("azure upload requested but info missing" )
226242 }
243+
227244 env , err := azure .EnvironmentFromName (conf .Environment )
228245 if err != nil {
229246 return nil , errors .Wrap (err , "azure environment" )
@@ -256,6 +273,29 @@ func makeAzureStorage(
256273 opts .Retry .TryTimeout = tryTimeout .Get (& args .Settings .SV )
257274
258275 var azClient * service.Client
276+
277+ clientConf := * conf
278+ clientConf .Prefix = "" // Prefix is not part of the client identity.
279+
280+ if reuseSession .Get (& args .Settings .SV ) {
281+ func () {
282+ azClientCache .Lock ()
283+ defer azClientCache .Unlock ()
284+ if cached := azClientCache .client ; cached != nil && azClientCache .key == clientConf && timeutil .Since (azClientCache .set ) < 2 * time .Minute {
285+ azClient = cached
286+ }
287+ }()
288+ if azClient != nil {
289+ return & azureStorage {
290+ conf : conf ,
291+ ioConf : args .IOConf ,
292+ container : azClient .NewContainerClient (conf .Container ),
293+ prefix : conf .Prefix ,
294+ settings : args .Settings ,
295+ }, nil
296+ }
297+ }
298+
259299 switch conf .Auth {
260300 case cloudpb .AzureAuth_LEGACY :
261301 credential , err := azblob .NewSharedKeyCredential (conf .AccountName , conf .AccountKey )
@@ -299,6 +339,14 @@ func makeAzureStorage(
299339 return nil , errors .Errorf ("unsupported value %s for %s" , conf .Auth , cloud .AuthParam )
300340 }
301341
342+ if reuseSession .Get (& args .Settings .SV ) {
343+ azClientCache .Lock ()
344+ defer azClientCache .Unlock ()
345+ azClientCache .key = clientConf
346+ azClientCache .client = azClient
347+ azClientCache .set = timeutil .Now ()
348+ }
349+
302350 return & azureStorage {
303351 conf : conf ,
304352 ioConf : args .IOConf ,
0 commit comments