Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: client/cipd/client.go

Issue 1870263002: cipd: instance cache (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/luci-go@master
Patch Set: add tests, fix gc Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // Package cipd implements client side of Chrome Infra Package Deployer. 5 // Package cipd implements client side of Chrome Infra Package Deployer.
6 // 6 //
7 // Binary package file format (in free form representation): 7 // Binary package file format (in free form representation):
8 // <binary package> := <zipped data> 8 // <binary package> := <zipped data>
9 // <zipped data> := DeterministicZip(<all input files> + <manifest json>) 9 // <zipped data> := DeterministicZip(<all input files> + <manifest json>)
10 // <manifest json> := File{ 10 // <manifest json> := File{
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 // RPC requests. 330 // RPC requests.
331 AuthenticatedClientFactory HTTPClientFactory 331 AuthenticatedClientFactory HTTPClientFactory
332 332
333 // AnonymousClientFactory lazily creates http.Client to use for making 333 // AnonymousClientFactory lazily creates http.Client to use for making
334 // requests to storage. 334 // requests to storage.
335 AnonymousClientFactory HTTPClientFactory 335 AnonymousClientFactory HTTPClientFactory
336 336
337 // UserAgent is put into User-Agent HTTP header with each request. 337 // UserAgent is put into User-Agent HTTP header with each request.
338 UserAgent string 338 UserAgent string
339 339
340 » // CacheDir is a directory for shared cache. If empty, tags are cached 340 » // CacheDir is a directory for shared cache. If empty, instances are not
341 » // inside the site root. If both Root and CacheDir are empty, tag cache 341 » // cached and tags are cached inside the site root. If both Root and
342 » // is disabled. 342 » // CacheDir are empty, tag cache is disabled.
343 CacheDir string 343 CacheDir string
344 } 344 }
345 345
346 // NewClient initializes CIPD client object. 346 // NewClient initializes CIPD client object.
347 func NewClient(opts ClientOptions) Client { 347 func NewClient(opts ClientOptions) Client {
348 if opts.ServiceURL == "" { 348 if opts.ServiceURL == "" {
349 opts.ServiceURL = ServiceURL 349 opts.ServiceURL = ServiceURL
350 } 350 }
351 if opts.Logger == nil { 351 if opts.Logger == nil {
352 opts.Logger = logging.Null() 352 opts.Logger = logging.Null()
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 // storage knows how to upload and download raw binaries using signed UR Ls. 385 // storage knows how to upload and download raw binaries using signed UR Ls.
386 // Thread safe. 386 // Thread safe.
387 storage storage 387 storage storage
388 388
389 // deployer knows how to install packages to local file system. Thread s afe. 389 // deployer knows how to install packages to local file system. Thread s afe.
390 deployer local.Deployer 390 deployer local.Deployer
391 391
392 // tagCacheLock is used to synchronize access to the tag cache file. 392 // tagCacheLock is used to synchronize access to the tag cache file.
393 tagCacheLock sync.Mutex 393 tagCacheLock sync.Mutex
394 394
395 // instanceCache is a file-system based cache of instances.
396 instanceCache *internal.InstanceCache
397 instanceCacheInit sync.Once
398
395 // authClient is a lazily created http.Client to use for authenticated 399 // authClient is a lazily created http.Client to use for authenticated
396 // requests. Thread safe, but lazily initialized under lock. 400 // requests. Thread safe, but lazily initialized under lock.
397 authClient *http.Client 401 authClient *http.Client
398 402
399 // anonClient is a lazily created http.Client to use for anonymous reque sts. 403 // anonClient is a lazily created http.Client to use for anonymous reque sts.
400 // Thread safe, but lazily initialized under lock. 404 // Thread safe, but lazily initialized under lock.
401 anonClient *http.Client 405 anonClient *http.Client
402 } 406 }
403 407
404 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call s. 408 // doAuthenticatedHTTPRequest is used by remote implementation to make HTTP call s.
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 if err != nil { 486 if err != nil {
483 client.Logger.Warningf("cipd: failed to update tag cache - %s", err) 487 client.Logger.Warningf("cipd: failed to update tag cache - %s", err)
484 } 488 }
485 } 489 }
486 490
487 if loadSaveTime > time.Second { 491 if loadSaveTime > time.Second {
488 client.Logger.Warningf("cipd: loading and saving tag cache with %d entries took %s", cache.Len(), loadSaveTime) 492 client.Logger.Warningf("cipd: loading and saving tag cache with %d entries took %s", cache.Len(), loadSaveTime)
489 } 493 }
490 } 494 }
491 495
496 // getInstanceCache lazy-initializes instanceCache and returns it.
497 // May return nil if instance cache is disabled.
498 func (client *clientImpl) getInstanceCache() *internal.InstanceCache {
499 client.instanceCacheInit.Do(func() {
500 if client.CacheDir == "" {
501 return
502 }
503 path := filepath.Join(client.CacheDir, "instances")
504 fs := local.NewFileSystem(path, client.Logger)
505 client.instanceCache = internal.NewInstanceCache(fs, client.Logg er)
506 })
507 return client.instanceCache
508 }
509
492 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) { 510 func (client *clientImpl) FetchACL(packagePath string) ([]PackageACL, error) {
493 return client.remote.fetchACL(packagePath) 511 return client.remote.fetchACL(packagePath)
494 } 512 }
495 513
496 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan ge) error { 514 func (client *clientImpl) ModifyACL(packagePath string, changes []PackageACLChan ge) error {
497 return client.remote.modifyACL(packagePath, changes) 515 return client.remote.modifyACL(packagePath, changes)
498 } 516 }
499 517
500 func (client *clientImpl) ListPackages(path string, recursive bool) ([]string, e rror) { 518 func (client *clientImpl) ListPackages(path string, recursive bool) ([]string, e rror) {
501 pkgs, dirs, err := client.remote.listPackages(path, recursive) 519 pkgs, dirs, err := client.remote.listPackages(path, recursive)
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 769
752 func (client *clientImpl) FetchInstanceRefs(pin common.Pin, refs []string) ([]Re fInfo, error) { 770 func (client *clientImpl) FetchInstanceRefs(pin common.Pin, refs []string) ([]Re fInfo, error) {
753 err := common.ValidatePin(pin) 771 err := common.ValidatePin(pin)
754 if err != nil { 772 if err != nil {
755 return nil, err 773 return nil, err
756 } 774 }
757 return client.remote.fetchRefs(pin, refs) 775 return client.remote.fetchRefs(pin, refs)
758 } 776 }
759 777
760 func (client *clientImpl) FetchInstance(pin common.Pin, output io.WriteSeeker) e rror { 778 func (client *clientImpl) FetchInstance(pin common.Pin, output io.WriteSeeker) e rror {
761 » err := common.ValidatePin(pin) 779 » cache := client.getInstanceCache()
Vadim Sh. 2016/04/13 21:49:02 you lost this check
nodir 2016/04/13 23:23:51 Done.
762 » if err != nil { 780 » if cache == nil {
781 » » return client.fetchInstanceNoCache(pin, output)
782 » }
783 » return client.fetchInstanceWithCache(pin, cache, output)
784 }
785
786 func (client *clientImpl) fetchInstanceNoCache(pin common.Pin, output io.WriteSe eker) error {
787 » if err := client.remoteFetchInstance(pin, output); err != nil {
763 return err 788 return err
764 } 789 }
790 client.Logger.Infof("cipd: successfully fetched %s", pin)
791 return nil
792 }
793
794 func (client *clientImpl) fetchInstanceWithCache(pin common.Pin, cache *internal .InstanceCache, output io.WriteSeeker) error {
795 // Try to get the instance from cache.
796 now := client.clock.now()
797 switch err := cache.Get(pin, output, now); {
798 case os.IsNotExist(err):
799 // output is not corrupted.
800
801 case err != nil:
802 client.Logger.Warningf("cipd: could not get %s from cache - %s", pin, err)
803 // Output may be corrupted. Rewinding back.
Vadim Sh. 2016/04/13 21:49:02 you still need to truncate the file :(
nodir 2016/04/13 23:23:52 it is not required. I've improved the comment
804 if _, err := output.Seek(0, 0); err != nil {
805 return err
806 }
807
808 default:
809 client.Logger.Debugf("cipd: instance cache hit for %s", pin)
810 return nil
811 }
812
813 return cache.Put(pin, now, func(f *os.File) error {
814 // Fetch to the file.
815 if err := client.remoteFetchInstance(pin, f); err != nil {
816 return err
817 }
818
819 // Copy fetched content to output.
820 if _, err := f.Seek(0, 0); err != nil {
821 return err
822 }
823 if _, err := io.Copy(output, f); err != nil {
Vadim Sh. 2016/04/13 21:49:02 eh.. probably good enough for now, but it is a bit
nodir 2016/04/13 23:23:52 Acknowledged.
824 return err
825 }
826 client.Logger.Infof("cipd: successfully fetched %s", pin)
827 return nil
828 })
829 }
830
831 func (client *clientImpl) remoteFetchInstance(pin common.Pin, output io.WriteSee ker) error {
765 client.Logger.Infof("cipd: resolving fetch URL for %s", pin) 832 client.Logger.Infof("cipd: resolving fetch URL for %s", pin)
766 fetchInfo, err := client.remote.fetchInstance(pin) 833 fetchInfo, err := client.remote.fetchInstance(pin)
767 if err == nil { 834 if err == nil {
768 err = client.storage.download(fetchInfo.fetchURL, output) 835 err = client.storage.download(fetchInfo.fetchURL, output)
769 } 836 }
770 if err != nil { 837 if err != nil {
771 client.Logger.Errorf("cipd: failed to fetch %s - %s", pin, err) 838 client.Logger.Errorf("cipd: failed to fetch %s - %s", pin, err)
772 return err
773 } 839 }
774 » client.Logger.Infof("cipd: successfully fetched %s", pin) 840 » return err
775 » return nil
776 } 841 }
777 842
778 func (client *clientImpl) FetchAndDeployInstance(pin common.Pin) error { 843 func (client *clientImpl) FetchAndDeployInstance(pin common.Pin) error {
779 err := common.ValidatePin(pin) 844 err := common.ValidatePin(pin)
780 if err != nil { 845 if err != nil {
781 return err 846 return err
782 } 847 }
783 848
784 // Use temp file for storing package file. Delete it when done. 849 // Use temp file for storing package file. Delete it when done.
785 var instance local.PackageInstance 850 var instance local.PackageInstance
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after
1040 } 1105 }
1041 1106
1042 // buildInstanceIDMap builds mapping {package name -> instance ID}. 1107 // buildInstanceIDMap builds mapping {package name -> instance ID}.
1043 func buildInstanceIDMap(pins []common.Pin) map[string]string { 1108 func buildInstanceIDMap(pins []common.Pin) map[string]string {
1044 out := map[string]string{} 1109 out := map[string]string{}
1045 for _, p := range pins { 1110 for _, p := range pins {
1046 out[p.PackageName] = p.InstanceID 1111 out[p.PackageName] = p.InstanceID
1047 } 1112 }
1048 return out 1113 return out
1049 } 1114 }
OLDNEW
« no previous file with comments | « no previous file | client/cipd/internal/instancecache.go » ('j') | client/cipd/internal/instancecache.go » ('J')

Powered by Google App Engine
This is Rietveld 408576698