mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	[Vendor] Update go-redis to v8.5.0 (#13749)
* Update go-redis to v8.4.0 * github.com/go-redis/redis/v8 v8.4.0 -> v8.5.0 * Apply suggestions from code review Co-authored-by: zeripath <art27@cantab.net> * TODO * Use the Queue termination channel as the default context for pushes Signed-off-by: Andrew Thornton <art27@cantab.net> * missed one Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: zeripath <art27@cantab.net>
This commit is contained in:
		
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @@ -35,7 +35,7 @@ require ( | |||||||
| 	github.com/go-git/go-billy/v5 v5.0.0 | 	github.com/go-git/go-billy/v5 v5.0.0 | ||||||
| 	github.com/go-git/go-git/v5 v5.2.0 | 	github.com/go-git/go-git/v5 v5.2.0 | ||||||
| 	github.com/go-ldap/ldap/v3 v3.2.4 | 	github.com/go-ldap/ldap/v3 v3.2.4 | ||||||
| 	github.com/go-redis/redis/v7 v7.4.0 | 	github.com/go-redis/redis/v8 v8.5.0 | ||||||
| 	github.com/go-sql-driver/mysql v1.5.0 | 	github.com/go-sql-driver/mysql v1.5.0 | ||||||
| 	github.com/go-swagger/go-swagger v0.26.0 | 	github.com/go-swagger/go-swagger v0.26.0 | ||||||
| 	github.com/go-testfixtures/testfixtures/v3 v3.4.1 | 	github.com/go-testfixtures/testfixtures/v3 v3.4.1 | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								go.sum
									
									
									
									
									
								
							| @@ -241,6 +241,7 @@ github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D | |||||||
| github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= | github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= | ||||||
| github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= | ||||||
| github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | ||||||
|  | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= | ||||||
| github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | ||||||
| github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= | github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= | ||||||
| github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | ||||||
| @@ -281,7 +282,6 @@ github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4 | |||||||
| github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= | github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= | ||||||
| github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= | github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= | ||||||
| github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= | github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= | ||||||
| github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= |  | ||||||
| github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= | github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= | ||||||
| github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= | github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= | ||||||
| github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= | github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= | ||||||
| @@ -291,13 +291,11 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo | |||||||
| github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= | ||||||
| github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= | ||||||
| github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | ||||||
| github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= |  | ||||||
| github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= | github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= | ||||||
| github.com/gliderlabs/ssh v0.3.1 h1:L6VrMUGZaMlNIMN8Hj+CHh4U9yodJE3FAt/rgvfaKvE= | github.com/gliderlabs/ssh v0.3.1 h1:L6VrMUGZaMlNIMN8Hj+CHh4U9yodJE3FAt/rgvfaKvE= | ||||||
| github.com/gliderlabs/ssh v0.3.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= | github.com/gliderlabs/ssh v0.3.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= | ||||||
| github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= | github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= | ||||||
| github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= | github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= | ||||||
| github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4= |  | ||||||
| github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= | github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= | ||||||
| github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a h1:FQqoVvjbiUioBBFUL5up+h+GdCa/AnJsL/1bIs/veSI= | github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a h1:FQqoVvjbiUioBBFUL5up+h+GdCa/AnJsL/1bIs/veSI= | ||||||
| github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= | github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= | ||||||
| @@ -338,7 +336,6 @@ github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpR | |||||||
| github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= | github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= | ||||||
| github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= | github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= | ||||||
| github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= | github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= | ||||||
| github.com/go-openapi/analysis v0.19.10 h1:5BHISBAXOc/aJK25irLZnx2D3s6WyYaY9D4gmuz9fdE= |  | ||||||
| github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= | github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ= | ||||||
| github.com/go-openapi/analysis v0.19.16 h1:Ub9e++M8sDwtHD+S587TYi+6ANBG1NRYGZDihqk0SaY= | github.com/go-openapi/analysis v0.19.16 h1:Ub9e++M8sDwtHD+S587TYi+6ANBG1NRYGZDihqk0SaY= | ||||||
| github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk= | github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk= | ||||||
| @@ -346,7 +343,6 @@ github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQH | |||||||
| github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= | github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= | ||||||
| github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= | github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= | ||||||
| github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= | github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= | ||||||
| github.com/go-openapi/errors v0.19.6 h1:xZMThgv5SQ7SMbWtKFkCf9bBdvR2iEyw9k3zGZONuys= |  | ||||||
| github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= | github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= | ||||||
| github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= | github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= | ||||||
| github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= | github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= | ||||||
| @@ -357,7 +353,6 @@ github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12f | |||||||
| github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= | github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= | ||||||
| github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= | github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= | ||||||
| github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= | github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= | ||||||
| github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= |  | ||||||
| github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= | github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= | ||||||
| github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= | github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= | ||||||
| github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= | github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= | ||||||
| @@ -372,7 +367,6 @@ github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf | |||||||
| github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= | github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= | ||||||
| github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= | github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= | ||||||
| github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= | github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI= | ||||||
| github.com/go-openapi/loads v0.19.5 h1:jZVYWawIQiA1NBnHla28ktg6hrcfTHsCE+3QLVRBIls= |  | ||||||
| github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY= | github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY= | ||||||
| github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= | github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= | ||||||
| github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= | github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc= | ||||||
| @@ -391,7 +385,6 @@ github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsd | |||||||
| github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= | github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= | ||||||
| github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= | github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= | ||||||
| github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= | github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= | ||||||
| github.com/go-openapi/spec v0.19.8 h1:qAdZLh1r6QF/hI/gTq+TJTvsQUodZsM7KLqkAJdiJNg= |  | ||||||
| github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= | github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= | ||||||
| github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= | github.com/go-openapi/spec v0.19.15/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= | ||||||
| github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= | github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU= | ||||||
| @@ -403,7 +396,6 @@ github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+Z | |||||||
| github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= | github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= | ||||||
| github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= | github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= | ||||||
| github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= | github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= | ||||||
| github.com/go-openapi/strfmt v0.19.5 h1:0utjKrw+BAh8s57XE9Xz8DUBsVvPmRUB6styvl9wWIM= |  | ||||||
| github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= | github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= | ||||||
| github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= | github.com/go-openapi/strfmt v0.19.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= | ||||||
| github.com/go-openapi/strfmt v0.20.0 h1:l2omNtmNbMc39IGptl9BuXBEKcZfS8zjrTsPKTiJiDM= | github.com/go-openapi/strfmt v0.20.0 h1:l2omNtmNbMc39IGptl9BuXBEKcZfS8zjrTsPKTiJiDM= | ||||||
| @@ -413,7 +405,6 @@ github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/ | |||||||
| github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= | github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= | ||||||
| github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= | github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= | ||||||
| github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= | github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= | ||||||
| github.com/go-openapi/swag v0.19.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE= |  | ||||||
| github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= | github.com/go-openapi/swag v0.19.9/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= | ||||||
| github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M= | github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M= | ||||||
| github.com/go-openapi/swag v0.19.13 h1:233UVgMy1DlmCYYfOiFpta6e2urloh+sEs5id6lyzog= | github.com/go-openapi/swag v0.19.13 h1:233UVgMy1DlmCYYfOiFpta6e2urloh+sEs5id6lyzog= | ||||||
| @@ -421,7 +412,6 @@ github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/ | |||||||
| github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= | github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= | ||||||
| github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= | github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= | ||||||
| github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= | github.com/go-openapi/validate v0.19.3/go.mod h1:90Vh6jjkTn+OT1Eefm0ZixWNFjhtOH7vS9k0lo6zwJo= | ||||||
| github.com/go-openapi/validate v0.19.10 h1:tG3SZ5DC5KF4cyt7nqLVcQXGj5A7mpaYkAcNPlDK+Yk= |  | ||||||
| github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= | github.com/go-openapi/validate v0.19.10/go.mod h1:RKEZTUWDkxKQxN2jDT7ZnZi2bhZlbNMAuKvKB+IaGx8= | ||||||
| github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= | github.com/go-openapi/validate v0.19.12/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= | ||||||
| github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI= | github.com/go-openapi/validate v0.19.15/go.mod h1:tbn/fdOwYHgrhPBzidZfJC2MIVvs9GA7monOmWBbeCI= | ||||||
| @@ -429,9 +419,10 @@ github.com/go-openapi/validate v0.20.1 h1:QGQ5CvK74E28t3DkegGweKR+auemUi5IdpMc4x | |||||||
| github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0= | github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE9E4k54HpKcJ0= | ||||||
| github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= | github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4= | ||||||
| github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= | github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= | ||||||
| github.com/go-redis/redis/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4= | github.com/go-redis/redis/v8 v8.4.0 h1:J5NCReIgh3QgUJu398hUncxDExN4gMOHI11NVbVicGQ= | ||||||
| github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= |  | ||||||
| github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= | github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= | ||||||
|  | github.com/go-redis/redis/v8 v8.5.0 h1:L3r1Q3I5WOUdXZGCP6g44EruKh0u3n6co5Hl5xWkdGA= | ||||||
|  | github.com/go-redis/redis/v8 v8.5.0/go.mod h1:YmEcgBDttjnkbMzDAhDtQxY9yVA7jMN6PCR5HeMvqFE= | ||||||
| github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||||||
| github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||||||
| github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= | github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= | ||||||
| @@ -476,8 +467,6 @@ github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx | |||||||
| github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= | github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= | ||||||
| github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||||
| github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||||
| github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= |  | ||||||
| github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= |  | ||||||
| github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= | ||||||
| github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 h1:gBeyun7mySAKWg7Fb0GOcv0upX9bdaZScs8QcRo8mEY= | github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 h1:gBeyun7mySAKWg7Fb0GOcv0upX9bdaZScs8QcRo8mEY= | ||||||
| github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= | github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14= | ||||||
| @@ -678,7 +667,6 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS | |||||||
| github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= | ||||||
| github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= | github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= | ||||||
| github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= | github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= | ||||||
| github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= |  | ||||||
| github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= | github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= | ||||||
| github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= | github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= | ||||||
| github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= | github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= | ||||||
| @@ -757,7 +745,6 @@ github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de/go.mod h1:3q8WtuPQsoRbat | |||||||
| github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= | github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VObJ7peltM+2n3PWOz7yTrfUuGbVFkzN0= | ||||||
| github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= | github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= | ||||||
| github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | ||||||
| github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= |  | ||||||
| github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | ||||||
| github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= | github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= | ||||||
| github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= | github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= | ||||||
| @@ -812,7 +799,6 @@ github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXd | |||||||
| github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= | ||||||
| github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo= | github.com/miekg/dns v1.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo= | ||||||
| github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= | github.com/miekg/dns v1.1.30/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= | ||||||
| github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4= |  | ||||||
| github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= | github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= | ||||||
| github.com/minio/md5-simd v1.1.1 h1:9ojcLbuZ4gXbB2sX53MKn8JUZ0sB/2wfwsEcRw+I08U= | github.com/minio/md5-simd v1.1.1 h1:9ojcLbuZ4gXbB2sX53MKn8JUZ0sB/2wfwsEcRw+I08U= | ||||||
| github.com/minio/md5-simd v1.1.1/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= | github.com/minio/md5-simd v1.1.1/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= | ||||||
| @@ -830,7 +816,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4 | |||||||
| github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= | ||||||
| github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||||||
| github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||||||
| github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= |  | ||||||
| github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | ||||||
| github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | ||||||
| github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | github.com/mitchellh/mapstructure v1.4.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | ||||||
| @@ -883,17 +868,19 @@ github.com/olivere/elastic/v7 v7.0.22/go.mod h1:VDexNy9NjmtAkrjNoI7tImv7FR4tf5zU | |||||||
| github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | ||||||
| github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | ||||||
| github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | ||||||
| github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |  | ||||||
| github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= | ||||||
| github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= | github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= | ||||||
| github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= | github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= | ||||||
|  | github.com/onsi/ginkgo v1.15.0 h1:1V1NfVQR87RtWAgp1lv9JZJ5Jap+XFGKPi00andXGi4= | ||||||
|  | github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= | ||||||
| github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | ||||||
| github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | ||||||
| github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |  | ||||||
| github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= | ||||||
| github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= | ||||||
| github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= | github.com/onsi/gomega v1.10.3 h1:gph6h/qe9GSUw1NhH1gp+qb+h8rXD8Cy60Z32Qw3ELA= | ||||||
| github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= | github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= | ||||||
|  | github.com/onsi/gomega v1.10.5 h1:7n6FEkpFmfCoo2t+YYqXH0evK+a9ICQz0xcAy9dYcaQ= | ||||||
|  | github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= | ||||||
| github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= | github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= | ||||||
| github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= | github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= | ||||||
| github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= | github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= | ||||||
| @@ -970,7 +957,6 @@ github.com/quasoft/websspi v1.0.0 h1:5nDgdM5xSur9s+B5w2xQ5kxf5nUGqgFgU4W0aDLZ8Mw | |||||||
| github.com/quasoft/websspi v1.0.0/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk= | github.com/quasoft/websspi v1.0.0/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk= | ||||||
| github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= | github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= | ||||||
| github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= | github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= | ||||||
| github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY= |  | ||||||
| github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= | github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= | ||||||
| github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= | github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= | ||||||
| github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= | ||||||
| @@ -1003,7 +989,6 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV | |||||||
| github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= | github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= | ||||||
| github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= | github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= | ||||||
| github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= | github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= | ||||||
| github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d h1:qQWKKOvHN7Q9c6GdmUteCef2F9ubxMpxY1IKwpIKz68= |  | ||||||
| github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= | github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d/go.mod h1:vq0tzqLRu6TS7Id0wMo2N5QzJoKedVeovOpHjnykSzY= | ||||||
| github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= | github.com/siddontang/ledisdb v0.0.0-20190202134119-8ceb77e66a92/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg= | ||||||
| github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= | github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= | ||||||
| @@ -1118,7 +1103,6 @@ github.com/yuin/goldmark v1.1.22/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de | |||||||
| github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||||
| github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||||
| github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||||
| github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM= |  | ||||||
| github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||||
| github.com/yuin/goldmark v1.3.1 h1:eVwehsLsZlCJCwXyGLgg+Q4iFWE/eTIMG0e8waCmm/I= | github.com/yuin/goldmark v1.3.1 h1:eVwehsLsZlCJCwXyGLgg+Q4iFWE/eTIMG0e8waCmm/I= | ||||||
| github.com/yuin/goldmark v1.3.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | github.com/yuin/goldmark v1.3.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||||
| @@ -1152,7 +1136,10 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | |||||||
| go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | ||||||
| go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | ||||||
| go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= | go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= | ||||||
|  | go.opentelemetry.io/otel v0.14.0 h1:YFBEfjCk9MTjaytCNSUkp9Q8lF7QJezA06T71FbQxLQ= | ||||||
| go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= | go.opentelemetry.io/otel v0.14.0/go.mod h1:vH5xEuwy7Rts0GNtsCW3HYQoZDY+OmBJ6t1bFGGlxgw= | ||||||
|  | go.opentelemetry.io/otel v0.16.0 h1:uIWEbdeb4vpKPGITLsRVUS44L5oDbDUCZxn8lkxhmgw= | ||||||
|  | go.opentelemetry.io/otel v0.16.0/go.mod h1:e4GKElweB8W2gWUqbghw0B8t5MCTccc9212eNHnOHwA= | ||||||
| go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | ||||||
| go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | ||||||
| go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= | ||||||
| @@ -1278,7 +1265,6 @@ golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwY | |||||||
| golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||||||
| golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||||||
| golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||||||
| golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw= |  | ||||||
| golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||||||
| golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= | golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= | ||||||
| golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||||||
| @@ -1288,9 +1274,7 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr | |||||||
| golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||||
| golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||||
| golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||||
| golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc= |  | ||||||
| golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||||
| golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 h1:Mj83v+wSRNEar42a/MQgxk9X42TdEmrOl9i+y8WbxLo= |  | ||||||
| golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||||
| golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013 h1:55H5j7lotzuFCEOKDsMch+fRNUQ9DgtyHOUP31FNqKc= | golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013 h1:55H5j7lotzuFCEOKDsMch+fRNUQ9DgtyHOUP31FNqKc= | ||||||
| golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= | ||||||
| @@ -1369,11 +1353,10 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w | |||||||
| golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= | ||||||
| golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= |  | ||||||
| golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= | ||||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= | ||||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||||
| @@ -1382,7 +1365,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||||||
| golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
| golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | ||||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
| golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= |  | ||||||
| golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
| golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= | golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= | ||||||
| golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
| @@ -1454,10 +1436,9 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc | |||||||
| golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= | golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= | ||||||
| golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= | golang.org/x/tools v0.0.0-20200928182047-19e03678916f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= | ||||||
| golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= | golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= | ||||||
| golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9 h1:sEvmEcJVKBNUvgCUClbUQeHOAa9U0I2Ce1BooMvVCY4= |  | ||||||
| golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | ||||||
| golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b h1:Lq5JUTFhiybGVf28jB6QRpqd13/JPOaCnET17PVzYJE= |  | ||||||
| golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | ||||||
|  | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | ||||||
| golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= | golang.org/x/tools v0.1.0 h1:po9/4sTYwZU9lPhi1tOrb4hCv3qrhiQ77LZfGa2OjwY= | ||||||
| golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= | golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= | ||||||
| golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| @@ -1594,7 +1575,6 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||||||
| gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
| gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
| gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
| gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= |  | ||||||
| gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
| gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||||||
| gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | ||||||
|   | |||||||
							
								
								
									
										33
									
								
								modules/cache/cache_redis.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								modules/cache/cache_redis.go
									
									
									
									
										vendored
									
									
								
							| @@ -8,10 +8,11 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/modules/graceful" | ||||||
| 	"code.gitea.io/gitea/modules/nosql" | 	"code.gitea.io/gitea/modules/nosql" | ||||||
|  |  | ||||||
| 	"gitea.com/go-chi/cache" | 	"gitea.com/go-chi/cache" | ||||||
| 	"github.com/go-redis/redis/v7" | 	"github.com/go-redis/redis/v8" | ||||||
| 	"github.com/unknwon/com" | 	"github.com/unknwon/com" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -28,7 +29,7 @@ type RedisCacher struct { | |||||||
| func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { | func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { | ||||||
| 	key = c.prefix + key | 	key = c.prefix + key | ||||||
| 	if expire == 0 { | 	if expire == 0 { | ||||||
| 		if err := c.c.Set(key, com.ToStr(val), 0).Err(); err != nil { | 		if err := c.c.Set(graceful.GetManager().HammerContext(), key, com.ToStr(val), 0).Err(); err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| @@ -36,7 +37,7 @@ func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 		if err = c.c.Set(key, com.ToStr(val), dur).Err(); err != nil { | 		if err = c.c.Set(graceful.GetManager().HammerContext(), key, com.ToStr(val), dur).Err(); err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -44,12 +45,12 @@ func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { | |||||||
| 	if c.occupyMode { | 	if c.occupyMode { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	return c.c.HSet(c.hsetName, key, "0").Err() | 	return c.c.HSet(graceful.GetManager().HammerContext(), c.hsetName, key, "0").Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // Get gets cached value by given key. | // Get gets cached value by given key. | ||||||
| func (c *RedisCacher) Get(key string) interface{} { | func (c *RedisCacher) Get(key string) interface{} { | ||||||
| 	val, err := c.c.Get(c.prefix + key).Result() | 	val, err := c.c.Get(graceful.GetManager().HammerContext(), c.prefix+key).Result() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| @@ -59,14 +60,14 @@ func (c *RedisCacher) Get(key string) interface{} { | |||||||
| // Delete deletes cached value by given key. | // Delete deletes cached value by given key. | ||||||
| func (c *RedisCacher) Delete(key string) error { | func (c *RedisCacher) Delete(key string) error { | ||||||
| 	key = c.prefix + key | 	key = c.prefix + key | ||||||
| 	if err := c.c.Del(key).Err(); err != nil { | 	if err := c.c.Del(graceful.GetManager().HammerContext(), key).Err(); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if c.occupyMode { | 	if c.occupyMode { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	return c.c.HDel(c.hsetName, key).Err() | 	return c.c.HDel(graceful.GetManager().HammerContext(), c.hsetName, key).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // Incr increases cached int-type value by given key as a counter. | // Incr increases cached int-type value by given key as a counter. | ||||||
| @@ -74,7 +75,7 @@ func (c *RedisCacher) Incr(key string) error { | |||||||
| 	if !c.IsExist(key) { | 	if !c.IsExist(key) { | ||||||
| 		return fmt.Errorf("key '%s' not exist", key) | 		return fmt.Errorf("key '%s' not exist", key) | ||||||
| 	} | 	} | ||||||
| 	return c.c.Incr(c.prefix + key).Err() | 	return c.c.Incr(graceful.GetManager().HammerContext(), c.prefix+key).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // Decr decreases cached int-type value by given key as a counter. | // Decr decreases cached int-type value by given key as a counter. | ||||||
| @@ -82,17 +83,17 @@ func (c *RedisCacher) Decr(key string) error { | |||||||
| 	if !c.IsExist(key) { | 	if !c.IsExist(key) { | ||||||
| 		return fmt.Errorf("key '%s' not exist", key) | 		return fmt.Errorf("key '%s' not exist", key) | ||||||
| 	} | 	} | ||||||
| 	return c.c.Decr(c.prefix + key).Err() | 	return c.c.Decr(graceful.GetManager().HammerContext(), c.prefix+key).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // IsExist returns true if cached value exists. | // IsExist returns true if cached value exists. | ||||||
| func (c *RedisCacher) IsExist(key string) bool { | func (c *RedisCacher) IsExist(key string) bool { | ||||||
| 	if c.c.Exists(c.prefix+key).Val() == 1 { | 	if c.c.Exists(graceful.GetManager().HammerContext(), c.prefix+key).Val() == 1 { | ||||||
| 		return true | 		return true | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if !c.occupyMode { | 	if !c.occupyMode { | ||||||
| 		c.c.HDel(c.hsetName, c.prefix+key) | 		c.c.HDel(graceful.GetManager().HammerContext(), c.hsetName, c.prefix+key) | ||||||
| 	} | 	} | ||||||
| 	return false | 	return false | ||||||
| } | } | ||||||
| @@ -100,17 +101,17 @@ func (c *RedisCacher) IsExist(key string) bool { | |||||||
| // Flush deletes all cached data. | // Flush deletes all cached data. | ||||||
| func (c *RedisCacher) Flush() error { | func (c *RedisCacher) Flush() error { | ||||||
| 	if c.occupyMode { | 	if c.occupyMode { | ||||||
| 		return c.c.FlushDB().Err() | 		return c.c.FlushDB(graceful.GetManager().HammerContext()).Err() | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	keys, err := c.c.HKeys(c.hsetName).Result() | 	keys, err := c.c.HKeys(graceful.GetManager().HammerContext(), c.hsetName).Result() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if err = c.c.Del(keys...).Err(); err != nil { | 	if err = c.c.Del(graceful.GetManager().HammerContext(), keys...).Err(); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	return c.c.Del(c.hsetName).Err() | 	return c.c.Del(graceful.GetManager().HammerContext(), c.hsetName).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // StartAndGC starts GC routine based on config string settings. | // StartAndGC starts GC routine based on config string settings. | ||||||
| @@ -132,7 +133,7 @@ func (c *RedisCacher) StartAndGC(opts cache.Options) error { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return c.c.Ping().Err() | 	return c.c.Ping(graceful.GetManager().HammerContext()).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/go-redis/redis/v7" | 	"github.com/go-redis/redis/v8" | ||||||
| 	"github.com/syndtr/goleveldb/leveldb" | 	"github.com/syndtr/goleveldb/leveldb" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ import ( | |||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/go-redis/redis/v7" | 	"github.com/go-redis/redis/v8" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var replacer = strings.NewReplacer("_", "", "-", "") | var replacer = strings.NewReplacer("_", "", "-", "") | ||||||
|   | |||||||
| @@ -163,6 +163,11 @@ func (q *ByteFIFOQueue) Shutdown() { | |||||||
| 	log.Debug("%s: %s Shutdown", q.typ, q.name) | 	log.Debug("%s: %s Shutdown", q.typ, q.name) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // IsShutdown returns a channel which is closed when this Queue is shutdown | ||||||
|  | func (q *ByteFIFOQueue) IsShutdown() <-chan struct{} { | ||||||
|  | 	return q.closed | ||||||
|  | } | ||||||
|  |  | ||||||
| // Terminate this queue and close the queue | // Terminate this queue and close the queue | ||||||
| func (q *ByteFIFOQueue) Terminate() { | func (q *ByteFIFOQueue) Terminate() { | ||||||
| 	log.Trace("%s: %s Terminating", q.typ, q.name) | 	log.Trace("%s: %s Terminating", q.typ, q.name) | ||||||
| @@ -185,6 +190,11 @@ func (q *ByteFIFOQueue) Terminate() { | |||||||
| 	log.Debug("%s: %s Terminated", q.typ, q.name) | 	log.Debug("%s: %s Terminated", q.typ, q.name) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // IsTerminated returns a channel which is closed when this Queue is terminated | ||||||
|  | func (q *ByteFIFOQueue) IsTerminated() <-chan struct{} { | ||||||
|  | 	return q.terminated | ||||||
|  | } | ||||||
|  |  | ||||||
| var _ (UniqueQueue) = &ByteFIFOUniqueQueue{} | var _ (UniqueQueue) = &ByteFIFOUniqueQueue{} | ||||||
|  |  | ||||||
| // ByteFIFOUniqueQueue represents a UniqueQueue formed from a UniqueByteFifo | // ByteFIFOUniqueQueue represents a UniqueQueue formed from a UniqueByteFifo | ||||||
|   | |||||||
| @@ -5,10 +5,14 @@ | |||||||
| package queue | package queue | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/modules/graceful" | ||||||
| 	"code.gitea.io/gitea/modules/log" | 	"code.gitea.io/gitea/modules/log" | ||||||
| 	"code.gitea.io/gitea/modules/nosql" | 	"code.gitea.io/gitea/modules/nosql" | ||||||
|  |  | ||||||
| 	"github.com/go-redis/redis/v7" | 	"github.com/go-redis/redis/v8" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // RedisQueueType is the type for redis queue | // RedisQueueType is the type for redis queue | ||||||
| @@ -43,6 +47,8 @@ func NewRedisQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error) | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	byteFIFO.ctx = graceful.NewChannelContext(byteFIFOQueue.IsTerminated(), fmt.Errorf("queue has been terminated")) | ||||||
|  |  | ||||||
| 	queue := &RedisQueue{ | 	queue := &RedisQueue{ | ||||||
| 		ByteFIFOQueue: byteFIFOQueue, | 		ByteFIFOQueue: byteFIFOQueue, | ||||||
| 	} | 	} | ||||||
| @@ -53,13 +59,13 @@ func NewRedisQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error) | |||||||
| } | } | ||||||
|  |  | ||||||
| type redisClient interface { | type redisClient interface { | ||||||
| 	RPush(key string, args ...interface{}) *redis.IntCmd | 	RPush(ctx context.Context, key string, args ...interface{}) *redis.IntCmd | ||||||
| 	LPop(key string) *redis.StringCmd | 	LPop(ctx context.Context, key string) *redis.StringCmd | ||||||
| 	LLen(key string) *redis.IntCmd | 	LLen(ctx context.Context, key string) *redis.IntCmd | ||||||
| 	SAdd(key string, members ...interface{}) *redis.IntCmd | 	SAdd(ctx context.Context, key string, members ...interface{}) *redis.IntCmd | ||||||
| 	SRem(key string, members ...interface{}) *redis.IntCmd | 	SRem(ctx context.Context, key string, members ...interface{}) *redis.IntCmd | ||||||
| 	SIsMember(key string, member interface{}) *redis.BoolCmd | 	SIsMember(ctx context.Context, key string, member interface{}) *redis.BoolCmd | ||||||
| 	Ping() *redis.StatusCmd | 	Ping(ctx context.Context) *redis.StatusCmd | ||||||
| 	Close() error | 	Close() error | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -67,6 +73,7 @@ var _ (ByteFIFO) = &RedisByteFIFO{} | |||||||
|  |  | ||||||
| // RedisByteFIFO represents a ByteFIFO formed from a redisClient | // RedisByteFIFO represents a ByteFIFO formed from a redisClient | ||||||
| type RedisByteFIFO struct { | type RedisByteFIFO struct { | ||||||
|  | 	ctx       context.Context | ||||||
| 	client    redisClient | 	client    redisClient | ||||||
| 	queueName string | 	queueName string | ||||||
| } | } | ||||||
| @@ -82,8 +89,9 @@ func NewRedisByteFIFO(config RedisByteFIFOConfiguration) (*RedisByteFIFO, error) | |||||||
| 	fifo := &RedisByteFIFO{ | 	fifo := &RedisByteFIFO{ | ||||||
| 		queueName: config.QueueName, | 		queueName: config.QueueName, | ||||||
| 	} | 	} | ||||||
|  | 	fifo.ctx = graceful.GetManager().TerminateContext() | ||||||
| 	fifo.client = nosql.GetManager().GetRedisClient(config.ConnectionString) | 	fifo.client = nosql.GetManager().GetRedisClient(config.ConnectionString) | ||||||
| 	if err := fifo.client.Ping().Err(); err != nil { | 	if err := fifo.client.Ping(graceful.GetManager().ShutdownContext()).Err(); err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	return fifo, nil | 	return fifo, nil | ||||||
| @@ -96,12 +104,12 @@ func (fifo *RedisByteFIFO) PushFunc(data []byte, fn func() error) error { | |||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return fifo.client.RPush(fifo.queueName, data).Err() | 	return fifo.client.RPush(fifo.ctx, fifo.queueName, data).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // Pop pops data from the start of the fifo | // Pop pops data from the start of the fifo | ||||||
| func (fifo *RedisByteFIFO) Pop() ([]byte, error) { | func (fifo *RedisByteFIFO) Pop() ([]byte, error) { | ||||||
| 	data, err := fifo.client.LPop(fifo.queueName).Bytes() | 	data, err := fifo.client.LPop(fifo.ctx, fifo.queueName).Bytes() | ||||||
| 	if err == nil || err == redis.Nil { | 	if err == nil || err == redis.Nil { | ||||||
| 		return data, nil | 		return data, nil | ||||||
| 	} | 	} | ||||||
| @@ -115,7 +123,7 @@ func (fifo *RedisByteFIFO) Close() error { | |||||||
|  |  | ||||||
| // Len returns the length of the fifo | // Len returns the length of the fifo | ||||||
| func (fifo *RedisByteFIFO) Len() int64 { | func (fifo *RedisByteFIFO) Len() int64 { | ||||||
| 	val, err := fifo.client.LLen(fifo.queueName).Result() | 	val, err := fifo.client.LLen(fifo.ctx, fifo.queueName).Result() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Error("Error whilst getting length of redis queue %s: Error: %v", fifo.queueName, err) | 		log.Error("Error whilst getting length of redis queue %s: Error: %v", fifo.queueName, err) | ||||||
| 		return -1 | 		return -1 | ||||||
|   | |||||||
| @@ -4,7 +4,12 @@ | |||||||
|  |  | ||||||
| package queue | package queue | ||||||
|  |  | ||||||
| import "github.com/go-redis/redis/v7" | import ( | ||||||
|  | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/modules/graceful" | ||||||
|  | 	"github.com/go-redis/redis/v8" | ||||||
|  | ) | ||||||
|  |  | ||||||
| // RedisUniqueQueueType is the type for redis queue | // RedisUniqueQueueType is the type for redis queue | ||||||
| const RedisUniqueQueueType Type = "unique-redis" | const RedisUniqueQueueType Type = "unique-redis" | ||||||
| @@ -46,6 +51,8 @@ func NewRedisUniqueQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	byteFIFO.ctx = graceful.NewChannelContext(byteFIFOQueue.IsTerminated(), fmt.Errorf("queue has been terminated")) | ||||||
|  |  | ||||||
| 	queue := &RedisUniqueQueue{ | 	queue := &RedisUniqueQueue{ | ||||||
| 		ByteFIFOUniqueQueue: byteFIFOQueue, | 		ByteFIFOUniqueQueue: byteFIFOQueue, | ||||||
| 	} | 	} | ||||||
| @@ -86,7 +93,7 @@ func NewRedisUniqueByteFIFO(config RedisUniqueByteFIFOConfiguration) (*RedisUniq | |||||||
|  |  | ||||||
| // PushFunc pushes data to the end of the fifo and calls the callback if it is added | // PushFunc pushes data to the end of the fifo and calls the callback if it is added | ||||||
| func (fifo *RedisUniqueByteFIFO) PushFunc(data []byte, fn func() error) error { | func (fifo *RedisUniqueByteFIFO) PushFunc(data []byte, fn func() error) error { | ||||||
| 	added, err := fifo.client.SAdd(fifo.setName, data).Result() | 	added, err := fifo.client.SAdd(fifo.ctx, fifo.setName, data).Result() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -98,12 +105,12 @@ func (fifo *RedisUniqueByteFIFO) PushFunc(data []byte, fn func() error) error { | |||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return fifo.client.RPush(fifo.queueName, data).Err() | 	return fifo.client.RPush(fifo.ctx, fifo.queueName, data).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // Pop pops data from the start of the fifo | // Pop pops data from the start of the fifo | ||||||
| func (fifo *RedisUniqueByteFIFO) Pop() ([]byte, error) { | func (fifo *RedisUniqueByteFIFO) Pop() ([]byte, error) { | ||||||
| 	data, err := fifo.client.LPop(fifo.queueName).Bytes() | 	data, err := fifo.client.LPop(fifo.ctx, fifo.queueName).Bytes() | ||||||
| 	if err != nil && err != redis.Nil { | 	if err != nil && err != redis.Nil { | ||||||
| 		return data, err | 		return data, err | ||||||
| 	} | 	} | ||||||
| @@ -112,13 +119,13 @@ func (fifo *RedisUniqueByteFIFO) Pop() ([]byte, error) { | |||||||
| 		return data, nil | 		return data, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	err = fifo.client.SRem(fifo.setName, data).Err() | 	err = fifo.client.SRem(fifo.ctx, fifo.setName, data).Err() | ||||||
| 	return data, err | 	return data, err | ||||||
| } | } | ||||||
|  |  | ||||||
| // Has returns whether the fifo contains this data | // Has returns whether the fifo contains this data | ||||||
| func (fifo *RedisUniqueByteFIFO) Has(data []byte) (bool, error) { | func (fifo *RedisUniqueByteFIFO) Has(data []byte) (bool, error) { | ||||||
| 	return fifo.client.SIsMember(fifo.setName, data).Result() | 	return fifo.client.SIsMember(fifo.ctx, fifo.setName, data).Result() | ||||||
| } | } | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
|   | |||||||
| @@ -21,10 +21,11 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"code.gitea.io/gitea/modules/graceful" | ||||||
| 	"code.gitea.io/gitea/modules/nosql" | 	"code.gitea.io/gitea/modules/nosql" | ||||||
|  |  | ||||||
| 	"gitea.com/go-chi/session" | 	"gitea.com/go-chi/session" | ||||||
| 	"github.com/go-redis/redis/v7" | 	"github.com/go-redis/redis/v8" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // RedisStore represents a redis session store implementation. | // RedisStore represents a redis session store implementation. | ||||||
| @@ -90,7 +91,7 @@ func (s *RedisStore) Release() error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return s.c.Set(s.prefix+s.sid, string(data), s.duration).Err() | 	return s.c.Set(graceful.GetManager().HammerContext(), s.prefix+s.sid, string(data), s.duration).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // Flush deletes all session data. | // Flush deletes all session data. | ||||||
| @@ -127,20 +128,20 @@ func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	p.c = nosql.GetManager().GetRedisClient(uri.String()) | 	p.c = nosql.GetManager().GetRedisClient(uri.String()) | ||||||
| 	return p.c.Ping().Err() | 	return p.c.Ping(graceful.GetManager().ShutdownContext()).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // Read returns raw session store by session ID. | // Read returns raw session store by session ID. | ||||||
| func (p *RedisProvider) Read(sid string) (session.RawStore, error) { | func (p *RedisProvider) Read(sid string) (session.RawStore, error) { | ||||||
| 	psid := p.prefix + sid | 	psid := p.prefix + sid | ||||||
| 	if !p.Exist(sid) { | 	if !p.Exist(sid) { | ||||||
| 		if err := p.c.Set(psid, "", p.duration).Err(); err != nil { | 		if err := p.c.Set(graceful.GetManager().HammerContext(), psid, "", p.duration).Err(); err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var kv map[interface{}]interface{} | 	var kv map[interface{}]interface{} | ||||||
| 	kvs, err := p.c.Get(psid).Result() | 	kvs, err := p.c.Get(graceful.GetManager().HammerContext(), psid).Result() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -158,13 +159,13 @@ func (p *RedisProvider) Read(sid string) (session.RawStore, error) { | |||||||
|  |  | ||||||
| // Exist returns true if session with given ID exists. | // Exist returns true if session with given ID exists. | ||||||
| func (p *RedisProvider) Exist(sid string) bool { | func (p *RedisProvider) Exist(sid string) bool { | ||||||
| 	v, err := p.c.Exists(p.prefix + sid).Result() | 	v, err := p.c.Exists(graceful.GetManager().HammerContext(), p.prefix+sid).Result() | ||||||
| 	return err == nil && v == 1 | 	return err == nil && v == 1 | ||||||
| } | } | ||||||
|  |  | ||||||
| // Destroy deletes a session by session ID. | // Destroy deletes a session by session ID. | ||||||
| func (p *RedisProvider) Destroy(sid string) error { | func (p *RedisProvider) Destroy(sid string) error { | ||||||
| 	return p.c.Del(p.prefix + sid).Err() | 	return p.c.Del(graceful.GetManager().HammerContext(), p.prefix+sid).Err() | ||||||
| } | } | ||||||
|  |  | ||||||
| // Regenerate regenerates a session store from old session ID to new one. | // Regenerate regenerates a session store from old session ID to new one. | ||||||
| @@ -176,17 +177,17 @@ func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err | |||||||
| 		return nil, fmt.Errorf("new sid '%s' already exists", sid) | 		return nil, fmt.Errorf("new sid '%s' already exists", sid) | ||||||
| 	} else if !p.Exist(oldsid) { | 	} else if !p.Exist(oldsid) { | ||||||
| 		// Make a fake old session. | 		// Make a fake old session. | ||||||
| 		if err = p.c.Set(poldsid, "", p.duration).Err(); err != nil { | 		if err = p.c.Set(graceful.GetManager().HammerContext(), poldsid, "", p.duration).Err(); err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err = p.c.Rename(poldsid, psid).Err(); err != nil { | 	if err = p.c.Rename(graceful.GetManager().HammerContext(), poldsid, psid).Err(); err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var kv map[interface{}]interface{} | 	var kv map[interface{}]interface{} | ||||||
| 	kvs, err := p.c.Get(psid).Result() | 	kvs, err := p.c.Get(graceful.GetManager().HammerContext(), psid).Result() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -205,7 +206,11 @@ func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err | |||||||
|  |  | ||||||
| // Count counts and returns number of sessions. | // Count counts and returns number of sessions. | ||||||
| func (p *RedisProvider) Count() int { | func (p *RedisProvider) Count() int { | ||||||
| 	return int(p.c.DBSize().Val()) | 	size, err := p.c.DBSize(graceful.GetManager().HammerContext()).Result() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0 | ||||||
|  | 	} | ||||||
|  | 	return int(size) | ||||||
| } | } | ||||||
|  |  | ||||||
| // GC calls GC to clean expired sessions. | // GC calls GC to clean expired sessions. | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								vendor/github.com/dgryski/go-rendezvous/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/dgryski/go-rendezvous/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | The MIT License (MIT) | ||||||
|  |  | ||||||
|  | Copyright (c) 2017-2020 Damian Gryski <damian@gryski.com> | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  | of this software and associated documentation files (the "Software"), to deal | ||||||
|  | in the Software without restriction, including without limitation the rights | ||||||
|  | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||||
|  | copies of the Software, and to permit persons to whom the Software is | ||||||
|  | furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in | ||||||
|  | all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||||
|  | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||||
|  | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||||
|  | THE SOFTWARE. | ||||||
							
								
								
									
										79
									
								
								vendor/github.com/dgryski/go-rendezvous/rdv.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								vendor/github.com/dgryski/go-rendezvous/rdv.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | |||||||
|  | package rendezvous | ||||||
|  |  | ||||||
|  | type Rendezvous struct { | ||||||
|  | 	nodes map[string]int | ||||||
|  | 	nstr  []string | ||||||
|  | 	nhash []uint64 | ||||||
|  | 	hash  Hasher | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Hasher func(s string) uint64 | ||||||
|  |  | ||||||
|  | func New(nodes []string, hash Hasher) *Rendezvous { | ||||||
|  | 	r := &Rendezvous{ | ||||||
|  | 		nodes: make(map[string]int, len(nodes)), | ||||||
|  | 		nstr:  make([]string, len(nodes)), | ||||||
|  | 		nhash: make([]uint64, len(nodes)), | ||||||
|  | 		hash:  hash, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for i, n := range nodes { | ||||||
|  | 		r.nodes[n] = i | ||||||
|  | 		r.nstr[i] = n | ||||||
|  | 		r.nhash[i] = hash(n) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *Rendezvous) Lookup(k string) string { | ||||||
|  | 	// short-circuit if we're empty | ||||||
|  | 	if len(r.nodes) == 0 { | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	khash := r.hash(k) | ||||||
|  |  | ||||||
|  | 	var midx int | ||||||
|  | 	var mhash = xorshiftMult64(khash ^ r.nhash[0]) | ||||||
|  |  | ||||||
|  | 	for i, nhash := range r.nhash[1:] { | ||||||
|  | 		if h := xorshiftMult64(khash ^ nhash); h > mhash { | ||||||
|  | 			midx = i + 1 | ||||||
|  | 			mhash = h | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return r.nstr[midx] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *Rendezvous) Add(node string) { | ||||||
|  | 	r.nodes[node] = len(r.nstr) | ||||||
|  | 	r.nstr = append(r.nstr, node) | ||||||
|  | 	r.nhash = append(r.nhash, r.hash(node)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *Rendezvous) Remove(node string) { | ||||||
|  | 	// find index of node to remove | ||||||
|  | 	nidx := r.nodes[node] | ||||||
|  |  | ||||||
|  | 	// remove from the slices | ||||||
|  | 	l := len(r.nstr) | ||||||
|  | 	r.nstr[nidx] = r.nstr[l] | ||||||
|  | 	r.nstr = r.nstr[:l] | ||||||
|  |  | ||||||
|  | 	r.nhash[nidx] = r.nhash[l] | ||||||
|  | 	r.nhash = r.nhash[:l] | ||||||
|  |  | ||||||
|  | 	// update the map | ||||||
|  | 	delete(r.nodes, node) | ||||||
|  | 	moved := r.nstr[nidx] | ||||||
|  | 	r.nodes[moved] = nidx | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func xorshiftMult64(x uint64) uint64 { | ||||||
|  | 	x ^= x >> 12 // a | ||||||
|  | 	x ^= x << 25 // b | ||||||
|  | 	x ^= x >> 27 // c | ||||||
|  | 	return x * 2685821657736338717 | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								vendor/github.com/go-redis/redis/v7/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/go-redis/redis/v7/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,22 +0,0 @@ | |||||||
| dist: xenial |  | ||||||
| language: go |  | ||||||
|  |  | ||||||
| services: |  | ||||||
|   - redis-server |  | ||||||
|  |  | ||||||
| go: |  | ||||||
|   - 1.12.x |  | ||||||
|   - 1.13.x |  | ||||||
|   - tip |  | ||||||
|  |  | ||||||
| matrix: |  | ||||||
|   allow_failures: |  | ||||||
|     - go: tip |  | ||||||
|  |  | ||||||
| env: |  | ||||||
|   - GO111MODULE=on |  | ||||||
|  |  | ||||||
| go_import_path: github.com/go-redis/redis |  | ||||||
|  |  | ||||||
| before_install: |  | ||||||
|   - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.21.0 |  | ||||||
							
								
								
									
										46
									
								
								vendor/github.com/go-redis/redis/v7/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								vendor/github.com/go-redis/redis/v7/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,46 +0,0 @@ | |||||||
| # Changelog |  | ||||||
|  |  | ||||||
| ## v7.2 |  | ||||||
|  |  | ||||||
| - Existing `HMSet` is renamed to `HSet` and old deprecated `HMSet` is restored for Redis 3 users. |  | ||||||
|  |  | ||||||
| ## v7.1 |  | ||||||
|  |  | ||||||
| - Existing `Cmd.String` is renamed to `Cmd.Text`. New `Cmd.String` implements `fmt.Stringer` interface. |  | ||||||
|  |  | ||||||
| ## v7 |  | ||||||
|  |  | ||||||
| - *Important*. Tx.Pipeline now returns a non-transactional pipeline. Use Tx.TxPipeline for a transactional pipeline. |  | ||||||
| - WrapProcess is replaced with more convenient AddHook that has access to context.Context. |  | ||||||
| - WithContext now can not be used to create a shallow copy of the client. |  | ||||||
| - New methods ProcessContext, DoContext, and ExecContext. |  | ||||||
| - Client respects Context.Deadline when setting net.Conn deadline. |  | ||||||
| - Client listens on Context.Done while waiting for a connection from the pool and returns an error when context context is cancelled. |  | ||||||
| - Add PubSub.ChannelWithSubscriptions that sends `*Subscription` in addition to `*Message` to allow detecting reconnections. |  | ||||||
| - `time.Time` is now marshalled in RFC3339 format. `rdb.Get("foo").Time()` helper is added to parse the time. |  | ||||||
| - `SetLimiter` is removed and added `Options.Limiter` instead. |  | ||||||
| - `HMSet` is deprecated as of Redis v4. |  | ||||||
|  |  | ||||||
| ## v6.15 |  | ||||||
|  |  | ||||||
| - Cluster and Ring pipelines process commands for each node in its own goroutine. |  | ||||||
|  |  | ||||||
| ## 6.14 |  | ||||||
|  |  | ||||||
| - Added Options.MinIdleConns. |  | ||||||
| - Added Options.MaxConnAge. |  | ||||||
| - PoolStats.FreeConns is renamed to PoolStats.IdleConns. |  | ||||||
| - Add Client.Do to simplify creating custom commands. |  | ||||||
| - Add Cmd.String, Cmd.Int, Cmd.Int64, Cmd.Uint64, Cmd.Float64, and Cmd.Bool helpers. |  | ||||||
| - Lower memory usage. |  | ||||||
|  |  | ||||||
| ## v6.13 |  | ||||||
|  |  | ||||||
| - Ring got new options called `HashReplicas` and `Hash`. It is recommended to set `HashReplicas = 1000` for better keys distribution between shards. |  | ||||||
| - Cluster client was optimized to use much less memory when reloading cluster state. |  | ||||||
| - PubSub.ReceiveMessage is re-worked to not use ReceiveTimeout so it does not lose data when timeout occurres. In most cases it is recommended to use PubSub.Channel instead. |  | ||||||
| - Dialer.KeepAlive is set to 5 minutes by default. |  | ||||||
|  |  | ||||||
| ## v6.12 |  | ||||||
|  |  | ||||||
| - ClusterClient got new option called `ClusterSlots` which allows to build cluster of normal Redis Servers that don't have cluster mode enabled. See https://godoc.org/github.com/go-redis/redis#example-NewClusterClient--ManualSetup |  | ||||||
							
								
								
									
										128
									
								
								vendor/github.com/go-redis/redis/v7/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/go-redis/redis/v7/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,128 +0,0 @@ | |||||||
| # Redis client for Golang |  | ||||||
|  |  | ||||||
| [](https://travis-ci.org/go-redis/redis) |  | ||||||
| [](https://godoc.org/github.com/go-redis/redis) |  | ||||||
| [](https://airbrake.io) |  | ||||||
|  |  | ||||||
| Supports: |  | ||||||
|  |  | ||||||
| - Redis 3 commands except QUIT, MONITOR, SLOWLOG and SYNC. |  | ||||||
| - Automatic connection pooling with [circuit breaker](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern) support. |  | ||||||
| - [Pub/Sub](https://godoc.org/github.com/go-redis/redis#PubSub). |  | ||||||
| - [Transactions](https://godoc.org/github.com/go-redis/redis#example-Client-TxPipeline). |  | ||||||
| - [Pipeline](https://godoc.org/github.com/go-redis/redis#example-Client-Pipeline) and [TxPipeline](https://godoc.org/github.com/go-redis/redis#example-Client-TxPipeline). |  | ||||||
| - [Scripting](https://godoc.org/github.com/go-redis/redis#Script). |  | ||||||
| - [Timeouts](https://godoc.org/github.com/go-redis/redis#Options). |  | ||||||
| - [Redis Sentinel](https://godoc.org/github.com/go-redis/redis#NewFailoverClient). |  | ||||||
| - [Redis Cluster](https://godoc.org/github.com/go-redis/redis#NewClusterClient). |  | ||||||
| - [Cluster of Redis Servers](https://godoc.org/github.com/go-redis/redis#example-NewClusterClient--ManualSetup) without using cluster mode and Redis Sentinel. |  | ||||||
| - [Ring](https://godoc.org/github.com/go-redis/redis#NewRing). |  | ||||||
| - [Instrumentation](https://godoc.org/github.com/go-redis/redis#ex-package--Instrumentation). |  | ||||||
| - [Cache friendly](https://github.com/go-redis/cache). |  | ||||||
| - [Rate limiting](https://github.com/go-redis/redis_rate). |  | ||||||
| - [Distributed Locks](https://github.com/bsm/redislock). |  | ||||||
|  |  | ||||||
| API docs: https://godoc.org/github.com/go-redis/redis. |  | ||||||
| Examples: https://godoc.org/github.com/go-redis/redis#pkg-examples. |  | ||||||
|  |  | ||||||
| ## Installation |  | ||||||
|  |  | ||||||
| go-redis requires a Go version with [Modules](https://github.com/golang/go/wiki/Modules) support and uses import versioning. So please make sure to initialize a Go module before installing go-redis: |  | ||||||
|  |  | ||||||
| ``` shell |  | ||||||
| go mod init github.com/my/repo |  | ||||||
| go get github.com/go-redis/redis/v7 |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| Import: |  | ||||||
|  |  | ||||||
| ``` go |  | ||||||
| import "github.com/go-redis/redis/v7" |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ## Quickstart |  | ||||||
|  |  | ||||||
| ``` go |  | ||||||
| func ExampleNewClient() { |  | ||||||
| 	client := redis.NewClient(&redis.Options{ |  | ||||||
| 		Addr:     "localhost:6379", |  | ||||||
| 		Password: "", // no password set |  | ||||||
| 		DB:       0,  // use default DB |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	pong, err := client.Ping().Result() |  | ||||||
| 	fmt.Println(pong, err) |  | ||||||
| 	// Output: PONG <nil> |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func ExampleClient() { |  | ||||||
| 	client := redis.NewClient(&redis.Options{ |  | ||||||
| 		Addr:     "localhost:6379", |  | ||||||
| 		Password: "", // no password set |  | ||||||
| 		DB:       0,  // use default DB |  | ||||||
| 	}) |  | ||||||
| 	err := client.Set("key", "value", 0).Err() |  | ||||||
| 	if err != nil { |  | ||||||
| 		panic(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	val, err := client.Get("key").Result() |  | ||||||
| 	if err != nil { |  | ||||||
| 		panic(err) |  | ||||||
| 	} |  | ||||||
| 	fmt.Println("key", val) |  | ||||||
|  |  | ||||||
| 	val2, err := client.Get("key2").Result() |  | ||||||
| 	if err == redis.Nil { |  | ||||||
| 		fmt.Println("key2 does not exist") |  | ||||||
| 	} else if err != nil { |  | ||||||
| 		panic(err) |  | ||||||
| 	} else { |  | ||||||
| 		fmt.Println("key2", val2) |  | ||||||
| 	} |  | ||||||
| 	// Output: key value |  | ||||||
| 	// key2 does not exist |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ## Howto |  | ||||||
|  |  | ||||||
| Please go through [examples](https://godoc.org/github.com/go-redis/redis#pkg-examples) to get an idea how to use this package. |  | ||||||
|  |  | ||||||
| ## Look and feel |  | ||||||
|  |  | ||||||
| Some corner cases: |  | ||||||
|  |  | ||||||
| ``` go |  | ||||||
| // SET key value EX 10 NX |  | ||||||
| set, err := client.SetNX("key", "value", 10*time.Second).Result() |  | ||||||
|  |  | ||||||
| // SORT list LIMIT 0 2 ASC |  | ||||||
| vals, err := client.Sort("list", &redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result() |  | ||||||
|  |  | ||||||
| // ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2 |  | ||||||
| vals, err := client.ZRangeByScoreWithScores("zset", &redis.ZRangeBy{ |  | ||||||
| 	Min: "-inf", |  | ||||||
| 	Max: "+inf", |  | ||||||
| 	Offset: 0, |  | ||||||
| 	Count: 2, |  | ||||||
| }).Result() |  | ||||||
|  |  | ||||||
| // ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM |  | ||||||
| vals, err := client.ZInterStore("out", &redis.ZStore{ |  | ||||||
| 	Keys: []string{"zset1", "zset2"}, |  | ||||||
| 	Weights: []int64{2, 3} |  | ||||||
| }).Result() |  | ||||||
|  |  | ||||||
| // EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello" |  | ||||||
| vals, err := client.Eval("return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result() |  | ||||||
|  |  | ||||||
| // custom command |  | ||||||
| res, err := client.Do("set", "key", "value").Result() |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ## See also |  | ||||||
|  |  | ||||||
| - [Golang PostgreSQL ORM](https://github.com/go-pg/pg) |  | ||||||
| - [Golang msgpack](https://github.com/vmihailenco/msgpack) |  | ||||||
| - [Golang message task queue](https://github.com/vmihailenco/taskq) |  | ||||||
							
								
								
									
										22
									
								
								vendor/github.com/go-redis/redis/v7/cluster_commands.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/go-redis/redis/v7/cluster_commands.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,22 +0,0 @@ | |||||||
| package redis |  | ||||||
|  |  | ||||||
| import "sync/atomic" |  | ||||||
|  |  | ||||||
| func (c *ClusterClient) DBSize() *IntCmd { |  | ||||||
| 	cmd := NewIntCmd("dbsize") |  | ||||||
| 	var size int64 |  | ||||||
| 	err := c.ForEachMaster(func(master *Client) error { |  | ||||||
| 		n, err := master.DBSize().Result() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		atomic.AddInt64(&size, n) |  | ||||||
| 		return nil |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		cmd.SetErr(err) |  | ||||||
| 		return cmd |  | ||||||
| 	} |  | ||||||
| 	cmd.val = size |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
							
								
								
									
										2643
									
								
								vendor/github.com/go-redis/redis/v7/commands.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2643
									
								
								vendor/github.com/go-redis/redis/v7/commands.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										15
									
								
								vendor/github.com/go-redis/redis/v7/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/go-redis/redis/v7/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,15 +0,0 @@ | |||||||
| module github.com/go-redis/redis/v7 |  | ||||||
|  |  | ||||||
| require ( |  | ||||||
| 	github.com/golang/protobuf v1.3.2 // indirect |  | ||||||
| 	github.com/kr/pretty v0.1.0 // indirect |  | ||||||
| 	github.com/onsi/ginkgo v1.10.1 |  | ||||||
| 	github.com/onsi/gomega v1.7.0 |  | ||||||
| 	golang.org/x/net v0.0.0-20190923162816-aa69164e4478 // indirect |  | ||||||
| 	golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect |  | ||||||
| 	golang.org/x/text v0.3.2 // indirect |  | ||||||
| 	gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect |  | ||||||
| 	gopkg.in/yaml.v2 v2.2.4 // indirect |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| go 1.11 |  | ||||||
							
								
								
									
										47
									
								
								vendor/github.com/go-redis/redis/v7/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								vendor/github.com/go-redis/redis/v7/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,47 +0,0 @@ | |||||||
| github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= |  | ||||||
| github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |  | ||||||
| github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= |  | ||||||
| github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |  | ||||||
| github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= |  | ||||||
| github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |  | ||||||
| github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= |  | ||||||
| github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |  | ||||||
| github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= |  | ||||||
| github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= |  | ||||||
| github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |  | ||||||
| github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= |  | ||||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= |  | ||||||
| github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |  | ||||||
| github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= |  | ||||||
| github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |  | ||||||
| github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= |  | ||||||
| github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |  | ||||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |  | ||||||
| golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= |  | ||||||
| golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |  | ||||||
| golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= |  | ||||||
| golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |  | ||||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA= |  | ||||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |  | ||||||
| golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= |  | ||||||
| golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |  | ||||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |  | ||||||
| golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= |  | ||||||
| golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |  | ||||||
| golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= |  | ||||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |  | ||||||
| golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= |  | ||||||
| golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= |  | ||||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |  | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= |  | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |  | ||||||
| gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= |  | ||||||
| gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |  | ||||||
| gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= |  | ||||||
| gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |  | ||||||
| gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= |  | ||||||
| gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |  | ||||||
| gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= |  | ||||||
| gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |  | ||||||
| gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= |  | ||||||
| gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |  | ||||||
							
								
								
									
										81
									
								
								vendor/github.com/go-redis/redis/v7/internal/consistenthash/consistenthash.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										81
									
								
								vendor/github.com/go-redis/redis/v7/internal/consistenthash/consistenthash.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,81 +0,0 @@ | |||||||
| /* |  | ||||||
| Copyright 2013 Google Inc. |  | ||||||
|  |  | ||||||
| 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. |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| // Package consistenthash provides an implementation of a ring hash. |  | ||||||
| package consistenthash |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"hash/crc32" |  | ||||||
| 	"sort" |  | ||||||
| 	"strconv" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type Hash func(data []byte) uint32 |  | ||||||
|  |  | ||||||
| type Map struct { |  | ||||||
| 	hash     Hash |  | ||||||
| 	replicas int |  | ||||||
| 	keys     []int // Sorted |  | ||||||
| 	hashMap  map[int]string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func New(replicas int, fn Hash) *Map { |  | ||||||
| 	m := &Map{ |  | ||||||
| 		replicas: replicas, |  | ||||||
| 		hash:     fn, |  | ||||||
| 		hashMap:  make(map[int]string), |  | ||||||
| 	} |  | ||||||
| 	if m.hash == nil { |  | ||||||
| 		m.hash = crc32.ChecksumIEEE |  | ||||||
| 	} |  | ||||||
| 	return m |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Returns true if there are no items available. |  | ||||||
| func (m *Map) IsEmpty() bool { |  | ||||||
| 	return len(m.keys) == 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Adds some keys to the hash. |  | ||||||
| func (m *Map) Add(keys ...string) { |  | ||||||
| 	for _, key := range keys { |  | ||||||
| 		for i := 0; i < m.replicas; i++ { |  | ||||||
| 			hash := int(m.hash([]byte(strconv.Itoa(i) + key))) |  | ||||||
| 			m.keys = append(m.keys, hash) |  | ||||||
| 			m.hashMap[hash] = key |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	sort.Ints(m.keys) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Gets the closest item in the hash to the provided key. |  | ||||||
| func (m *Map) Get(key string) string { |  | ||||||
| 	if m.IsEmpty() { |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	hash := int(m.hash([]byte(key))) |  | ||||||
|  |  | ||||||
| 	// Binary search for appropriate replica. |  | ||||||
| 	idx := sort.Search(len(m.keys), func(i int) bool { return m.keys[i] >= hash }) |  | ||||||
|  |  | ||||||
| 	// Means we have cycled back to the first replica. |  | ||||||
| 	if idx == len(m.keys) { |  | ||||||
| 		idx = 0 |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return m.hashMap[m.keys[idx]] |  | ||||||
| } |  | ||||||
							
								
								
									
										24
									
								
								vendor/github.com/go-redis/redis/v7/internal/internal.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/go-redis/redis/v7/internal/internal.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,24 +0,0 @@ | |||||||
| package internal |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"math/rand" |  | ||||||
| 	"time" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Retry backoff with jitter sleep to prevent overloaded conditions during intervals |  | ||||||
| // https://www.awsarchitectureblog.com/2015/03/backoff.html |  | ||||||
| func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration { |  | ||||||
| 	if retry < 0 { |  | ||||||
| 		retry = 0 |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	backoff := minBackoff << uint(retry) |  | ||||||
| 	if backoff > maxBackoff || backoff < minBackoff { |  | ||||||
| 		backoff = maxBackoff |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if backoff == 0 { |  | ||||||
| 		return 0 |  | ||||||
| 	} |  | ||||||
| 	return time.Duration(rand.Int63n(int64(backoff))) |  | ||||||
| } |  | ||||||
							
								
								
									
										8
									
								
								vendor/github.com/go-redis/redis/v7/internal/log.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/go-redis/redis/v7/internal/log.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,8 +0,0 @@ | |||||||
| package internal |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"log" |  | ||||||
| 	"os" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var Logger = log.New(os.Stderr, "redis: ", log.LstdFlags|log.Lshortfile) |  | ||||||
							
								
								
									
										112
									
								
								vendor/github.com/go-redis/redis/v7/internal/pool/pool_sticky.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/go-redis/redis/v7/internal/pool/pool_sticky.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,112 +0,0 @@ | |||||||
| package pool |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"sync" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type StickyConnPool struct { |  | ||||||
| 	pool     *ConnPool |  | ||||||
| 	reusable bool |  | ||||||
|  |  | ||||||
| 	cn     *Conn |  | ||||||
| 	closed bool |  | ||||||
| 	mu     sync.Mutex |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var _ Pooler = (*StickyConnPool)(nil) |  | ||||||
|  |  | ||||||
| func NewStickyConnPool(pool *ConnPool, reusable bool) *StickyConnPool { |  | ||||||
| 	return &StickyConnPool{ |  | ||||||
| 		pool:     pool, |  | ||||||
| 		reusable: reusable, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) NewConn(context.Context) (*Conn, error) { |  | ||||||
| 	panic("not implemented") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) CloseConn(*Conn) error { |  | ||||||
| 	panic("not implemented") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) Get(ctx context.Context) (*Conn, error) { |  | ||||||
| 	p.mu.Lock() |  | ||||||
| 	defer p.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	if p.closed { |  | ||||||
| 		return nil, ErrClosed |  | ||||||
| 	} |  | ||||||
| 	if p.cn != nil { |  | ||||||
| 		return p.cn, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	cn, err := p.pool.Get(ctx) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	p.cn = cn |  | ||||||
| 	return cn, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) putUpstream() { |  | ||||||
| 	p.pool.Put(p.cn) |  | ||||||
| 	p.cn = nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) Put(cn *Conn) {} |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) removeUpstream(reason error) { |  | ||||||
| 	p.pool.Remove(p.cn, reason) |  | ||||||
| 	p.cn = nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) Remove(cn *Conn, reason error) { |  | ||||||
| 	p.removeUpstream(reason) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) Len() int { |  | ||||||
| 	p.mu.Lock() |  | ||||||
| 	defer p.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	if p.cn == nil { |  | ||||||
| 		return 0 |  | ||||||
| 	} |  | ||||||
| 	return 1 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) IdleLen() int { |  | ||||||
| 	p.mu.Lock() |  | ||||||
| 	defer p.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	if p.cn == nil { |  | ||||||
| 		return 1 |  | ||||||
| 	} |  | ||||||
| 	return 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) Stats() *Stats { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *StickyConnPool) Close() error { |  | ||||||
| 	p.mu.Lock() |  | ||||||
| 	defer p.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	if p.closed { |  | ||||||
| 		return ErrClosed |  | ||||||
| 	} |  | ||||||
| 	p.closed = true |  | ||||||
|  |  | ||||||
| 	if p.cn != nil { |  | ||||||
| 		if p.reusable { |  | ||||||
| 			p.putUpstream() |  | ||||||
| 		} else { |  | ||||||
| 			p.removeUpstream(ErrClosed) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
							
								
								
									
										56
									
								
								vendor/github.com/go-redis/redis/v7/internal/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/go-redis/redis/v7/internal/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,56 +0,0 @@ | |||||||
| package internal |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/go-redis/redis/v7/internal/util" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func Sleep(ctx context.Context, dur time.Duration) error { |  | ||||||
| 	t := time.NewTimer(dur) |  | ||||||
| 	defer t.Stop() |  | ||||||
|  |  | ||||||
| 	select { |  | ||||||
| 	case <-t.C: |  | ||||||
| 		return nil |  | ||||||
| 	case <-ctx.Done(): |  | ||||||
| 		return ctx.Err() |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func ToLower(s string) string { |  | ||||||
| 	if isLower(s) { |  | ||||||
| 		return s |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	b := make([]byte, len(s)) |  | ||||||
| 	for i := range b { |  | ||||||
| 		c := s[i] |  | ||||||
| 		if c >= 'A' && c <= 'Z' { |  | ||||||
| 			c += 'a' - 'A' |  | ||||||
| 		} |  | ||||||
| 		b[i] = c |  | ||||||
| 	} |  | ||||||
| 	return util.BytesToString(b) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func isLower(s string) bool { |  | ||||||
| 	for i := 0; i < len(s); i++ { |  | ||||||
| 		c := s[i] |  | ||||||
| 		if c >= 'A' && c <= 'Z' { |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func Unwrap(err error) error { |  | ||||||
| 	u, ok := err.(interface { |  | ||||||
| 		Unwrap() error |  | ||||||
| 	}) |  | ||||||
| 	if !ok { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| 	return u.Unwrap() |  | ||||||
| } |  | ||||||
							
								
								
									
										62
									
								
								vendor/github.com/go-redis/redis/v7/script.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										62
									
								
								vendor/github.com/go-redis/redis/v7/script.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,62 +0,0 @@ | |||||||
| package redis |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"crypto/sha1" |  | ||||||
| 	"encoding/hex" |  | ||||||
| 	"io" |  | ||||||
| 	"strings" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type scripter interface { |  | ||||||
| 	Eval(script string, keys []string, args ...interface{}) *Cmd |  | ||||||
| 	EvalSha(sha1 string, keys []string, args ...interface{}) *Cmd |  | ||||||
| 	ScriptExists(hashes ...string) *BoolSliceCmd |  | ||||||
| 	ScriptLoad(script string) *StringCmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var _ scripter = (*Client)(nil) |  | ||||||
| var _ scripter = (*Ring)(nil) |  | ||||||
| var _ scripter = (*ClusterClient)(nil) |  | ||||||
|  |  | ||||||
| type Script struct { |  | ||||||
| 	src, hash string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewScript(src string) *Script { |  | ||||||
| 	h := sha1.New() |  | ||||||
| 	_, _ = io.WriteString(h, src) |  | ||||||
| 	return &Script{ |  | ||||||
| 		src:  src, |  | ||||||
| 		hash: hex.EncodeToString(h.Sum(nil)), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Script) Hash() string { |  | ||||||
| 	return s.hash |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Script) Load(c scripter) *StringCmd { |  | ||||||
| 	return c.ScriptLoad(s.src) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Script) Exists(c scripter) *BoolSliceCmd { |  | ||||||
| 	return c.ScriptExists(s.hash) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Script) Eval(c scripter, keys []string, args ...interface{}) *Cmd { |  | ||||||
| 	return c.Eval(s.src, keys, args...) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Script) EvalSha(c scripter, keys []string, args ...interface{}) *Cmd { |  | ||||||
| 	return c.EvalSha(s.hash, keys, args...) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Run optimistically uses EVALSHA to run the script. If script does not exist |  | ||||||
| // it is retried using EVAL. |  | ||||||
| func (s *Script) Run(c scripter, keys []string, args ...interface{}) *Cmd { |  | ||||||
| 	r := s.EvalSha(c, keys, args...) |  | ||||||
| 	if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") { |  | ||||||
| 		return s.Eval(c, keys, args...) |  | ||||||
| 	} |  | ||||||
| 	return r |  | ||||||
| } |  | ||||||
							
								
								
									
										509
									
								
								vendor/github.com/go-redis/redis/v7/sentinel.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										509
									
								
								vendor/github.com/go-redis/redis/v7/sentinel.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,509 +0,0 @@ | |||||||
| package redis |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"crypto/tls" |  | ||||||
| 	"errors" |  | ||||||
| 	"net" |  | ||||||
| 	"strings" |  | ||||||
| 	"sync" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/go-redis/redis/v7/internal" |  | ||||||
| 	"github.com/go-redis/redis/v7/internal/pool" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
| // FailoverOptions are used to configure a failover client and should |  | ||||||
| // be passed to NewFailoverClient. |  | ||||||
| type FailoverOptions struct { |  | ||||||
| 	// The master name. |  | ||||||
| 	MasterName string |  | ||||||
| 	// A seed list of host:port addresses of sentinel nodes. |  | ||||||
| 	SentinelAddrs    []string |  | ||||||
| 	SentinelUsername string |  | ||||||
| 	SentinelPassword string |  | ||||||
|  |  | ||||||
| 	// Following options are copied from Options struct. |  | ||||||
|  |  | ||||||
| 	Dialer    func(ctx context.Context, network, addr string) (net.Conn, error) |  | ||||||
| 	OnConnect func(*Conn) error |  | ||||||
|  |  | ||||||
| 	Username string |  | ||||||
| 	Password string |  | ||||||
| 	DB       int |  | ||||||
|  |  | ||||||
| 	MaxRetries      int |  | ||||||
| 	MinRetryBackoff time.Duration |  | ||||||
| 	MaxRetryBackoff time.Duration |  | ||||||
|  |  | ||||||
| 	DialTimeout  time.Duration |  | ||||||
| 	ReadTimeout  time.Duration |  | ||||||
| 	WriteTimeout time.Duration |  | ||||||
|  |  | ||||||
| 	PoolSize           int |  | ||||||
| 	MinIdleConns       int |  | ||||||
| 	MaxConnAge         time.Duration |  | ||||||
| 	PoolTimeout        time.Duration |  | ||||||
| 	IdleTimeout        time.Duration |  | ||||||
| 	IdleCheckFrequency time.Duration |  | ||||||
|  |  | ||||||
| 	TLSConfig *tls.Config |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (opt *FailoverOptions) options() *Options { |  | ||||||
| 	return &Options{ |  | ||||||
| 		Addr:      "FailoverClient", |  | ||||||
| 		Dialer:    opt.Dialer, |  | ||||||
| 		OnConnect: opt.OnConnect, |  | ||||||
|  |  | ||||||
| 		DB:       opt.DB, |  | ||||||
| 		Username: opt.Username, |  | ||||||
| 		Password: opt.Password, |  | ||||||
|  |  | ||||||
| 		MaxRetries:      opt.MaxRetries, |  | ||||||
| 		MinRetryBackoff: opt.MinRetryBackoff, |  | ||||||
| 		MaxRetryBackoff: opt.MaxRetryBackoff, |  | ||||||
|  |  | ||||||
| 		DialTimeout:  opt.DialTimeout, |  | ||||||
| 		ReadTimeout:  opt.ReadTimeout, |  | ||||||
| 		WriteTimeout: opt.WriteTimeout, |  | ||||||
|  |  | ||||||
| 		PoolSize:           opt.PoolSize, |  | ||||||
| 		PoolTimeout:        opt.PoolTimeout, |  | ||||||
| 		IdleTimeout:        opt.IdleTimeout, |  | ||||||
| 		IdleCheckFrequency: opt.IdleCheckFrequency, |  | ||||||
| 		MinIdleConns:       opt.MinIdleConns, |  | ||||||
| 		MaxConnAge:         opt.MaxConnAge, |  | ||||||
|  |  | ||||||
| 		TLSConfig: opt.TLSConfig, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewFailoverClient returns a Redis client that uses Redis Sentinel |  | ||||||
| // for automatic failover. It's safe for concurrent use by multiple |  | ||||||
| // goroutines. |  | ||||||
| func NewFailoverClient(failoverOpt *FailoverOptions) *Client { |  | ||||||
| 	opt := failoverOpt.options() |  | ||||||
| 	opt.init() |  | ||||||
|  |  | ||||||
| 	failover := &sentinelFailover{ |  | ||||||
| 		masterName:    failoverOpt.MasterName, |  | ||||||
| 		sentinelAddrs: failoverOpt.SentinelAddrs, |  | ||||||
| 		username:      failoverOpt.SentinelUsername, |  | ||||||
| 		password:      failoverOpt.SentinelPassword, |  | ||||||
|  |  | ||||||
| 		opt: opt, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	c := Client{ |  | ||||||
| 		baseClient: newBaseClient(opt, failover.Pool()), |  | ||||||
| 		ctx:        context.Background(), |  | ||||||
| 	} |  | ||||||
| 	c.cmdable = c.Process |  | ||||||
| 	c.onClose = failover.Close |  | ||||||
|  |  | ||||||
| 	return &c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ |  | ||||||
|  |  | ||||||
| type SentinelClient struct { |  | ||||||
| 	*baseClient |  | ||||||
| 	ctx context.Context |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewSentinelClient(opt *Options) *SentinelClient { |  | ||||||
| 	opt.init() |  | ||||||
| 	c := &SentinelClient{ |  | ||||||
| 		baseClient: &baseClient{ |  | ||||||
| 			opt:      opt, |  | ||||||
| 			connPool: newConnPool(opt), |  | ||||||
| 		}, |  | ||||||
| 		ctx: context.Background(), |  | ||||||
| 	} |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *SentinelClient) Context() context.Context { |  | ||||||
| 	return c.ctx |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *SentinelClient) WithContext(ctx context.Context) *SentinelClient { |  | ||||||
| 	if ctx == nil { |  | ||||||
| 		panic("nil context") |  | ||||||
| 	} |  | ||||||
| 	clone := *c |  | ||||||
| 	clone.ctx = ctx |  | ||||||
| 	return &clone |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *SentinelClient) Process(cmd Cmder) error { |  | ||||||
| 	return c.ProcessContext(c.ctx, cmd) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *SentinelClient) ProcessContext(ctx context.Context, cmd Cmder) error { |  | ||||||
| 	return c.baseClient.process(ctx, cmd) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *SentinelClient) pubSub() *PubSub { |  | ||||||
| 	pubsub := &PubSub{ |  | ||||||
| 		opt: c.opt, |  | ||||||
|  |  | ||||||
| 		newConn: func(channels []string) (*pool.Conn, error) { |  | ||||||
| 			return c.newConn(context.TODO()) |  | ||||||
| 		}, |  | ||||||
| 		closeConn: c.connPool.CloseConn, |  | ||||||
| 	} |  | ||||||
| 	pubsub.init() |  | ||||||
| 	return pubsub |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Ping is used to test if a connection is still alive, or to |  | ||||||
| // measure latency. |  | ||||||
| func (c *SentinelClient) Ping() *StringCmd { |  | ||||||
| 	cmd := NewStringCmd("ping") |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Subscribe subscribes the client to the specified channels. |  | ||||||
| // Channels can be omitted to create empty subscription. |  | ||||||
| func (c *SentinelClient) Subscribe(channels ...string) *PubSub { |  | ||||||
| 	pubsub := c.pubSub() |  | ||||||
| 	if len(channels) > 0 { |  | ||||||
| 		_ = pubsub.Subscribe(channels...) |  | ||||||
| 	} |  | ||||||
| 	return pubsub |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // PSubscribe subscribes the client to the given patterns. |  | ||||||
| // Patterns can be omitted to create empty subscription. |  | ||||||
| func (c *SentinelClient) PSubscribe(channels ...string) *PubSub { |  | ||||||
| 	pubsub := c.pubSub() |  | ||||||
| 	if len(channels) > 0 { |  | ||||||
| 		_ = pubsub.PSubscribe(channels...) |  | ||||||
| 	} |  | ||||||
| 	return pubsub |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *SentinelClient) GetMasterAddrByName(name string) *StringSliceCmd { |  | ||||||
| 	cmd := NewStringSliceCmd("sentinel", "get-master-addr-by-name", name) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *SentinelClient) Sentinels(name string) *SliceCmd { |  | ||||||
| 	cmd := NewSliceCmd("sentinel", "sentinels", name) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Failover forces a failover as if the master was not reachable, and without |  | ||||||
| // asking for agreement to other Sentinels. |  | ||||||
| func (c *SentinelClient) Failover(name string) *StatusCmd { |  | ||||||
| 	cmd := NewStatusCmd("sentinel", "failover", name) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Reset resets all the masters with matching name. The pattern argument is a |  | ||||||
| // glob-style pattern. The reset process clears any previous state in a master |  | ||||||
| // (including a failover in progress), and removes every slave and sentinel |  | ||||||
| // already discovered and associated with the master. |  | ||||||
| func (c *SentinelClient) Reset(pattern string) *IntCmd { |  | ||||||
| 	cmd := NewIntCmd("sentinel", "reset", pattern) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // FlushConfig forces Sentinel to rewrite its configuration on disk, including |  | ||||||
| // the current Sentinel state. |  | ||||||
| func (c *SentinelClient) FlushConfig() *StatusCmd { |  | ||||||
| 	cmd := NewStatusCmd("sentinel", "flushconfig") |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Master shows the state and info of the specified master. |  | ||||||
| func (c *SentinelClient) Master(name string) *StringStringMapCmd { |  | ||||||
| 	cmd := NewStringStringMapCmd("sentinel", "master", name) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Masters shows a list of monitored masters and their state. |  | ||||||
| func (c *SentinelClient) Masters() *SliceCmd { |  | ||||||
| 	cmd := NewSliceCmd("sentinel", "masters") |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Slaves shows a list of slaves for the specified master and their state. |  | ||||||
| func (c *SentinelClient) Slaves(name string) *SliceCmd { |  | ||||||
| 	cmd := NewSliceCmd("sentinel", "slaves", name) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // CkQuorum checks if the current Sentinel configuration is able to reach the |  | ||||||
| // quorum needed to failover a master, and the majority needed to authorize the |  | ||||||
| // failover. This command should be used in monitoring systems to check if a |  | ||||||
| // Sentinel deployment is ok. |  | ||||||
| func (c *SentinelClient) CkQuorum(name string) *StringCmd { |  | ||||||
| 	cmd := NewStringCmd("sentinel", "ckquorum", name) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Monitor tells the Sentinel to start monitoring a new master with the specified |  | ||||||
| // name, ip, port, and quorum. |  | ||||||
| func (c *SentinelClient) Monitor(name, ip, port, quorum string) *StringCmd { |  | ||||||
| 	cmd := NewStringCmd("sentinel", "monitor", name, ip, port, quorum) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Set is used in order to change configuration parameters of a specific master. |  | ||||||
| func (c *SentinelClient) Set(name, option, value string) *StringCmd { |  | ||||||
| 	cmd := NewStringCmd("sentinel", "set", name, option, value) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Remove is used in order to remove the specified master: the master will no |  | ||||||
| // longer be monitored, and will totally be removed from the internal state of |  | ||||||
| // the Sentinel. |  | ||||||
| func (c *SentinelClient) Remove(name string) *StringCmd { |  | ||||||
| 	cmd := NewStringCmd("sentinel", "remove", name) |  | ||||||
| 	_ = c.Process(cmd) |  | ||||||
| 	return cmd |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type sentinelFailover struct { |  | ||||||
| 	sentinelAddrs []string |  | ||||||
|  |  | ||||||
| 	opt      *Options |  | ||||||
| 	username string |  | ||||||
| 	password string |  | ||||||
|  |  | ||||||
| 	pool     *pool.ConnPool |  | ||||||
| 	poolOnce sync.Once |  | ||||||
|  |  | ||||||
| 	mu          sync.RWMutex |  | ||||||
| 	masterName  string |  | ||||||
| 	_masterAddr string |  | ||||||
| 	sentinel    *SentinelClient |  | ||||||
| 	pubsub      *PubSub |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) Close() error { |  | ||||||
| 	c.mu.Lock() |  | ||||||
| 	defer c.mu.Unlock() |  | ||||||
| 	if c.sentinel != nil { |  | ||||||
| 		return c.closeSentinel() |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) closeSentinel() error { |  | ||||||
| 	firstErr := c.pubsub.Close() |  | ||||||
| 	c.pubsub = nil |  | ||||||
|  |  | ||||||
| 	err := c.sentinel.Close() |  | ||||||
| 	if err != nil && firstErr == nil { |  | ||||||
| 		firstErr = err |  | ||||||
| 	} |  | ||||||
| 	c.sentinel = nil |  | ||||||
|  |  | ||||||
| 	return firstErr |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) Pool() *pool.ConnPool { |  | ||||||
| 	c.poolOnce.Do(func() { |  | ||||||
| 		opt := *c.opt |  | ||||||
| 		opt.Dialer = c.dial |  | ||||||
| 		c.pool = newConnPool(&opt) |  | ||||||
| 	}) |  | ||||||
| 	return c.pool |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) dial(ctx context.Context, network, _ string) (net.Conn, error) { |  | ||||||
| 	addr, err := c.MasterAddr() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if c.opt.Dialer != nil { |  | ||||||
| 		return c.opt.Dialer(ctx, network, addr) |  | ||||||
| 	} |  | ||||||
| 	return net.DialTimeout("tcp", addr, c.opt.DialTimeout) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) MasterAddr() (string, error) { |  | ||||||
| 	addr, err := c.masterAddr() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	c.switchMaster(addr) |  | ||||||
| 	return addr, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) masterAddr() (string, error) { |  | ||||||
| 	c.mu.RLock() |  | ||||||
| 	sentinel := c.sentinel |  | ||||||
| 	c.mu.RUnlock() |  | ||||||
|  |  | ||||||
| 	if sentinel != nil { |  | ||||||
| 		addr := c.getMasterAddr(sentinel) |  | ||||||
| 		if addr != "" { |  | ||||||
| 			return addr, nil |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	c.mu.Lock() |  | ||||||
| 	defer c.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	if c.sentinel != nil { |  | ||||||
| 		addr := c.getMasterAddr(c.sentinel) |  | ||||||
| 		if addr != "" { |  | ||||||
| 			return addr, nil |  | ||||||
| 		} |  | ||||||
| 		_ = c.closeSentinel() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for i, sentinelAddr := range c.sentinelAddrs { |  | ||||||
| 		sentinel := NewSentinelClient(&Options{ |  | ||||||
| 			Addr:   sentinelAddr, |  | ||||||
| 			Dialer: c.opt.Dialer, |  | ||||||
|  |  | ||||||
| 			Username: c.username, |  | ||||||
| 			Password: c.password, |  | ||||||
|  |  | ||||||
| 			MaxRetries: c.opt.MaxRetries, |  | ||||||
|  |  | ||||||
| 			DialTimeout:  c.opt.DialTimeout, |  | ||||||
| 			ReadTimeout:  c.opt.ReadTimeout, |  | ||||||
| 			WriteTimeout: c.opt.WriteTimeout, |  | ||||||
|  |  | ||||||
| 			PoolSize:           c.opt.PoolSize, |  | ||||||
| 			PoolTimeout:        c.opt.PoolTimeout, |  | ||||||
| 			IdleTimeout:        c.opt.IdleTimeout, |  | ||||||
| 			IdleCheckFrequency: c.opt.IdleCheckFrequency, |  | ||||||
|  |  | ||||||
| 			TLSConfig: c.opt.TLSConfig, |  | ||||||
| 		}) |  | ||||||
|  |  | ||||||
| 		masterAddr, err := sentinel.GetMasterAddrByName(c.masterName).Result() |  | ||||||
| 		if err != nil { |  | ||||||
| 			internal.Logger.Printf("sentinel: GetMasterAddrByName master=%q failed: %s", |  | ||||||
| 				c.masterName, err) |  | ||||||
| 			_ = sentinel.Close() |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Push working sentinel to the top. |  | ||||||
| 		c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0] |  | ||||||
| 		c.setSentinel(sentinel) |  | ||||||
|  |  | ||||||
| 		addr := net.JoinHostPort(masterAddr[0], masterAddr[1]) |  | ||||||
| 		return addr, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return "", errors.New("redis: all sentinels are unreachable") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) getMasterAddr(sentinel *SentinelClient) string { |  | ||||||
| 	addr, err := sentinel.GetMasterAddrByName(c.masterName).Result() |  | ||||||
| 	if err != nil { |  | ||||||
| 		internal.Logger.Printf("sentinel: GetMasterAddrByName name=%q failed: %s", |  | ||||||
| 			c.masterName, err) |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
| 	return net.JoinHostPort(addr[0], addr[1]) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) switchMaster(addr string) { |  | ||||||
| 	c.mu.RLock() |  | ||||||
| 	masterAddr := c._masterAddr |  | ||||||
| 	c.mu.RUnlock() |  | ||||||
| 	if masterAddr == addr { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	c.mu.Lock() |  | ||||||
| 	defer c.mu.Unlock() |  | ||||||
|  |  | ||||||
| 	if c._masterAddr == addr { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	internal.Logger.Printf("sentinel: new master=%q addr=%q", |  | ||||||
| 		c.masterName, addr) |  | ||||||
| 	_ = c.Pool().Filter(func(cn *pool.Conn) bool { |  | ||||||
| 		return cn.RemoteAddr().String() != addr |  | ||||||
| 	}) |  | ||||||
| 	c._masterAddr = addr |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) setSentinel(sentinel *SentinelClient) { |  | ||||||
| 	if c.sentinel != nil { |  | ||||||
| 		panic("not reached") |  | ||||||
| 	} |  | ||||||
| 	c.sentinel = sentinel |  | ||||||
| 	c.discoverSentinels() |  | ||||||
|  |  | ||||||
| 	c.pubsub = sentinel.Subscribe("+switch-master") |  | ||||||
| 	go c.listen(c.pubsub) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) discoverSentinels() { |  | ||||||
| 	sentinels, err := c.sentinel.Sentinels(c.masterName).Result() |  | ||||||
| 	if err != nil { |  | ||||||
| 		internal.Logger.Printf("sentinel: Sentinels master=%q failed: %s", c.masterName, err) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	for _, sentinel := range sentinels { |  | ||||||
| 		vals := sentinel.([]interface{}) |  | ||||||
| 		for i := 0; i < len(vals); i += 2 { |  | ||||||
| 			key := vals[i].(string) |  | ||||||
| 			if key == "name" { |  | ||||||
| 				sentinelAddr := vals[i+1].(string) |  | ||||||
| 				if !contains(c.sentinelAddrs, sentinelAddr) { |  | ||||||
| 					internal.Logger.Printf("sentinel: discovered new sentinel=%q for master=%q", |  | ||||||
| 						sentinelAddr, c.masterName) |  | ||||||
| 					c.sentinelAddrs = append(c.sentinelAddrs, sentinelAddr) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *sentinelFailover) listen(pubsub *PubSub) { |  | ||||||
| 	ch := pubsub.Channel() |  | ||||||
| 	for { |  | ||||||
| 		msg, ok := <-ch |  | ||||||
| 		if !ok { |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if msg.Channel == "+switch-master" { |  | ||||||
| 			parts := strings.Split(msg.Payload, " ") |  | ||||||
| 			if parts[0] != c.masterName { |  | ||||||
| 				internal.Logger.Printf("sentinel: ignore addr for master=%q", parts[0]) |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			addr := net.JoinHostPort(parts[3], parts[4]) |  | ||||||
| 			c.switchMaster(addr) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func contains(slice []string, str string) bool { |  | ||||||
| 	for _, s := range slice { |  | ||||||
| 		if s == str { |  | ||||||
| 			return true |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
| @@ -1,2 +1,3 @@ | |||||||
| *.rdb | *.rdb | ||||||
| testdata/*/ | testdata/*/ | ||||||
|  | .idea/ | ||||||
| @@ -7,9 +7,18 @@ linters: | |||||||
|   disable: |   disable: | ||||||
|     - funlen |     - funlen | ||||||
|     - gochecknoglobals |     - gochecknoglobals | ||||||
|  |     - gochecknoinits | ||||||
|     - gocognit |     - gocognit | ||||||
|     - goconst |     - goconst | ||||||
|     - godox |     - godox | ||||||
|     - gosec |     - gosec | ||||||
|     - maligned |     - maligned | ||||||
|     - wsl |     - wsl | ||||||
|  |     - gomnd | ||||||
|  |     - goerr113 | ||||||
|  |     - exhaustive | ||||||
|  |     - nestif | ||||||
|  |     - nlreturn | ||||||
|  |     - exhaustivestruct | ||||||
|  |     - wrapcheck | ||||||
|  |     - errorlint | ||||||
							
								
								
									
										4
									
								
								vendor/github.com/go-redis/redis/v8/.prettierrc
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/go-redis/redis/v8/.prettierrc
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | semi: false | ||||||
|  | singleQuote: true | ||||||
|  | proseWrap: always | ||||||
|  | printWidth: 100 | ||||||
							
								
								
									
										20
									
								
								vendor/github.com/go-redis/redis/v8/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/go-redis/redis/v8/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | dist: xenial | ||||||
|  | language: go | ||||||
|  |  | ||||||
|  | services: | ||||||
|  |   - redis-server | ||||||
|  |  | ||||||
|  | go: | ||||||
|  |   - 1.14.x | ||||||
|  |   - 1.15.x | ||||||
|  |   - tip | ||||||
|  |  | ||||||
|  | matrix: | ||||||
|  |   allow_failures: | ||||||
|  |     - go: tip | ||||||
|  |  | ||||||
|  | go_import_path: github.com/go-redis/redis | ||||||
|  |  | ||||||
|  | before_install: | ||||||
|  |   - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- | ||||||
|  |     -b $(go env GOPATH)/bin v1.32.2 | ||||||
							
								
								
									
										5
									
								
								vendor/github.com/go-redis/redis/v8/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/go-redis/redis/v8/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | # Changelog | ||||||
|  |  | ||||||
|  | > :heart: [**Uptrace.dev** - distributed traces, logs, and errors in one place](https://uptrace.dev) | ||||||
|  |  | ||||||
|  | See https://redis.uptrace.dev/changelog/ | ||||||
| @@ -3,6 +3,7 @@ all: testdeps | |||||||
| 	go test ./... -short -race | 	go test ./... -short -race | ||||||
| 	go test ./... -run=NONE -bench=. -benchmem | 	go test ./... -run=NONE -bench=. -benchmem | ||||||
| 	env GOOS=linux GOARCH=386 go test ./... | 	env GOOS=linux GOARCH=386 go test ./... | ||||||
|  | 	go vet | ||||||
| 	golangci-lint run | 	golangci-lint run | ||||||
| 
 | 
 | ||||||
| testdeps: testdata/redis/src/redis-server | testdeps: testdata/redis/src/redis-server | ||||||
| @@ -18,3 +19,9 @@ testdata/redis: | |||||||
| 
 | 
 | ||||||
| testdata/redis/src/redis-server: testdata/redis | testdata/redis/src/redis-server: testdata/redis | ||||||
| 	cd $< && make all | 	cd $< && make all | ||||||
|  | 
 | ||||||
|  | tag: | ||||||
|  | 	git tag $(VERSION) | ||||||
|  | 	git tag extra/rediscmd/$(VERSION) | ||||||
|  | 	git tag extra/redisotel/$(VERSION) | ||||||
|  | 	git tag extra/rediscensus/$(VERSION) | ||||||
							
								
								
									
										159
									
								
								vendor/github.com/go-redis/redis/v8/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								vendor/github.com/go-redis/redis/v8/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,159 @@ | |||||||
|  | # Redis client for Golang | ||||||
|  |  | ||||||
|  | [](https://travis-ci.org/go-redis/redis) | ||||||
|  | [](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc) | ||||||
|  | [](https://redis.uptrace.dev/) | ||||||
|  | [](https://discord.gg/rWtp5Aj) | ||||||
|  |  | ||||||
|  | > :heart: [**Uptrace.dev** - distributed traces, logs, and errors in one place](https://uptrace.dev) | ||||||
|  |  | ||||||
|  | - Join [Discord](https://discord.gg/rWtp5Aj) to ask questions. | ||||||
|  | - [Documentation](https://redis.uptrace.dev) | ||||||
|  | - [Reference](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc) | ||||||
|  | - [Examples](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#pkg-examples) | ||||||
|  | - [RealWorld example app](https://github.com/uptrace/go-treemux-realworld-example-app) | ||||||
|  |  | ||||||
|  | ## Ecosystem | ||||||
|  |  | ||||||
|  | - [Redis Mock](https://github.com/go-redis/redismock). | ||||||
|  | - [Distributed Locks](https://github.com/bsm/redislock). | ||||||
|  | - [Redis Cache](https://github.com/go-redis/cache). | ||||||
|  | - [Rate limiting](https://github.com/go-redis/redis_rate). | ||||||
|  |  | ||||||
|  | ## Features | ||||||
|  |  | ||||||
|  | - Redis 3 commands except QUIT, MONITOR, and SYNC. | ||||||
|  | - Automatic connection pooling with | ||||||
|  |   [circuit breaker](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern) support. | ||||||
|  | - [Pub/Sub](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#PubSub). | ||||||
|  | - [Transactions](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-Client-TxPipeline). | ||||||
|  | - [Pipeline](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-Client-Pipeline) and | ||||||
|  |   [TxPipeline](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-Client-TxPipeline). | ||||||
|  | - [Scripting](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#Script). | ||||||
|  | - [Timeouts](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#Options). | ||||||
|  | - [Redis Sentinel](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewFailoverClient). | ||||||
|  | - [Redis Cluster](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewClusterClient). | ||||||
|  | - [Cluster of Redis Servers](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#example-NewClusterClient--ManualSetup) | ||||||
|  |   without using cluster mode and Redis Sentinel. | ||||||
|  | - [Ring](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#NewRing). | ||||||
|  | - [Instrumentation](https://pkg.go.dev/github.com/go-redis/redis/v8?tab=doc#ex-package--Instrumentation). | ||||||
|  |  | ||||||
|  | ## Installation | ||||||
|  |  | ||||||
|  | go-redis supports 2 last Go versions and requires a Go version with | ||||||
|  | [modules](https://github.com/golang/go/wiki/Modules) support. So make sure to initialize a Go | ||||||
|  | module: | ||||||
|  |  | ||||||
|  | ```shell | ||||||
|  | go mod init github.com/my/repo | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | And then install go-redis/v8 (note _v8_ in the import; omitting it is a popular mistake): | ||||||
|  |  | ||||||
|  | ```shell | ||||||
|  | go get github.com/go-redis/redis/v8 | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Quickstart | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | import ( | ||||||
|  |     "context" | ||||||
|  |     "github.com/go-redis/redis/v8" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ctx = context.Background() | ||||||
|  |  | ||||||
|  | func ExampleClient() { | ||||||
|  |     rdb := redis.NewClient(&redis.Options{ | ||||||
|  |         Addr:     "localhost:6379", | ||||||
|  |         Password: "", // no password set | ||||||
|  |         DB:       0,  // use default DB | ||||||
|  |     }) | ||||||
|  |  | ||||||
|  |     err := rdb.Set(ctx, "key", "value", 0).Err() | ||||||
|  |     if err != nil { | ||||||
|  |         panic(err) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     val, err := rdb.Get(ctx, "key").Result() | ||||||
|  |     if err != nil { | ||||||
|  |         panic(err) | ||||||
|  |     } | ||||||
|  |     fmt.Println("key", val) | ||||||
|  |  | ||||||
|  |     val2, err := rdb.Get(ctx, "key2").Result() | ||||||
|  |     if err == redis.Nil { | ||||||
|  |         fmt.Println("key2 does not exist") | ||||||
|  |     } else if err != nil { | ||||||
|  |         panic(err) | ||||||
|  |     } else { | ||||||
|  |         fmt.Println("key2", val2) | ||||||
|  |     } | ||||||
|  |     // Output: key value | ||||||
|  |     // key2 does not exist | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Look and feel | ||||||
|  |  | ||||||
|  | Some corner cases: | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | // SET key value EX 10 NX | ||||||
|  | set, err := rdb.SetNX(ctx, "key", "value", 10*time.Second).Result() | ||||||
|  |  | ||||||
|  | // SET key value keepttl NX | ||||||
|  | set, err := rdb.SetNX(ctx, "key", "value", redis.KeepTTL).Result() | ||||||
|  |  | ||||||
|  | // SORT list LIMIT 0 2 ASC | ||||||
|  | vals, err := rdb.Sort(ctx, "list", &redis.Sort{Offset: 0, Count: 2, Order: "ASC"}).Result() | ||||||
|  |  | ||||||
|  | // ZRANGEBYSCORE zset -inf +inf WITHSCORES LIMIT 0 2 | ||||||
|  | vals, err := rdb.ZRangeByScoreWithScores(ctx, "zset", &redis.ZRangeBy{ | ||||||
|  |     Min: "-inf", | ||||||
|  |     Max: "+inf", | ||||||
|  |     Offset: 0, | ||||||
|  |     Count: 2, | ||||||
|  | }).Result() | ||||||
|  |  | ||||||
|  | // ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3 AGGREGATE SUM | ||||||
|  | vals, err := rdb.ZInterStore(ctx, "out", &redis.ZStore{ | ||||||
|  |     Keys: []string{"zset1", "zset2"}, | ||||||
|  |     Weights: []int64{2, 3} | ||||||
|  | }).Result() | ||||||
|  |  | ||||||
|  | // EVAL "return {KEYS[1],ARGV[1]}" 1 "key" "hello" | ||||||
|  | vals, err := rdb.Eval(ctx, "return {KEYS[1],ARGV[1]}", []string{"key"}, "hello").Result() | ||||||
|  |  | ||||||
|  | // custom command | ||||||
|  | res, err := rdb.Do(ctx, "set", "key", "value").Result() | ||||||
|  | ``` | ||||||
|  | ## Run the test | ||||||
|  | go-redis will start a redis-server and run the test cases.  | ||||||
|  |  | ||||||
|  | The paths of redis-server bin file and redis config file are definded in `main_test.go`: | ||||||
|  | ``` | ||||||
|  | var ( | ||||||
|  | 	redisServerBin, _  = filepath.Abs(filepath.Join("testdata", "redis", "src", "redis-server")) | ||||||
|  | 	redisServerConf, _ = filepath.Abs(filepath.Join("testdata", "redis", "redis.conf")) | ||||||
|  | ) | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | For local testing, you can change the variables to refer to your local files, or create a soft link to the corresponding folder for redis-server and copy the config file to `testdata/redis/`: | ||||||
|  | ``` | ||||||
|  | ln -s /usr/bin/redis-server ./go-redis/testdata/redis/src | ||||||
|  | cp ./go-redis/testdata/redis.conf ./go-redis/testdata/redis/ | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Lastly, run: | ||||||
|  | ``` | ||||||
|  | go test | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## See also | ||||||
|  |  | ||||||
|  | - [Fast and flexible HTTP router](https://github.com/vmihailenco/treemux) | ||||||
|  | - [Golang PostgreSQL ORM](https://github.com/go-pg/pg) | ||||||
|  | - [Golang msgpack](https://github.com/vmihailenco/msgpack) | ||||||
|  | - [Golang message task queue](https://github.com/vmihailenco/taskq) | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										25
									
								
								vendor/github.com/go-redis/redis/v8/cluster_commands.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/go-redis/redis/v8/cluster_commands.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | package redis | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"sync/atomic" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func (c *ClusterClient) DBSize(ctx context.Context) *IntCmd { | ||||||
|  | 	cmd := NewIntCmd(ctx, "dbsize") | ||||||
|  | 	var size int64 | ||||||
|  | 	err := c.ForEachMaster(ctx, func(ctx context.Context, master *Client) error { | ||||||
|  | 		n, err := master.DBSize(ctx).Result() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		atomic.AddInt64(&size, n) | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
|  | 	if err != nil { | ||||||
|  | 		cmd.SetErr(err) | ||||||
|  | 		return cmd | ||||||
|  | 	} | ||||||
|  | 	cmd.val = size | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2790
									
								
								vendor/github.com/go-redis/redis/v8/commands.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2790
									
								
								vendor/github.com/go-redis/redis/v8/commands.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -6,8 +6,8 @@ import ( | |||||||
| 	"net" | 	"net" | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal/pool" | 	"github.com/go-redis/redis/v8/internal/pool" | ||||||
| 	"github.com/go-redis/redis/v7/internal/proto" | 	"github.com/go-redis/redis/v8/internal/proto" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var ErrClosed = pool.ErrClosed | var ErrClosed = pool.ErrClosed | ||||||
| @@ -24,15 +24,16 @@ type Error interface { | |||||||
| 
 | 
 | ||||||
| var _ Error = proto.RedisError("") | var _ Error = proto.RedisError("") | ||||||
| 
 | 
 | ||||||
| func isRetryableError(err error, retryTimeout bool) bool { | func shouldRetry(err error, retryTimeout bool) bool { | ||||||
| 	switch err { | 	switch err { | ||||||
|  | 	case io.EOF, io.ErrUnexpectedEOF: | ||||||
|  | 		return true | ||||||
| 	case nil, context.Canceled, context.DeadlineExceeded: | 	case nil, context.Canceled, context.DeadlineExceeded: | ||||||
| 		return false | 		return false | ||||||
| 	case io.EOF: |  | ||||||
| 		return true |  | ||||||
| 	} | 	} | ||||||
| 	if netErr, ok := err.(net.Error); ok { | 
 | ||||||
| 		if netErr.Timeout() { | 	if v, ok := err.(timeoutError); ok { | ||||||
|  | 		if v.Timeout() { | ||||||
| 			return retryTimeout | 			return retryTimeout | ||||||
| 		} | 		} | ||||||
| 		return true | 		return true | ||||||
| @@ -51,6 +52,10 @@ func isRetryableError(err error, retryTimeout bool) bool { | |||||||
| 	if strings.HasPrefix(s, "CLUSTERDOWN ") { | 	if strings.HasPrefix(s, "CLUSTERDOWN ") { | ||||||
| 		return true | 		return true | ||||||
| 	} | 	} | ||||||
|  | 	if strings.HasPrefix(s, "TRYAGAIN ") { | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return false | 	return false | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -60,19 +65,25 @@ func isRedisError(err error) bool { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func isBadConn(err error, allowTimeout bool) bool { | func isBadConn(err error, allowTimeout bool) bool { | ||||||
| 	if err == nil { | 	switch err { | ||||||
|  | 	case nil: | ||||||
| 		return false | 		return false | ||||||
|  | 	case context.Canceled, context.DeadlineExceeded: | ||||||
|  | 		return true | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	if isRedisError(err) { | 	if isRedisError(err) { | ||||||
| 		// Close connections in read only state in case domain addr is used | 		// Close connections in read only state in case domain addr is used | ||||||
| 		// and domain resolves to a different Redis Server. See #790. | 		// and domain resolves to a different Redis Server. See #790. | ||||||
| 		return isReadOnlyError(err) | 		return isReadOnlyError(err) | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	if allowTimeout { | 	if allowTimeout { | ||||||
| 		if netErr, ok := err.(net.Error); ok && netErr.Timeout() { | 		if netErr, ok := err.(net.Error); ok && netErr.Timeout() { | ||||||
| 			return false | 			return !netErr.Temporary() | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	return true | 	return true | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -106,3 +117,9 @@ func isLoadingError(err error) bool { | |||||||
| func isReadOnlyError(err error) bool { | func isReadOnlyError(err error) bool { | ||||||
| 	return strings.HasPrefix(err.Error(), "READONLY ") | 	return strings.HasPrefix(err.Error(), "READONLY ") | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | 
 | ||||||
|  | type timeoutError interface { | ||||||
|  | 	Timeout() bool | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								vendor/github.com/go-redis/redis/v8/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/go-redis/redis/v8/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | module github.com/go-redis/redis/v8 | ||||||
|  |  | ||||||
|  | go 1.13 | ||||||
|  |  | ||||||
|  | require ( | ||||||
|  | 	github.com/cespare/xxhash/v2 v2.1.1 | ||||||
|  | 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f | ||||||
|  | 	github.com/onsi/ginkgo v1.15.0 | ||||||
|  | 	github.com/onsi/gomega v1.10.5 | ||||||
|  | 	go.opentelemetry.io/otel v0.16.0 | ||||||
|  | ) | ||||||
							
								
								
									
										97
									
								
								vendor/github.com/go-redis/redis/v8/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								vendor/github.com/go-redis/redis/v8/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | |||||||
|  | github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= | ||||||
|  | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= | ||||||
|  | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||||||
|  | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
|  | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= | ||||||
|  | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= | ||||||
|  | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | ||||||
|  | github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= | ||||||
|  | github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= | ||||||
|  | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||||
|  | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= | ||||||
|  | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= | ||||||
|  | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= | ||||||
|  | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= | ||||||
|  | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= | ||||||
|  | github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= | ||||||
|  | github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= | ||||||
|  | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||||
|  | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||||
|  | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||||
|  | github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= | ||||||
|  | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||||
|  | github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | ||||||
|  | github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= | ||||||
|  | github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= | ||||||
|  | github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | ||||||
|  | github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= | ||||||
|  | github.com/onsi/ginkgo v1.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= | ||||||
|  | github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= | ||||||
|  | github.com/onsi/ginkgo v1.15.0/go.mod h1:hF8qUzuuC8DJGygJH3726JnCZX4MYbRB8yFfISqnKUg= | ||||||
|  | github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= | ||||||
|  | github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= | ||||||
|  | github.com/onsi/gomega v1.10.4 h1:NiTx7EEvBzu9sFOD1zORteLSt3o8gnlvZZwSE9TnY9U= | ||||||
|  | github.com/onsi/gomega v1.10.4/go.mod h1:g/HbgYopi++010VEqkFgJHKC09uJiW9UkXvMUuKHUCQ= | ||||||
|  | github.com/onsi/gomega v1.10.5/go.mod h1:gza4q3jKQJijlu05nKWRCW/GavJumGt8aNRxWg7mt48= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
|  | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
|  | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= | ||||||
|  | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||||
|  | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||||
|  | go.opentelemetry.io/otel v0.16.0 h1:uIWEbdeb4vpKPGITLsRVUS44L5oDbDUCZxn8lkxhmgw= | ||||||
|  | go.opentelemetry.io/otel v0.16.0/go.mod h1:e4GKElweB8W2gWUqbghw0B8t5MCTccc9212eNHnOHwA= | ||||||
|  | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||||
|  | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||||
|  | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||||
|  | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||||
|  | golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||||
|  | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||||
|  | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
|  | golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | ||||||
|  | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||||||
|  | golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb h1:eBmm0M9fYhWpKZLjQUUKka/LtIxf46G4fxeEz5KJr9U= | ||||||
|  | golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||||||
|  | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
|  | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
|  | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
|  | golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||||
|  | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= | ||||||
|  | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
|  | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | ||||||
|  | golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | ||||||
|  | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||||
|  | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
|  | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||||
|  | golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | ||||||
|  | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
|  | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
|  | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | ||||||
|  | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
|  | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
|  | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= | ||||||
|  | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= | ||||||
|  | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= | ||||||
|  | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= | ||||||
|  | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= | ||||||
|  | google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM= | ||||||
|  | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | ||||||
|  | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||||
|  | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
|  | gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | ||||||
|  | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= | ||||||
|  | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | ||||||
|  | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
|  | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | ||||||
|  | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
|  | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | ||||||
|  | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
							
								
								
									
										56
									
								
								vendor/github.com/go-redis/redis/v8/internal/arg.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/go-redis/redis/v8/internal/arg.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | package internal | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  | 	"time" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func AppendArg(b []byte, v interface{}) []byte { | ||||||
|  | 	switch v := v.(type) { | ||||||
|  | 	case nil: | ||||||
|  | 		return append(b, "<nil>"...) | ||||||
|  | 	case string: | ||||||
|  | 		return appendUTF8String(b, Bytes(v)) | ||||||
|  | 	case []byte: | ||||||
|  | 		return appendUTF8String(b, v) | ||||||
|  | 	case int: | ||||||
|  | 		return strconv.AppendInt(b, int64(v), 10) | ||||||
|  | 	case int8: | ||||||
|  | 		return strconv.AppendInt(b, int64(v), 10) | ||||||
|  | 	case int16: | ||||||
|  | 		return strconv.AppendInt(b, int64(v), 10) | ||||||
|  | 	case int32: | ||||||
|  | 		return strconv.AppendInt(b, int64(v), 10) | ||||||
|  | 	case int64: | ||||||
|  | 		return strconv.AppendInt(b, v, 10) | ||||||
|  | 	case uint: | ||||||
|  | 		return strconv.AppendUint(b, uint64(v), 10) | ||||||
|  | 	case uint8: | ||||||
|  | 		return strconv.AppendUint(b, uint64(v), 10) | ||||||
|  | 	case uint16: | ||||||
|  | 		return strconv.AppendUint(b, uint64(v), 10) | ||||||
|  | 	case uint32: | ||||||
|  | 		return strconv.AppendUint(b, uint64(v), 10) | ||||||
|  | 	case uint64: | ||||||
|  | 		return strconv.AppendUint(b, v, 10) | ||||||
|  | 	case float32: | ||||||
|  | 		return strconv.AppendFloat(b, float64(v), 'f', -1, 64) | ||||||
|  | 	case float64: | ||||||
|  | 		return strconv.AppendFloat(b, v, 'f', -1, 64) | ||||||
|  | 	case bool: | ||||||
|  | 		if v { | ||||||
|  | 			return append(b, "true"...) | ||||||
|  | 		} | ||||||
|  | 		return append(b, "false"...) | ||||||
|  | 	case time.Time: | ||||||
|  | 		return v.AppendFormat(b, time.RFC3339Nano) | ||||||
|  | 	default: | ||||||
|  | 		return append(b, fmt.Sprint(v)...) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func appendUTF8String(dst []byte, src []byte) []byte { | ||||||
|  | 	dst = append(dst, src...) | ||||||
|  | 	return dst | ||||||
|  | } | ||||||
| @@ -1,8 +1,9 @@ | |||||||
| package hashtag | package hashtag | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"math/rand" |  | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/rand" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const slotNumber = 16384 | const slotNumber = 16384 | ||||||
							
								
								
									
										151
									
								
								vendor/github.com/go-redis/redis/v8/internal/hscan/hscan.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								vendor/github.com/go-redis/redis/v8/internal/hscan/hscan.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,151 @@ | |||||||
|  | package hscan | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"reflect" | ||||||
|  | 	"strconv" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // decoderFunc represents decoding functions for default built-in types. | ||||||
|  | type decoderFunc func(reflect.Value, string) error | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// List of built-in decoders indexed by their numeric constant values (eg: reflect.Bool = 1). | ||||||
|  | 	decoders = []decoderFunc{ | ||||||
|  | 		reflect.Bool:          decodeBool, | ||||||
|  | 		reflect.Int:           decodeInt, | ||||||
|  | 		reflect.Int8:          decodeInt, | ||||||
|  | 		reflect.Int16:         decodeInt, | ||||||
|  | 		reflect.Int32:         decodeInt, | ||||||
|  | 		reflect.Int64:         decodeInt, | ||||||
|  | 		reflect.Uint:          decodeUint, | ||||||
|  | 		reflect.Uint8:         decodeUint, | ||||||
|  | 		reflect.Uint16:        decodeUint, | ||||||
|  | 		reflect.Uint32:        decodeUint, | ||||||
|  | 		reflect.Uint64:        decodeUint, | ||||||
|  | 		reflect.Float32:       decodeFloat, | ||||||
|  | 		reflect.Float64:       decodeFloat, | ||||||
|  | 		reflect.Complex64:     decodeUnsupported, | ||||||
|  | 		reflect.Complex128:    decodeUnsupported, | ||||||
|  | 		reflect.Array:         decodeUnsupported, | ||||||
|  | 		reflect.Chan:          decodeUnsupported, | ||||||
|  | 		reflect.Func:          decodeUnsupported, | ||||||
|  | 		reflect.Interface:     decodeUnsupported, | ||||||
|  | 		reflect.Map:           decodeUnsupported, | ||||||
|  | 		reflect.Ptr:           decodeUnsupported, | ||||||
|  | 		reflect.Slice:         decodeSlice, | ||||||
|  | 		reflect.String:        decodeString, | ||||||
|  | 		reflect.Struct:        decodeUnsupported, | ||||||
|  | 		reflect.UnsafePointer: decodeUnsupported, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Global map of struct field specs that is populated once for every new | ||||||
|  | 	// struct type that is scanned. This caches the field types and the corresponding | ||||||
|  | 	// decoder functions to avoid iterating through struct fields on subsequent scans. | ||||||
|  | 	globalStructMap = newStructMap() | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func Struct(dst interface{}) (StructValue, error) { | ||||||
|  | 	v := reflect.ValueOf(dst) | ||||||
|  |  | ||||||
|  | 	// The dstination to scan into should be a struct pointer. | ||||||
|  | 	if v.Kind() != reflect.Ptr || v.IsNil() { | ||||||
|  | 		return StructValue{}, fmt.Errorf("redis.Scan(non-pointer %T)", dst) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	v = v.Elem() | ||||||
|  | 	if v.Kind() != reflect.Struct { | ||||||
|  | 		return StructValue{}, fmt.Errorf("redis.Scan(non-struct %T)", dst) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return StructValue{ | ||||||
|  | 		spec:  globalStructMap.get(v.Type()), | ||||||
|  | 		value: v, | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Scan scans the results from a key-value Redis map result set to a destination struct. | ||||||
|  | // The Redis keys are matched to the struct's field with the `redis` tag. | ||||||
|  | func Scan(dst interface{}, keys []interface{}, vals []interface{}) error { | ||||||
|  | 	if len(keys) != len(vals) { | ||||||
|  | 		return errors.New("args should have the same number of keys and vals") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	strct, err := Struct(dst) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Iterate through the (key, value) sequence. | ||||||
|  | 	for i := 0; i < len(vals); i++ { | ||||||
|  | 		key, ok := keys[i].(string) | ||||||
|  | 		if !ok { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		val, ok := vals[i].(string) | ||||||
|  | 		if !ok { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if err := strct.Scan(key, val); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func decodeBool(f reflect.Value, s string) error { | ||||||
|  | 	b, err := strconv.ParseBool(s) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	f.SetBool(b) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func decodeInt(f reflect.Value, s string) error { | ||||||
|  | 	v, err := strconv.ParseInt(s, 10, 0) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	f.SetInt(v) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func decodeUint(f reflect.Value, s string) error { | ||||||
|  | 	v, err := strconv.ParseUint(s, 10, 0) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	f.SetUint(v) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func decodeFloat(f reflect.Value, s string) error { | ||||||
|  | 	v, err := strconv.ParseFloat(s, 0) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	f.SetFloat(v) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func decodeString(f reflect.Value, s string) error { | ||||||
|  | 	f.SetString(s) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func decodeSlice(f reflect.Value, s string) error { | ||||||
|  | 	// []byte slice ([]uint8). | ||||||
|  | 	if f.Type().Elem().Kind() == reflect.Uint8 { | ||||||
|  | 		f.SetBytes([]byte(s)) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func decodeUnsupported(v reflect.Value, s string) error { | ||||||
|  | 	return fmt.Errorf("redis.Scan(unsupported %s)", v.Type()) | ||||||
|  | } | ||||||
							
								
								
									
										87
									
								
								vendor/github.com/go-redis/redis/v8/internal/hscan/structmap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								vendor/github.com/go-redis/redis/v8/internal/hscan/structmap.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | |||||||
|  | package hscan | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"reflect" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // structMap contains the map of struct fields for target structs | ||||||
|  | // indexed by the struct type. | ||||||
|  | type structMap struct { | ||||||
|  | 	m sync.Map | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newStructMap() *structMap { | ||||||
|  | 	return new(structMap) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *structMap) get(t reflect.Type) *structSpec { | ||||||
|  | 	if v, ok := s.m.Load(t); ok { | ||||||
|  | 		return v.(*structSpec) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	spec := newStructSpec(t, "redis") | ||||||
|  | 	s.m.Store(t, spec) | ||||||
|  | 	return spec | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | // structSpec contains the list of all fields in a target struct. | ||||||
|  | type structSpec struct { | ||||||
|  | 	m map[string]*structField | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *structSpec) set(tag string, sf *structField) { | ||||||
|  | 	s.m[tag] = sf | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newStructSpec(t reflect.Type, fieldTag string) *structSpec { | ||||||
|  | 	out := &structSpec{ | ||||||
|  | 		m: make(map[string]*structField), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	num := t.NumField() | ||||||
|  | 	for i := 0; i < num; i++ { | ||||||
|  | 		f := t.Field(i) | ||||||
|  |  | ||||||
|  | 		tag := f.Tag.Get(fieldTag) | ||||||
|  | 		if tag == "" || tag == "-" { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		tag = strings.Split(tag, ",")[0] | ||||||
|  | 		if tag == "" { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Use the built-in decoder. | ||||||
|  | 		out.set(tag, &structField{index: i, fn: decoders[f.Type.Kind()]}) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return out | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | // structField represents a single field in a target struct. | ||||||
|  | type structField struct { | ||||||
|  | 	index int | ||||||
|  | 	fn    decoderFunc | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | type StructValue struct { | ||||||
|  | 	spec  *structSpec | ||||||
|  | 	value reflect.Value | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s StructValue) Scan(key string, value string) error { | ||||||
|  | 	field, ok := s.spec.m[key] | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	return field.fn(s.value.Field(field.index), value) | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								vendor/github.com/go-redis/redis/v8/internal/instruments.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/go-redis/redis/v8/internal/instruments.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | package internal | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  |  | ||||||
|  | 	"go.opentelemetry.io/otel" | ||||||
|  | 	"go.opentelemetry.io/otel/metric" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// WritesCounter is a count of write commands performed. | ||||||
|  | 	WritesCounter metric.Int64Counter | ||||||
|  | 	// NewConnectionsCounter is a count of new connections. | ||||||
|  | 	NewConnectionsCounter metric.Int64Counter | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	defer func() { | ||||||
|  | 		if r := recover(); r != nil { | ||||||
|  | 			Logger.Printf(context.Background(), "Error creating meter github.com/go-redis/redis for Instruments", r) | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	meter := metric.Must(otel.Meter("github.com/go-redis/redis")) | ||||||
|  |  | ||||||
|  | 	WritesCounter = meter.NewInt64Counter("redis.writes", | ||||||
|  | 		metric.WithDescription("the number of writes initiated"), | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | 	NewConnectionsCounter = meter.NewInt64Counter("redis.new_connections", | ||||||
|  | 		metric.WithDescription("the number of connections created"), | ||||||
|  | 	) | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								vendor/github.com/go-redis/redis/v8/internal/internal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/go-redis/redis/v8/internal/internal.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | package internal | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/rand" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func RetryBackoff(retry int, minBackoff, maxBackoff time.Duration) time.Duration { | ||||||
|  | 	if retry < 0 { | ||||||
|  | 		panic("not reached") | ||||||
|  | 	} | ||||||
|  | 	if minBackoff == 0 { | ||||||
|  | 		return 0 | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	d := minBackoff << uint(retry) | ||||||
|  | 	if d < minBackoff { | ||||||
|  | 		return maxBackoff | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	d = minBackoff + time.Duration(rand.Int63n(int64(d))) | ||||||
|  |  | ||||||
|  | 	if d > maxBackoff || d < minBackoff { | ||||||
|  | 		d = maxBackoff | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return d | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								vendor/github.com/go-redis/redis/v8/internal/log.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/go-redis/redis/v8/internal/log.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | package internal | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Logging interface { | ||||||
|  | 	Printf(ctx context.Context, format string, v ...interface{}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type logger struct { | ||||||
|  | 	log *log.Logger | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *logger) Printf(ctx context.Context, format string, v ...interface{}) { | ||||||
|  | 	_ = l.log.Output(2, fmt.Sprintf(format, v...)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var Logger Logging = &logger{ | ||||||
|  | 	log: log.New(os.Stderr, "redis: ", log.LstdFlags|log.Lshortfile), | ||||||
|  | } | ||||||
| @@ -1,26 +1,30 @@ | |||||||
| package pool | package pool | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"bufio" | ||||||
| 	"context" | 	"context" | ||||||
| 	"net" | 	"net" | ||||||
| 	"sync/atomic" | 	"sync/atomic" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal/proto" | 	"github.com/go-redis/redis/v8/internal" | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/proto" | ||||||
|  | 	"go.opentelemetry.io/otel/trace" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var noDeadline = time.Time{} | var noDeadline = time.Time{} | ||||||
| 
 | 
 | ||||||
| type Conn struct { | type Conn struct { | ||||||
|  | 	usedAt  int64 // atomic | ||||||
| 	netConn net.Conn | 	netConn net.Conn | ||||||
| 
 | 
 | ||||||
| 	rd *proto.Reader | 	rd *proto.Reader | ||||||
|  | 	bw *bufio.Writer | ||||||
| 	wr *proto.Writer | 	wr *proto.Writer | ||||||
| 
 | 
 | ||||||
| 	Inited    bool | 	Inited    bool | ||||||
| 	pooled    bool | 	pooled    bool | ||||||
| 	createdAt time.Time | 	createdAt time.Time | ||||||
| 	usedAt    int64 // atomic |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewConn(netConn net.Conn) *Conn { | func NewConn(netConn net.Conn) *Conn { | ||||||
| @@ -29,7 +33,8 @@ func NewConn(netConn net.Conn) *Conn { | |||||||
| 		createdAt: time.Now(), | 		createdAt: time.Now(), | ||||||
| 	} | 	} | ||||||
| 	cn.rd = proto.NewReader(netConn) | 	cn.rd = proto.NewReader(netConn) | ||||||
| 	cn.wr = proto.NewWriter(netConn) | 	cn.bw = bufio.NewWriter(netConn) | ||||||
|  | 	cn.wr = proto.NewWriter(cn.bw) | ||||||
| 	cn.SetUsedAt(time.Now()) | 	cn.SetUsedAt(time.Now()) | ||||||
| 	return cn | 	return cn | ||||||
| } | } | ||||||
| @@ -46,7 +51,7 @@ func (cn *Conn) SetUsedAt(tm time.Time) { | |||||||
| func (cn *Conn) SetNetConn(netConn net.Conn) { | func (cn *Conn) SetNetConn(netConn net.Conn) { | ||||||
| 	cn.netConn = netConn | 	cn.netConn = netConn | ||||||
| 	cn.rd.Reset(netConn) | 	cn.rd.Reset(netConn) | ||||||
| 	cn.wr.Reset(netConn) | 	cn.bw.Reset(netConn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (cn *Conn) Write(b []byte) (int, error) { | func (cn *Conn) Write(b []byte) (int, error) { | ||||||
| @@ -54,35 +59,48 @@ func (cn *Conn) Write(b []byte) (int, error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (cn *Conn) RemoteAddr() net.Addr { | func (cn *Conn) RemoteAddr() net.Addr { | ||||||
| 	return cn.netConn.RemoteAddr() | 	if cn.netConn != nil { | ||||||
|  | 		return cn.netConn.RemoteAddr() | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (cn *Conn) WithReader(ctx context.Context, timeout time.Duration, fn func(rd *proto.Reader) error) error { | func (cn *Conn) WithReader(ctx context.Context, timeout time.Duration, fn func(rd *proto.Reader) error) error { | ||||||
| 	err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)) | 	return internal.WithSpan(ctx, "redis.with_reader", func(ctx context.Context, span trace.Span) error { | ||||||
| 	if err != nil { | 		if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil { | ||||||
| 		return err | 			return internal.RecordError(ctx, span, err) | ||||||
| 	} | 		} | ||||||
| 	return fn(cn.rd) | 		if err := fn(cn.rd); err != nil { | ||||||
|  | 			return internal.RecordError(ctx, span, err) | ||||||
|  | 		} | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (cn *Conn) WithWriter( | func (cn *Conn) WithWriter( | ||||||
| 	ctx context.Context, timeout time.Duration, fn func(wr *proto.Writer) error, | 	ctx context.Context, timeout time.Duration, fn func(wr *proto.Writer) error, | ||||||
| ) error { | ) error { | ||||||
| 	err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)) | 	return internal.WithSpan(ctx, "redis.with_writer", func(ctx context.Context, span trace.Span) error { | ||||||
| 	if err != nil { | 		if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil { | ||||||
| 		return err | 			return internal.RecordError(ctx, span, err) | ||||||
| 	} | 		} | ||||||
| 
 | 
 | ||||||
| 	if cn.wr.Buffered() > 0 { | 		if cn.bw.Buffered() > 0 { | ||||||
| 		cn.wr.Reset(cn.netConn) | 			cn.bw.Reset(cn.netConn) | ||||||
| 	} | 		} | ||||||
| 
 | 
 | ||||||
| 	err = fn(cn.wr) | 		if err := fn(cn.wr); err != nil { | ||||||
| 	if err != nil { | 			return internal.RecordError(ctx, span, err) | ||||||
| 		return err | 		} | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	return cn.wr.Flush() | 		if err := cn.bw.Flush(); err != nil { | ||||||
|  | 			return internal.RecordError(ctx, span, err) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		internal.WritesCounter.Add(ctx, 1) | ||||||
|  | 
 | ||||||
|  | 		return nil | ||||||
|  | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (cn *Conn) Close() error { | func (cn *Conn) Close() error { | ||||||
| @@ -8,11 +8,13 @@ import ( | |||||||
| 	"sync/atomic" | 	"sync/atomic" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal" | 	"github.com/go-redis/redis/v8/internal" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var ErrClosed = errors.New("redis: client is closed") | var ( | ||||||
| var ErrPoolTimeout = errors.New("redis: connection pool timeout") | 	ErrClosed      = errors.New("redis: client is closed") | ||||||
|  | 	ErrPoolTimeout = errors.New("redis: connection pool timeout") | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| var timers = sync.Pool{ | var timers = sync.Pool{ | ||||||
| 	New: func() interface{} { | 	New: func() interface{} { | ||||||
| @@ -38,8 +40,8 @@ type Pooler interface { | |||||||
| 	CloseConn(*Conn) error | 	CloseConn(*Conn) error | ||||||
| 
 | 
 | ||||||
| 	Get(context.Context) (*Conn, error) | 	Get(context.Context) (*Conn, error) | ||||||
| 	Put(*Conn) | 	Put(context.Context, *Conn) | ||||||
| 	Remove(*Conn, error) | 	Remove(context.Context, *Conn, error) | ||||||
| 
 | 
 | ||||||
| 	Len() int | 	Len() int | ||||||
| 	IdleLen() int | 	IdleLen() int | ||||||
| @@ -60,13 +62,16 @@ type Options struct { | |||||||
| 	IdleCheckFrequency time.Duration | 	IdleCheckFrequency time.Duration | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type lastDialErrorWrap struct { | ||||||
|  | 	err error | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type ConnPool struct { | type ConnPool struct { | ||||||
| 	opt *Options | 	opt *Options | ||||||
| 
 | 
 | ||||||
| 	dialErrorsNum uint32 // atomic | 	dialErrorsNum uint32 // atomic | ||||||
| 
 | 
 | ||||||
| 	lastDialErrorMu sync.RWMutex | 	lastDialError atomic.Value | ||||||
| 	lastDialError   error |  | ||||||
| 
 | 
 | ||||||
| 	queue chan struct{} | 	queue chan struct{} | ||||||
| 
 | 
 | ||||||
| @@ -158,6 +163,7 @@ func (p *ConnPool) newConn(ctx context.Context, pooled bool) (*Conn, error) { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	p.connsMu.Unlock() | 	p.connsMu.Unlock() | ||||||
|  | 
 | ||||||
| 	return cn, nil | 	return cn, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -179,6 +185,7 @@ func (p *ConnPool) dialConn(ctx context.Context, pooled bool) (*Conn, error) { | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	internal.NewConnectionsCounter.Add(ctx, 1) | ||||||
| 	cn := NewConn(netConn) | 	cn := NewConn(netConn) | ||||||
| 	cn.pooled = pooled | 	cn.pooled = pooled | ||||||
| 	return cn, nil | 	return cn, nil | ||||||
| @@ -204,16 +211,15 @@ func (p *ConnPool) tryDial() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *ConnPool) setLastDialError(err error) { | func (p *ConnPool) setLastDialError(err error) { | ||||||
| 	p.lastDialErrorMu.Lock() | 	p.lastDialError.Store(&lastDialErrorWrap{err: err}) | ||||||
| 	p.lastDialError = err |  | ||||||
| 	p.lastDialErrorMu.Unlock() |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *ConnPool) getLastDialError() error { | func (p *ConnPool) getLastDialError() error { | ||||||
| 	p.lastDialErrorMu.RLock() | 	err, _ := p.lastDialError.Load().(*lastDialErrorWrap) | ||||||
| 	err := p.lastDialError | 	if err != nil { | ||||||
| 	p.lastDialErrorMu.RUnlock() | 		return err.err | ||||||
| 	return err | 	} | ||||||
|  | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Get returns existed connection from the pool or creates a new one. | // Get returns existed connection from the pool or creates a new one. | ||||||
| @@ -313,15 +319,15 @@ func (p *ConnPool) popIdle() *Conn { | |||||||
| 	return cn | 	return cn | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *ConnPool) Put(cn *Conn) { | func (p *ConnPool) Put(ctx context.Context, cn *Conn) { | ||||||
| 	if cn.rd.Buffered() > 0 { | 	if cn.rd.Buffered() > 0 { | ||||||
| 		internal.Logger.Printf("Conn has unread data") | 		internal.Logger.Printf(ctx, "Conn has unread data") | ||||||
| 		p.Remove(cn, BadConnError{}) | 		p.Remove(ctx, cn, BadConnError{}) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !cn.pooled { | 	if !cn.pooled { | ||||||
| 		p.Remove(cn, nil) | 		p.Remove(ctx, cn, nil) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -332,7 +338,7 @@ func (p *ConnPool) Put(cn *Conn) { | |||||||
| 	p.freeTurn() | 	p.freeTurn() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *ConnPool) Remove(cn *Conn, reason error) { | func (p *ConnPool) Remove(ctx context.Context, cn *Conn, reason error) { | ||||||
| 	p.removeConnWithLock(cn) | 	p.removeConnWithLock(cn) | ||||||
| 	p.freeTurn() | 	p.freeTurn() | ||||||
| 	_ = p.closeConn(cn) | 	_ = p.closeConn(cn) | ||||||
| @@ -403,8 +409,10 @@ func (p *ConnPool) closed() bool { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *ConnPool) Filter(fn func(*Conn) bool) error { | func (p *ConnPool) Filter(fn func(*Conn) bool) error { | ||||||
| 	var firstErr error |  | ||||||
| 	p.connsMu.Lock() | 	p.connsMu.Lock() | ||||||
|  | 	defer p.connsMu.Unlock() | ||||||
|  | 
 | ||||||
|  | 	var firstErr error | ||||||
| 	for _, cn := range p.conns { | 	for _, cn := range p.conns { | ||||||
| 		if fn(cn) { | 		if fn(cn) { | ||||||
| 			if err := p.closeConn(cn); err != nil && firstErr == nil { | 			if err := p.closeConn(cn); err != nil && firstErr == nil { | ||||||
| @@ -412,7 +420,6 @@ func (p *ConnPool) Filter(fn func(*Conn) bool) error { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	p.connsMu.Unlock() |  | ||||||
| 	return firstErr | 	return firstErr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -453,7 +460,7 @@ func (p *ConnPool) reaper(frequency time.Duration) { | |||||||
| 			} | 			} | ||||||
| 			_, err := p.ReapStaleConns() | 			_, err := p.ReapStaleConns() | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				internal.Logger.Printf("ReapStaleConns failed: %s", err) | 				internal.Logger.Printf(context.Background(), "ReapStaleConns failed: %s", err) | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
| 		case <-p.closedCh: | 		case <-p.closedCh: | ||||||
| @@ -470,6 +477,7 @@ func (p *ConnPool) ReapStaleConns() (int, error) { | |||||||
| 		p.connsMu.Lock() | 		p.connsMu.Lock() | ||||||
| 		cn := p.reapStaleConn() | 		cn := p.reapStaleConn() | ||||||
| 		p.connsMu.Unlock() | 		p.connsMu.Unlock() | ||||||
|  | 
 | ||||||
| 		p.freeTurn() | 		p.freeTurn() | ||||||
| 
 | 
 | ||||||
| 		if cn != nil { | 		if cn != nil { | ||||||
							
								
								
									
										58
									
								
								vendor/github.com/go-redis/redis/v8/internal/pool/pool_single.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								vendor/github.com/go-redis/redis/v8/internal/pool/pool_single.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | package pool | ||||||
|  |  | ||||||
|  | import "context" | ||||||
|  |  | ||||||
|  | type SingleConnPool struct { | ||||||
|  | 	pool      Pooler | ||||||
|  | 	cn        *Conn | ||||||
|  | 	stickyErr error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var _ Pooler = (*SingleConnPool)(nil) | ||||||
|  |  | ||||||
|  | func NewSingleConnPool(pool Pooler, cn *Conn) *SingleConnPool { | ||||||
|  | 	return &SingleConnPool{ | ||||||
|  | 		pool: pool, | ||||||
|  | 		cn:   cn, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *SingleConnPool) NewConn(ctx context.Context) (*Conn, error) { | ||||||
|  | 	return p.pool.NewConn(ctx) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *SingleConnPool) CloseConn(cn *Conn) error { | ||||||
|  | 	return p.pool.CloseConn(cn) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *SingleConnPool) Get(ctx context.Context) (*Conn, error) { | ||||||
|  | 	if p.stickyErr != nil { | ||||||
|  | 		return nil, p.stickyErr | ||||||
|  | 	} | ||||||
|  | 	return p.cn, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *SingleConnPool) Put(ctx context.Context, cn *Conn) {} | ||||||
|  |  | ||||||
|  | func (p *SingleConnPool) Remove(ctx context.Context, cn *Conn, reason error) { | ||||||
|  | 	p.cn = nil | ||||||
|  | 	p.stickyErr = reason | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *SingleConnPool) Close() error { | ||||||
|  | 	p.cn = nil | ||||||
|  | 	p.stickyErr = ErrClosed | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *SingleConnPool) Len() int { | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *SingleConnPool) IdleLen() int { | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *SingleConnPool) Stats() *Stats { | ||||||
|  | 	return &Stats{} | ||||||
|  | } | ||||||
| @@ -2,6 +2,7 @@ package pool | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"sync/atomic" | 	"sync/atomic" | ||||||
| ) | ) | ||||||
| @@ -30,9 +31,11 @@ func (e BadConnError) Unwrap() error { | |||||||
| 	return e.wrapped | 	return e.wrapped | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type SingleConnPool struct { | //------------------------------------------------------------------------------ | ||||||
| 	pool  Pooler | 
 | ||||||
| 	level int32 // atomic | type StickyConnPool struct { | ||||||
|  | 	pool   Pooler | ||||||
|  | 	shared int32 // atomic | ||||||
| 
 | 
 | ||||||
| 	state uint32 // atomic | 	state uint32 // atomic | ||||||
| 	ch    chan *Conn | 	ch    chan *Conn | ||||||
| @@ -40,37 +43,29 @@ type SingleConnPool struct { | |||||||
| 	_badConnError atomic.Value | 	_badConnError atomic.Value | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var _ Pooler = (*SingleConnPool)(nil) | var _ Pooler = (*StickyConnPool)(nil) | ||||||
| 
 | 
 | ||||||
| func NewSingleConnPool(pool Pooler) *SingleConnPool { | func NewStickyConnPool(pool Pooler) *StickyConnPool { | ||||||
| 	p, ok := pool.(*SingleConnPool) | 	p, ok := pool.(*StickyConnPool) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		p = &SingleConnPool{ | 		p = &StickyConnPool{ | ||||||
| 			pool: pool, | 			pool: pool, | ||||||
| 			ch:   make(chan *Conn, 1), | 			ch:   make(chan *Conn, 1), | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	atomic.AddInt32(&p.level, 1) | 	atomic.AddInt32(&p.shared, 1) | ||||||
| 	return p | 	return p | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *SingleConnPool) SetConn(cn *Conn) { | func (p *StickyConnPool) NewConn(ctx context.Context) (*Conn, error) { | ||||||
| 	if atomic.CompareAndSwapUint32(&p.state, stateDefault, stateInited) { |  | ||||||
| 		p.ch <- cn |  | ||||||
| 	} else { |  | ||||||
| 		panic("not reached") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (p *SingleConnPool) NewConn(ctx context.Context) (*Conn, error) { |  | ||||||
| 	return p.pool.NewConn(ctx) | 	return p.pool.NewConn(ctx) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *SingleConnPool) CloseConn(cn *Conn) error { | func (p *StickyConnPool) CloseConn(cn *Conn) error { | ||||||
| 	return p.pool.CloseConn(cn) | 	return p.pool.CloseConn(cn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *SingleConnPool) Get(ctx context.Context) (*Conn, error) { | func (p *StickyConnPool) Get(ctx context.Context) (*Conn, error) { | ||||||
| 	// In worst case this races with Close which is not a very common operation. | 	// In worst case this races with Close which is not a very common operation. | ||||||
| 	for i := 0; i < 1000; i++ { | 	for i := 0; i < 1000; i++ { | ||||||
| 		switch atomic.LoadUint32(&p.state) { | 		switch atomic.LoadUint32(&p.state) { | ||||||
| @@ -82,7 +77,7 @@ func (p *SingleConnPool) Get(ctx context.Context) (*Conn, error) { | |||||||
| 			if atomic.CompareAndSwapUint32(&p.state, stateDefault, stateInited) { | 			if atomic.CompareAndSwapUint32(&p.state, stateDefault, stateInited) { | ||||||
| 				return cn, nil | 				return cn, nil | ||||||
| 			} | 			} | ||||||
| 			p.pool.Remove(cn, ErrClosed) | 			p.pool.Remove(ctx, cn, ErrClosed) | ||||||
| 		case stateInited: | 		case stateInited: | ||||||
| 			if err := p.badConnError(); err != nil { | 			if err := p.badConnError(); err != nil { | ||||||
| 				return nil, err | 				return nil, err | ||||||
| @@ -98,60 +93,38 @@ func (p *SingleConnPool) Get(ctx context.Context) (*Conn, error) { | |||||||
| 			panic("not reached") | 			panic("not reached") | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return nil, fmt.Errorf("redis: SingleConnPool.Get: infinite loop") | 	return nil, fmt.Errorf("redis: StickyConnPool.Get: infinite loop") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *SingleConnPool) Put(cn *Conn) { | func (p *StickyConnPool) Put(ctx context.Context, cn *Conn) { | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if recover() != nil { | 		if recover() != nil { | ||||||
| 			p.freeConn(cn) | 			p.freeConn(ctx, cn) | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
| 	p.ch <- cn | 	p.ch <- cn | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *SingleConnPool) freeConn(cn *Conn) { | func (p *StickyConnPool) freeConn(ctx context.Context, cn *Conn) { | ||||||
| 	if err := p.badConnError(); err != nil { | 	if err := p.badConnError(); err != nil { | ||||||
| 		p.pool.Remove(cn, err) | 		p.pool.Remove(ctx, cn, err) | ||||||
| 	} else { | 	} else { | ||||||
| 		p.pool.Put(cn) | 		p.pool.Put(ctx, cn) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *SingleConnPool) Remove(cn *Conn, reason error) { | func (p *StickyConnPool) Remove(ctx context.Context, cn *Conn, reason error) { | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		if recover() != nil { | 		if recover() != nil { | ||||||
| 			p.pool.Remove(cn, ErrClosed) | 			p.pool.Remove(ctx, cn, ErrClosed) | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
| 	p._badConnError.Store(BadConnError{wrapped: reason}) | 	p._badConnError.Store(BadConnError{wrapped: reason}) | ||||||
| 	p.ch <- cn | 	p.ch <- cn | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *SingleConnPool) Len() int { | func (p *StickyConnPool) Close() error { | ||||||
| 	switch atomic.LoadUint32(&p.state) { | 	if shared := atomic.AddInt32(&p.shared, -1); shared > 0 { | ||||||
| 	case stateDefault: |  | ||||||
| 		return 0 |  | ||||||
| 	case stateInited: |  | ||||||
| 		return 1 |  | ||||||
| 	case stateClosed: |  | ||||||
| 		return 0 |  | ||||||
| 	default: |  | ||||||
| 		panic("not reached") |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (p *SingleConnPool) IdleLen() int { |  | ||||||
| 	return len(p.ch) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (p *SingleConnPool) Stats() *Stats { |  | ||||||
| 	return &Stats{} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (p *SingleConnPool) Close() error { |  | ||||||
| 	level := atomic.AddInt32(&p.level, -1) |  | ||||||
| 	if level > 0 { |  | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -164,16 +137,16 @@ func (p *SingleConnPool) Close() error { | |||||||
| 			close(p.ch) | 			close(p.ch) | ||||||
| 			cn, ok := <-p.ch | 			cn, ok := <-p.ch | ||||||
| 			if ok { | 			if ok { | ||||||
| 				p.freeConn(cn) | 				p.freeConn(context.TODO(), cn) | ||||||
| 			} | 			} | ||||||
| 			return nil | 			return nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return fmt.Errorf("redis: SingleConnPool.Close: infinite loop") | 	return errors.New("redis: StickyConnPool.Close: infinite loop") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *SingleConnPool) Reset() error { | func (p *StickyConnPool) Reset(ctx context.Context) error { | ||||||
| 	if p.badConnError() == nil { | 	if p.badConnError() == nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| @@ -183,21 +156,21 @@ func (p *SingleConnPool) Reset() error { | |||||||
| 		if !ok { | 		if !ok { | ||||||
| 			return ErrClosed | 			return ErrClosed | ||||||
| 		} | 		} | ||||||
| 		p.pool.Remove(cn, ErrClosed) | 		p.pool.Remove(ctx, cn, ErrClosed) | ||||||
| 		p._badConnError.Store(BadConnError{wrapped: nil}) | 		p._badConnError.Store(BadConnError{wrapped: nil}) | ||||||
| 	default: | 	default: | ||||||
| 		return fmt.Errorf("redis: SingleConnPool does not have a Conn") | 		return errors.New("redis: StickyConnPool does not have a Conn") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !atomic.CompareAndSwapUint32(&p.state, stateInited, stateDefault) { | 	if !atomic.CompareAndSwapUint32(&p.state, stateInited, stateDefault) { | ||||||
| 		state := atomic.LoadUint32(&p.state) | 		state := atomic.LoadUint32(&p.state) | ||||||
| 		return fmt.Errorf("redis: invalid SingleConnPool state: %d", state) | 		return fmt.Errorf("redis: invalid StickyConnPool state: %d", state) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (p *SingleConnPool) badConnError() error { | func (p *StickyConnPool) badConnError() error { | ||||||
| 	if v := p._badConnError.Load(); v != nil { | 	if v := p._badConnError.Load(); v != nil { | ||||||
| 		err := v.(BadConnError) | 		err := v.(BadConnError) | ||||||
| 		if err.wrapped != nil { | 		if err.wrapped != nil { | ||||||
| @@ -206,3 +179,24 @@ func (p *SingleConnPool) badConnError() error { | |||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (p *StickyConnPool) Len() int { | ||||||
|  | 	switch atomic.LoadUint32(&p.state) { | ||||||
|  | 	case stateDefault: | ||||||
|  | 		return 0 | ||||||
|  | 	case stateInited: | ||||||
|  | 		return 1 | ||||||
|  | 	case stateClosed: | ||||||
|  | 		return 0 | ||||||
|  | 	default: | ||||||
|  | 		panic("not reached") | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *StickyConnPool) IdleLen() int { | ||||||
|  | 	return len(p.ch) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (p *StickyConnPool) Stats() *Stats { | ||||||
|  | 	return &Stats{} | ||||||
|  | } | ||||||
| @@ -5,7 +5,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal/util" | 	"github.com/go-redis/redis/v8/internal/util" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| @@ -71,13 +71,25 @@ func (r *Reader) ReadLine() ([]byte, error) { | |||||||
| func (r *Reader) readLine() ([]byte, error) { | func (r *Reader) readLine() ([]byte, error) { | ||||||
| 	b, err := r.rd.ReadSlice('\n') | 	b, err := r.rd.ReadSlice('\n') | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		if err != bufio.ErrBufferFull { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		full := make([]byte, len(b)) | ||||||
|  | 		copy(full, b) | ||||||
|  | 
 | ||||||
|  | 		b, err = r.rd.ReadBytes('\n') | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		full = append(full, b...) | ||||||
|  | 		b = full | ||||||
| 	} | 	} | ||||||
| 	if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' { | 	if len(b) <= 2 || b[len(b)-1] != '\n' || b[len(b)-2] != '\r' { | ||||||
| 		return nil, fmt.Errorf("redis: invalid reply: %q", b) | 		return nil, fmt.Errorf("redis: invalid reply: %q", b) | ||||||
| 	} | 	} | ||||||
| 	b = b[:len(b)-2] | 	return b[:len(b)-2], nil | ||||||
| 	return b, nil |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) { | func (r *Reader) ReadReply(m MultiBulkParse) (interface{}, error) { | ||||||
| @@ -181,7 +193,7 @@ func (r *Reader) ReadArrayReply(m MultiBulkParse) (interface{}, error) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (r *Reader) ReadArrayLen() (int64, error) { | func (r *Reader) ReadArrayLen() (int, error) { | ||||||
| 	line, err := r.ReadLine() | 	line, err := r.ReadLine() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return 0, err | 		return 0, err | ||||||
| @@ -190,7 +202,11 @@ func (r *Reader) ReadArrayLen() (int64, error) { | |||||||
| 	case ErrorReply: | 	case ErrorReply: | ||||||
| 		return 0, ParseErrorReply(line) | 		return 0, ParseErrorReply(line) | ||||||
| 	case ArrayReply: | 	case ArrayReply: | ||||||
| 		return parseArrayLen(line) | 		n, err := parseArrayLen(line) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return 0, err | ||||||
|  | 		} | ||||||
|  | 		return int(n), nil | ||||||
| 	default: | 	default: | ||||||
| 		return 0, fmt.Errorf("redis: can't parse array reply: %.100q", line) | 		return 0, fmt.Errorf("redis: can't parse array reply: %.100q", line) | ||||||
| 	} | 	} | ||||||
| @@ -216,7 +232,8 @@ func (r *Reader) ReadScanReply() ([]string, uint64, error) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	keys := make([]string, n) | 	keys := make([]string, n) | ||||||
| 	for i := int64(0); i < n; i++ { | 
 | ||||||
|  | 	for i := 0; i < n; i++ { | ||||||
| 		key, err := r.ReadString() | 		key, err := r.ReadString() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, 0, err | 			return nil, 0, err | ||||||
| @@ -4,10 +4,13 @@ import ( | |||||||
| 	"encoding" | 	"encoding" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"reflect" | 	"reflect" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal/util" | 	"github.com/go-redis/redis/v8/internal/util" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | // Scan parses bytes `b` to `v` with appropriate type. | ||||||
|  | // nolint: gocyclo | ||||||
| func Scan(b []byte, v interface{}) error { | func Scan(b []byte, v interface{}) error { | ||||||
| 	switch v := v.(type) { | 	switch v := v.(type) { | ||||||
| 	case nil: | 	case nil: | ||||||
| @@ -99,6 +102,10 @@ func Scan(b []byte, v interface{}) error { | |||||||
| 	case *bool: | 	case *bool: | ||||||
| 		*v = len(b) == 1 && b[0] == '1' | 		*v = len(b) == 1 && b[0] == '1' | ||||||
| 		return nil | 		return nil | ||||||
|  | 	case *time.Time: | ||||||
|  | 		var err error | ||||||
|  | 		*v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b)) | ||||||
|  | 		return err | ||||||
| 	case encoding.BinaryUnmarshaler: | 	case encoding.BinaryUnmarshaler: | ||||||
| 		return v.UnmarshalBinary(b) | 		return v.UnmarshalBinary(b) | ||||||
| 	default: | 	default: | ||||||
| @@ -124,7 +131,7 @@ func ScanSlice(data []string, slice interface{}) error { | |||||||
| 	for i, s := range data { | 	for i, s := range data { | ||||||
| 		elem := next() | 		elem := next() | ||||||
| 		if err := Scan([]byte(s), elem.Addr().Interface()); err != nil { | 		if err := Scan([]byte(s), elem.Addr().Interface()); err != nil { | ||||||
| 			err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %s", i, s, err) | 			err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %w", i, s, err) | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -1,26 +1,32 @@ | |||||||
| package proto | package proto | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"bufio" |  | ||||||
| 	"encoding" | 	"encoding" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal/util" | 	"github.com/go-redis/redis/v8/internal/util" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | type writer interface { | ||||||
|  | 	io.Writer | ||||||
|  | 	io.ByteWriter | ||||||
|  | 	// io.StringWriter | ||||||
|  | 	WriteString(s string) (n int, err error) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| type Writer struct { | type Writer struct { | ||||||
| 	wr *bufio.Writer | 	writer | ||||||
| 
 | 
 | ||||||
| 	lenBuf []byte | 	lenBuf []byte | ||||||
| 	numBuf []byte | 	numBuf []byte | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewWriter(wr io.Writer) *Writer { | func NewWriter(wr writer) *Writer { | ||||||
| 	return &Writer{ | 	return &Writer{ | ||||||
| 		wr: bufio.NewWriter(wr), | 		writer: wr, | ||||||
| 
 | 
 | ||||||
| 		lenBuf: make([]byte, 64), | 		lenBuf: make([]byte, 64), | ||||||
| 		numBuf: make([]byte, 64), | 		numBuf: make([]byte, 64), | ||||||
| @@ -28,19 +34,16 @@ func NewWriter(wr io.Writer) *Writer { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (w *Writer) WriteArgs(args []interface{}) error { | func (w *Writer) WriteArgs(args []interface{}) error { | ||||||
| 	err := w.wr.WriteByte(ArrayReply) | 	if err := w.WriteByte(ArrayReply); err != nil { | ||||||
| 	if err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = w.writeLen(len(args)) | 	if err := w.writeLen(len(args)); err != nil { | ||||||
| 	if err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, arg := range args { | 	for _, arg := range args { | ||||||
| 		err := w.writeArg(arg) | 		if err := w.WriteArg(arg); err != nil { | ||||||
| 		if err != nil { |  | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -51,11 +54,11 @@ func (w *Writer) WriteArgs(args []interface{}) error { | |||||||
| func (w *Writer) writeLen(n int) error { | func (w *Writer) writeLen(n int) error { | ||||||
| 	w.lenBuf = strconv.AppendUint(w.lenBuf[:0], uint64(n), 10) | 	w.lenBuf = strconv.AppendUint(w.lenBuf[:0], uint64(n), 10) | ||||||
| 	w.lenBuf = append(w.lenBuf, '\r', '\n') | 	w.lenBuf = append(w.lenBuf, '\r', '\n') | ||||||
| 	_, err := w.wr.Write(w.lenBuf) | 	_, err := w.Write(w.lenBuf) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (w *Writer) writeArg(v interface{}) error { | func (w *Writer) WriteArg(v interface{}) error { | ||||||
| 	switch v := v.(type) { | 	switch v := v.(type) { | ||||||
| 	case nil: | 	case nil: | ||||||
| 		return w.string("") | 		return w.string("") | ||||||
| @@ -93,7 +96,8 @@ func (w *Writer) writeArg(v interface{}) error { | |||||||
| 		} | 		} | ||||||
| 		return w.int(0) | 		return w.int(0) | ||||||
| 	case time.Time: | 	case time.Time: | ||||||
| 		return w.string(v.Format(time.RFC3339Nano)) | 		w.numBuf = v.AppendFormat(w.numBuf[:0], time.RFC3339Nano) | ||||||
|  | 		return w.bytes(w.numBuf) | ||||||
| 	case encoding.BinaryMarshaler: | 	case encoding.BinaryMarshaler: | ||||||
| 		b, err := v.MarshalBinary() | 		b, err := v.MarshalBinary() | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| @@ -107,18 +111,15 @@ func (w *Writer) writeArg(v interface{}) error { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (w *Writer) bytes(b []byte) error { | func (w *Writer) bytes(b []byte) error { | ||||||
| 	err := w.wr.WriteByte(StringReply) | 	if err := w.WriteByte(StringReply); err != nil { | ||||||
| 	if err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = w.writeLen(len(b)) | 	if err := w.writeLen(len(b)); err != nil { | ||||||
| 	if err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	_, err = w.wr.Write(b) | 	if _, err := w.Write(b); err != nil { | ||||||
| 	if err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -145,21 +146,8 @@ func (w *Writer) float(f float64) error { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (w *Writer) crlf() error { | func (w *Writer) crlf() error { | ||||||
| 	err := w.wr.WriteByte('\r') | 	if err := w.WriteByte('\r'); err != nil { | ||||||
| 	if err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	return w.wr.WriteByte('\n') | 	return w.WriteByte('\n') | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (w *Writer) Buffered() int { |  | ||||||
| 	return w.wr.Buffered() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (w *Writer) Reset(wr io.Writer) { |  | ||||||
| 	w.wr.Reset(wr) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (w *Writer) Flush() error { |  | ||||||
| 	return w.wr.Flush() |  | ||||||
| } | } | ||||||
							
								
								
									
										45
									
								
								vendor/github.com/go-redis/redis/v8/internal/rand/rand.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/go-redis/redis/v8/internal/rand/rand.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | package rand | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"math/rand" | ||||||
|  | 	"sync" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Int returns a non-negative pseudo-random int. | ||||||
|  | func Int() int { return pseudo.Int() } | ||||||
|  |  | ||||||
|  | // Intn returns, as an int, a non-negative pseudo-random number in [0,n). | ||||||
|  | // It panics if n <= 0. | ||||||
|  | func Intn(n int) int { return pseudo.Intn(n) } | ||||||
|  |  | ||||||
|  | // Int63n returns, as an int64, a non-negative pseudo-random number in [0,n). | ||||||
|  | // It panics if n <= 0. | ||||||
|  | func Int63n(n int64) int64 { return pseudo.Int63n(n) } | ||||||
|  |  | ||||||
|  | // Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n). | ||||||
|  | func Perm(n int) []int { return pseudo.Perm(n) } | ||||||
|  |  | ||||||
|  | // Seed uses the provided seed value to initialize the default Source to a | ||||||
|  | // deterministic state. If Seed is not called, the generator behaves as if | ||||||
|  | // seeded by Seed(1). | ||||||
|  | func Seed(n int64) { pseudo.Seed(n) } | ||||||
|  |  | ||||||
|  | var pseudo = rand.New(&source{src: rand.NewSource(1)}) | ||||||
|  |  | ||||||
|  | type source struct { | ||||||
|  | 	src rand.Source | ||||||
|  | 	mu  sync.Mutex | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *source) Int63() int64 { | ||||||
|  | 	s.mu.Lock() | ||||||
|  | 	n := s.src.Int63() | ||||||
|  | 	s.mu.Unlock() | ||||||
|  | 	return n | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *source) Seed(seed int64) { | ||||||
|  | 	s.mu.Lock() | ||||||
|  | 	s.src.Seed(seed) | ||||||
|  | 	s.mu.Unlock() | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								vendor/github.com/go-redis/redis/v8/internal/safe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/go-redis/redis/v8/internal/safe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | // +build appengine | ||||||
|  |  | ||||||
|  | package internal | ||||||
|  |  | ||||||
|  | func String(b []byte) string { | ||||||
|  | 	return string(b) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Bytes(s string) []byte { | ||||||
|  | 	return []byte(s) | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								vendor/github.com/go-redis/redis/v8/internal/unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/go-redis/redis/v8/internal/unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | // +build !appengine | ||||||
|  |  | ||||||
|  | package internal | ||||||
|  |  | ||||||
|  | import "unsafe" | ||||||
|  |  | ||||||
|  | // String converts byte slice to string. | ||||||
|  | func String(b []byte) string { | ||||||
|  | 	return *(*string)(unsafe.Pointer(&b)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Bytes converts string to byte slice. | ||||||
|  | func Bytes(s string) []byte { | ||||||
|  | 	return *(*[]byte)(unsafe.Pointer( | ||||||
|  | 		&struct { | ||||||
|  | 			string | ||||||
|  | 			Cap int | ||||||
|  | 		}{s, len(s)}, | ||||||
|  | 	)) | ||||||
|  | } | ||||||
							
								
								
									
										73
									
								
								vendor/github.com/go-redis/redis/v8/internal/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								vendor/github.com/go-redis/redis/v8/internal/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  | package internal | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/proto" | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/util" | ||||||
|  | 	"go.opentelemetry.io/otel" | ||||||
|  | 	"go.opentelemetry.io/otel/trace" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func Sleep(ctx context.Context, dur time.Duration) error { | ||||||
|  | 	return WithSpan(ctx, "time.Sleep", func(ctx context.Context, span trace.Span) error { | ||||||
|  | 		t := time.NewTimer(dur) | ||||||
|  | 		defer t.Stop() | ||||||
|  |  | ||||||
|  | 		select { | ||||||
|  | 		case <-t.C: | ||||||
|  | 			return nil | ||||||
|  | 		case <-ctx.Done(): | ||||||
|  | 			return ctx.Err() | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func ToLower(s string) string { | ||||||
|  | 	if isLower(s) { | ||||||
|  | 		return s | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	b := make([]byte, len(s)) | ||||||
|  | 	for i := range b { | ||||||
|  | 		c := s[i] | ||||||
|  | 		if c >= 'A' && c <= 'Z' { | ||||||
|  | 			c += 'a' - 'A' | ||||||
|  | 		} | ||||||
|  | 		b[i] = c | ||||||
|  | 	} | ||||||
|  | 	return util.BytesToString(b) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func isLower(s string) bool { | ||||||
|  | 	for i := 0; i < len(s); i++ { | ||||||
|  | 		c := s[i] | ||||||
|  | 		if c >= 'A' && c <= 'Z' { | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return true | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | var tracer = otel.Tracer("github.com/go-redis/redis") | ||||||
|  |  | ||||||
|  | func WithSpan(ctx context.Context, name string, fn func(context.Context, trace.Span) error) error { | ||||||
|  | 	if span := trace.SpanFromContext(ctx); !span.IsRecording() { | ||||||
|  | 		return fn(ctx, span) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ctx, span := tracer.Start(ctx, name) | ||||||
|  | 	defer span.End() | ||||||
|  |  | ||||||
|  | 	return fn(ctx, span) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RecordError(ctx context.Context, span trace.Span, err error) error { | ||||||
|  | 	if err != proto.Nil { | ||||||
|  | 		span.RecordError(err) | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
| @@ -1,6 +1,7 @@ | |||||||
| package redis | package redis | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"context" | ||||||
| 	"sync" | 	"sync" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @@ -21,7 +22,7 @@ func (it *ScanIterator) Err() error { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Next advances the cursor and returns true if more values can be read. | // Next advances the cursor and returns true if more values can be read. | ||||||
| func (it *ScanIterator) Next() bool { | func (it *ScanIterator) Next(ctx context.Context) bool { | ||||||
| 	it.mu.Lock() | 	it.mu.Lock() | ||||||
| 	defer it.mu.Unlock() | 	defer it.mu.Unlock() | ||||||
| 
 | 
 | ||||||
| @@ -43,13 +44,14 @@ func (it *ScanIterator) Next() bool { | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Fetch next page. | 		// Fetch next page. | ||||||
| 		if it.cmd.args[0] == "scan" { | 		switch it.cmd.args[0] { | ||||||
|  | 		case "scan", "qscan": | ||||||
| 			it.cmd.args[1] = it.cmd.cursor | 			it.cmd.args[1] = it.cmd.cursor | ||||||
| 		} else { | 		default: | ||||||
| 			it.cmd.args[2] = it.cmd.cursor | 			it.cmd.args[2] = it.cmd.cursor | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		err := it.cmd.process(it.cmd) | 		err := it.cmd.process(ctx, it.cmd) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return false | 			return false | ||||||
| 		} | 		} | ||||||
| @@ -12,7 +12,10 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal/pool" | 	"github.com/go-redis/redis/v8/internal" | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/pool" | ||||||
|  | 	"go.opentelemetry.io/otel/label" | ||||||
|  | 	"go.opentelemetry.io/otel/trace" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Limiter is the interface of a rate limiter or a circuit breaker. | // Limiter is the interface of a rate limiter or a circuit breaker. | ||||||
| @@ -26,6 +29,7 @@ type Limiter interface { | |||||||
| 	ReportResult(result error) | 	ReportResult(result error) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Options keeps the settings to setup redis connection. | ||||||
| type Options struct { | type Options struct { | ||||||
| 	// The network type, either tcp or unix. | 	// The network type, either tcp or unix. | ||||||
| 	// Default is tcp. | 	// Default is tcp. | ||||||
| @@ -38,21 +42,23 @@ type Options struct { | |||||||
| 	Dialer func(ctx context.Context, network, addr string) (net.Conn, error) | 	Dialer func(ctx context.Context, network, addr string) (net.Conn, error) | ||||||
| 
 | 
 | ||||||
| 	// Hook that is called when new connection is established. | 	// Hook that is called when new connection is established. | ||||||
| 	OnConnect func(*Conn) error | 	OnConnect func(ctx context.Context, cn *Conn) error | ||||||
| 
 | 
 | ||||||
| 	// Use the specified Username to authenticate the current connection with one of the connections defined in the ACL | 	// Use the specified Username to authenticate the current connection | ||||||
| 	// list when connecting to a Redis 6.0 instance, or greater, that is using the Redis ACL system. | 	// with one of the connections defined in the ACL list when connecting | ||||||
|  | 	// to a Redis 6.0 instance, or greater, that is using the Redis ACL system. | ||||||
| 	Username string | 	Username string | ||||||
| 
 |  | ||||||
| 	// Optional password. Must match the password specified in the | 	// Optional password. Must match the password specified in the | ||||||
| 	// requirepass server configuration option (if connecting to a Redis 5.0 instance, or lower), | 	// requirepass server configuration option (if connecting to a Redis 5.0 instance, or lower), | ||||||
| 	// or the User Password when connecting to a Redis 6.0 instance, or greater, that is using the Redis ACL system. | 	// or the User Password when connecting to a Redis 6.0 instance, or greater, | ||||||
|  | 	// that is using the Redis ACL system. | ||||||
| 	Password string | 	Password string | ||||||
|  | 
 | ||||||
| 	// Database to be selected after connecting to the server. | 	// Database to be selected after connecting to the server. | ||||||
| 	DB int | 	DB int | ||||||
| 
 | 
 | ||||||
| 	// Maximum number of retries before giving up. | 	// Maximum number of retries before giving up. | ||||||
| 	// Default is to not retry failed commands. | 	// Default is 3 retries; -1 (not 0) disables retries. | ||||||
| 	MaxRetries int | 	MaxRetries int | ||||||
| 	// Minimum backoff between each retry. | 	// Minimum backoff between each retry. | ||||||
| 	// Default is 8 milliseconds; -1 disables backoff. | 	// Default is 8 milliseconds; -1 disables backoff. | ||||||
| @@ -117,6 +123,9 @@ func (opt *Options) init() { | |||||||
| 			opt.Network = "tcp" | 			opt.Network = "tcp" | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if opt.DialTimeout == 0 { | ||||||
|  | 		opt.DialTimeout = 5 * time.Second | ||||||
|  | 	} | ||||||
| 	if opt.Dialer == nil { | 	if opt.Dialer == nil { | ||||||
| 		opt.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) { | 		opt.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) { | ||||||
| 			netDialer := &net.Dialer{ | 			netDialer := &net.Dialer{ | ||||||
| @@ -132,9 +141,6 @@ func (opt *Options) init() { | |||||||
| 	if opt.PoolSize == 0 { | 	if opt.PoolSize == 0 { | ||||||
| 		opt.PoolSize = 10 * runtime.NumCPU() | 		opt.PoolSize = 10 * runtime.NumCPU() | ||||||
| 	} | 	} | ||||||
| 	if opt.DialTimeout == 0 { |  | ||||||
| 		opt.DialTimeout = 5 * time.Second |  | ||||||
| 	} |  | ||||||
| 	switch opt.ReadTimeout { | 	switch opt.ReadTimeout { | ||||||
| 	case -1: | 	case -1: | ||||||
| 		opt.ReadTimeout = 0 | 		opt.ReadTimeout = 0 | ||||||
| @@ -159,6 +165,8 @@ func (opt *Options) init() { | |||||||
| 
 | 
 | ||||||
| 	if opt.MaxRetries == -1 { | 	if opt.MaxRetries == -1 { | ||||||
| 		opt.MaxRetries = 0 | 		opt.MaxRetries = 0 | ||||||
|  | 	} else if opt.MaxRetries == 0 { | ||||||
|  | 		opt.MaxRetries = 3 | ||||||
| 	} | 	} | ||||||
| 	switch opt.MinRetryBackoff { | 	switch opt.MinRetryBackoff { | ||||||
| 	case -1: | 	case -1: | ||||||
| @@ -180,26 +188,35 @@ func (opt *Options) clone() *Options { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ParseURL parses an URL into Options that can be used to connect to Redis. | // ParseURL parses an URL into Options that can be used to connect to Redis. | ||||||
|  | // Scheme is required. | ||||||
|  | // There are two connection types: by tcp socket and by unix socket. | ||||||
|  | // Tcp connection: | ||||||
|  | // 		redis://<user>:<password>@<host>:<port>/<db_number> | ||||||
|  | // Unix connection: | ||||||
|  | //		unix://<user>:<password>@</path/to/redis.sock>?db=<db_number> | ||||||
| func ParseURL(redisURL string) (*Options, error) { | func ParseURL(redisURL string) (*Options, error) { | ||||||
| 	o := &Options{Network: "tcp"} |  | ||||||
| 	u, err := url.Parse(redisURL) | 	u, err := url.Parse(redisURL) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if u.Scheme != "redis" && u.Scheme != "rediss" { | 	switch u.Scheme { | ||||||
| 		return nil, errors.New("invalid redis URL scheme: " + u.Scheme) | 	case "redis", "rediss": | ||||||
|  | 		return setupTCPConn(u) | ||||||
|  | 	case "unix": | ||||||
|  | 		return setupUnixConn(u) | ||||||
|  | 	default: | ||||||
|  | 		return nil, fmt.Errorf("redis: invalid URL scheme: %s", u.Scheme) | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	if u.User != nil { | func setupTCPConn(u *url.URL) (*Options, error) { | ||||||
| 		o.Username = u.User.Username() | 	o := &Options{Network: "tcp"} | ||||||
| 		if p, ok := u.User.Password(); ok { | 
 | ||||||
| 			o.Password = p | 	o.Username, o.Password = getUserPassword(u) | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if len(u.Query()) > 0 { | 	if len(u.Query()) > 0 { | ||||||
| 		return nil, errors.New("no options supported") | 		return nil, errors.New("redis: no options supported") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	h, p, err := net.SplitHostPort(u.Host) | 	h, p, err := net.SplitHostPort(u.Host) | ||||||
| @@ -222,22 +239,73 @@ func ParseURL(redisURL string) (*Options, error) { | |||||||
| 		o.DB = 0 | 		o.DB = 0 | ||||||
| 	case 1: | 	case 1: | ||||||
| 		if o.DB, err = strconv.Atoi(f[0]); err != nil { | 		if o.DB, err = strconv.Atoi(f[0]); err != nil { | ||||||
| 			return nil, fmt.Errorf("invalid redis database number: %q", f[0]) | 			return nil, fmt.Errorf("redis: invalid database number: %q", f[0]) | ||||||
| 		} | 		} | ||||||
| 	default: | 	default: | ||||||
| 		return nil, errors.New("invalid redis URL path: " + u.Path) | 		return nil, fmt.Errorf("redis: invalid URL path: %s", u.Path) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if u.Scheme == "rediss" { | 	if u.Scheme == "rediss" { | ||||||
| 		o.TLSConfig = &tls.Config{ServerName: h} | 		o.TLSConfig = &tls.Config{ServerName: h} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	return o, nil | 	return o, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func setupUnixConn(u *url.URL) (*Options, error) { | ||||||
|  | 	o := &Options{ | ||||||
|  | 		Network: "unix", | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if strings.TrimSpace(u.Path) == "" { // path is required with unix connection | ||||||
|  | 		return nil, errors.New("redis: empty unix socket path") | ||||||
|  | 	} | ||||||
|  | 	o.Addr = u.Path | ||||||
|  | 
 | ||||||
|  | 	o.Username, o.Password = getUserPassword(u) | ||||||
|  | 
 | ||||||
|  | 	dbStr := u.Query().Get("db") | ||||||
|  | 	if dbStr == "" { | ||||||
|  | 		return o, nil // if database is not set, connect to 0 db. | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	db, err := strconv.Atoi(dbStr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, fmt.Errorf("redis: invalid database number: %w", err) | ||||||
|  | 	} | ||||||
|  | 	o.DB = db | ||||||
|  | 
 | ||||||
|  | 	return o, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func getUserPassword(u *url.URL) (string, string) { | ||||||
|  | 	var user, password string | ||||||
|  | 	if u.User != nil { | ||||||
|  | 		user = u.User.Username() | ||||||
|  | 		if p, ok := u.User.Password(); ok { | ||||||
|  | 			password = p | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return user, password | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func newConnPool(opt *Options) *pool.ConnPool { | func newConnPool(opt *Options) *pool.ConnPool { | ||||||
| 	return pool.NewConnPool(&pool.Options{ | 	return pool.NewConnPool(&pool.Options{ | ||||||
| 		Dialer: func(ctx context.Context) (net.Conn, error) { | 		Dialer: func(ctx context.Context) (net.Conn, error) { | ||||||
| 			return opt.Dialer(ctx, opt.Network, opt.Addr) | 			var conn net.Conn | ||||||
|  | 			err := internal.WithSpan(ctx, "redis.dial", func(ctx context.Context, span trace.Span) error { | ||||||
|  | 				span.SetAttributes( | ||||||
|  | 					label.String("db.connection_string", opt.Addr), | ||||||
|  | 				) | ||||||
|  | 
 | ||||||
|  | 				var err error | ||||||
|  | 				conn, err = opt.Dialer(ctx, opt.Network, opt.Addr) | ||||||
|  | 				if err != nil { | ||||||
|  | 					_ = internal.RecordError(ctx, span, err) | ||||||
|  | 				} | ||||||
|  | 				return err | ||||||
|  | 			}) | ||||||
|  | 			return conn, err | ||||||
| 		}, | 		}, | ||||||
| 		PoolSize:           opt.PoolSize, | 		PoolSize:           opt.PoolSize, | ||||||
| 		MinIdleConns:       opt.MinIdleConns, | 		MinIdleConns:       opt.MinIdleConns, | ||||||
| @@ -4,7 +4,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"sync" | 	"sync" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal/pool" | 	"github.com/go-redis/redis/v8/internal/pool" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type pipelineExecer func(context.Context, []Cmder) error | type pipelineExecer func(context.Context, []Cmder) error | ||||||
| @@ -24,12 +24,11 @@ type pipelineExecer func(context.Context, []Cmder) error | |||||||
| // depends of your batch size and/or use TxPipeline. | // depends of your batch size and/or use TxPipeline. | ||||||
| type Pipeliner interface { | type Pipeliner interface { | ||||||
| 	StatefulCmdable | 	StatefulCmdable | ||||||
| 	Do(args ...interface{}) *Cmd | 	Do(ctx context.Context, args ...interface{}) *Cmd | ||||||
| 	Process(cmd Cmder) error | 	Process(ctx context.Context, cmd Cmder) error | ||||||
| 	Close() error | 	Close() error | ||||||
| 	Discard() error | 	Discard() error | ||||||
| 	Exec() ([]Cmder, error) | 	Exec(ctx context.Context) ([]Cmder, error) | ||||||
| 	ExecContext(ctx context.Context) ([]Cmder, error) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var _ Pipeliner = (*Pipeline)(nil) | var _ Pipeliner = (*Pipeline)(nil) | ||||||
| @@ -54,14 +53,14 @@ func (c *Pipeline) init() { | |||||||
| 	c.statefulCmdable = c.Process | 	c.statefulCmdable = c.Process | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Pipeline) Do(args ...interface{}) *Cmd { | func (c *Pipeline) Do(ctx context.Context, args ...interface{}) *Cmd { | ||||||
| 	cmd := NewCmd(args...) | 	cmd := NewCmd(ctx, args...) | ||||||
| 	_ = c.Process(cmd) | 	_ = c.Process(ctx, cmd) | ||||||
| 	return cmd | 	return cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Process queues the cmd for later execution. | // Process queues the cmd for later execution. | ||||||
| func (c *Pipeline) Process(cmd Cmder) error { | func (c *Pipeline) Process(ctx context.Context, cmd Cmder) error { | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| 	c.cmds = append(c.cmds, cmd) | 	c.cmds = append(c.cmds, cmd) | ||||||
| 	c.mu.Unlock() | 	c.mu.Unlock() | ||||||
| @@ -98,11 +97,7 @@ func (c *Pipeline) discard() error { | |||||||
| // | // | ||||||
| // Exec always returns list of commands and error of the first failed | // Exec always returns list of commands and error of the first failed | ||||||
| // command if any. | // command if any. | ||||||
| func (c *Pipeline) Exec() ([]Cmder, error) { | func (c *Pipeline) Exec(ctx context.Context) ([]Cmder, error) { | ||||||
| 	return c.ExecContext(c.ctx) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *Pipeline) ExecContext(ctx context.Context) ([]Cmder, error) { |  | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| 	defer c.mu.Unlock() | 	defer c.mu.Unlock() | ||||||
| 
 | 
 | ||||||
| @@ -120,11 +115,11 @@ func (c *Pipeline) ExecContext(ctx context.Context) ([]Cmder, error) { | |||||||
| 	return cmds, c.exec(ctx, cmds) | 	return cmds, c.exec(ctx, cmds) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Pipeline) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Pipeline) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
| 	if err := fn(c); err != nil { | 	if err := fn(c); err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	cmds, err := c.Exec() | 	cmds, err := c.Exec(ctx) | ||||||
| 	_ = c.Close() | 	_ = c.Close() | ||||||
| 	return cmds, err | 	return cmds, err | ||||||
| } | } | ||||||
| @@ -133,8 +128,8 @@ func (c *Pipeline) Pipeline() Pipeliner { | |||||||
| 	return c | 	return c | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Pipeline) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Pipeline) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
| 	return c.Pipelined(fn) | 	return c.Pipelined(ctx, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Pipeline) TxPipeline() Pipeliner { | func (c *Pipeline) TxPipeline() Pipeliner { | ||||||
| @@ -8,12 +8,15 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal" | 	"github.com/go-redis/redis/v8/internal" | ||||||
| 	"github.com/go-redis/redis/v7/internal/pool" | 	"github.com/go-redis/redis/v8/internal/pool" | ||||||
| 	"github.com/go-redis/redis/v7/internal/proto" | 	"github.com/go-redis/redis/v8/internal/proto" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const pingTimeout = 30 * time.Second | const ( | ||||||
|  | 	pingTimeout     = time.Second | ||||||
|  | 	chanSendTimeout = time.Minute | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| var errPingTimeout = errors.New("redis: ping timeout") | var errPingTimeout = errors.New("redis: ping timeout") | ||||||
| 
 | 
 | ||||||
| @@ -26,7 +29,7 @@ var errPingTimeout = errors.New("redis: ping timeout") | |||||||
| type PubSub struct { | type PubSub struct { | ||||||
| 	opt *Options | 	opt *Options | ||||||
| 
 | 
 | ||||||
| 	newConn   func([]string) (*pool.Conn, error) | 	newConn   func(ctx context.Context, channels []string) (*pool.Conn, error) | ||||||
| 	closeConn func(*pool.Conn) error | 	closeConn func(*pool.Conn) error | ||||||
| 
 | 
 | ||||||
| 	mu       sync.Mutex | 	mu       sync.Mutex | ||||||
| @@ -55,14 +58,14 @@ func (c *PubSub) init() { | |||||||
| 	c.exit = make(chan struct{}) | 	c.exit = make(chan struct{}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) connWithLock() (*pool.Conn, error) { | func (c *PubSub) connWithLock(ctx context.Context) (*pool.Conn, error) { | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| 	cn, err := c.conn(nil) | 	cn, err := c.conn(ctx, nil) | ||||||
| 	c.mu.Unlock() | 	c.mu.Unlock() | ||||||
| 	return cn, err | 	return cn, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) conn(newChannels []string) (*pool.Conn, error) { | func (c *PubSub) conn(ctx context.Context, newChannels []string) (*pool.Conn, error) { | ||||||
| 	if c.closed { | 	if c.closed { | ||||||
| 		return nil, pool.ErrClosed | 		return nil, pool.ErrClosed | ||||||
| 	} | 	} | ||||||
| @@ -73,12 +76,12 @@ func (c *PubSub) conn(newChannels []string) (*pool.Conn, error) { | |||||||
| 	channels := mapKeys(c.channels) | 	channels := mapKeys(c.channels) | ||||||
| 	channels = append(channels, newChannels...) | 	channels = append(channels, newChannels...) | ||||||
| 
 | 
 | ||||||
| 	cn, err := c.newConn(channels) | 	cn, err := c.newConn(ctx, channels) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if err := c.resubscribe(cn); err != nil { | 	if err := c.resubscribe(ctx, cn); err != nil { | ||||||
| 		_ = c.closeConn(cn) | 		_ = c.closeConn(cn) | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -93,15 +96,15 @@ func (c *PubSub) writeCmd(ctx context.Context, cn *pool.Conn, cmd Cmder) error { | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) resubscribe(cn *pool.Conn) error { | func (c *PubSub) resubscribe(ctx context.Context, cn *pool.Conn) error { | ||||||
| 	var firstErr error | 	var firstErr error | ||||||
| 
 | 
 | ||||||
| 	if len(c.channels) > 0 { | 	if len(c.channels) > 0 { | ||||||
| 		firstErr = c._subscribe(cn, "subscribe", mapKeys(c.channels)) | 		firstErr = c._subscribe(ctx, cn, "subscribe", mapKeys(c.channels)) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if len(c.patterns) > 0 { | 	if len(c.patterns) > 0 { | ||||||
| 		err := c._subscribe(cn, "psubscribe", mapKeys(c.patterns)) | 		err := c._subscribe(ctx, cn, "psubscribe", mapKeys(c.patterns)) | ||||||
| 		if err != nil && firstErr == nil { | 		if err != nil && firstErr == nil { | ||||||
| 			firstErr = err | 			firstErr = err | ||||||
| 		} | 		} | ||||||
| @@ -121,35 +124,40 @@ func mapKeys(m map[string]struct{}) []string { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) _subscribe( | func (c *PubSub) _subscribe( | ||||||
| 	cn *pool.Conn, redisCmd string, channels []string, | 	ctx context.Context, cn *pool.Conn, redisCmd string, channels []string, | ||||||
| ) error { | ) error { | ||||||
| 	args := make([]interface{}, 0, 1+len(channels)) | 	args := make([]interface{}, 0, 1+len(channels)) | ||||||
| 	args = append(args, redisCmd) | 	args = append(args, redisCmd) | ||||||
| 	for _, channel := range channels { | 	for _, channel := range channels { | ||||||
| 		args = append(args, channel) | 		args = append(args, channel) | ||||||
| 	} | 	} | ||||||
| 	cmd := NewSliceCmd(args...) | 	cmd := NewSliceCmd(ctx, args...) | ||||||
| 	return c.writeCmd(context.TODO(), cn, cmd) | 	return c.writeCmd(ctx, cn, cmd) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) releaseConnWithLock(cn *pool.Conn, err error, allowTimeout bool) { | func (c *PubSub) releaseConnWithLock( | ||||||
|  | 	ctx context.Context, | ||||||
|  | 	cn *pool.Conn, | ||||||
|  | 	err error, | ||||||
|  | 	allowTimeout bool, | ||||||
|  | ) { | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| 	c.releaseConn(cn, err, allowTimeout) | 	c.releaseConn(ctx, cn, err, allowTimeout) | ||||||
| 	c.mu.Unlock() | 	c.mu.Unlock() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) releaseConn(cn *pool.Conn, err error, allowTimeout bool) { | func (c *PubSub) releaseConn(ctx context.Context, cn *pool.Conn, err error, allowTimeout bool) { | ||||||
| 	if c.cn != cn { | 	if c.cn != cn { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if isBadConn(err, allowTimeout) { | 	if isBadConn(err, allowTimeout) { | ||||||
| 		c.reconnect(err) | 		c.reconnect(ctx, err) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) reconnect(reason error) { | func (c *PubSub) reconnect(ctx context.Context, reason error) { | ||||||
| 	_ = c.closeTheCn(reason) | 	_ = c.closeTheCn(reason) | ||||||
| 	_, _ = c.conn(nil) | 	_, _ = c.conn(ctx, nil) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) closeTheCn(reason error) error { | func (c *PubSub) closeTheCn(reason error) error { | ||||||
| @@ -157,7 +165,7 @@ func (c *PubSub) closeTheCn(reason error) error { | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	if !c.closed { | 	if !c.closed { | ||||||
| 		internal.Logger.Printf("redis: discarding bad PubSub connection: %s", reason) | 		internal.Logger.Printf(c.getContext(), "redis: discarding bad PubSub connection: %s", reason) | ||||||
| 	} | 	} | ||||||
| 	err := c.closeConn(c.cn) | 	err := c.closeConn(c.cn) | ||||||
| 	c.cn = nil | 	c.cn = nil | ||||||
| @@ -179,11 +187,11 @@ func (c *PubSub) Close() error { | |||||||
| 
 | 
 | ||||||
| // Subscribe the client to the specified channels. It returns | // Subscribe the client to the specified channels. It returns | ||||||
| // empty subscription if there are no channels. | // empty subscription if there are no channels. | ||||||
| func (c *PubSub) Subscribe(channels ...string) error { | func (c *PubSub) Subscribe(ctx context.Context, channels ...string) error { | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| 	defer c.mu.Unlock() | 	defer c.mu.Unlock() | ||||||
| 
 | 
 | ||||||
| 	err := c.subscribe("subscribe", channels...) | 	err := c.subscribe(ctx, "subscribe", channels...) | ||||||
| 	if c.channels == nil { | 	if c.channels == nil { | ||||||
| 		c.channels = make(map[string]struct{}) | 		c.channels = make(map[string]struct{}) | ||||||
| 	} | 	} | ||||||
| @@ -195,11 +203,11 @@ func (c *PubSub) Subscribe(channels ...string) error { | |||||||
| 
 | 
 | ||||||
| // PSubscribe the client to the given patterns. It returns | // PSubscribe the client to the given patterns. It returns | ||||||
| // empty subscription if there are no patterns. | // empty subscription if there are no patterns. | ||||||
| func (c *PubSub) PSubscribe(patterns ...string) error { | func (c *PubSub) PSubscribe(ctx context.Context, patterns ...string) error { | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| 	defer c.mu.Unlock() | 	defer c.mu.Unlock() | ||||||
| 
 | 
 | ||||||
| 	err := c.subscribe("psubscribe", patterns...) | 	err := c.subscribe(ctx, "psubscribe", patterns...) | ||||||
| 	if c.patterns == nil { | 	if c.patterns == nil { | ||||||
| 		c.patterns = make(map[string]struct{}) | 		c.patterns = make(map[string]struct{}) | ||||||
| 	} | 	} | ||||||
| @@ -211,55 +219,55 @@ func (c *PubSub) PSubscribe(patterns ...string) error { | |||||||
| 
 | 
 | ||||||
| // Unsubscribe the client from the given channels, or from all of | // Unsubscribe the client from the given channels, or from all of | ||||||
| // them if none is given. | // them if none is given. | ||||||
| func (c *PubSub) Unsubscribe(channels ...string) error { | func (c *PubSub) Unsubscribe(ctx context.Context, channels ...string) error { | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| 	defer c.mu.Unlock() | 	defer c.mu.Unlock() | ||||||
| 
 | 
 | ||||||
| 	for _, channel := range channels { | 	for _, channel := range channels { | ||||||
| 		delete(c.channels, channel) | 		delete(c.channels, channel) | ||||||
| 	} | 	} | ||||||
| 	err := c.subscribe("unsubscribe", channels...) | 	err := c.subscribe(ctx, "unsubscribe", channels...) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // PUnsubscribe the client from the given patterns, or from all of | // PUnsubscribe the client from the given patterns, or from all of | ||||||
| // them if none is given. | // them if none is given. | ||||||
| func (c *PubSub) PUnsubscribe(patterns ...string) error { | func (c *PubSub) PUnsubscribe(ctx context.Context, patterns ...string) error { | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| 	defer c.mu.Unlock() | 	defer c.mu.Unlock() | ||||||
| 
 | 
 | ||||||
| 	for _, pattern := range patterns { | 	for _, pattern := range patterns { | ||||||
| 		delete(c.patterns, pattern) | 		delete(c.patterns, pattern) | ||||||
| 	} | 	} | ||||||
| 	err := c.subscribe("punsubscribe", patterns...) | 	err := c.subscribe(ctx, "punsubscribe", patterns...) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) subscribe(redisCmd string, channels ...string) error { | func (c *PubSub) subscribe(ctx context.Context, redisCmd string, channels ...string) error { | ||||||
| 	cn, err := c.conn(channels) | 	cn, err := c.conn(ctx, channels) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = c._subscribe(cn, redisCmd, channels) | 	err = c._subscribe(ctx, cn, redisCmd, channels) | ||||||
| 	c.releaseConn(cn, err, false) | 	c.releaseConn(ctx, cn, err, false) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *PubSub) Ping(payload ...string) error { | func (c *PubSub) Ping(ctx context.Context, payload ...string) error { | ||||||
| 	args := []interface{}{"ping"} | 	args := []interface{}{"ping"} | ||||||
| 	if len(payload) == 1 { | 	if len(payload) == 1 { | ||||||
| 		args = append(args, payload[0]) | 		args = append(args, payload[0]) | ||||||
| 	} | 	} | ||||||
| 	cmd := NewCmd(args...) | 	cmd := NewCmd(ctx, args...) | ||||||
| 
 | 
 | ||||||
| 	cn, err := c.connWithLock() | 	cn, err := c.connWithLock(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = c.writeCmd(context.TODO(), cn, cmd) | 	err = c.writeCmd(ctx, cn, cmd) | ||||||
| 	c.releaseConnWithLock(cn, err, false) | 	c.releaseConnWithLock(ctx, cn, err, false) | ||||||
| 	return err | 	return err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -279,9 +287,10 @@ func (m *Subscription) String() string { | |||||||
| 
 | 
 | ||||||
| // Message received as result of a PUBLISH command issued by another client. | // Message received as result of a PUBLISH command issued by another client. | ||||||
| type Message struct { | type Message struct { | ||||||
| 	Channel string | 	Channel      string | ||||||
| 	Pattern string | 	Pattern      string | ||||||
| 	Payload string | 	Payload      string | ||||||
|  | 	PayloadSlice []string | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *Message) String() string { | func (m *Message) String() string { | ||||||
| @@ -317,10 +326,24 @@ func (c *PubSub) newMessage(reply interface{}) (interface{}, error) { | |||||||
| 				Count:   int(reply[2].(int64)), | 				Count:   int(reply[2].(int64)), | ||||||
| 			}, nil | 			}, nil | ||||||
| 		case "message": | 		case "message": | ||||||
| 			return &Message{ | 			switch payload := reply[2].(type) { | ||||||
| 				Channel: reply[1].(string), | 			case string: | ||||||
| 				Payload: reply[2].(string), | 				return &Message{ | ||||||
| 			}, nil | 					Channel: reply[1].(string), | ||||||
|  | 					Payload: payload, | ||||||
|  | 				}, nil | ||||||
|  | 			case []interface{}: | ||||||
|  | 				ss := make([]string, len(payload)) | ||||||
|  | 				for i, s := range payload { | ||||||
|  | 					ss[i] = s.(string) | ||||||
|  | 				} | ||||||
|  | 				return &Message{ | ||||||
|  | 					Channel:      reply[1].(string), | ||||||
|  | 					PayloadSlice: ss, | ||||||
|  | 				}, nil | ||||||
|  | 			default: | ||||||
|  | 				return nil, fmt.Errorf("redis: unsupported pubsub message payload: %T", payload) | ||||||
|  | 			} | ||||||
| 		case "pmessage": | 		case "pmessage": | ||||||
| 			return &Message{ | 			return &Message{ | ||||||
| 				Pattern: reply[1].(string), | 				Pattern: reply[1].(string), | ||||||
| @@ -342,21 +365,21 @@ func (c *PubSub) newMessage(reply interface{}) (interface{}, error) { | |||||||
| // ReceiveTimeout acts like Receive but returns an error if message | // ReceiveTimeout acts like Receive but returns an error if message | ||||||
| // is not received in time. This is low-level API and in most cases | // is not received in time. This is low-level API and in most cases | ||||||
| // Channel should be used instead. | // Channel should be used instead. | ||||||
| func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) { | func (c *PubSub) ReceiveTimeout(ctx context.Context, timeout time.Duration) (interface{}, error) { | ||||||
| 	if c.cmd == nil { | 	if c.cmd == nil { | ||||||
| 		c.cmd = NewCmd() | 		c.cmd = NewCmd(ctx) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cn, err := c.connWithLock() | 	cn, err := c.connWithLock(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = cn.WithReader(context.TODO(), timeout, func(rd *proto.Reader) error { | 	err = cn.WithReader(ctx, timeout, func(rd *proto.Reader) error { | ||||||
| 		return c.cmd.readReply(rd) | 		return c.cmd.readReply(rd) | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
| 	c.releaseConnWithLock(cn, err, timeout > 0) | 	c.releaseConnWithLock(ctx, cn, err, timeout > 0) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -367,16 +390,16 @@ func (c *PubSub) ReceiveTimeout(timeout time.Duration) (interface{}, error) { | |||||||
| // Receive returns a message as a Subscription, Message, Pong or error. | // Receive returns a message as a Subscription, Message, Pong or error. | ||||||
| // See PubSub example for details. This is low-level API and in most cases | // See PubSub example for details. This is low-level API and in most cases | ||||||
| // Channel should be used instead. | // Channel should be used instead. | ||||||
| func (c *PubSub) Receive() (interface{}, error) { | func (c *PubSub) Receive(ctx context.Context) (interface{}, error) { | ||||||
| 	return c.ReceiveTimeout(0) | 	return c.ReceiveTimeout(ctx, 0) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ReceiveMessage returns a Message or error ignoring Subscription and Pong | // ReceiveMessage returns a Message or error ignoring Subscription and Pong | ||||||
| // messages. This is low-level API and in most cases Channel should be used | // messages. This is low-level API and in most cases Channel should be used | ||||||
| // instead. | // instead. | ||||||
| func (c *PubSub) ReceiveMessage() (*Message, error) { | func (c *PubSub) ReceiveMessage(ctx context.Context) (*Message, error) { | ||||||
| 	for { | 	for { | ||||||
| 		msg, err := c.Receive() | 		msg, err := c.Receive(ctx) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| @@ -429,7 +452,7 @@ func (c *PubSub) ChannelSize(size int) <-chan *Message { | |||||||
| // reconnections. | // reconnections. | ||||||
| // | // | ||||||
| // ChannelWithSubscriptions can not be used together with Channel or ChannelSize. | // ChannelWithSubscriptions can not be used together with Channel or ChannelSize. | ||||||
| func (c *PubSub) ChannelWithSubscriptions(size int) <-chan interface{} { | func (c *PubSub) ChannelWithSubscriptions(ctx context.Context, size int) <-chan interface{} { | ||||||
| 	c.chOnce.Do(func() { | 	c.chOnce.Do(func() { | ||||||
| 		c.initPing() | 		c.initPing() | ||||||
| 		c.initAllChan(size) | 		c.initAllChan(size) | ||||||
| @@ -445,10 +468,18 @@ func (c *PubSub) ChannelWithSubscriptions(size int) <-chan interface{} { | |||||||
| 	return c.allCh | 	return c.allCh | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (c *PubSub) getContext() context.Context { | ||||||
|  | 	if c.cmd != nil { | ||||||
|  | 		return c.cmd.ctx | ||||||
|  | 	} | ||||||
|  | 	return context.Background() | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (c *PubSub) initPing() { | func (c *PubSub) initPing() { | ||||||
|  | 	ctx := context.TODO() | ||||||
| 	c.ping = make(chan struct{}, 1) | 	c.ping = make(chan struct{}, 1) | ||||||
| 	go func() { | 	go func() { | ||||||
| 		timer := time.NewTimer(pingTimeout) | 		timer := time.NewTimer(time.Minute) | ||||||
| 		timer.Stop() | 		timer.Stop() | ||||||
| 
 | 
 | ||||||
| 		healthy := true | 		healthy := true | ||||||
| @@ -461,7 +492,7 @@ func (c *PubSub) initPing() { | |||||||
| 					<-timer.C | 					<-timer.C | ||||||
| 				} | 				} | ||||||
| 			case <-timer.C: | 			case <-timer.C: | ||||||
| 				pingErr := c.Ping() | 				pingErr := c.Ping(ctx) | ||||||
| 				if healthy { | 				if healthy { | ||||||
| 					healthy = false | 					healthy = false | ||||||
| 				} else { | 				} else { | ||||||
| @@ -469,7 +500,7 @@ func (c *PubSub) initPing() { | |||||||
| 						pingErr = errPingTimeout | 						pingErr = errPingTimeout | ||||||
| 					} | 					} | ||||||
| 					c.mu.Lock() | 					c.mu.Lock() | ||||||
| 					c.reconnect(pingErr) | 					c.reconnect(ctx, pingErr) | ||||||
| 					healthy = true | 					healthy = true | ||||||
| 					c.mu.Unlock() | 					c.mu.Unlock() | ||||||
| 				} | 				} | ||||||
| @@ -482,21 +513,22 @@ func (c *PubSub) initPing() { | |||||||
| 
 | 
 | ||||||
| // initMsgChan must be in sync with initAllChan. | // initMsgChan must be in sync with initAllChan. | ||||||
| func (c *PubSub) initMsgChan(size int) { | func (c *PubSub) initMsgChan(size int) { | ||||||
|  | 	ctx := context.TODO() | ||||||
| 	c.msgCh = make(chan *Message, size) | 	c.msgCh = make(chan *Message, size) | ||||||
| 	go func() { | 	go func() { | ||||||
| 		timer := time.NewTimer(pingTimeout) | 		timer := time.NewTimer(time.Minute) | ||||||
| 		timer.Stop() | 		timer.Stop() | ||||||
| 
 | 
 | ||||||
| 		var errCount int | 		var errCount int | ||||||
| 		for { | 		for { | ||||||
| 			msg, err := c.Receive() | 			msg, err := c.Receive(ctx) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				if err == pool.ErrClosed { | 				if err == pool.ErrClosed { | ||||||
| 					close(c.msgCh) | 					close(c.msgCh) | ||||||
| 					return | 					return | ||||||
| 				} | 				} | ||||||
| 				if errCount > 0 { | 				if errCount > 0 { | ||||||
| 					time.Sleep(c.retryBackoff(errCount)) | 					time.Sleep(100 * time.Millisecond) | ||||||
| 				} | 				} | ||||||
| 				errCount++ | 				errCount++ | ||||||
| 				continue | 				continue | ||||||
| @@ -516,7 +548,7 @@ func (c *PubSub) initMsgChan(size int) { | |||||||
| 			case *Pong: | 			case *Pong: | ||||||
| 				// Ignore. | 				// Ignore. | ||||||
| 			case *Message: | 			case *Message: | ||||||
| 				timer.Reset(pingTimeout) | 				timer.Reset(chanSendTimeout) | ||||||
| 				select { | 				select { | ||||||
| 				case c.msgCh <- msg: | 				case c.msgCh <- msg: | ||||||
| 					if !timer.Stop() { | 					if !timer.Stop() { | ||||||
| @@ -524,10 +556,14 @@ func (c *PubSub) initMsgChan(size int) { | |||||||
| 					} | 					} | ||||||
| 				case <-timer.C: | 				case <-timer.C: | ||||||
| 					internal.Logger.Printf( | 					internal.Logger.Printf( | ||||||
| 						"redis: %s channel is full for %s (message is dropped)", c, pingTimeout) | 						c.getContext(), | ||||||
|  | 						"redis: %s channel is full for %s (message is dropped)", | ||||||
|  | 						c, | ||||||
|  | 						chanSendTimeout, | ||||||
|  | 					) | ||||||
| 				} | 				} | ||||||
| 			default: | 			default: | ||||||
| 				internal.Logger.Printf("redis: unknown message type: %T", msg) | 				internal.Logger.Printf(c.getContext(), "redis: unknown message type: %T", msg) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
| @@ -535,6 +571,7 @@ func (c *PubSub) initMsgChan(size int) { | |||||||
| 
 | 
 | ||||||
| // initAllChan must be in sync with initMsgChan. | // initAllChan must be in sync with initMsgChan. | ||||||
| func (c *PubSub) initAllChan(size int) { | func (c *PubSub) initAllChan(size int) { | ||||||
|  | 	ctx := context.TODO() | ||||||
| 	c.allCh = make(chan interface{}, size) | 	c.allCh = make(chan interface{}, size) | ||||||
| 	go func() { | 	go func() { | ||||||
| 		timer := time.NewTimer(pingTimeout) | 		timer := time.NewTimer(pingTimeout) | ||||||
| @@ -542,14 +579,14 @@ func (c *PubSub) initAllChan(size int) { | |||||||
| 
 | 
 | ||||||
| 		var errCount int | 		var errCount int | ||||||
| 		for { | 		for { | ||||||
| 			msg, err := c.Receive() | 			msg, err := c.Receive(ctx) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				if err == pool.ErrClosed { | 				if err == pool.ErrClosed { | ||||||
| 					close(c.allCh) | 					close(c.allCh) | ||||||
| 					return | 					return | ||||||
| 				} | 				} | ||||||
| 				if errCount > 0 { | 				if errCount > 0 { | ||||||
| 					time.Sleep(c.retryBackoff(errCount)) | 					time.Sleep(100 * time.Millisecond) | ||||||
| 				} | 				} | ||||||
| 				errCount++ | 				errCount++ | ||||||
| 				continue | 				continue | ||||||
| @@ -571,7 +608,7 @@ func (c *PubSub) initAllChan(size int) { | |||||||
| 			case *Message: | 			case *Message: | ||||||
| 				c.sendMessage(msg, timer) | 				c.sendMessage(msg, timer) | ||||||
| 			default: | 			default: | ||||||
| 				internal.Logger.Printf("redis: unknown message type: %T", msg) | 				internal.Logger.Printf(c.getContext(), "redis: unknown message type: %T", msg) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
| @@ -586,10 +623,7 @@ func (c *PubSub) sendMessage(msg interface{}, timer *time.Timer) { | |||||||
| 		} | 		} | ||||||
| 	case <-timer.C: | 	case <-timer.C: | ||||||
| 		internal.Logger.Printf( | 		internal.Logger.Printf( | ||||||
|  | 			c.getContext(), | ||||||
| 			"redis: %s channel is full for %s (message is dropped)", c, pingTimeout) | 			"redis: %s channel is full for %s (message is dropped)", c, pingTimeout) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func (c *PubSub) retryBackoff(attempt int) time.Duration { |  | ||||||
| 	return internal.RetryBackoff(attempt, c.opt.MinRetryBackoff, c.opt.MaxRetryBackoff) |  | ||||||
| } |  | ||||||
							
								
								
									
										336
									
								
								vendor/github.com/go-redis/redis/v7/redis.go → vendor/github.com/go-redis/redis/v8/redis.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										336
									
								
								vendor/github.com/go-redis/redis/v7/redis.go → vendor/github.com/go-redis/redis/v8/redis.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,19 +2,22 @@ package redis | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log" | 	"sync/atomic" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal" | 	"github.com/go-redis/redis/v8/internal" | ||||||
| 	"github.com/go-redis/redis/v7/internal/pool" | 	"github.com/go-redis/redis/v8/internal/pool" | ||||||
| 	"github.com/go-redis/redis/v7/internal/proto" | 	"github.com/go-redis/redis/v8/internal/proto" | ||||||
|  | 	"go.opentelemetry.io/otel/label" | ||||||
|  | 	"go.opentelemetry.io/otel/trace" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Nil reply returned by Redis when key does not exist. | // Nil reply returned by Redis when key does not exist. | ||||||
| const Nil = proto.Nil | const Nil = proto.Nil | ||||||
| 
 | 
 | ||||||
| func SetLogger(logger *log.Logger) { | func SetLogger(logger internal.Logging) { | ||||||
| 	internal.Logger = logger | 	internal.Logger = logger | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -49,92 +52,88 @@ func (hs *hooks) AddHook(hook Hook) { | |||||||
| func (hs hooks) process( | func (hs hooks) process( | ||||||
| 	ctx context.Context, cmd Cmder, fn func(context.Context, Cmder) error, | 	ctx context.Context, cmd Cmder, fn func(context.Context, Cmder) error, | ||||||
| ) error { | ) error { | ||||||
| 	ctx, err := hs.beforeProcess(ctx, cmd) | 	if len(hs.hooks) == 0 { | ||||||
| 	if err != nil { | 		err := hs.withContext(ctx, func() error { | ||||||
|  | 			return fn(ctx, cmd) | ||||||
|  | 		}) | ||||||
| 		cmd.SetErr(err) | 		cmd.SetErr(err) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cmdErr := fn(ctx, cmd) | 	var hookIndex int | ||||||
|  | 	var retErr error | ||||||
| 
 | 
 | ||||||
| 	if err := hs.afterProcess(ctx, cmd); err != nil { | 	for ; hookIndex < len(hs.hooks) && retErr == nil; hookIndex++ { | ||||||
| 		cmd.SetErr(err) | 		ctx, retErr = hs.hooks[hookIndex].BeforeProcess(ctx, cmd) | ||||||
| 		return err | 		if retErr != nil { | ||||||
| 	} | 			cmd.SetErr(retErr) | ||||||
| 
 |  | ||||||
| 	return cmdErr |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (hs hooks) beforeProcess(ctx context.Context, cmd Cmder) (context.Context, error) { |  | ||||||
| 	for _, h := range hs.hooks { |  | ||||||
| 		var err error |  | ||||||
| 		ctx, err = h.BeforeProcess(ctx, cmd) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return ctx, nil |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| func (hs hooks) afterProcess(ctx context.Context, cmd Cmder) error { | 	if retErr == nil { | ||||||
| 	var firstErr error | 		retErr = hs.withContext(ctx, func() error { | ||||||
| 	for _, h := range hs.hooks { | 			return fn(ctx, cmd) | ||||||
| 		err := h.AfterProcess(ctx, cmd) | 		}) | ||||||
| 		if err != nil && firstErr == nil { | 		cmd.SetErr(retErr) | ||||||
| 			firstErr = err | 	} | ||||||
|  | 
 | ||||||
|  | 	for hookIndex--; hookIndex >= 0; hookIndex-- { | ||||||
|  | 		if err := hs.hooks[hookIndex].AfterProcess(ctx, cmd); err != nil { | ||||||
|  | 			retErr = err | ||||||
|  | 			cmd.SetErr(retErr) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return firstErr | 
 | ||||||
|  | 	return retErr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (hs hooks) processPipeline( | func (hs hooks) processPipeline( | ||||||
| 	ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error, | 	ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error, | ||||||
| ) error { | ) error { | ||||||
| 	ctx, err := hs.beforeProcessPipeline(ctx, cmds) | 	if len(hs.hooks) == 0 { | ||||||
| 	if err != nil { | 		err := hs.withContext(ctx, func() error { | ||||||
| 		setCmdsErr(cmds, err) | 			return fn(ctx, cmds) | ||||||
|  | 		}) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cmdsErr := fn(ctx, cmds) | 	var hookIndex int | ||||||
|  | 	var retErr error | ||||||
| 
 | 
 | ||||||
| 	if err := hs.afterProcessPipeline(ctx, cmds); err != nil { | 	for ; hookIndex < len(hs.hooks) && retErr == nil; hookIndex++ { | ||||||
| 		setCmdsErr(cmds, err) | 		ctx, retErr = hs.hooks[hookIndex].BeforeProcessPipeline(ctx, cmds) | ||||||
| 		return err | 		if retErr != nil { | ||||||
| 	} | 			setCmdsErr(cmds, retErr) | ||||||
| 
 |  | ||||||
| 	return cmdsErr |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (hs hooks) beforeProcessPipeline(ctx context.Context, cmds []Cmder) (context.Context, error) { |  | ||||||
| 	for _, h := range hs.hooks { |  | ||||||
| 		var err error |  | ||||||
| 		ctx, err = h.BeforeProcessPipeline(ctx, cmds) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return ctx, nil |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| func (hs hooks) afterProcessPipeline(ctx context.Context, cmds []Cmder) error { | 	if retErr == nil { | ||||||
| 	var firstErr error | 		retErr = hs.withContext(ctx, func() error { | ||||||
| 	for _, h := range hs.hooks { | 			return fn(ctx, cmds) | ||||||
| 		err := h.AfterProcessPipeline(ctx, cmds) | 		}) | ||||||
| 		if err != nil && firstErr == nil { | 	} | ||||||
| 			firstErr = err | 
 | ||||||
|  | 	for hookIndex--; hookIndex >= 0; hookIndex-- { | ||||||
|  | 		if err := hs.hooks[hookIndex].AfterProcessPipeline(ctx, cmds); err != nil { | ||||||
|  | 			retErr = err | ||||||
|  | 			setCmdsErr(cmds, retErr) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return firstErr | 
 | ||||||
|  | 	return retErr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (hs hooks) processTxPipeline( | func (hs hooks) processTxPipeline( | ||||||
| 	ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error, | 	ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error, | ||||||
| ) error { | ) error { | ||||||
| 	cmds = wrapMultiExec(cmds) | 	cmds = wrapMultiExec(ctx, cmds) | ||||||
| 	return hs.processPipeline(ctx, cmds, fn) | 	return hs.processPipeline(ctx, cmds, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (hs hooks) withContext(ctx context.Context, fn func() error) error { | ||||||
|  | 	return fn() | ||||||
|  | } | ||||||
|  | 
 | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| 
 | 
 | ||||||
| type baseClient struct { | type baseClient struct { | ||||||
| @@ -201,6 +200,7 @@ func (c *baseClient) getConn(ctx context.Context) (*pool.Conn, error) { | |||||||
| 		} | 		} | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	return cn, nil | 	return cn, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -210,10 +210,16 @@ func (c *baseClient) _getConn(ctx context.Context) (*pool.Conn, error) { | |||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = c.initConn(ctx, cn) | 	if cn.Inited { | ||||||
|  | 		return cn, nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	err = internal.WithSpan(ctx, "redis.init_conn", func(ctx context.Context, span trace.Span) error { | ||||||
|  | 		return c.initConn(ctx, cn) | ||||||
|  | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		c.connPool.Remove(cn, err) | 		c.connPool.Remove(ctx, cn, err) | ||||||
| 		if err := internal.Unwrap(err); err != nil { | 		if err := errors.Unwrap(err); err != nil { | ||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 		return nil, err | 		return nil, err | ||||||
| @@ -235,25 +241,24 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error { | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	connPool := pool.NewSingleConnPool(nil) | 	connPool := pool.NewSingleConnPool(c.connPool, cn) | ||||||
| 	connPool.SetConn(cn) |  | ||||||
| 	conn := newConn(ctx, c.opt, connPool) | 	conn := newConn(ctx, c.opt, connPool) | ||||||
| 
 | 
 | ||||||
| 	_, err := conn.Pipelined(func(pipe Pipeliner) error { | 	_, err := conn.Pipelined(ctx, func(pipe Pipeliner) error { | ||||||
| 		if c.opt.Password != "" { | 		if c.opt.Password != "" { | ||||||
| 			if c.opt.Username != "" { | 			if c.opt.Username != "" { | ||||||
| 				pipe.AuthACL(c.opt.Username, c.opt.Password) | 				pipe.AuthACL(ctx, c.opt.Username, c.opt.Password) | ||||||
| 			} else { | 			} else { | ||||||
| 				pipe.Auth(c.opt.Password) | 				pipe.Auth(ctx, c.opt.Password) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if c.opt.DB > 0 { | 		if c.opt.DB > 0 { | ||||||
| 			pipe.Select(c.opt.DB) | 			pipe.Select(ctx, c.opt.DB) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if c.opt.readOnly { | 		if c.opt.readOnly { | ||||||
| 			pipe.ReadOnly() | 			pipe.ReadOnly(ctx) | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		return nil | 		return nil | ||||||
| @@ -263,76 +268,107 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if c.opt.OnConnect != nil { | 	if c.opt.OnConnect != nil { | ||||||
| 		return c.opt.OnConnect(conn) | 		return c.opt.OnConnect(ctx, conn) | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *baseClient) releaseConn(cn *pool.Conn, err error) { | func (c *baseClient) releaseConn(ctx context.Context, cn *pool.Conn, err error) { | ||||||
| 	if c.opt.Limiter != nil { | 	if c.opt.Limiter != nil { | ||||||
| 		c.opt.Limiter.ReportResult(err) | 		c.opt.Limiter.ReportResult(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if isBadConn(err, false) { | 	if isBadConn(err, false) { | ||||||
| 		c.connPool.Remove(cn, err) | 		c.connPool.Remove(ctx, cn, err) | ||||||
| 	} else { | 	} else { | ||||||
| 		c.connPool.Put(cn) | 		c.connPool.Put(ctx, cn) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *baseClient) withConn( | func (c *baseClient) withConn( | ||||||
| 	ctx context.Context, fn func(context.Context, *pool.Conn) error, | 	ctx context.Context, fn func(context.Context, *pool.Conn) error, | ||||||
| ) error { | ) error { | ||||||
| 	cn, err := c.getConn(ctx) | 	return internal.WithSpan(ctx, "redis.with_conn", func(ctx context.Context, span trace.Span) error { | ||||||
| 	if err != nil { | 		cn, err := c.getConn(ctx) | ||||||
| 		return err | 		if err != nil { | ||||||
| 	} | 			return err | ||||||
| 	defer func() { | 		} | ||||||
| 		c.releaseConn(cn, err) |  | ||||||
| 	}() |  | ||||||
| 
 | 
 | ||||||
| 	err = fn(ctx, cn) | 		if span.IsRecording() { | ||||||
| 	return err | 			if remoteAddr := cn.RemoteAddr(); remoteAddr != nil { | ||||||
|  | 				span.SetAttributes(label.String("net.peer.ip", remoteAddr.String())) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		defer func() { | ||||||
|  | 			c.releaseConn(ctx, cn, err) | ||||||
|  | 		}() | ||||||
|  | 
 | ||||||
|  | 		done := ctx.Done() | ||||||
|  | 		if done == nil { | ||||||
|  | 			err = fn(ctx, cn) | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		errc := make(chan error, 1) | ||||||
|  | 		go func() { errc <- fn(ctx, cn) }() | ||||||
|  | 
 | ||||||
|  | 		select { | ||||||
|  | 		case <-done: | ||||||
|  | 			_ = cn.Close() | ||||||
|  | 			// Wait for the goroutine to finish and send something. | ||||||
|  | 			<-errc | ||||||
|  | 
 | ||||||
|  | 			err = ctx.Err() | ||||||
|  | 			return err | ||||||
|  | 		case err = <-errc: | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *baseClient) process(ctx context.Context, cmd Cmder) error { | func (c *baseClient) process(ctx context.Context, cmd Cmder) error { | ||||||
| 	err := c._process(ctx, cmd) |  | ||||||
| 	if err != nil { |  | ||||||
| 		cmd.SetErr(err) |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *baseClient) _process(ctx context.Context, cmd Cmder) error { |  | ||||||
| 	var lastErr error | 	var lastErr error | ||||||
| 	for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ { | 	for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ { | ||||||
| 		if attempt > 0 { | 		attempt := attempt | ||||||
| 			if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		retryTimeout := true | 		var retry bool | ||||||
| 		lastErr = c.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { | 		err := internal.WithSpan(ctx, "redis.process", func(ctx context.Context, span trace.Span) error { | ||||||
| 			err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error { | 			if attempt > 0 { | ||||||
| 				return writeCmd(wr, cmd) | 				if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			retryTimeout := uint32(1) | ||||||
|  | 			err := c.withConn(ctx, func(ctx context.Context, cn *pool.Conn) error { | ||||||
|  | 				err := cn.WithWriter(ctx, c.opt.WriteTimeout, func(wr *proto.Writer) error { | ||||||
|  | 					return writeCmd(wr, cmd) | ||||||
|  | 				}) | ||||||
|  | 				if err != nil { | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				err = cn.WithReader(ctx, c.cmdTimeout(cmd), cmd.readReply) | ||||||
|  | 				if err != nil { | ||||||
|  | 					if cmd.readTimeout() == nil { | ||||||
|  | 						atomic.StoreUint32(&retryTimeout, 1) | ||||||
|  | 					} | ||||||
|  | 					return err | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				return nil | ||||||
| 			}) | 			}) | ||||||
| 			if err != nil { | 			if err == nil { | ||||||
| 				return err | 				return nil | ||||||
| 			} | 			} | ||||||
| 
 | 			retry = shouldRetry(err, atomic.LoadUint32(&retryTimeout) == 1) | ||||||
| 			err = cn.WithReader(ctx, c.cmdTimeout(cmd), cmd.readReply) | 			return err | ||||||
| 			if err != nil { |  | ||||||
| 				retryTimeout = cmd.readTimeout() == nil |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			return nil |  | ||||||
| 		}) | 		}) | ||||||
| 		if lastErr == nil || !isRetryableError(lastErr, retryTimeout) { | 		if err == nil || !retry { | ||||||
| 			return lastErr | 			return err | ||||||
| 		} | 		} | ||||||
|  | 		lastErr = err | ||||||
| 	} | 	} | ||||||
| 	return lastErr | 	return lastErr | ||||||
| } | } | ||||||
| @@ -411,7 +447,7 @@ func (c *baseClient) _generalProcessPipeline( | |||||||
| 			canRetry, err = p(ctx, cn, cmds) | 			canRetry, err = p(ctx, cn, cmds) | ||||||
| 			return err | 			return err | ||||||
| 		}) | 		}) | ||||||
| 		if lastErr == nil || !canRetry || !isRetryableError(lastErr, true) { | 		if lastErr == nil || !canRetry || !shouldRetry(lastErr, true) { | ||||||
| 			return lastErr | 			return lastErr | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -437,6 +473,7 @@ func (c *baseClient) pipelineProcessCmds( | |||||||
| func pipelineReadCmds(rd *proto.Reader, cmds []Cmder) error { | func pipelineReadCmds(rd *proto.Reader, cmds []Cmder) error { | ||||||
| 	for _, cmd := range cmds { | 	for _, cmd := range cmds { | ||||||
| 		err := cmd.readReply(rd) | 		err := cmd.readReply(rd) | ||||||
|  | 		cmd.SetErr(err) | ||||||
| 		if err != nil && !isRedisError(err) { | 		if err != nil && !isRedisError(err) { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @@ -469,15 +506,15 @@ func (c *baseClient) txPipelineProcessCmds( | |||||||
| 	return false, err | 	return false, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func wrapMultiExec(cmds []Cmder) []Cmder { | func wrapMultiExec(ctx context.Context, cmds []Cmder) []Cmder { | ||||||
| 	if len(cmds) == 0 { | 	if len(cmds) == 0 { | ||||||
| 		panic("not reached") | 		panic("not reached") | ||||||
| 	} | 	} | ||||||
| 	cmds = append(cmds, make([]Cmder, 2)...) | 	cmdCopy := make([]Cmder, len(cmds)+2) | ||||||
| 	copy(cmds[1:], cmds[:len(cmds)-2]) | 	cmdCopy[0] = NewStatusCmd(ctx, "multi") | ||||||
| 	cmds[0] = NewStatusCmd("multi") | 	copy(cmdCopy[1:], cmds) | ||||||
| 	cmds[len(cmds)-1] = NewSliceCmd("exec") | 	cmdCopy[len(cmdCopy)-1] = NewSliceCmd(ctx, "exec") | ||||||
| 	return cmds | 	return cmdCopy | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func txPipelineReadQueued(rd *proto.Reader, statusCmd *StatusCmd, cmds []Cmder) error { | func txPipelineReadQueued(rd *proto.Reader, statusCmd *StatusCmd, cmds []Cmder) error { | ||||||
| @@ -565,26 +602,18 @@ func (c *Client) WithContext(ctx context.Context) *Client { | |||||||
| 	return clone | 	return clone | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Client) Conn() *Conn { | func (c *Client) Conn(ctx context.Context) *Conn { | ||||||
| 	return newConn(c.ctx, c.opt, pool.NewSingleConnPool(c.connPool)) | 	return newConn(ctx, c.opt, pool.NewStickyConnPool(c.connPool)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Do creates a Cmd from the args and processes the cmd. | // Do creates a Cmd from the args and processes the cmd. | ||||||
| func (c *Client) Do(args ...interface{}) *Cmd { | func (c *Client) Do(ctx context.Context, args ...interface{}) *Cmd { | ||||||
| 	return c.DoContext(c.ctx, args...) | 	cmd := NewCmd(ctx, args...) | ||||||
| } | 	_ = c.Process(ctx, cmd) | ||||||
| 
 |  | ||||||
| func (c *Client) DoContext(ctx context.Context, args ...interface{}) *Cmd { |  | ||||||
| 	cmd := NewCmd(args...) |  | ||||||
| 	_ = c.ProcessContext(ctx, cmd) |  | ||||||
| 	return cmd | 	return cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Client) Process(cmd Cmder) error { | func (c *Client) Process(ctx context.Context, cmd Cmder) error { | ||||||
| 	return c.ProcessContext(c.ctx, cmd) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *Client) ProcessContext(ctx context.Context, cmd Cmder) error { |  | ||||||
| 	return c.hooks.process(ctx, cmd, c.baseClient.process) | 	return c.hooks.process(ctx, cmd, c.baseClient.process) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -609,8 +638,8 @@ func (c *Client) PoolStats() *PoolStats { | |||||||
| 	return (*PoolStats)(stats) | 	return (*PoolStats)(stats) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Client) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Client) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
| 	return c.Pipeline().Pipelined(fn) | 	return c.Pipeline().Pipelined(ctx, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Client) Pipeline() Pipeliner { | func (c *Client) Pipeline() Pipeliner { | ||||||
| @@ -622,8 +651,8 @@ func (c *Client) Pipeline() Pipeliner { | |||||||
| 	return &pipe | 	return &pipe | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Client) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Client) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
| 	return c.TxPipeline().Pipelined(fn) | 	return c.TxPipeline().Pipelined(ctx, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. | // TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. | ||||||
| @@ -640,8 +669,8 @@ func (c *Client) pubSub() *PubSub { | |||||||
| 	pubsub := &PubSub{ | 	pubsub := &PubSub{ | ||||||
| 		opt: c.opt, | 		opt: c.opt, | ||||||
| 
 | 
 | ||||||
| 		newConn: func(channels []string) (*pool.Conn, error) { | 		newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) { | ||||||
| 			return c.newConn(context.TODO()) | 			return c.newConn(ctx) | ||||||
| 		}, | 		}, | ||||||
| 		closeConn: c.connPool.CloseConn, | 		closeConn: c.connPool.CloseConn, | ||||||
| 	} | 	} | ||||||
| @@ -675,20 +704,20 @@ func (c *Client) pubSub() *PubSub { | |||||||
| //    } | //    } | ||||||
| // | // | ||||||
| //    ch := sub.Channel() | //    ch := sub.Channel() | ||||||
| func (c *Client) Subscribe(channels ...string) *PubSub { | func (c *Client) Subscribe(ctx context.Context, channels ...string) *PubSub { | ||||||
| 	pubsub := c.pubSub() | 	pubsub := c.pubSub() | ||||||
| 	if len(channels) > 0 { | 	if len(channels) > 0 { | ||||||
| 		_ = pubsub.Subscribe(channels...) | 		_ = pubsub.Subscribe(ctx, channels...) | ||||||
| 	} | 	} | ||||||
| 	return pubsub | 	return pubsub | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // PSubscribe subscribes the client to the given patterns. | // PSubscribe subscribes the client to the given patterns. | ||||||
| // Patterns can be omitted to create empty subscription. | // Patterns can be omitted to create empty subscription. | ||||||
| func (c *Client) PSubscribe(channels ...string) *PubSub { | func (c *Client) PSubscribe(ctx context.Context, channels ...string) *PubSub { | ||||||
| 	pubsub := c.pubSub() | 	pubsub := c.pubSub() | ||||||
| 	if len(channels) > 0 { | 	if len(channels) > 0 { | ||||||
| 		_ = pubsub.PSubscribe(channels...) | 		_ = pubsub.PSubscribe(ctx, channels...) | ||||||
| 	} | 	} | ||||||
| 	return pubsub | 	return pubsub | ||||||
| } | } | ||||||
| @@ -699,6 +728,7 @@ type conn struct { | |||||||
| 	baseClient | 	baseClient | ||||||
| 	cmdable | 	cmdable | ||||||
| 	statefulCmdable | 	statefulCmdable | ||||||
|  | 	hooks // TODO: inherit hooks | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Conn is like Client, but its pool contains single connection. | // Conn is like Client, but its pool contains single connection. | ||||||
| @@ -722,16 +752,20 @@ func newConn(ctx context.Context, opt *Options, connPool pool.Pooler) *Conn { | |||||||
| 	return &c | 	return &c | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Conn) Process(cmd Cmder) error { | func (c *Conn) Process(ctx context.Context, cmd Cmder) error { | ||||||
| 	return c.ProcessContext(c.ctx, cmd) | 	return c.hooks.process(ctx, cmd, c.baseClient.process) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Conn) ProcessContext(ctx context.Context, cmd Cmder) error { | func (c *Conn) processPipeline(ctx context.Context, cmds []Cmder) error { | ||||||
| 	return c.baseClient.process(ctx, cmd) | 	return c.hooks.processPipeline(ctx, cmds, c.baseClient.processPipeline) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Conn) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Conn) processTxPipeline(ctx context.Context, cmds []Cmder) error { | ||||||
| 	return c.Pipeline().Pipelined(fn) | 	return c.hooks.processTxPipeline(ctx, cmds, c.baseClient.processTxPipeline) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *Conn) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
|  | 	return c.Pipeline().Pipelined(ctx, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Conn) Pipeline() Pipeliner { | func (c *Conn) Pipeline() Pipeliner { | ||||||
| @@ -743,8 +777,8 @@ func (c *Conn) Pipeline() Pipeliner { | |||||||
| 	return &pipe | 	return &pipe | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Conn) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Conn) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
| 	return c.TxPipeline().Pipelined(fn) | 	return c.TxPipeline().Pipelined(ctx, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. | // TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. | ||||||
| @@ -2,7 +2,7 @@ package redis | |||||||
| 
 | 
 | ||||||
| import "time" | import "time" | ||||||
| 
 | 
 | ||||||
| // NewCmdResult returns a Cmd initialised with val and err for testing | // NewCmdResult returns a Cmd initialised with val and err for testing. | ||||||
| func NewCmdResult(val interface{}, err error) *Cmd { | func NewCmdResult(val interface{}, err error) *Cmd { | ||||||
| 	var cmd Cmd | 	var cmd Cmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -10,7 +10,7 @@ func NewCmdResult(val interface{}, err error) *Cmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewSliceResult returns a SliceCmd initialised with val and err for testing | // NewSliceResult returns a SliceCmd initialised with val and err for testing. | ||||||
| func NewSliceResult(val []interface{}, err error) *SliceCmd { | func NewSliceResult(val []interface{}, err error) *SliceCmd { | ||||||
| 	var cmd SliceCmd | 	var cmd SliceCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -18,7 +18,7 @@ func NewSliceResult(val []interface{}, err error) *SliceCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewStatusResult returns a StatusCmd initialised with val and err for testing | // NewStatusResult returns a StatusCmd initialised with val and err for testing. | ||||||
| func NewStatusResult(val string, err error) *StatusCmd { | func NewStatusResult(val string, err error) *StatusCmd { | ||||||
| 	var cmd StatusCmd | 	var cmd StatusCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -26,7 +26,7 @@ func NewStatusResult(val string, err error) *StatusCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewIntResult returns an IntCmd initialised with val and err for testing | // NewIntResult returns an IntCmd initialised with val and err for testing. | ||||||
| func NewIntResult(val int64, err error) *IntCmd { | func NewIntResult(val int64, err error) *IntCmd { | ||||||
| 	var cmd IntCmd | 	var cmd IntCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -34,7 +34,7 @@ func NewIntResult(val int64, err error) *IntCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewDurationResult returns a DurationCmd initialised with val and err for testing | // NewDurationResult returns a DurationCmd initialised with val and err for testing. | ||||||
| func NewDurationResult(val time.Duration, err error) *DurationCmd { | func NewDurationResult(val time.Duration, err error) *DurationCmd { | ||||||
| 	var cmd DurationCmd | 	var cmd DurationCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -42,7 +42,7 @@ func NewDurationResult(val time.Duration, err error) *DurationCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewBoolResult returns a BoolCmd initialised with val and err for testing | // NewBoolResult returns a BoolCmd initialised with val and err for testing. | ||||||
| func NewBoolResult(val bool, err error) *BoolCmd { | func NewBoolResult(val bool, err error) *BoolCmd { | ||||||
| 	var cmd BoolCmd | 	var cmd BoolCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -50,7 +50,7 @@ func NewBoolResult(val bool, err error) *BoolCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewStringResult returns a StringCmd initialised with val and err for testing | // NewStringResult returns a StringCmd initialised with val and err for testing. | ||||||
| func NewStringResult(val string, err error) *StringCmd { | func NewStringResult(val string, err error) *StringCmd { | ||||||
| 	var cmd StringCmd | 	var cmd StringCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -58,7 +58,7 @@ func NewStringResult(val string, err error) *StringCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewFloatResult returns a FloatCmd initialised with val and err for testing | // NewFloatResult returns a FloatCmd initialised with val and err for testing. | ||||||
| func NewFloatResult(val float64, err error) *FloatCmd { | func NewFloatResult(val float64, err error) *FloatCmd { | ||||||
| 	var cmd FloatCmd | 	var cmd FloatCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -66,7 +66,7 @@ func NewFloatResult(val float64, err error) *FloatCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewStringSliceResult returns a StringSliceCmd initialised with val and err for testing | // NewStringSliceResult returns a StringSliceCmd initialised with val and err for testing. | ||||||
| func NewStringSliceResult(val []string, err error) *StringSliceCmd { | func NewStringSliceResult(val []string, err error) *StringSliceCmd { | ||||||
| 	var cmd StringSliceCmd | 	var cmd StringSliceCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -74,7 +74,7 @@ func NewStringSliceResult(val []string, err error) *StringSliceCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewBoolSliceResult returns a BoolSliceCmd initialised with val and err for testing | // NewBoolSliceResult returns a BoolSliceCmd initialised with val and err for testing. | ||||||
| func NewBoolSliceResult(val []bool, err error) *BoolSliceCmd { | func NewBoolSliceResult(val []bool, err error) *BoolSliceCmd { | ||||||
| 	var cmd BoolSliceCmd | 	var cmd BoolSliceCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -82,7 +82,7 @@ func NewBoolSliceResult(val []bool, err error) *BoolSliceCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewStringStringMapResult returns a StringStringMapCmd initialised with val and err for testing | // NewStringStringMapResult returns a StringStringMapCmd initialised with val and err for testing. | ||||||
| func NewStringStringMapResult(val map[string]string, err error) *StringStringMapCmd { | func NewStringStringMapResult(val map[string]string, err error) *StringStringMapCmd { | ||||||
| 	var cmd StringStringMapCmd | 	var cmd StringStringMapCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -90,7 +90,7 @@ func NewStringStringMapResult(val map[string]string, err error) *StringStringMap | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewStringIntMapCmdResult returns a StringIntMapCmd initialised with val and err for testing | // NewStringIntMapCmdResult returns a StringIntMapCmd initialised with val and err for testing. | ||||||
| func NewStringIntMapCmdResult(val map[string]int64, err error) *StringIntMapCmd { | func NewStringIntMapCmdResult(val map[string]int64, err error) *StringIntMapCmd { | ||||||
| 	var cmd StringIntMapCmd | 	var cmd StringIntMapCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -98,7 +98,7 @@ func NewStringIntMapCmdResult(val map[string]int64, err error) *StringIntMapCmd | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewTimeCmdResult returns a TimeCmd initialised with val and err for testing | // NewTimeCmdResult returns a TimeCmd initialised with val and err for testing. | ||||||
| func NewTimeCmdResult(val time.Time, err error) *TimeCmd { | func NewTimeCmdResult(val time.Time, err error) *TimeCmd { | ||||||
| 	var cmd TimeCmd | 	var cmd TimeCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -106,7 +106,7 @@ func NewTimeCmdResult(val time.Time, err error) *TimeCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewZSliceCmdResult returns a ZSliceCmd initialised with val and err for testing | // NewZSliceCmdResult returns a ZSliceCmd initialised with val and err for testing. | ||||||
| func NewZSliceCmdResult(val []Z, err error) *ZSliceCmd { | func NewZSliceCmdResult(val []Z, err error) *ZSliceCmd { | ||||||
| 	var cmd ZSliceCmd | 	var cmd ZSliceCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -114,7 +114,7 @@ func NewZSliceCmdResult(val []Z, err error) *ZSliceCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewZWithKeyCmdResult returns a NewZWithKeyCmd initialised with val and err for testing | // NewZWithKeyCmdResult returns a NewZWithKeyCmd initialised with val and err for testing. | ||||||
| func NewZWithKeyCmdResult(val *ZWithKey, err error) *ZWithKeyCmd { | func NewZWithKeyCmdResult(val *ZWithKey, err error) *ZWithKeyCmd { | ||||||
| 	var cmd ZWithKeyCmd | 	var cmd ZWithKeyCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -122,7 +122,7 @@ func NewZWithKeyCmdResult(val *ZWithKey, err error) *ZWithKeyCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewScanCmdResult returns a ScanCmd initialised with val and err for testing | // NewScanCmdResult returns a ScanCmd initialised with val and err for testing. | ||||||
| func NewScanCmdResult(keys []string, cursor uint64, err error) *ScanCmd { | func NewScanCmdResult(keys []string, cursor uint64, err error) *ScanCmd { | ||||||
| 	var cmd ScanCmd | 	var cmd ScanCmd | ||||||
| 	cmd.page = keys | 	cmd.page = keys | ||||||
| @@ -131,7 +131,7 @@ func NewScanCmdResult(keys []string, cursor uint64, err error) *ScanCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewClusterSlotsCmdResult returns a ClusterSlotsCmd initialised with val and err for testing | // NewClusterSlotsCmdResult returns a ClusterSlotsCmd initialised with val and err for testing. | ||||||
| func NewClusterSlotsCmdResult(val []ClusterSlot, err error) *ClusterSlotsCmd { | func NewClusterSlotsCmdResult(val []ClusterSlot, err error) *ClusterSlotsCmd { | ||||||
| 	var cmd ClusterSlotsCmd | 	var cmd ClusterSlotsCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -139,7 +139,7 @@ func NewClusterSlotsCmdResult(val []ClusterSlot, err error) *ClusterSlotsCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewGeoLocationCmdResult returns a GeoLocationCmd initialised with val and err for testing | // NewGeoLocationCmdResult returns a GeoLocationCmd initialised with val and err for testing. | ||||||
| func NewGeoLocationCmdResult(val []GeoLocation, err error) *GeoLocationCmd { | func NewGeoLocationCmdResult(val []GeoLocation, err error) *GeoLocationCmd { | ||||||
| 	var cmd GeoLocationCmd | 	var cmd GeoLocationCmd | ||||||
| 	cmd.locations = val | 	cmd.locations = val | ||||||
| @@ -147,7 +147,7 @@ func NewGeoLocationCmdResult(val []GeoLocation, err error) *GeoLocationCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewGeoPosCmdResult returns a GeoPosCmd initialised with val and err for testing | // NewGeoPosCmdResult returns a GeoPosCmd initialised with val and err for testing. | ||||||
| func NewGeoPosCmdResult(val []*GeoPos, err error) *GeoPosCmd { | func NewGeoPosCmdResult(val []*GeoPos, err error) *GeoPosCmd { | ||||||
| 	var cmd GeoPosCmd | 	var cmd GeoPosCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -155,7 +155,7 @@ func NewGeoPosCmdResult(val []*GeoPos, err error) *GeoPosCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewCommandsInfoCmdResult returns a CommandsInfoCmd initialised with val and err for testing | // NewCommandsInfoCmdResult returns a CommandsInfoCmd initialised with val and err for testing. | ||||||
| func NewCommandsInfoCmdResult(val map[string]*CommandInfo, err error) *CommandsInfoCmd { | func NewCommandsInfoCmdResult(val map[string]*CommandInfo, err error) *CommandsInfoCmd { | ||||||
| 	var cmd CommandsInfoCmd | 	var cmd CommandsInfoCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -163,7 +163,7 @@ func NewCommandsInfoCmdResult(val map[string]*CommandInfo, err error) *CommandsI | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewXMessageSliceCmdResult returns a XMessageSliceCmd initialised with val and err for testing | // NewXMessageSliceCmdResult returns a XMessageSliceCmd initialised with val and err for testing. | ||||||
| func NewXMessageSliceCmdResult(val []XMessage, err error) *XMessageSliceCmd { | func NewXMessageSliceCmdResult(val []XMessage, err error) *XMessageSliceCmd { | ||||||
| 	var cmd XMessageSliceCmd | 	var cmd XMessageSliceCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
| @@ -171,7 +171,7 @@ func NewXMessageSliceCmdResult(val []XMessage, err error) *XMessageSliceCmd { | |||||||
| 	return &cmd | 	return &cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewXStreamSliceCmdResult returns a XStreamSliceCmd initialised with val and err for testing | // NewXStreamSliceCmdResult returns a XStreamSliceCmd initialised with val and err for testing. | ||||||
| func NewXStreamSliceCmdResult(val []XStream, err error) *XStreamSliceCmd { | func NewXStreamSliceCmdResult(val []XStream, err error) *XStreamSliceCmd { | ||||||
| 	var cmd XStreamSliceCmd | 	var cmd XStreamSliceCmd | ||||||
| 	cmd.val = val | 	cmd.val = val | ||||||
							
								
								
									
										349
									
								
								vendor/github.com/go-redis/redis/v7/ring.go → vendor/github.com/go-redis/redis/v8/ring.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										349
									
								
								vendor/github.com/go-redis/redis/v7/ring.go → vendor/github.com/go-redis/redis/v8/ring.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,72 +2,73 @@ package redis | |||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"crypto/tls" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"math/rand" | 	"net" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"sync/atomic" | 	"sync/atomic" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal" | 	"github.com/cespare/xxhash/v2" | ||||||
| 	"github.com/go-redis/redis/v7/internal/consistenthash" | 	"github.com/dgryski/go-rendezvous" | ||||||
| 	"github.com/go-redis/redis/v7/internal/hashtag" | 	"github.com/go-redis/redis/v8/internal" | ||||||
| 	"github.com/go-redis/redis/v7/internal/pool" | 	"github.com/go-redis/redis/v8/internal/hashtag" | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/pool" | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/rand" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Hash is type of hash function used in consistent hash. |  | ||||||
| type Hash consistenthash.Hash |  | ||||||
| 
 |  | ||||||
| var errRingShardsDown = errors.New("redis: all ring shards are down") | var errRingShardsDown = errors.New("redis: all ring shards are down") | ||||||
| 
 | 
 | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | 
 | ||||||
|  | type ConsistentHash interface { | ||||||
|  | 	Get(string) string | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type rendezvousWrapper struct { | ||||||
|  | 	*rendezvous.Rendezvous | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (w rendezvousWrapper) Get(key string) string { | ||||||
|  | 	return w.Lookup(key) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func newRendezvous(shards []string) ConsistentHash { | ||||||
|  | 	return rendezvousWrapper{rendezvous.New(shards, xxhash.Sum64String)} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  | 
 | ||||||
| // RingOptions are used to configure a ring client and should be | // RingOptions are used to configure a ring client and should be | ||||||
| // passed to NewRing. | // passed to NewRing. | ||||||
| type RingOptions struct { | type RingOptions struct { | ||||||
| 	// Map of name => host:port addresses of ring shards. | 	// Map of name => host:port addresses of ring shards. | ||||||
| 	Addrs map[string]string | 	Addrs map[string]string | ||||||
| 
 | 
 | ||||||
| 	// Map of name => password of ring shards, to allow different shards to have | 	// NewClient creates a shard client with provided name and options. | ||||||
| 	// different passwords. It will be ignored if the Password field is set. | 	NewClient func(name string, opt *Options) *Client | ||||||
| 	Passwords map[string]string |  | ||||||
| 
 | 
 | ||||||
| 	// Frequency of PING commands sent to check shards availability. | 	// Frequency of PING commands sent to check shards availability. | ||||||
| 	// Shard is considered down after 3 subsequent failed checks. | 	// Shard is considered down after 3 subsequent failed checks. | ||||||
| 	HeartbeatFrequency time.Duration | 	HeartbeatFrequency time.Duration | ||||||
| 
 | 
 | ||||||
| 	// Hash function used in consistent hash. | 	// NewConsistentHash returns a consistent hash that is used | ||||||
| 	// Default is crc32.ChecksumIEEE. | 	// to distribute keys across the shards. | ||||||
| 	Hash Hash |  | ||||||
| 
 |  | ||||||
| 	// Number of replicas in consistent hash. |  | ||||||
| 	// Default is 100 replicas. |  | ||||||
| 	// | 	// | ||||||
| 	// Higher number of replicas will provide less deviation, that is keys will be | 	// See https://medium.com/@dgryski/consistent-hashing-algorithmic-tradeoffs-ef6b8e2fcae8 | ||||||
| 	// distributed to nodes more evenly. | 	// for consistent hashing algorithmic tradeoffs. | ||||||
| 	// | 	NewConsistentHash func(shards []string) ConsistentHash | ||||||
| 	// Following is deviation for common nreplicas: |  | ||||||
| 	//  -------------------------------------------------------- |  | ||||||
| 	//  | nreplicas | standard error | 99% confidence interval | |  | ||||||
| 	//  |     10    |     0.3152     |      (0.37, 1.98)       | |  | ||||||
| 	//  |    100    |     0.0997     |      (0.76, 1.28)       | |  | ||||||
| 	//  |   1000    |     0.0316     |      (0.92, 1.09)       | |  | ||||||
| 	//  -------------------------------------------------------- |  | ||||||
| 	// |  | ||||||
| 	//  See https://arxiv.org/abs/1406.2294 for reference |  | ||||||
| 	HashReplicas int |  | ||||||
| 
 |  | ||||||
| 	// NewClient creates a shard client with provided name and options. |  | ||||||
| 	NewClient func(name string, opt *Options) *Client |  | ||||||
| 
 |  | ||||||
| 	// Optional hook that is called when a new shard is created. |  | ||||||
| 	OnNewShard func(*Client) |  | ||||||
| 
 | 
 | ||||||
| 	// Following options are copied from Options struct. | 	// Following options are copied from Options struct. | ||||||
| 
 | 
 | ||||||
| 	OnConnect func(*Conn) error | 	Dialer    func(ctx context.Context, network, addr string) (net.Conn, error) | ||||||
|  | 	OnConnect func(ctx context.Context, cn *Conn) error | ||||||
| 
 | 
 | ||||||
| 	DB       int | 	Username string | ||||||
| 	Password string | 	Password string | ||||||
|  | 	DB       int | ||||||
| 
 | 
 | ||||||
| 	MaxRetries      int | 	MaxRetries      int | ||||||
| 	MinRetryBackoff time.Duration | 	MinRetryBackoff time.Duration | ||||||
| @@ -83,17 +84,31 @@ type RingOptions struct { | |||||||
| 	PoolTimeout        time.Duration | 	PoolTimeout        time.Duration | ||||||
| 	IdleTimeout        time.Duration | 	IdleTimeout        time.Duration | ||||||
| 	IdleCheckFrequency time.Duration | 	IdleCheckFrequency time.Duration | ||||||
|  | 
 | ||||||
|  | 	TLSConfig *tls.Config | ||||||
|  | 	Limiter   Limiter | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (opt *RingOptions) init() { | func (opt *RingOptions) init() { | ||||||
|  | 	if opt.NewClient == nil { | ||||||
|  | 		opt.NewClient = func(name string, opt *Options) *Client { | ||||||
|  | 			return NewClient(opt) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if opt.HeartbeatFrequency == 0 { | 	if opt.HeartbeatFrequency == 0 { | ||||||
| 		opt.HeartbeatFrequency = 500 * time.Millisecond | 		opt.HeartbeatFrequency = 500 * time.Millisecond | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if opt.HashReplicas == 0 { | 	if opt.NewConsistentHash == nil { | ||||||
| 		opt.HashReplicas = 100 | 		opt.NewConsistentHash = newRendezvous | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if opt.MaxRetries == -1 { | ||||||
|  | 		opt.MaxRetries = 0 | ||||||
|  | 	} else if opt.MaxRetries == 0 { | ||||||
|  | 		opt.MaxRetries = 3 | ||||||
|  | 	} | ||||||
| 	switch opt.MinRetryBackoff { | 	switch opt.MinRetryBackoff { | ||||||
| 	case -1: | 	case -1: | ||||||
| 		opt.MinRetryBackoff = 0 | 		opt.MinRetryBackoff = 0 | ||||||
| @@ -108,12 +123,16 @@ func (opt *RingOptions) init() { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (opt *RingOptions) clientOptions(shard string) *Options { | func (opt *RingOptions) clientOptions() *Options { | ||||||
| 	return &Options{ | 	return &Options{ | ||||||
|  | 		Dialer:    opt.Dialer, | ||||||
| 		OnConnect: opt.OnConnect, | 		OnConnect: opt.OnConnect, | ||||||
| 
 | 
 | ||||||
|  | 		Username: opt.Username, | ||||||
|  | 		Password: opt.Password, | ||||||
| 		DB:       opt.DB, | 		DB:       opt.DB, | ||||||
| 		Password: opt.getPassword(shard), | 
 | ||||||
|  | 		MaxRetries: -1, | ||||||
| 
 | 
 | ||||||
| 		DialTimeout:  opt.DialTimeout, | 		DialTimeout:  opt.DialTimeout, | ||||||
| 		ReadTimeout:  opt.ReadTimeout, | 		ReadTimeout:  opt.ReadTimeout, | ||||||
| @@ -125,14 +144,10 @@ func (opt *RingOptions) clientOptions(shard string) *Options { | |||||||
| 		PoolTimeout:        opt.PoolTimeout, | 		PoolTimeout:        opt.PoolTimeout, | ||||||
| 		IdleTimeout:        opt.IdleTimeout, | 		IdleTimeout:        opt.IdleTimeout, | ||||||
| 		IdleCheckFrequency: opt.IdleCheckFrequency, | 		IdleCheckFrequency: opt.IdleCheckFrequency, | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| func (opt *RingOptions) getPassword(shard string) string { | 		TLSConfig: opt.TLSConfig, | ||||||
| 	if opt.Password == "" { | 		Limiter:   opt.Limiter, | ||||||
| 		return opt.Passwords[shard] |  | ||||||
| 	} | 	} | ||||||
| 	return opt.Password |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
| @@ -142,6 +157,15 @@ type ringShard struct { | |||||||
| 	down   int32 | 	down   int32 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func newRingShard(opt *RingOptions, name, addr string) *ringShard { | ||||||
|  | 	clopt := opt.clientOptions() | ||||||
|  | 	clopt.Addr = addr | ||||||
|  | 
 | ||||||
|  | 	return &ringShard{ | ||||||
|  | 		Client: opt.NewClient(name, clopt), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (shard *ringShard) String() string { | func (shard *ringShard) String() string { | ||||||
| 	var state string | 	var state string | ||||||
| 	if shard.IsUp() { | 	if shard.IsUp() { | ||||||
| @@ -182,41 +206,59 @@ func (shard *ringShard) Vote(up bool) bool { | |||||||
| type ringShards struct { | type ringShards struct { | ||||||
| 	opt *RingOptions | 	opt *RingOptions | ||||||
| 
 | 
 | ||||||
| 	mu     sync.RWMutex | 	mu       sync.RWMutex | ||||||
| 	hash   *consistenthash.Map | 	hash     ConsistentHash | ||||||
| 	shards map[string]*ringShard // read only | 	shards   map[string]*ringShard // read only | ||||||
| 	list   []*ringShard          // read only | 	list     []*ringShard          // read only | ||||||
| 	len    int | 	numShard int | ||||||
| 	closed bool | 	closed   bool | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func newRingShards(opt *RingOptions) *ringShards { | func newRingShards(opt *RingOptions) *ringShards { | ||||||
| 	return &ringShards{ | 	shards := make(map[string]*ringShard, len(opt.Addrs)) | ||||||
|  | 	list := make([]*ringShard, 0, len(shards)) | ||||||
|  | 
 | ||||||
|  | 	for name, addr := range opt.Addrs { | ||||||
|  | 		shard := newRingShard(opt, name, addr) | ||||||
|  | 		shards[name] = shard | ||||||
|  | 
 | ||||||
|  | 		list = append(list, shard) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	c := &ringShards{ | ||||||
| 		opt: opt, | 		opt: opt, | ||||||
| 
 | 
 | ||||||
| 		hash:   newConsistentHash(opt), | 		shards: shards, | ||||||
| 		shards: make(map[string]*ringShard), | 		list:   list, | ||||||
| 	} | 	} | ||||||
| } | 	c.rebalance() | ||||||
| 
 | 
 | ||||||
| func (c *ringShards) Add(name string, cl *Client) { | 	return c | ||||||
| 	shard := &ringShard{Client: cl} |  | ||||||
| 	c.hash.Add(name) |  | ||||||
| 	c.shards[name] = shard |  | ||||||
| 	c.list = append(c.list, shard) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *ringShards) List() []*ringShard { | func (c *ringShards) List() []*ringShard { | ||||||
|  | 	var list []*ringShard | ||||||
|  | 
 | ||||||
| 	c.mu.RLock() | 	c.mu.RLock() | ||||||
| 	list := c.list | 	if !c.closed { | ||||||
|  | 		list = c.list | ||||||
|  | 	} | ||||||
| 	c.mu.RUnlock() | 	c.mu.RUnlock() | ||||||
|  | 
 | ||||||
| 	return list | 	return list | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *ringShards) Hash(key string) string { | func (c *ringShards) Hash(key string) string { | ||||||
|  | 	key = hashtag.Key(key) | ||||||
|  | 
 | ||||||
|  | 	var hash string | ||||||
|  | 
 | ||||||
| 	c.mu.RLock() | 	c.mu.RLock() | ||||||
| 	hash := c.hash.Get(key) | 	if c.numShard > 0 { | ||||||
|  | 		hash = c.hash.Get(key) | ||||||
|  | 	} | ||||||
| 	c.mu.RUnlock() | 	c.mu.RUnlock() | ||||||
|  | 
 | ||||||
| 	return hash | 	return hash | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -230,6 +272,11 @@ func (c *ringShards) GetByKey(key string) (*ringShard, error) { | |||||||
| 		return nil, pool.ErrClosed | 		return nil, pool.ErrClosed | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if c.numShard == 0 { | ||||||
|  | 		c.mu.RUnlock() | ||||||
|  | 		return nil, errRingShardsDown | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	hash := c.hash.Get(key) | 	hash := c.hash.Get(key) | ||||||
| 	if hash == "" { | 	if hash == "" { | ||||||
| 		c.mu.RUnlock() | 		c.mu.RUnlock() | ||||||
| @@ -242,13 +289,13 @@ func (c *ringShards) GetByKey(key string) (*ringShard, error) { | |||||||
| 	return shard, nil | 	return shard, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *ringShards) GetByHash(name string) (*ringShard, error) { | func (c *ringShards) GetByName(shardName string) (*ringShard, error) { | ||||||
| 	if name == "" { | 	if shardName == "" { | ||||||
| 		return c.Random() | 		return c.Random() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	c.mu.RLock() | 	c.mu.RLock() | ||||||
| 	shard := c.shards[name] | 	shard := c.shards[shardName] | ||||||
| 	c.mu.RUnlock() | 	c.mu.RUnlock() | ||||||
| 	return shard, nil | 	return shard, nil | ||||||
| } | } | ||||||
| @@ -261,23 +308,16 @@ func (c *ringShards) Random() (*ringShard, error) { | |||||||
| func (c *ringShards) Heartbeat(frequency time.Duration) { | func (c *ringShards) Heartbeat(frequency time.Duration) { | ||||||
| 	ticker := time.NewTicker(frequency) | 	ticker := time.NewTicker(frequency) | ||||||
| 	defer ticker.Stop() | 	defer ticker.Stop() | ||||||
|  | 
 | ||||||
|  | 	ctx := context.Background() | ||||||
| 	for range ticker.C { | 	for range ticker.C { | ||||||
| 		var rebalance bool | 		var rebalance bool | ||||||
| 
 | 
 | ||||||
| 		c.mu.RLock() | 		for _, shard := range c.List() { | ||||||
| 
 | 			err := shard.Client.Ping(ctx).Err() | ||||||
| 		if c.closed { | 			isUp := err == nil || err == pool.ErrPoolTimeout | ||||||
| 			c.mu.RUnlock() | 			if shard.Vote(isUp) { | ||||||
| 			break | 				internal.Logger.Printf(context.Background(), "ring shard state changed: %s", shard) | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		shards := c.list |  | ||||||
| 		c.mu.RUnlock() |  | ||||||
| 
 |  | ||||||
| 		for _, shard := range shards { |  | ||||||
| 			err := shard.Client.Ping().Err() |  | ||||||
| 			if shard.Vote(err == nil || err == pool.ErrPoolTimeout) { |  | ||||||
| 				internal.Logger.Printf("ring shard state changed: %s", shard) |  | ||||||
| 				rebalance = true | 				rebalance = true | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @@ -294,24 +334,25 @@ func (c *ringShards) rebalance() { | |||||||
| 	shards := c.shards | 	shards := c.shards | ||||||
| 	c.mu.RUnlock() | 	c.mu.RUnlock() | ||||||
| 
 | 
 | ||||||
| 	hash := newConsistentHash(c.opt) | 	liveShards := make([]string, 0, len(shards)) | ||||||
| 	var shardsNum int | 
 | ||||||
| 	for name, shard := range shards { | 	for name, shard := range shards { | ||||||
| 		if shard.IsUp() { | 		if shard.IsUp() { | ||||||
| 			hash.Add(name) | 			liveShards = append(liveShards, name) | ||||||
| 			shardsNum++ |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	hash := c.opt.NewConsistentHash(liveShards) | ||||||
|  | 
 | ||||||
| 	c.mu.Lock() | 	c.mu.Lock() | ||||||
| 	c.hash = hash | 	c.hash = hash | ||||||
| 	c.len = shardsNum | 	c.numShard = len(liveShards) | ||||||
| 	c.mu.Unlock() | 	c.mu.Unlock() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *ringShards) Len() int { | func (c *ringShards) Len() int { | ||||||
| 	c.mu.RLock() | 	c.mu.RLock() | ||||||
| 	l := c.len | 	l := c.numShard | ||||||
| 	c.mu.RUnlock() | 	c.mu.RUnlock() | ||||||
| 	return l | 	return l | ||||||
| } | } | ||||||
| @@ -377,34 +418,15 @@ func NewRing(opt *RingOptions) *Ring { | |||||||
| 		}, | 		}, | ||||||
| 		ctx: context.Background(), | 		ctx: context.Background(), | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	ring.cmdsInfoCache = newCmdsInfoCache(ring.cmdsInfo) | 	ring.cmdsInfoCache = newCmdsInfoCache(ring.cmdsInfo) | ||||||
| 	ring.cmdable = ring.Process | 	ring.cmdable = ring.Process | ||||||
| 
 | 
 | ||||||
| 	for name, addr := range opt.Addrs { |  | ||||||
| 		shard := newRingShard(opt, name, addr) |  | ||||||
| 		ring.shards.Add(name, shard) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	go ring.shards.Heartbeat(opt.HeartbeatFrequency) | 	go ring.shards.Heartbeat(opt.HeartbeatFrequency) | ||||||
| 
 | 
 | ||||||
| 	return &ring | 	return &ring | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func newRingShard(opt *RingOptions, name, addr string) *Client { |  | ||||||
| 	clopt := opt.clientOptions(name) |  | ||||||
| 	clopt.Addr = addr |  | ||||||
| 	var shard *Client |  | ||||||
| 	if opt.NewClient != nil { |  | ||||||
| 		shard = opt.NewClient(name, clopt) |  | ||||||
| 	} else { |  | ||||||
| 		shard = NewClient(clopt) |  | ||||||
| 	} |  | ||||||
| 	if opt.OnNewShard != nil { |  | ||||||
| 		opt.OnNewShard(shard) |  | ||||||
| 	} |  | ||||||
| 	return shard |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *Ring) Context() context.Context { | func (c *Ring) Context() context.Context { | ||||||
| 	return c.ctx | 	return c.ctx | ||||||
| } | } | ||||||
| @@ -421,21 +443,13 @@ func (c *Ring) WithContext(ctx context.Context) *Ring { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Do creates a Cmd from the args and processes the cmd. | // Do creates a Cmd from the args and processes the cmd. | ||||||
| func (c *Ring) Do(args ...interface{}) *Cmd { | func (c *Ring) Do(ctx context.Context, args ...interface{}) *Cmd { | ||||||
| 	return c.DoContext(c.ctx, args...) | 	cmd := NewCmd(ctx, args...) | ||||||
| } | 	_ = c.Process(ctx, cmd) | ||||||
| 
 |  | ||||||
| func (c *Ring) DoContext(ctx context.Context, args ...interface{}) *Cmd { |  | ||||||
| 	cmd := NewCmd(args...) |  | ||||||
| 	_ = c.ProcessContext(ctx, cmd) |  | ||||||
| 	return cmd | 	return cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Ring) Process(cmd Cmder) error { | func (c *Ring) Process(ctx context.Context, cmd Cmder) error { | ||||||
| 	return c.ProcessContext(c.ctx, cmd) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *Ring) ProcessContext(ctx context.Context, cmd Cmder) error { |  | ||||||
| 	return c.hooks.process(ctx, cmd, c.process) | 	return c.hooks.process(ctx, cmd, c.process) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -469,36 +483,39 @@ func (c *Ring) Len() int { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Subscribe subscribes the client to the specified channels. | // Subscribe subscribes the client to the specified channels. | ||||||
| func (c *Ring) Subscribe(channels ...string) *PubSub { | func (c *Ring) Subscribe(ctx context.Context, channels ...string) *PubSub { | ||||||
| 	if len(channels) == 0 { | 	if len(channels) == 0 { | ||||||
| 		panic("at least one channel is required") | 		panic("at least one channel is required") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	shard, err := c.shards.GetByKey(channels[0]) | 	shard, err := c.shards.GetByKey(channels[0]) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		//TODO: return PubSub with sticky error | 		// TODO: return PubSub with sticky error | ||||||
| 		panic(err) | 		panic(err) | ||||||
| 	} | 	} | ||||||
| 	return shard.Client.Subscribe(channels...) | 	return shard.Client.Subscribe(ctx, channels...) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // PSubscribe subscribes the client to the given patterns. | // PSubscribe subscribes the client to the given patterns. | ||||||
| func (c *Ring) PSubscribe(channels ...string) *PubSub { | func (c *Ring) PSubscribe(ctx context.Context, channels ...string) *PubSub { | ||||||
| 	if len(channels) == 0 { | 	if len(channels) == 0 { | ||||||
| 		panic("at least one channel is required") | 		panic("at least one channel is required") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	shard, err := c.shards.GetByKey(channels[0]) | 	shard, err := c.shards.GetByKey(channels[0]) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		//TODO: return PubSub with sticky error | 		// TODO: return PubSub with sticky error | ||||||
| 		panic(err) | 		panic(err) | ||||||
| 	} | 	} | ||||||
| 	return shard.Client.PSubscribe(channels...) | 	return shard.Client.PSubscribe(ctx, channels...) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ForEachShard concurrently calls the fn on each live shard in the ring. | // ForEachShard concurrently calls the fn on each live shard in the ring. | ||||||
| // It returns the first error if any. | // It returns the first error if any. | ||||||
| func (c *Ring) ForEachShard(fn func(client *Client) error) error { | func (c *Ring) ForEachShard( | ||||||
|  | 	ctx context.Context, | ||||||
|  | 	fn func(ctx context.Context, client *Client) error, | ||||||
|  | ) error { | ||||||
| 	shards := c.shards.List() | 	shards := c.shards.List() | ||||||
| 	var wg sync.WaitGroup | 	var wg sync.WaitGroup | ||||||
| 	errCh := make(chan error, 1) | 	errCh := make(chan error, 1) | ||||||
| @@ -510,7 +527,7 @@ func (c *Ring) ForEachShard(fn func(client *Client) error) error { | |||||||
| 		wg.Add(1) | 		wg.Add(1) | ||||||
| 		go func(shard *ringShard) { | 		go func(shard *ringShard) { | ||||||
| 			defer wg.Done() | 			defer wg.Done() | ||||||
| 			err := fn(shard.Client) | 			err := fn(ctx, shard.Client) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				select { | 				select { | ||||||
| 				case errCh <- err: | 				case errCh <- err: | ||||||
| @@ -529,11 +546,11 @@ func (c *Ring) ForEachShard(fn func(client *Client) error) error { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Ring) cmdsInfo() (map[string]*CommandInfo, error) { | func (c *Ring) cmdsInfo(ctx context.Context) (map[string]*CommandInfo, error) { | ||||||
| 	shards := c.shards.List() | 	shards := c.shards.List() | ||||||
| 	firstErr := errRingShardsDown | 	var firstErr error | ||||||
| 	for _, shard := range shards { | 	for _, shard := range shards { | ||||||
| 		cmdsInfo, err := shard.Client.Command().Result() | 		cmdsInfo, err := shard.Client.Command(ctx).Result() | ||||||
| 		if err == nil { | 		if err == nil { | ||||||
| 			return cmdsInfo, nil | 			return cmdsInfo, nil | ||||||
| 		} | 		} | ||||||
| @@ -541,23 +558,26 @@ func (c *Ring) cmdsInfo() (map[string]*CommandInfo, error) { | |||||||
| 			firstErr = err | 			firstErr = err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	if firstErr == nil { | ||||||
|  | 		return nil, errRingShardsDown | ||||||
|  | 	} | ||||||
| 	return nil, firstErr | 	return nil, firstErr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Ring) cmdInfo(name string) *CommandInfo { | func (c *Ring) cmdInfo(ctx context.Context, name string) *CommandInfo { | ||||||
| 	cmdsInfo, err := c.cmdsInfoCache.Get() | 	cmdsInfo, err := c.cmdsInfoCache.Get(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	info := cmdsInfo[name] | 	info := cmdsInfo[name] | ||||||
| 	if info == nil { | 	if info == nil { | ||||||
| 		internal.Logger.Printf("info for cmd=%s not found", name) | 		internal.Logger.Printf(c.Context(), "info for cmd=%s not found", name) | ||||||
| 	} | 	} | ||||||
| 	return info | 	return info | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) { | func (c *Ring) cmdShard(ctx context.Context, cmd Cmder) (*ringShard, error) { | ||||||
| 	cmdInfo := c.cmdInfo(cmd.Name()) | 	cmdInfo := c.cmdInfo(ctx, cmd.Name()) | ||||||
| 	pos := cmdFirstKeyPos(cmd, cmdInfo) | 	pos := cmdFirstKeyPos(cmd, cmdInfo) | ||||||
| 	if pos == 0 { | 	if pos == 0 { | ||||||
| 		return c.shards.Random() | 		return c.shards.Random() | ||||||
| @@ -567,15 +587,6 @@ func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Ring) process(ctx context.Context, cmd Cmder) error { | func (c *Ring) process(ctx context.Context, cmd Cmder) error { | ||||||
| 	err := c._process(ctx, cmd) |  | ||||||
| 	if err != nil { |  | ||||||
| 		cmd.SetErr(err) |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *Ring) _process(ctx context.Context, cmd Cmder) error { |  | ||||||
| 	var lastErr error | 	var lastErr error | ||||||
| 	for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ { | 	for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ { | ||||||
| 		if attempt > 0 { | 		if attempt > 0 { | ||||||
| @@ -584,21 +595,21 @@ func (c *Ring) _process(ctx context.Context, cmd Cmder) error { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		shard, err := c.cmdShard(cmd) | 		shard, err := c.cmdShard(ctx, cmd) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		lastErr = shard.Client.ProcessContext(ctx, cmd) | 		lastErr = shard.Client.Process(ctx, cmd) | ||||||
| 		if lastErr == nil || !isRetryableError(lastErr, cmd.readTimeout() == nil) { | 		if lastErr == nil || !shouldRetry(lastErr, cmd.readTimeout() == nil) { | ||||||
| 			return lastErr | 			return lastErr | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return lastErr | 	return lastErr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Ring) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Ring) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
| 	return c.Pipeline().Pipelined(fn) | 	return c.Pipeline().Pipelined(ctx, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Ring) Pipeline() Pipeliner { | func (c *Ring) Pipeline() Pipeliner { | ||||||
| @@ -616,8 +627,8 @@ func (c *Ring) processPipeline(ctx context.Context, cmds []Cmder) error { | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Ring) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Ring) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
| 	return c.TxPipeline().Pipelined(fn) | 	return c.TxPipeline().Pipelined(ctx, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Ring) TxPipeline() Pipeliner { | func (c *Ring) TxPipeline() Pipeliner { | ||||||
| @@ -640,10 +651,10 @@ func (c *Ring) generalProcessPipeline( | |||||||
| ) error { | ) error { | ||||||
| 	cmdsMap := make(map[string][]Cmder) | 	cmdsMap := make(map[string][]Cmder) | ||||||
| 	for _, cmd := range cmds { | 	for _, cmd := range cmds { | ||||||
| 		cmdInfo := c.cmdInfo(cmd.Name()) | 		cmdInfo := c.cmdInfo(ctx, cmd.Name()) | ||||||
| 		hash := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo)) | 		hash := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo)) | ||||||
| 		if hash != "" { | 		if hash != "" { | ||||||
| 			hash = c.shards.Hash(hashtag.Key(hash)) | 			hash = c.shards.Hash(hash) | ||||||
| 		} | 		} | ||||||
| 		cmdsMap[hash] = append(cmdsMap[hash], cmd) | 		cmdsMap[hash] = append(cmdsMap[hash], cmd) | ||||||
| 	} | 	} | ||||||
| @@ -665,30 +676,20 @@ func (c *Ring) generalProcessPipeline( | |||||||
| func (c *Ring) processShardPipeline( | func (c *Ring) processShardPipeline( | ||||||
| 	ctx context.Context, hash string, cmds []Cmder, tx bool, | 	ctx context.Context, hash string, cmds []Cmder, tx bool, | ||||||
| ) error { | ) error { | ||||||
| 	//TODO: retry? | 	// TODO: retry? | ||||||
| 	shard, err := c.shards.GetByHash(hash) | 	shard, err := c.shards.GetByName(hash) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		setCmdsErr(cmds, err) | 		setCmdsErr(cmds, err) | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if tx { | 	if tx { | ||||||
| 		err = shard.Client.processTxPipeline(ctx, cmds) | 		return shard.Client.processTxPipeline(ctx, cmds) | ||||||
| 	} else { |  | ||||||
| 		err = shard.Client.processPipeline(ctx, cmds) |  | ||||||
| 	} | 	} | ||||||
| 	return err | 	return shard.Client.processPipeline(ctx, cmds) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Close closes the ring client, releasing any open resources. | func (c *Ring) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error { | ||||||
| // |  | ||||||
| // It is rare to Close a Ring, as the Ring is meant to be long-lived |  | ||||||
| // and shared between many goroutines. |  | ||||||
| func (c *Ring) Close() error { |  | ||||||
| 	return c.shards.Close() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *Ring) Watch(fn func(*Tx) error, keys ...string) error { |  | ||||||
| 	if len(keys) == 0 { | 	if len(keys) == 0 { | ||||||
| 		return fmt.Errorf("redis: Watch requires at least one key") | 		return fmt.Errorf("redis: Watch requires at least one key") | ||||||
| 	} | 	} | ||||||
| @@ -718,9 +719,13 @@ func (c *Ring) Watch(fn func(*Tx) error, keys ...string) error { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return shards[0].Client.Watch(fn, keys...) | 	return shards[0].Client.Watch(ctx, fn, keys...) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func newConsistentHash(opt *RingOptions) *consistenthash.Map { | // Close closes the ring client, releasing any open resources. | ||||||
| 	return consistenthash.New(opt.HashReplicas, consistenthash.Hash(opt.Hash)) | // | ||||||
|  | // It is rare to Close a Ring, as the Ring is meant to be long-lived | ||||||
|  | // and shared between many goroutines. | ||||||
|  | func (c *Ring) Close() error { | ||||||
|  | 	return c.shards.Close() | ||||||
| } | } | ||||||
							
								
								
									
										65
									
								
								vendor/github.com/go-redis/redis/v8/script.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/go-redis/redis/v8/script.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | |||||||
|  | package redis | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"crypto/sha1" | ||||||
|  | 	"encoding/hex" | ||||||
|  | 	"io" | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Scripter interface { | ||||||
|  | 	Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd | ||||||
|  | 	EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd | ||||||
|  | 	ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd | ||||||
|  | 	ScriptLoad(ctx context.Context, script string) *StringCmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	_ Scripter = (*Client)(nil) | ||||||
|  | 	_ Scripter = (*Ring)(nil) | ||||||
|  | 	_ Scripter = (*ClusterClient)(nil) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Script struct { | ||||||
|  | 	src, hash string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewScript(src string) *Script { | ||||||
|  | 	h := sha1.New() | ||||||
|  | 	_, _ = io.WriteString(h, src) | ||||||
|  | 	return &Script{ | ||||||
|  | 		src:  src, | ||||||
|  | 		hash: hex.EncodeToString(h.Sum(nil)), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Script) Hash() string { | ||||||
|  | 	return s.hash | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Script) Load(ctx context.Context, c Scripter) *StringCmd { | ||||||
|  | 	return c.ScriptLoad(ctx, s.src) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Script) Exists(ctx context.Context, c Scripter) *BoolSliceCmd { | ||||||
|  | 	return c.ScriptExists(ctx, s.hash) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Script) Eval(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd { | ||||||
|  | 	return c.Eval(ctx, s.src, keys, args...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (s *Script) EvalSha(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd { | ||||||
|  | 	return c.EvalSha(ctx, s.hash, keys, args...) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Run optimistically uses EVALSHA to run the script. If script does not exist | ||||||
|  | // it is retried using EVAL. | ||||||
|  | func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd { | ||||||
|  | 	r := s.EvalSha(ctx, c, keys, args...) | ||||||
|  | 	if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") { | ||||||
|  | 		return s.Eval(ctx, c, keys, args...) | ||||||
|  | 	} | ||||||
|  | 	return r | ||||||
|  | } | ||||||
							
								
								
									
										738
									
								
								vendor/github.com/go-redis/redis/v8/sentinel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										738
									
								
								vendor/github.com/go-redis/redis/v8/sentinel.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,738 @@ | |||||||
|  | package redis | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"crypto/tls" | ||||||
|  | 	"errors" | ||||||
|  | 	"net" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/go-redis/redis/v8/internal" | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/pool" | ||||||
|  | 	"github.com/go-redis/redis/v8/internal/rand" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | // FailoverOptions are used to configure a failover client and should | ||||||
|  | // be passed to NewFailoverClient. | ||||||
|  | type FailoverOptions struct { | ||||||
|  | 	// The master name. | ||||||
|  | 	MasterName string | ||||||
|  | 	// A seed list of host:port addresses of sentinel nodes. | ||||||
|  | 	SentinelAddrs []string | ||||||
|  | 	// Sentinel password from "requirepass <password>" (if enabled) in Sentinel configuration | ||||||
|  | 	SentinelPassword string | ||||||
|  |  | ||||||
|  | 	// Allows routing read-only commands to the closest master or slave node. | ||||||
|  | 	// This option only works with NewFailoverClusterClient. | ||||||
|  | 	RouteByLatency bool | ||||||
|  | 	// Allows routing read-only commands to the random master or slave node. | ||||||
|  | 	// This option only works with NewFailoverClusterClient. | ||||||
|  | 	RouteRandomly bool | ||||||
|  |  | ||||||
|  | 	// Route all commands to slave read-only nodes. | ||||||
|  | 	SlaveOnly bool | ||||||
|  |  | ||||||
|  | 	// Following options are copied from Options struct. | ||||||
|  |  | ||||||
|  | 	Dialer    func(ctx context.Context, network, addr string) (net.Conn, error) | ||||||
|  | 	OnConnect func(ctx context.Context, cn *Conn) error | ||||||
|  |  | ||||||
|  | 	Username string | ||||||
|  | 	Password string | ||||||
|  | 	DB       int | ||||||
|  |  | ||||||
|  | 	MaxRetries      int | ||||||
|  | 	MinRetryBackoff time.Duration | ||||||
|  | 	MaxRetryBackoff time.Duration | ||||||
|  |  | ||||||
|  | 	DialTimeout  time.Duration | ||||||
|  | 	ReadTimeout  time.Duration | ||||||
|  | 	WriteTimeout time.Duration | ||||||
|  |  | ||||||
|  | 	PoolSize           int | ||||||
|  | 	MinIdleConns       int | ||||||
|  | 	MaxConnAge         time.Duration | ||||||
|  | 	PoolTimeout        time.Duration | ||||||
|  | 	IdleTimeout        time.Duration | ||||||
|  | 	IdleCheckFrequency time.Duration | ||||||
|  |  | ||||||
|  | 	TLSConfig *tls.Config | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (opt *FailoverOptions) clientOptions() *Options { | ||||||
|  | 	return &Options{ | ||||||
|  | 		Addr: "FailoverClient", | ||||||
|  |  | ||||||
|  | 		Dialer:    opt.Dialer, | ||||||
|  | 		OnConnect: opt.OnConnect, | ||||||
|  |  | ||||||
|  | 		DB:       opt.DB, | ||||||
|  | 		Username: opt.Username, | ||||||
|  | 		Password: opt.Password, | ||||||
|  |  | ||||||
|  | 		MaxRetries:      opt.MaxRetries, | ||||||
|  | 		MinRetryBackoff: opt.MinRetryBackoff, | ||||||
|  | 		MaxRetryBackoff: opt.MaxRetryBackoff, | ||||||
|  |  | ||||||
|  | 		DialTimeout:  opt.DialTimeout, | ||||||
|  | 		ReadTimeout:  opt.ReadTimeout, | ||||||
|  | 		WriteTimeout: opt.WriteTimeout, | ||||||
|  |  | ||||||
|  | 		PoolSize:           opt.PoolSize, | ||||||
|  | 		PoolTimeout:        opt.PoolTimeout, | ||||||
|  | 		IdleTimeout:        opt.IdleTimeout, | ||||||
|  | 		IdleCheckFrequency: opt.IdleCheckFrequency, | ||||||
|  | 		MinIdleConns:       opt.MinIdleConns, | ||||||
|  | 		MaxConnAge:         opt.MaxConnAge, | ||||||
|  |  | ||||||
|  | 		TLSConfig: opt.TLSConfig, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (opt *FailoverOptions) sentinelOptions(addr string) *Options { | ||||||
|  | 	return &Options{ | ||||||
|  | 		Addr: addr, | ||||||
|  |  | ||||||
|  | 		Dialer:    opt.Dialer, | ||||||
|  | 		OnConnect: opt.OnConnect, | ||||||
|  |  | ||||||
|  | 		DB:       0, | ||||||
|  | 		Password: opt.SentinelPassword, | ||||||
|  |  | ||||||
|  | 		MaxRetries:      opt.MaxRetries, | ||||||
|  | 		MinRetryBackoff: opt.MinRetryBackoff, | ||||||
|  | 		MaxRetryBackoff: opt.MaxRetryBackoff, | ||||||
|  |  | ||||||
|  | 		DialTimeout:  opt.DialTimeout, | ||||||
|  | 		ReadTimeout:  opt.ReadTimeout, | ||||||
|  | 		WriteTimeout: opt.WriteTimeout, | ||||||
|  |  | ||||||
|  | 		PoolSize:           opt.PoolSize, | ||||||
|  | 		PoolTimeout:        opt.PoolTimeout, | ||||||
|  | 		IdleTimeout:        opt.IdleTimeout, | ||||||
|  | 		IdleCheckFrequency: opt.IdleCheckFrequency, | ||||||
|  | 		MinIdleConns:       opt.MinIdleConns, | ||||||
|  | 		MaxConnAge:         opt.MaxConnAge, | ||||||
|  |  | ||||||
|  | 		TLSConfig: opt.TLSConfig, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (opt *FailoverOptions) clusterOptions() *ClusterOptions { | ||||||
|  | 	return &ClusterOptions{ | ||||||
|  | 		Dialer:    opt.Dialer, | ||||||
|  | 		OnConnect: opt.OnConnect, | ||||||
|  |  | ||||||
|  | 		Username: opt.Username, | ||||||
|  | 		Password: opt.Password, | ||||||
|  |  | ||||||
|  | 		MaxRedirects: opt.MaxRetries, | ||||||
|  |  | ||||||
|  | 		RouteByLatency: opt.RouteByLatency, | ||||||
|  | 		RouteRandomly:  opt.RouteRandomly, | ||||||
|  |  | ||||||
|  | 		MinRetryBackoff: opt.MinRetryBackoff, | ||||||
|  | 		MaxRetryBackoff: opt.MaxRetryBackoff, | ||||||
|  |  | ||||||
|  | 		DialTimeout:  opt.DialTimeout, | ||||||
|  | 		ReadTimeout:  opt.ReadTimeout, | ||||||
|  | 		WriteTimeout: opt.WriteTimeout, | ||||||
|  |  | ||||||
|  | 		PoolSize:           opt.PoolSize, | ||||||
|  | 		PoolTimeout:        opt.PoolTimeout, | ||||||
|  | 		IdleTimeout:        opt.IdleTimeout, | ||||||
|  | 		IdleCheckFrequency: opt.IdleCheckFrequency, | ||||||
|  | 		MinIdleConns:       opt.MinIdleConns, | ||||||
|  | 		MaxConnAge:         opt.MaxConnAge, | ||||||
|  |  | ||||||
|  | 		TLSConfig: opt.TLSConfig, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewFailoverClient returns a Redis client that uses Redis Sentinel | ||||||
|  | // for automatic failover. It's safe for concurrent use by multiple | ||||||
|  | // goroutines. | ||||||
|  | func NewFailoverClient(failoverOpt *FailoverOptions) *Client { | ||||||
|  | 	if failoverOpt.RouteByLatency { | ||||||
|  | 		panic("to route commands by latency, use NewFailoverClusterClient") | ||||||
|  | 	} | ||||||
|  | 	if failoverOpt.RouteRandomly { | ||||||
|  | 		panic("to route commands randomly, use NewFailoverClusterClient") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs)) | ||||||
|  | 	copy(sentinelAddrs, failoverOpt.SentinelAddrs) | ||||||
|  |  | ||||||
|  | 	failover := &sentinelFailover{ | ||||||
|  | 		opt:           failoverOpt, | ||||||
|  | 		sentinelAddrs: sentinelAddrs, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	opt := failoverOpt.clientOptions() | ||||||
|  | 	opt.Dialer = masterSlaveDialer(failover) | ||||||
|  | 	opt.init() | ||||||
|  |  | ||||||
|  | 	connPool := newConnPool(opt) | ||||||
|  |  | ||||||
|  | 	failover.mu.Lock() | ||||||
|  | 	failover.onFailover = func(ctx context.Context, addr string) { | ||||||
|  | 		_ = connPool.Filter(func(cn *pool.Conn) bool { | ||||||
|  | 			return cn.RemoteAddr().String() != addr | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 	failover.mu.Unlock() | ||||||
|  |  | ||||||
|  | 	c := Client{ | ||||||
|  | 		baseClient: newBaseClient(opt, connPool), | ||||||
|  | 		ctx:        context.Background(), | ||||||
|  | 	} | ||||||
|  | 	c.cmdable = c.Process | ||||||
|  | 	c.onClose = failover.Close | ||||||
|  |  | ||||||
|  | 	return &c | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func masterSlaveDialer( | ||||||
|  | 	failover *sentinelFailover, | ||||||
|  | ) func(ctx context.Context, network, addr string) (net.Conn, error) { | ||||||
|  | 	return func(ctx context.Context, network, _ string) (net.Conn, error) { | ||||||
|  | 		var addr string | ||||||
|  | 		var err error | ||||||
|  |  | ||||||
|  | 		if failover.opt.SlaveOnly { | ||||||
|  | 			addr, err = failover.RandomSlaveAddr(ctx) | ||||||
|  | 		} else { | ||||||
|  | 			addr, err = failover.MasterAddr(ctx) | ||||||
|  | 			if err == nil { | ||||||
|  | 				failover.trySwitchMaster(ctx, addr) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  | 		if failover.opt.Dialer != nil { | ||||||
|  | 			return failover.opt.Dialer(ctx, network, addr) | ||||||
|  | 		} | ||||||
|  | 		return net.DialTimeout("tcp", addr, failover.opt.DialTimeout) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | // SentinelClient is a client for a Redis Sentinel. | ||||||
|  | type SentinelClient struct { | ||||||
|  | 	*baseClient | ||||||
|  | 	hooks | ||||||
|  | 	ctx context.Context | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewSentinelClient(opt *Options) *SentinelClient { | ||||||
|  | 	opt.init() | ||||||
|  | 	c := &SentinelClient{ | ||||||
|  | 		baseClient: &baseClient{ | ||||||
|  | 			opt:      opt, | ||||||
|  | 			connPool: newConnPool(opt), | ||||||
|  | 		}, | ||||||
|  | 		ctx: context.Background(), | ||||||
|  | 	} | ||||||
|  | 	return c | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *SentinelClient) Context() context.Context { | ||||||
|  | 	return c.ctx | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *SentinelClient) WithContext(ctx context.Context) *SentinelClient { | ||||||
|  | 	if ctx == nil { | ||||||
|  | 		panic("nil context") | ||||||
|  | 	} | ||||||
|  | 	clone := *c | ||||||
|  | 	clone.ctx = ctx | ||||||
|  | 	return &clone | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *SentinelClient) Process(ctx context.Context, cmd Cmder) error { | ||||||
|  | 	return c.hooks.process(ctx, cmd, c.baseClient.process) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *SentinelClient) pubSub() *PubSub { | ||||||
|  | 	pubsub := &PubSub{ | ||||||
|  | 		opt: c.opt, | ||||||
|  |  | ||||||
|  | 		newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) { | ||||||
|  | 			return c.newConn(ctx) | ||||||
|  | 		}, | ||||||
|  | 		closeConn: c.connPool.CloseConn, | ||||||
|  | 	} | ||||||
|  | 	pubsub.init() | ||||||
|  | 	return pubsub | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Ping is used to test if a connection is still alive, or to | ||||||
|  | // measure latency. | ||||||
|  | func (c *SentinelClient) Ping(ctx context.Context) *StringCmd { | ||||||
|  | 	cmd := NewStringCmd(ctx, "ping") | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Subscribe subscribes the client to the specified channels. | ||||||
|  | // Channels can be omitted to create empty subscription. | ||||||
|  | func (c *SentinelClient) Subscribe(ctx context.Context, channels ...string) *PubSub { | ||||||
|  | 	pubsub := c.pubSub() | ||||||
|  | 	if len(channels) > 0 { | ||||||
|  | 		_ = pubsub.Subscribe(ctx, channels...) | ||||||
|  | 	} | ||||||
|  | 	return pubsub | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // PSubscribe subscribes the client to the given patterns. | ||||||
|  | // Patterns can be omitted to create empty subscription. | ||||||
|  | func (c *SentinelClient) PSubscribe(ctx context.Context, channels ...string) *PubSub { | ||||||
|  | 	pubsub := c.pubSub() | ||||||
|  | 	if len(channels) > 0 { | ||||||
|  | 		_ = pubsub.PSubscribe(ctx, channels...) | ||||||
|  | 	} | ||||||
|  | 	return pubsub | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *SentinelClient) GetMasterAddrByName(ctx context.Context, name string) *StringSliceCmd { | ||||||
|  | 	cmd := NewStringSliceCmd(ctx, "sentinel", "get-master-addr-by-name", name) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *SentinelClient) Sentinels(ctx context.Context, name string) *SliceCmd { | ||||||
|  | 	cmd := NewSliceCmd(ctx, "sentinel", "sentinels", name) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Failover forces a failover as if the master was not reachable, and without | ||||||
|  | // asking for agreement to other Sentinels. | ||||||
|  | func (c *SentinelClient) Failover(ctx context.Context, name string) *StatusCmd { | ||||||
|  | 	cmd := NewStatusCmd(ctx, "sentinel", "failover", name) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Reset resets all the masters with matching name. The pattern argument is a | ||||||
|  | // glob-style pattern. The reset process clears any previous state in a master | ||||||
|  | // (including a failover in progress), and removes every slave and sentinel | ||||||
|  | // already discovered and associated with the master. | ||||||
|  | func (c *SentinelClient) Reset(ctx context.Context, pattern string) *IntCmd { | ||||||
|  | 	cmd := NewIntCmd(ctx, "sentinel", "reset", pattern) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // FlushConfig forces Sentinel to rewrite its configuration on disk, including | ||||||
|  | // the current Sentinel state. | ||||||
|  | func (c *SentinelClient) FlushConfig(ctx context.Context) *StatusCmd { | ||||||
|  | 	cmd := NewStatusCmd(ctx, "sentinel", "flushconfig") | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Master shows the state and info of the specified master. | ||||||
|  | func (c *SentinelClient) Master(ctx context.Context, name string) *StringStringMapCmd { | ||||||
|  | 	cmd := NewStringStringMapCmd(ctx, "sentinel", "master", name) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Masters shows a list of monitored masters and their state. | ||||||
|  | func (c *SentinelClient) Masters(ctx context.Context) *SliceCmd { | ||||||
|  | 	cmd := NewSliceCmd(ctx, "sentinel", "masters") | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Slaves shows a list of slaves for the specified master and their state. | ||||||
|  | func (c *SentinelClient) Slaves(ctx context.Context, name string) *SliceCmd { | ||||||
|  | 	cmd := NewSliceCmd(ctx, "sentinel", "slaves", name) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // CkQuorum checks if the current Sentinel configuration is able to reach the | ||||||
|  | // quorum needed to failover a master, and the majority needed to authorize the | ||||||
|  | // failover. This command should be used in monitoring systems to check if a | ||||||
|  | // Sentinel deployment is ok. | ||||||
|  | func (c *SentinelClient) CkQuorum(ctx context.Context, name string) *StringCmd { | ||||||
|  | 	cmd := NewStringCmd(ctx, "sentinel", "ckquorum", name) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Monitor tells the Sentinel to start monitoring a new master with the specified | ||||||
|  | // name, ip, port, and quorum. | ||||||
|  | func (c *SentinelClient) Monitor(ctx context.Context, name, ip, port, quorum string) *StringCmd { | ||||||
|  | 	cmd := NewStringCmd(ctx, "sentinel", "monitor", name, ip, port, quorum) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Set is used in order to change configuration parameters of a specific master. | ||||||
|  | func (c *SentinelClient) Set(ctx context.Context, name, option, value string) *StringCmd { | ||||||
|  | 	cmd := NewStringCmd(ctx, "sentinel", "set", name, option, value) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Remove is used in order to remove the specified master: the master will no | ||||||
|  | // longer be monitored, and will totally be removed from the internal state of | ||||||
|  | // the Sentinel. | ||||||
|  | func (c *SentinelClient) Remove(ctx context.Context, name string) *StringCmd { | ||||||
|  | 	cmd := NewStringCmd(ctx, "sentinel", "remove", name) | ||||||
|  | 	_ = c.Process(ctx, cmd) | ||||||
|  | 	return cmd | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | type sentinelFailover struct { | ||||||
|  | 	opt *FailoverOptions | ||||||
|  |  | ||||||
|  | 	sentinelAddrs []string | ||||||
|  |  | ||||||
|  | 	onFailover func(ctx context.Context, addr string) | ||||||
|  | 	onUpdate   func(ctx context.Context) | ||||||
|  |  | ||||||
|  | 	mu          sync.RWMutex | ||||||
|  | 	_masterAddr string | ||||||
|  | 	sentinel    *SentinelClient | ||||||
|  | 	pubsub      *PubSub | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) Close() error { | ||||||
|  | 	c.mu.Lock() | ||||||
|  | 	defer c.mu.Unlock() | ||||||
|  | 	if c.sentinel != nil { | ||||||
|  | 		return c.closeSentinel() | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) closeSentinel() error { | ||||||
|  | 	firstErr := c.pubsub.Close() | ||||||
|  | 	c.pubsub = nil | ||||||
|  |  | ||||||
|  | 	err := c.sentinel.Close() | ||||||
|  | 	if err != nil && firstErr == nil { | ||||||
|  | 		firstErr = err | ||||||
|  | 	} | ||||||
|  | 	c.sentinel = nil | ||||||
|  |  | ||||||
|  | 	return firstErr | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) RandomSlaveAddr(ctx context.Context) (string, error) { | ||||||
|  | 	addresses, err := c.slaveAddrs(ctx) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return "", err | ||||||
|  | 	} | ||||||
|  | 	if len(addresses) == 0 { | ||||||
|  | 		return c.MasterAddr(ctx) | ||||||
|  | 	} | ||||||
|  | 	return addresses[rand.Intn(len(addresses))], nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) MasterAddr(ctx context.Context) (string, error) { | ||||||
|  | 	c.mu.RLock() | ||||||
|  | 	sentinel := c.sentinel | ||||||
|  | 	c.mu.RUnlock() | ||||||
|  |  | ||||||
|  | 	if sentinel != nil { | ||||||
|  | 		addr := c.getMasterAddr(ctx, sentinel) | ||||||
|  | 		if addr != "" { | ||||||
|  | 			return addr, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.mu.Lock() | ||||||
|  | 	defer c.mu.Unlock() | ||||||
|  |  | ||||||
|  | 	if c.sentinel != nil { | ||||||
|  | 		addr := c.getMasterAddr(ctx, c.sentinel) | ||||||
|  | 		if addr != "" { | ||||||
|  | 			return addr, nil | ||||||
|  | 		} | ||||||
|  | 		_ = c.closeSentinel() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for i, sentinelAddr := range c.sentinelAddrs { | ||||||
|  | 		sentinel := NewSentinelClient(c.opt.sentinelOptions(sentinelAddr)) | ||||||
|  |  | ||||||
|  | 		masterAddr, err := sentinel.GetMasterAddrByName(ctx, c.opt.MasterName).Result() | ||||||
|  | 		if err != nil { | ||||||
|  | 			internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName master=%q failed: %s", | ||||||
|  | 				c.opt.MasterName, err) | ||||||
|  | 			_ = sentinel.Close() | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Push working sentinel to the top. | ||||||
|  | 		c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0] | ||||||
|  | 		c.setSentinel(ctx, sentinel) | ||||||
|  |  | ||||||
|  | 		addr := net.JoinHostPort(masterAddr[0], masterAddr[1]) | ||||||
|  | 		return addr, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return "", errors.New("redis: all sentinels specified in configuration are unreachable") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) slaveAddrs(ctx context.Context) ([]string, error) { | ||||||
|  | 	c.mu.RLock() | ||||||
|  | 	sentinel := c.sentinel | ||||||
|  | 	c.mu.RUnlock() | ||||||
|  |  | ||||||
|  | 	if sentinel != nil { | ||||||
|  | 		addrs := c.getSlaveAddrs(ctx, sentinel) | ||||||
|  | 		if len(addrs) > 0 { | ||||||
|  | 			return addrs, nil | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.mu.Lock() | ||||||
|  | 	defer c.mu.Unlock() | ||||||
|  |  | ||||||
|  | 	if c.sentinel != nil { | ||||||
|  | 		addrs := c.getSlaveAddrs(ctx, c.sentinel) | ||||||
|  | 		if len(addrs) > 0 { | ||||||
|  | 			return addrs, nil | ||||||
|  | 		} | ||||||
|  | 		_ = c.closeSentinel() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for i, sentinelAddr := range c.sentinelAddrs { | ||||||
|  | 		sentinel := NewSentinelClient(c.opt.sentinelOptions(sentinelAddr)) | ||||||
|  |  | ||||||
|  | 		slaves, err := sentinel.Slaves(ctx, c.opt.MasterName).Result() | ||||||
|  | 		if err != nil { | ||||||
|  | 			internal.Logger.Printf(ctx, "sentinel: Slaves master=%q failed: %s", | ||||||
|  | 				c.opt.MasterName, err) | ||||||
|  | 			_ = sentinel.Close() | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Push working sentinel to the top. | ||||||
|  | 		c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0] | ||||||
|  | 		c.setSentinel(ctx, sentinel) | ||||||
|  |  | ||||||
|  | 		addrs := parseSlaveAddrs(slaves) | ||||||
|  | 		return addrs, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return []string{}, errors.New("redis: all sentinels specified in configuration are unreachable") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) getMasterAddr(ctx context.Context, sentinel *SentinelClient) string { | ||||||
|  | 	addr, err := sentinel.GetMasterAddrByName(ctx, c.opt.MasterName).Result() | ||||||
|  | 	if err != nil { | ||||||
|  | 		internal.Logger.Printf(ctx, "sentinel: GetMasterAddrByName name=%q failed: %s", | ||||||
|  | 			c.opt.MasterName, err) | ||||||
|  | 		return "" | ||||||
|  | 	} | ||||||
|  | 	return net.JoinHostPort(addr[0], addr[1]) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) getSlaveAddrs(ctx context.Context, sentinel *SentinelClient) []string { | ||||||
|  | 	addrs, err := sentinel.Slaves(ctx, c.opt.MasterName).Result() | ||||||
|  | 	if err != nil { | ||||||
|  | 		internal.Logger.Printf(ctx, "sentinel: Slaves name=%q failed: %s", | ||||||
|  | 			c.opt.MasterName, err) | ||||||
|  | 		return []string{} | ||||||
|  | 	} | ||||||
|  | 	return parseSlaveAddrs(addrs) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func parseSlaveAddrs(addrs []interface{}) []string { | ||||||
|  | 	nodes := make([]string, 0, len(addrs)) | ||||||
|  |  | ||||||
|  | 	for _, node := range addrs { | ||||||
|  | 		ip := "" | ||||||
|  | 		port := "" | ||||||
|  | 		flags := []string{} | ||||||
|  | 		lastkey := "" | ||||||
|  | 		isDown := false | ||||||
|  |  | ||||||
|  | 		for _, key := range node.([]interface{}) { | ||||||
|  | 			switch lastkey { | ||||||
|  | 			case "ip": | ||||||
|  | 				ip = key.(string) | ||||||
|  | 			case "port": | ||||||
|  | 				port = key.(string) | ||||||
|  | 			case "flags": | ||||||
|  | 				flags = strings.Split(key.(string), ",") | ||||||
|  | 			} | ||||||
|  | 			lastkey = key.(string) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for _, flag := range flags { | ||||||
|  | 			switch flag { | ||||||
|  | 			case "s_down", "o_down", "disconnected": | ||||||
|  | 				isDown = true | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if !isDown { | ||||||
|  | 			nodes = append(nodes, net.JoinHostPort(ip, port)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nodes | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) trySwitchMaster(ctx context.Context, addr string) { | ||||||
|  | 	c.mu.RLock() | ||||||
|  | 	currentAddr := c._masterAddr | ||||||
|  | 	c.mu.RUnlock() | ||||||
|  |  | ||||||
|  | 	if addr == currentAddr { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c.mu.Lock() | ||||||
|  | 	defer c.mu.Unlock() | ||||||
|  |  | ||||||
|  | 	if addr == c._masterAddr { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	c._masterAddr = addr | ||||||
|  |  | ||||||
|  | 	internal.Logger.Printf(ctx, "sentinel: new master=%q addr=%q", | ||||||
|  | 		c.opt.MasterName, addr) | ||||||
|  | 	if c.onFailover != nil { | ||||||
|  | 		c.onFailover(ctx, addr) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) setSentinel(ctx context.Context, sentinel *SentinelClient) { | ||||||
|  | 	if c.sentinel != nil { | ||||||
|  | 		panic("not reached") | ||||||
|  | 	} | ||||||
|  | 	c.sentinel = sentinel | ||||||
|  | 	c.discoverSentinels(ctx) | ||||||
|  |  | ||||||
|  | 	c.pubsub = sentinel.Subscribe(ctx, "+switch-master", "+slave-reconf-done") | ||||||
|  | 	go c.listen(c.pubsub) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) discoverSentinels(ctx context.Context) { | ||||||
|  | 	sentinels, err := c.sentinel.Sentinels(ctx, c.opt.MasterName).Result() | ||||||
|  | 	if err != nil { | ||||||
|  | 		internal.Logger.Printf(ctx, "sentinel: Sentinels master=%q failed: %s", c.opt.MasterName, err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	for _, sentinel := range sentinels { | ||||||
|  | 		vals := sentinel.([]interface{}) | ||||||
|  | 		for i := 0; i < len(vals); i += 2 { | ||||||
|  | 			key := vals[i].(string) | ||||||
|  | 			if key == "name" { | ||||||
|  | 				sentinelAddr := vals[i+1].(string) | ||||||
|  | 				if !contains(c.sentinelAddrs, sentinelAddr) { | ||||||
|  | 					internal.Logger.Printf(ctx, "sentinel: discovered new sentinel=%q for master=%q", | ||||||
|  | 						sentinelAddr, c.opt.MasterName) | ||||||
|  | 					c.sentinelAddrs = append(c.sentinelAddrs, sentinelAddr) | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *sentinelFailover) listen(pubsub *PubSub) { | ||||||
|  | 	ctx := context.TODO() | ||||||
|  |  | ||||||
|  | 	if c.onUpdate != nil { | ||||||
|  | 		c.onUpdate(ctx) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ch := pubsub.Channel() | ||||||
|  | 	for msg := range ch { | ||||||
|  | 		if msg.Channel == "+switch-master" { | ||||||
|  | 			parts := strings.Split(msg.Payload, " ") | ||||||
|  | 			if parts[0] != c.opt.MasterName { | ||||||
|  | 				internal.Logger.Printf(pubsub.getContext(), "sentinel: ignore addr for master=%q", parts[0]) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 			addr := net.JoinHostPort(parts[3], parts[4]) | ||||||
|  | 			c.trySwitchMaster(pubsub.getContext(), addr) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if c.onUpdate != nil { | ||||||
|  | 			c.onUpdate(ctx) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func contains(slice []string, str string) bool { | ||||||
|  | 	for _, s := range slice { | ||||||
|  | 		if s == str { | ||||||
|  | 			return true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
|  | // NewFailoverClusterClient returns a client that supports routing read-only commands | ||||||
|  | // to a slave node. | ||||||
|  | func NewFailoverClusterClient(failoverOpt *FailoverOptions) *ClusterClient { | ||||||
|  | 	sentinelAddrs := make([]string, len(failoverOpt.SentinelAddrs)) | ||||||
|  | 	copy(sentinelAddrs, failoverOpt.SentinelAddrs) | ||||||
|  |  | ||||||
|  | 	failover := &sentinelFailover{ | ||||||
|  | 		opt:           failoverOpt, | ||||||
|  | 		sentinelAddrs: sentinelAddrs, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	opt := failoverOpt.clusterOptions() | ||||||
|  | 	opt.ClusterSlots = func(ctx context.Context) ([]ClusterSlot, error) { | ||||||
|  | 		masterAddr, err := failover.MasterAddr(ctx) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		nodes := []ClusterNode{{ | ||||||
|  | 			Addr: masterAddr, | ||||||
|  | 		}} | ||||||
|  |  | ||||||
|  | 		slaveAddrs, err := failover.slaveAddrs(ctx) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for _, slaveAddr := range slaveAddrs { | ||||||
|  | 			nodes = append(nodes, ClusterNode{ | ||||||
|  | 				Addr: slaveAddr, | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		slots := []ClusterSlot{ | ||||||
|  | 			{ | ||||||
|  | 				Start: 0, | ||||||
|  | 				End:   16383, | ||||||
|  | 				Nodes: nodes, | ||||||
|  | 			}, | ||||||
|  | 		} | ||||||
|  | 		return slots, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	c := NewClusterClient(opt) | ||||||
|  |  | ||||||
|  | 	failover.mu.Lock() | ||||||
|  | 	failover.onUpdate = func(ctx context.Context) { | ||||||
|  | 		c.ReloadState(ctx) | ||||||
|  | 	} | ||||||
|  | 	failover.mu.Unlock() | ||||||
|  |  | ||||||
|  | 	return c | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								vendor/github.com/go-redis/redis/v7/tx.go → vendor/github.com/go-redis/redis/v8/tx.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										51
									
								
								vendor/github.com/go-redis/redis/v7/tx.go → vendor/github.com/go-redis/redis/v8/tx.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,8 +3,8 @@ package redis | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 
 | 
 | ||||||
| 	"github.com/go-redis/redis/v7/internal/pool" | 	"github.com/go-redis/redis/v8/internal/pool" | ||||||
| 	"github.com/go-redis/redis/v7/internal/proto" | 	"github.com/go-redis/redis/v8/internal/proto" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // TxFailedErr transaction redis failed. | // TxFailedErr transaction redis failed. | ||||||
| @@ -26,7 +26,7 @@ func (c *Client) newTx(ctx context.Context) *Tx { | |||||||
| 	tx := Tx{ | 	tx := Tx{ | ||||||
| 		baseClient: baseClient{ | 		baseClient: baseClient{ | ||||||
| 			opt:      c.opt, | 			opt:      c.opt, | ||||||
| 			connPool: pool.NewStickyConnPool(c.connPool.(*pool.ConnPool), true), | 			connPool: pool.NewStickyConnPool(c.connPool), | ||||||
| 		}, | 		}, | ||||||
| 		hooks: c.hooks.clone(), | 		hooks: c.hooks.clone(), | ||||||
| 		ctx:   ctx, | 		ctx:   ctx, | ||||||
| @@ -55,11 +55,7 @@ func (c *Tx) WithContext(ctx context.Context) *Tx { | |||||||
| 	return &clone | 	return &clone | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Tx) Process(cmd Cmder) error { | func (c *Tx) Process(ctx context.Context, cmd Cmder) error { | ||||||
| 	return c.ProcessContext(c.ctx, cmd) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *Tx) ProcessContext(ctx context.Context, cmd Cmder) error { |  | ||||||
| 	return c.hooks.process(ctx, cmd, c.baseClient.process) | 	return c.hooks.process(ctx, cmd, c.baseClient.process) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -67,52 +63,45 @@ func (c *Tx) ProcessContext(ctx context.Context, cmd Cmder) error { | |||||||
| // for conditional execution if there are any keys. | // for conditional execution if there are any keys. | ||||||
| // | // | ||||||
| // The transaction is automatically closed when fn exits. | // The transaction is automatically closed when fn exits. | ||||||
| func (c *Client) Watch(fn func(*Tx) error, keys ...string) error { | func (c *Client) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error { | ||||||
| 	return c.WatchContext(c.ctx, fn, keys...) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *Client) WatchContext(ctx context.Context, fn func(*Tx) error, keys ...string) error { |  | ||||||
| 	tx := c.newTx(ctx) | 	tx := c.newTx(ctx) | ||||||
|  | 	defer tx.Close(ctx) | ||||||
| 	if len(keys) > 0 { | 	if len(keys) > 0 { | ||||||
| 		if err := tx.Watch(keys...).Err(); err != nil { | 		if err := tx.Watch(ctx, keys...).Err(); err != nil { | ||||||
| 			_ = tx.Close() |  | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 	return fn(tx) | ||||||
| 	err := fn(tx) |  | ||||||
| 	_ = tx.Close() |  | ||||||
| 	return err |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Close closes the transaction, releasing any open resources. | // Close closes the transaction, releasing any open resources. | ||||||
| func (c *Tx) Close() error { | func (c *Tx) Close(ctx context.Context) error { | ||||||
| 	_ = c.Unwatch().Err() | 	_ = c.Unwatch(ctx).Err() | ||||||
| 	return c.baseClient.Close() | 	return c.baseClient.Close() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Watch marks the keys to be watched for conditional execution | // Watch marks the keys to be watched for conditional execution | ||||||
| // of a transaction. | // of a transaction. | ||||||
| func (c *Tx) Watch(keys ...string) *StatusCmd { | func (c *Tx) Watch(ctx context.Context, keys ...string) *StatusCmd { | ||||||
| 	args := make([]interface{}, 1+len(keys)) | 	args := make([]interface{}, 1+len(keys)) | ||||||
| 	args[0] = "watch" | 	args[0] = "watch" | ||||||
| 	for i, key := range keys { | 	for i, key := range keys { | ||||||
| 		args[1+i] = key | 		args[1+i] = key | ||||||
| 	} | 	} | ||||||
| 	cmd := NewStatusCmd(args...) | 	cmd := NewStatusCmd(ctx, args...) | ||||||
| 	_ = c.Process(cmd) | 	_ = c.Process(ctx, cmd) | ||||||
| 	return cmd | 	return cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Unwatch flushes all the previously watched keys for a transaction. | // Unwatch flushes all the previously watched keys for a transaction. | ||||||
| func (c *Tx) Unwatch(keys ...string) *StatusCmd { | func (c *Tx) Unwatch(ctx context.Context, keys ...string) *StatusCmd { | ||||||
| 	args := make([]interface{}, 1+len(keys)) | 	args := make([]interface{}, 1+len(keys)) | ||||||
| 	args[0] = "unwatch" | 	args[0] = "unwatch" | ||||||
| 	for i, key := range keys { | 	for i, key := range keys { | ||||||
| 		args[1+i] = key | 		args[1+i] = key | ||||||
| 	} | 	} | ||||||
| 	cmd := NewStatusCmd(args...) | 	cmd := NewStatusCmd(ctx, args...) | ||||||
| 	_ = c.Process(cmd) | 	_ = c.Process(ctx, cmd) | ||||||
| 	return cmd | 	return cmd | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -130,8 +119,8 @@ func (c *Tx) Pipeline() Pipeliner { | |||||||
| 
 | 
 | ||||||
| // Pipelined executes commands queued in the fn outside of the transaction. | // Pipelined executes commands queued in the fn outside of the transaction. | ||||||
| // Use TxPipelined if you need transactional behavior. | // Use TxPipelined if you need transactional behavior. | ||||||
| func (c *Tx) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Tx) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
| 	return c.Pipeline().Pipelined(fn) | 	return c.Pipeline().Pipelined(ctx, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TxPipelined executes commands queued in the fn in the transaction. | // TxPipelined executes commands queued in the fn in the transaction. | ||||||
| @@ -142,8 +131,8 @@ func (c *Tx) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | |||||||
| // Exec always returns list of commands. If transaction fails | // Exec always returns list of commands. If transaction fails | ||||||
| // TxFailedErr is returned. Otherwise Exec returns an error of the first | // TxFailedErr is returned. Otherwise Exec returns an error of the first | ||||||
| // failed command or nil. | // failed command or nil. | ||||||
| func (c *Tx) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { | func (c *Tx) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||||
| 	return c.TxPipeline().Pipelined(fn) | 	return c.TxPipeline().Pipelined(ctx, fn) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TxPipeline creates a pipeline. Usually it is more convenient to use TxPipelined. | // TxPipeline creates a pipeline. Usually it is more convenient to use TxPipelined. | ||||||
| @@ -20,23 +20,29 @@ type UniversalOptions struct { | |||||||
| 
 | 
 | ||||||
| 	// Common options. | 	// Common options. | ||||||
| 
 | 
 | ||||||
| 	Dialer             func(ctx context.Context, network, addr string) (net.Conn, error) | 	Dialer    func(ctx context.Context, network, addr string) (net.Conn, error) | ||||||
| 	OnConnect          func(*Conn) error | 	OnConnect func(ctx context.Context, cn *Conn) error | ||||||
| 	Username           string | 
 | ||||||
| 	Password           string | 	Username         string | ||||||
| 	MaxRetries         int | 	Password         string | ||||||
| 	MinRetryBackoff    time.Duration | 	SentinelPassword string | ||||||
| 	MaxRetryBackoff    time.Duration | 
 | ||||||
| 	DialTimeout        time.Duration | 	MaxRetries      int | ||||||
| 	ReadTimeout        time.Duration | 	MinRetryBackoff time.Duration | ||||||
| 	WriteTimeout       time.Duration | 	MaxRetryBackoff time.Duration | ||||||
|  | 
 | ||||||
|  | 	DialTimeout  time.Duration | ||||||
|  | 	ReadTimeout  time.Duration | ||||||
|  | 	WriteTimeout time.Duration | ||||||
|  | 
 | ||||||
| 	PoolSize           int | 	PoolSize           int | ||||||
| 	MinIdleConns       int | 	MinIdleConns       int | ||||||
| 	MaxConnAge         time.Duration | 	MaxConnAge         time.Duration | ||||||
| 	PoolTimeout        time.Duration | 	PoolTimeout        time.Duration | ||||||
| 	IdleTimeout        time.Duration | 	IdleTimeout        time.Duration | ||||||
| 	IdleCheckFrequency time.Duration | 	IdleCheckFrequency time.Duration | ||||||
| 	TLSConfig          *tls.Config | 
 | ||||||
|  | 	TLSConfig *tls.Config | ||||||
| 
 | 
 | ||||||
| 	// Only cluster clients. | 	// Only cluster clients. | ||||||
| 
 | 
 | ||||||
| @@ -100,9 +106,10 @@ func (o *UniversalOptions) Failover() *FailoverOptions { | |||||||
| 		Dialer:    o.Dialer, | 		Dialer:    o.Dialer, | ||||||
| 		OnConnect: o.OnConnect, | 		OnConnect: o.OnConnect, | ||||||
| 
 | 
 | ||||||
| 		DB:       o.DB, | 		DB:               o.DB, | ||||||
| 		Username: o.Username, | 		Username:         o.Username, | ||||||
| 		Password: o.Password, | 		Password:         o.Password, | ||||||
|  | 		SentinelPassword: o.SentinelPassword, | ||||||
| 
 | 
 | ||||||
| 		MaxRetries:      o.MaxRetries, | 		MaxRetries:      o.MaxRetries, | ||||||
| 		MinRetryBackoff: o.MinRetryBackoff, | 		MinRetryBackoff: o.MinRetryBackoff, | ||||||
| @@ -168,19 +175,20 @@ type UniversalClient interface { | |||||||
| 	Cmdable | 	Cmdable | ||||||
| 	Context() context.Context | 	Context() context.Context | ||||||
| 	AddHook(Hook) | 	AddHook(Hook) | ||||||
| 	Watch(fn func(*Tx) error, keys ...string) error | 	Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error | ||||||
| 	Do(args ...interface{}) *Cmd | 	Do(ctx context.Context, args ...interface{}) *Cmd | ||||||
| 	DoContext(ctx context.Context, args ...interface{}) *Cmd | 	Process(ctx context.Context, cmd Cmder) error | ||||||
| 	Process(cmd Cmder) error | 	Subscribe(ctx context.Context, channels ...string) *PubSub | ||||||
| 	ProcessContext(ctx context.Context, cmd Cmder) error | 	PSubscribe(ctx context.Context, channels ...string) *PubSub | ||||||
| 	Subscribe(channels ...string) *PubSub |  | ||||||
| 	PSubscribe(channels ...string) *PubSub |  | ||||||
| 	Close() error | 	Close() error | ||||||
|  | 	PoolStats() *PoolStats | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var _ UniversalClient = (*Client)(nil) | var ( | ||||||
| var _ UniversalClient = (*ClusterClient)(nil) | 	_ UniversalClient = (*Client)(nil) | ||||||
| var _ UniversalClient = (*Ring)(nil) | 	_ UniversalClient = (*ClusterClient)(nil) | ||||||
|  | 	_ UniversalClient = (*Ring)(nil) | ||||||
|  | ) | ||||||
| 
 | 
 | ||||||
| // NewUniversalClient returns a new multi client. The type of client returned depends | // NewUniversalClient returns a new multi client. The type of client returned depends | ||||||
| // on the following three conditions: | // on the following three conditions: | ||||||
							
								
								
									
										23
									
								
								vendor/go.opentelemetry.io/otel/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/go.opentelemetry.io/otel/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | .DS_Store | ||||||
|  | Thumbs.db | ||||||
|  |  | ||||||
|  | .tools/ | ||||||
|  | .idea/ | ||||||
|  | .vscode/ | ||||||
|  | *.iml | ||||||
|  | *.so | ||||||
|  | coverage.* | ||||||
|  |  | ||||||
|  | gen/ | ||||||
|  |  | ||||||
|  | /example/grpc/client/client | ||||||
|  | /example/grpc/server/server | ||||||
|  | /example/http/client/client | ||||||
|  | /example/http/server/server | ||||||
|  | /example/jaeger/jaeger | ||||||
|  | /example/namedtracer/namedtracer | ||||||
|  | /example/opencensus/opencensus | ||||||
|  | /example/prometheus/prometheus | ||||||
|  | /example/prom-collector/prom-collector | ||||||
|  | /example/zipkin/zipkin | ||||||
|  | /example/otel-collector/otel-collector | ||||||
							
								
								
									
										3
									
								
								vendor/go.opentelemetry.io/otel/.gitmodules
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/go.opentelemetry.io/otel/.gitmodules
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | [submodule "opentelemetry-proto"] | ||||||
|  | 	path = exporters/otlp/internal/opentelemetry-proto | ||||||
|  | 	url = https://github.com/open-telemetry/opentelemetry-proto | ||||||
							
								
								
									
										32
									
								
								vendor/go.opentelemetry.io/otel/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								vendor/go.opentelemetry.io/otel/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | # See https://github.com/golangci/golangci-lint#config-file | ||||||
|  | run: | ||||||
|  |   issues-exit-code: 1 #Default | ||||||
|  |   tests: true #Default | ||||||
|  |  | ||||||
|  | linters: | ||||||
|  |   enable: | ||||||
|  |     - misspell | ||||||
|  |     - goimports | ||||||
|  |     - golint | ||||||
|  |     - gofmt | ||||||
|  |  | ||||||
|  | issues: | ||||||
|  |   exclude-rules: | ||||||
|  |     # helpers in tests often (rightfully) pass a *testing.T as their first argument | ||||||
|  |     - path: _test\.go | ||||||
|  |       text: "context.Context should be the first parameter of a function" | ||||||
|  |       linters: | ||||||
|  |         - golint | ||||||
|  |     # Yes, they are, but it's okay in a test | ||||||
|  |     - path: _test\.go | ||||||
|  |       text: "exported func.*returns unexported type.*which can be annoying to use" | ||||||
|  |       linters: | ||||||
|  |         - golint | ||||||
|  |  | ||||||
|  | linters-settings: | ||||||
|  |   misspell: | ||||||
|  |     locale: US | ||||||
|  |     ignore-words: | ||||||
|  |       - cancelled | ||||||
|  |   goimports: | ||||||
|  |     local-prefixes: go.opentelemetry.io | ||||||
							
								
								
									
										1054
									
								
								vendor/go.opentelemetry.io/otel/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1054
									
								
								vendor/go.opentelemetry.io/otel/CHANGELOG.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										17
									
								
								vendor/go.opentelemetry.io/otel/CODEOWNERS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/go.opentelemetry.io/otel/CODEOWNERS
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | |||||||
|  | ##################################################### | ||||||
|  | # | ||||||
|  | # List of approvers for this repository | ||||||
|  | # | ||||||
|  | ##################################################### | ||||||
|  | # | ||||||
|  | # Learn about membership in OpenTelemetry community: | ||||||
|  | #  https://github.com/open-telemetry/community/blob/master/community-membership.md | ||||||
|  | # | ||||||
|  | # | ||||||
|  | # Learn about CODEOWNERS file format: | ||||||
|  | #  https://help.github.com/en/articles/about-code-owners | ||||||
|  | # | ||||||
|  |  | ||||||
|  | * @jmacd @lizthegrey @MrAlias @Aneurysm9 @evantorrie @XSAM @dashpole | ||||||
|  |  | ||||||
|  | CODEOWNERS @MrAlias @Aneurysm9 | ||||||
							
								
								
									
										374
									
								
								vendor/go.opentelemetry.io/otel/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										374
									
								
								vendor/go.opentelemetry.io/otel/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,374 @@ | |||||||
|  | # Contributing to opentelemetry-go | ||||||
|  |  | ||||||
|  | The Go special interest group (SIG) meets regularly. See the | ||||||
|  | OpenTelemetry | ||||||
|  | [community](https://github.com/open-telemetry/community#golang-sdk) | ||||||
|  | repo for information on this and other language SIGs. | ||||||
|  |  | ||||||
|  | See the [public meeting | ||||||
|  | notes](https://docs.google.com/document/d/1A63zSWX0x2CyCK_LoNhmQC4rqhLpYXJzXbEPDUQ2n6w/edit#heading=h.9tngw7jdwd6b) | ||||||
|  | for a summary description of past meetings. To request edit access, | ||||||
|  | join the meeting or get in touch on | ||||||
|  | [Gitter](https://gitter.im/open-telemetry/opentelemetry-go). | ||||||
|  |  | ||||||
|  | ## Development | ||||||
|  |  | ||||||
|  | You can view and edit the source code by cloning this repository: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | git clone https://github.com/open-telemetry/opentelemetry-go.git | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Run `make test` to run the tests instead of `go test`.  | ||||||
|  |  | ||||||
|  | There are some generated files checked into the repo. To make sure | ||||||
|  | that the generated files are up-to-date, run `make` (or `make | ||||||
|  | precommit` - the `precommit` target is the default). | ||||||
|  |  | ||||||
|  | The `precommit` target also fixes the formatting of the code and | ||||||
|  | checks the status of the go module files. | ||||||
|  |  | ||||||
|  | If after running `make precommit` the output of `git status` contains | ||||||
|  | `nothing to commit, working tree clean` then it means that everything | ||||||
|  | is up-to-date and properly formatted. | ||||||
|  |  | ||||||
|  | ## Pull Requests | ||||||
|  |  | ||||||
|  | ### How to Send Pull Requests | ||||||
|  |  | ||||||
|  | Everyone is welcome to contribute code to `opentelemetry-go` via | ||||||
|  | GitHub pull requests (PRs). | ||||||
|  |  | ||||||
|  | To create a new PR, fork the project in GitHub and clone the upstream | ||||||
|  | repo: | ||||||
|  |  | ||||||
|  | ```sh | ||||||
|  | $ go get -d go.opentelemetry.io/otel | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | (This may print some warning about "build constraints exclude all Go | ||||||
|  | files", just ignore it.) | ||||||
|  |  | ||||||
|  | This will put the project in `${GOPATH}/src/go.opentelemetry.io/otel`. You | ||||||
|  | can alternatively use `git` directly with: | ||||||
|  |  | ||||||
|  | ```sh | ||||||
|  | $ git clone https://github.com/open-telemetry/opentelemetry-go | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | (Note that `git clone` is *not* using the `go.opentelemetry.io/otel` name - | ||||||
|  | that name is a kind of a redirector to GitHub that `go get` can | ||||||
|  | understand, but `git` does not.) | ||||||
|  |  | ||||||
|  | This would put the project in the `opentelemetry-go` directory in | ||||||
|  | current working directory. | ||||||
|  |  | ||||||
|  | Enter the newly created directory and add your fork as a new remote: | ||||||
|  |  | ||||||
|  | ```sh | ||||||
|  | $ git remote add <YOUR_FORK> git@github.com:<YOUR_GITHUB_USERNAME>/opentelemetry-go | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Check out a new branch, make modifications, run linters and tests, update | ||||||
|  | `CHANGELOG.md`, and push the branch to your fork: | ||||||
|  |  | ||||||
|  | ```sh | ||||||
|  | $ git checkout -b <YOUR_BRANCH_NAME> | ||||||
|  | # edit files | ||||||
|  | # update changelog | ||||||
|  | $ make precommit | ||||||
|  | $ git add -p | ||||||
|  | $ git commit | ||||||
|  | $ git push <YOUR_FORK> <YOUR_BRANCH_NAME> | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Open a pull request against the main `opentelemetry-go` repo. Be sure to add the pull | ||||||
|  | request ID to the entry you added to `CHANGELOG.md`. | ||||||
|  |  | ||||||
|  | ### How to Receive Comments | ||||||
|  |  | ||||||
|  | * If the PR is not ready for review, please put `[WIP]` in the title, | ||||||
|  |   tag it as `work-in-progress`, or mark it as | ||||||
|  |   [`draft`](https://github.blog/2019-02-14-introducing-draft-pull-requests/). | ||||||
|  | * Make sure CLA is signed and CI is clear. | ||||||
|  |  | ||||||
|  | ### How to Get PRs Merged | ||||||
|  |  | ||||||
|  | A PR is considered to be **ready to merge** when: | ||||||
|  |  | ||||||
|  | * It has received two approvals from Collaborators/Maintainers (at | ||||||
|  |   different companies). This is not enforced through technical means | ||||||
|  |   and a PR may be **ready to merge** with a single approval if the change | ||||||
|  |   and its approach have been discussed and consensus reached. | ||||||
|  | * Major feedbacks are resolved. | ||||||
|  | * It has been open for review for at least one working day. This gives | ||||||
|  |   people reasonable time to review. | ||||||
|  | * Trivial changes (typo, cosmetic, doc, etc.) do not have to wait for | ||||||
|  |   one day and may be merged with a single Maintainer's approval. | ||||||
|  | * `CHANGELOG.md` has been updated to reflect what has been | ||||||
|  |   added, changed, removed, or fixed. | ||||||
|  | * Urgent fix can take exception as long as it has been actively | ||||||
|  |   communicated. | ||||||
|  |  | ||||||
|  | Any Maintainer can merge the PR once it is **ready to merge**. | ||||||
|  |  | ||||||
|  | ## Design Choices | ||||||
|  |  | ||||||
|  | As with other OpenTelemetry clients, opentelemetry-go follows the | ||||||
|  | [opentelemetry-specification](https://github.com/open-telemetry/opentelemetry-specification). | ||||||
|  |  | ||||||
|  | It's especially valuable to read through the [library | ||||||
|  | guidelines](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/library-guidelines.md). | ||||||
|  |  | ||||||
|  | ### Focus on Capabilities, Not Structure Compliance | ||||||
|  |  | ||||||
|  | OpenTelemetry is an evolving specification, one where the desires and | ||||||
|  | use cases are clear, but the method to satisfy those uses cases are | ||||||
|  | not. | ||||||
|  |  | ||||||
|  | As such, Contributions should provide functionality and behavior that | ||||||
|  | conforms to the specification, but the interface and structure is | ||||||
|  | flexible. | ||||||
|  |  | ||||||
|  | It is preferable to have contributions follow the idioms of the | ||||||
|  | language rather than conform to specific API names or argument | ||||||
|  | patterns in the spec. | ||||||
|  |  | ||||||
|  | For a deeper discussion, see: | ||||||
|  | https://github.com/open-telemetry/opentelemetry-specification/issues/165 | ||||||
|  |  | ||||||
|  | ## Style Guide | ||||||
|  |  | ||||||
|  | One of the primary goals of this project is that it is actually used by | ||||||
|  | developers. With this goal in mind the project strives to build | ||||||
|  | user-friendly and idiomatic Go code adhering to the Go community's best | ||||||
|  | practices. | ||||||
|  |  | ||||||
|  | For a non-comprehensive but foundational overview of these best practices | ||||||
|  | the [Effective Go](https://golang.org/doc/effective_go.html) documentation | ||||||
|  | is an excellent starting place. | ||||||
|  |  | ||||||
|  | As a convenience for developers building this project the `make precommit` | ||||||
|  | will format, lint, validate, and in some cases fix the changes you plan to | ||||||
|  | submit. This check will need to pass for your changes to be able to be | ||||||
|  | merged. | ||||||
|  |  | ||||||
|  | In addition to idiomatic Go, the project has adopted certain standards for | ||||||
|  | implementations of common patterns. These standards should be followed as a | ||||||
|  | default, and if they are not followed documentation needs to be included as | ||||||
|  | to the reasons why. | ||||||
|  |  | ||||||
|  | ### Configuration | ||||||
|  |  | ||||||
|  | When creating an instantiation function for a complex `struct` it is useful | ||||||
|  | to allow variable number of options to be applied. However, the strong type | ||||||
|  | system of Go restricts the function design options. There are a few ways to | ||||||
|  | solve this problem, but we have landed on the following design. | ||||||
|  |  | ||||||
|  | #### `config` | ||||||
|  |  | ||||||
|  | Configuration should be held in a `struct` named `config`, or prefixed with | ||||||
|  | specific type name this Configuration applies to if there are multiple | ||||||
|  | `config` in the package. This `struct` must contain configuration options. | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | // config contains configuration options for a thing. | ||||||
|  | type config struct { | ||||||
|  |     // options ... | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | In general the `config` `struct` will not need to be used externally to the | ||||||
|  | package and should be unexported. If, however, it is expected that the user | ||||||
|  | will likely want to build custom options for the configuration, the `config` | ||||||
|  | should be exported. Please, include in the documentation for the `config` | ||||||
|  | how the user can extend the configuration. | ||||||
|  |  | ||||||
|  | It is important that `config` are not shared across package boundaries. | ||||||
|  | Meaning a `config` from one package should not be directly used by another. | ||||||
|  |  | ||||||
|  | Optionally, it is common to include a `newConfig` function (with the same | ||||||
|  | naming scheme). This function wraps any defaults setting and looping over | ||||||
|  | all options to create a configured `config`. | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | // newConfig returns an appropriately configured config. | ||||||
|  | func newConfig([]Option) config { | ||||||
|  |     // Set default values for config. | ||||||
|  |     config := config{/* […] */} | ||||||
|  |     for _, option := range options { | ||||||
|  |         option.Apply(&config) | ||||||
|  |     } | ||||||
|  |     // Preform any validation here. | ||||||
|  |     return config | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | If validation of the `config` options is also preformed this can return an | ||||||
|  | error as well that is expected to be handled by the instantiation function | ||||||
|  | or propagated to the user. | ||||||
|  |  | ||||||
|  | Given the design goal of not having the user need to work with the `config`, | ||||||
|  | the `newConfig` function should also be unexported. | ||||||
|  |  | ||||||
|  | #### `Option` | ||||||
|  |  | ||||||
|  | To set the value of the options a `config` contains, a corresponding | ||||||
|  | `Option` interface type should be used. | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | type Option interface { | ||||||
|  |   Apply(*config) | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | The name of the interface should be prefixed in the same way the | ||||||
|  | corresponding `config` is (if at all). | ||||||
|  |  | ||||||
|  | #### Options | ||||||
|  |  | ||||||
|  | All user configurable options for a `config` must have a related unexported | ||||||
|  | implementation of the `Option` interface and an exported configuration | ||||||
|  | function that wraps this implementation. | ||||||
|  |  | ||||||
|  | The wrapping function name should be prefixed with `With*` (or in the | ||||||
|  | special case of a boolean options `Without*`) and should have the following | ||||||
|  | function signature. | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | func With*(…) Option { … } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ##### `bool` Options | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | type defaultFalseOption bool | ||||||
|  |  | ||||||
|  | func (o defaultFalseOption) Apply(c *config) { | ||||||
|  |     c.Bool = bool(o) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithOption sets a T* to have an option included. | ||||||
|  | func WithOption() Option { | ||||||
|  |     return defaultFalseOption(true) | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | type defaultTrueOption bool | ||||||
|  |  | ||||||
|  | func (o defaultTrueOption) Apply(c *config) { | ||||||
|  |     c.Bool = bool(o) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithoutOption sets a T* to have Bool option excluded. | ||||||
|  | func WithoutOption() Option { | ||||||
|  |     return defaultTrueOption(false) | ||||||
|  | } | ||||||
|  | ```` | ||||||
|  |  | ||||||
|  | ##### Declared Type Options | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | type myTypeOption struct { | ||||||
|  |     MyType MyType | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (o myTypeOption) Apply(c *config) { | ||||||
|  |     c.MyType = o.MyType | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithMyType sets T* to have include MyType. | ||||||
|  | func WithMyType(t MyType) Option { | ||||||
|  |     return myTypeOption{t} | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | #### Instantiation | ||||||
|  |  | ||||||
|  | Using this configuration pattern to configure instantiation with a `New*` | ||||||
|  | function. | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | func NewT*(options ...Option) T* {…} | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Any required parameters can be declared before the variadic `options`. | ||||||
|  |  | ||||||
|  | #### Dealing with Overlap | ||||||
|  |  | ||||||
|  | Sometimes there are multiple complex `struct` that share common | ||||||
|  | configuration and also have distinct configuration. To avoid repeated | ||||||
|  | portions of `config`s, a common `config` can be used with the union of | ||||||
|  | options being handled with the `Option` interface. | ||||||
|  |  | ||||||
|  | For example. | ||||||
|  |  | ||||||
|  | ```go | ||||||
|  | // config holds options for all animals. | ||||||
|  | type config struct { | ||||||
|  | 	Weight      float64 | ||||||
|  | 	Color       string | ||||||
|  | 	MaxAltitude float64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DogOption apply Dog specific options. | ||||||
|  | type DogOption interface { | ||||||
|  | 	ApplyDog(*config) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // BirdOption apply Bird specific options. | ||||||
|  | type BirdOption interface { | ||||||
|  | 	ApplyBird(*config) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Option apply options for all animals. | ||||||
|  | type Option interface { | ||||||
|  | 	BirdOption | ||||||
|  | 	DogOption | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type weightOption float64 | ||||||
|  | func (o weightOption) ApplyDog(c *config)  { c.Weight = float64(o) } | ||||||
|  | func (o weightOption) ApplyBird(c *config) { c.Weight = float64(o) } | ||||||
|  | func WithWeight(w float64) Option          { return weightOption(w) } | ||||||
|  |  | ||||||
|  | type furColorOption string | ||||||
|  | func (o furColorOption) ApplyDog(c *config) { c.Color = string(o) } | ||||||
|  | func WithFurColor(c string) DogOption       { return furColorOption(c) } | ||||||
|  |  | ||||||
|  | type maxAltitudeOption float64 | ||||||
|  | func (o maxAltitudeOption) ApplyBird(c *config) { c.MaxAltitude = float64(o) } | ||||||
|  | func WithMaxAltitude(a float64) BirdOption      { return maxAltitudeOption(a) } | ||||||
|  |  | ||||||
|  | func NewDog(name string, o ...DogOption) Dog    {…} | ||||||
|  | func NewBird(name string, o ...BirdOption) Bird {…} | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ### Interface Type | ||||||
|  |  | ||||||
|  | To allow other developers to better comprehend the code, it is important | ||||||
|  | to ensure it is sufficiently documented. One simple measure that contributes | ||||||
|  | to this aim is self-documenting by naming method parameters. Therefore, | ||||||
|  | where appropriate, methods of every exported interface type should have | ||||||
|  | their parameters appropriately named. | ||||||
|  |  | ||||||
|  | ## Approvers and Maintainers | ||||||
|  |  | ||||||
|  | Approvers: | ||||||
|  |  | ||||||
|  | - [Liz Fong-Jones](https://github.com/lizthegrey), Honeycomb | ||||||
|  | - [Evan Torrie](https://github.com/evantorrie), Verizon Media | ||||||
|  | - [Josh MacDonald](https://github.com/jmacd), LightStep | ||||||
|  | - [Sam Xie](https://github.com/XSAM) | ||||||
|  | - [David Ashpole](https://github.com/dashpole), Google | ||||||
|  |  | ||||||
|  | Maintainers: | ||||||
|  |  | ||||||
|  | - [Anthony Mirabella](https://github.com/Aneurysm9), Centene | ||||||
|  | - [Tyler Yahn](https://github.com/MrAlias), New Relic | ||||||
|  |  | ||||||
|  | ### Become an Approver or a Maintainer | ||||||
|  |  | ||||||
|  | See the [community membership document in OpenTelemetry community | ||||||
|  | repo](https://github.com/open-telemetry/community/blob/master/community-membership.md). | ||||||
							
								
								
									
										201
									
								
								vendor/go.opentelemetry.io/otel/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								vendor/go.opentelemetry.io/otel/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,201 @@ | |||||||
|  |                                  Apache License | ||||||
|  |                            Version 2.0, January 2004 | ||||||
|  |                         http://www.apache.org/licenses/ | ||||||
|  |  | ||||||
|  |    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||||
|  |  | ||||||
|  |    1. Definitions. | ||||||
|  |  | ||||||
|  |       "License" shall mean the terms and conditions for use, reproduction, | ||||||
|  |       and distribution as defined by Sections 1 through 9 of this document. | ||||||
|  |  | ||||||
|  |       "Licensor" shall mean the copyright owner or entity authorized by | ||||||
|  |       the copyright owner that is granting the License. | ||||||
|  |  | ||||||
|  |       "Legal Entity" shall mean the union of the acting entity and all | ||||||
|  |       other entities that control, are controlled by, or are under common | ||||||
|  |       control with that entity. For the purposes of this definition, | ||||||
|  |       "control" means (i) the power, direct or indirect, to cause the | ||||||
|  |       direction or management of such entity, whether by contract or | ||||||
|  |       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||||
|  |       outstanding shares, or (iii) beneficial ownership of such entity. | ||||||
|  |  | ||||||
|  |       "You" (or "Your") shall mean an individual or Legal Entity | ||||||
|  |       exercising permissions granted by this License. | ||||||
|  |  | ||||||
|  |       "Source" form shall mean the preferred form for making modifications, | ||||||
|  |       including but not limited to software source code, documentation | ||||||
|  |       source, and configuration files. | ||||||
|  |  | ||||||
|  |       "Object" form shall mean any form resulting from mechanical | ||||||
|  |       transformation or translation of a Source form, including but | ||||||
|  |       not limited to compiled object code, generated documentation, | ||||||
|  |       and conversions to other media types. | ||||||
|  |  | ||||||
|  |       "Work" shall mean the work of authorship, whether in Source or | ||||||
|  |       Object form, made available under the License, as indicated by a | ||||||
|  |       copyright notice that is included in or attached to the work | ||||||
|  |       (an example is provided in the Appendix below). | ||||||
|  |  | ||||||
|  |       "Derivative Works" shall mean any work, whether in Source or Object | ||||||
|  |       form, that is based on (or derived from) the Work and for which the | ||||||
|  |       editorial revisions, annotations, elaborations, or other modifications | ||||||
|  |       represent, as a whole, an original work of authorship. For the purposes | ||||||
|  |       of this License, Derivative Works shall not include works that remain | ||||||
|  |       separable from, or merely link (or bind by name) to the interfaces of, | ||||||
|  |       the Work and Derivative Works thereof. | ||||||
|  |  | ||||||
|  |       "Contribution" shall mean any work of authorship, including | ||||||
|  |       the original version of the Work and any modifications or additions | ||||||
|  |       to that Work or Derivative Works thereof, that is intentionally | ||||||
|  |       submitted to Licensor for inclusion in the Work by the copyright owner | ||||||
|  |       or by an individual or Legal Entity authorized to submit on behalf of | ||||||
|  |       the copyright owner. For the purposes of this definition, "submitted" | ||||||
|  |       means any form of electronic, verbal, or written communication sent | ||||||
|  |       to the Licensor or its representatives, including but not limited to | ||||||
|  |       communication on electronic mailing lists, source code control systems, | ||||||
|  |       and issue tracking systems that are managed by, or on behalf of, the | ||||||
|  |       Licensor for the purpose of discussing and improving the Work, but | ||||||
|  |       excluding communication that is conspicuously marked or otherwise | ||||||
|  |       designated in writing by the copyright owner as "Not a Contribution." | ||||||
|  |  | ||||||
|  |       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||||
|  |       on behalf of whom a Contribution has been received by Licensor and | ||||||
|  |       subsequently incorporated within the Work. | ||||||
|  |  | ||||||
|  |    2. Grant of Copyright License. Subject to the terms and conditions of | ||||||
|  |       this License, each Contributor hereby grants to You a perpetual, | ||||||
|  |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||||
|  |       copyright license to reproduce, prepare Derivative Works of, | ||||||
|  |       publicly display, publicly perform, sublicense, and distribute the | ||||||
|  |       Work and such Derivative Works in Source or Object form. | ||||||
|  |  | ||||||
|  |    3. Grant of Patent License. Subject to the terms and conditions of | ||||||
|  |       this License, each Contributor hereby grants to You a perpetual, | ||||||
|  |       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||||
|  |       (except as stated in this section) patent license to make, have made, | ||||||
|  |       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||||
|  |       where such license applies only to those patent claims licensable | ||||||
|  |       by such Contributor that are necessarily infringed by their | ||||||
|  |       Contribution(s) alone or by combination of their Contribution(s) | ||||||
|  |       with the Work to which such Contribution(s) was submitted. If You | ||||||
|  |       institute patent litigation against any entity (including a | ||||||
|  |       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||||
|  |       or a Contribution incorporated within the Work constitutes direct | ||||||
|  |       or contributory patent infringement, then any patent licenses | ||||||
|  |       granted to You under this License for that Work shall terminate | ||||||
|  |       as of the date such litigation is filed. | ||||||
|  |  | ||||||
|  |    4. Redistribution. You may reproduce and distribute copies of the | ||||||
|  |       Work or Derivative Works thereof in any medium, with or without | ||||||
|  |       modifications, and in Source or Object form, provided that You | ||||||
|  |       meet the following conditions: | ||||||
|  |  | ||||||
|  |       (a) You must give any other recipients of the Work or | ||||||
|  |           Derivative Works a copy of this License; and | ||||||
|  |  | ||||||
|  |       (b) You must cause any modified files to carry prominent notices | ||||||
|  |           stating that You changed the files; and | ||||||
|  |  | ||||||
|  |       (c) You must retain, in the Source form of any Derivative Works | ||||||
|  |           that You distribute, all copyright, patent, trademark, and | ||||||
|  |           attribution notices from the Source form of the Work, | ||||||
|  |           excluding those notices that do not pertain to any part of | ||||||
|  |           the Derivative Works; and | ||||||
|  |  | ||||||
|  |       (d) If the Work includes a "NOTICE" text file as part of its | ||||||
|  |           distribution, then any Derivative Works that You distribute must | ||||||
|  |           include a readable copy of the attribution notices contained | ||||||
|  |           within such NOTICE file, excluding those notices that do not | ||||||
|  |           pertain to any part of the Derivative Works, in at least one | ||||||
|  |           of the following places: within a NOTICE text file distributed | ||||||
|  |           as part of the Derivative Works; within the Source form or | ||||||
|  |           documentation, if provided along with the Derivative Works; or, | ||||||
|  |           within a display generated by the Derivative Works, if and | ||||||
|  |           wherever such third-party notices normally appear. The contents | ||||||
|  |           of the NOTICE file are for informational purposes only and | ||||||
|  |           do not modify the License. You may add Your own attribution | ||||||
|  |           notices within Derivative Works that You distribute, alongside | ||||||
|  |           or as an addendum to the NOTICE text from the Work, provided | ||||||
|  |           that such additional attribution notices cannot be construed | ||||||
|  |           as modifying the License. | ||||||
|  |  | ||||||
|  |       You may add Your own copyright statement to Your modifications and | ||||||
|  |       may provide additional or different license terms and conditions | ||||||
|  |       for use, reproduction, or distribution of Your modifications, or | ||||||
|  |       for any such Derivative Works as a whole, provided Your use, | ||||||
|  |       reproduction, and distribution of the Work otherwise complies with | ||||||
|  |       the conditions stated in this License. | ||||||
|  |  | ||||||
|  |    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||||
|  |       any Contribution intentionally submitted for inclusion in the Work | ||||||
|  |       by You to the Licensor shall be under the terms and conditions of | ||||||
|  |       this License, without any additional terms or conditions. | ||||||
|  |       Notwithstanding the above, nothing herein shall supersede or modify | ||||||
|  |       the terms of any separate license agreement you may have executed | ||||||
|  |       with Licensor regarding such Contributions. | ||||||
|  |  | ||||||
|  |    6. Trademarks. This License does not grant permission to use the trade | ||||||
|  |       names, trademarks, service marks, or product names of the Licensor, | ||||||
|  |       except as required for reasonable and customary use in describing the | ||||||
|  |       origin of the Work and reproducing the content of the NOTICE file. | ||||||
|  |  | ||||||
|  |    7. Disclaimer of Warranty. Unless required by applicable law or | ||||||
|  |       agreed to in writing, Licensor provides the Work (and each | ||||||
|  |       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||||
|  |       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||||
|  |       implied, including, without limitation, any warranties or conditions | ||||||
|  |       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||||
|  |       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||||
|  |       appropriateness of using or redistributing the Work and assume any | ||||||
|  |       risks associated with Your exercise of permissions under this License. | ||||||
|  |  | ||||||
|  |    8. Limitation of Liability. In no event and under no legal theory, | ||||||
|  |       whether in tort (including negligence), contract, or otherwise, | ||||||
|  |       unless required by applicable law (such as deliberate and grossly | ||||||
|  |       negligent acts) or agreed to in writing, shall any Contributor be | ||||||
|  |       liable to You for damages, including any direct, indirect, special, | ||||||
|  |       incidental, or consequential damages of any character arising as a | ||||||
|  |       result of this License or out of the use or inability to use the | ||||||
|  |       Work (including but not limited to damages for loss of goodwill, | ||||||
|  |       work stoppage, computer failure or malfunction, or any and all | ||||||
|  |       other commercial damages or losses), even if such Contributor | ||||||
|  |       has been advised of the possibility of such damages. | ||||||
|  |  | ||||||
|  |    9. Accepting Warranty or Additional Liability. While redistributing | ||||||
|  |       the Work or Derivative Works thereof, You may choose to offer, | ||||||
|  |       and charge a fee for, acceptance of support, warranty, indemnity, | ||||||
|  |       or other liability obligations and/or rights consistent with this | ||||||
|  |       License. However, in accepting such obligations, You may act only | ||||||
|  |       on Your own behalf and on Your sole responsibility, not on behalf | ||||||
|  |       of any other Contributor, and only if You agree to indemnify, | ||||||
|  |       defend, and hold each Contributor harmless for any liability | ||||||
|  |       incurred by, or claims asserted against, such Contributor by reason | ||||||
|  |       of your accepting any such warranty or additional liability. | ||||||
|  |  | ||||||
|  |    END OF TERMS AND CONDITIONS | ||||||
|  |  | ||||||
|  |    APPENDIX: How to apply the Apache License to your work. | ||||||
|  |  | ||||||
|  |       To apply the Apache License to your work, attach the following | ||||||
|  |       boilerplate notice, with the fields enclosed by brackets "[]" | ||||||
|  |       replaced with your own identifying information. (Don't include | ||||||
|  |       the brackets!)  The text should be enclosed in the appropriate | ||||||
|  |       comment syntax for the file format. We also recommend that a | ||||||
|  |       file or class name and description of purpose be included on the | ||||||
|  |       same "printed page" as the copyright notice for easier | ||||||
|  |       identification within third-party archives. | ||||||
|  |  | ||||||
|  |    Copyright [yyyy] [name of copyright owner] | ||||||
|  |  | ||||||
|  |    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. | ||||||
							
								
								
									
										177
									
								
								vendor/go.opentelemetry.io/otel/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								vendor/go.opentelemetry.io/otel/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | |||||||
|  | # Copyright The OpenTelemetry Authors | ||||||
|  | # | ||||||
|  | # 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. | ||||||
|  |  | ||||||
|  | EXAMPLES := $(shell ./get_main_pkgs.sh ./example) | ||||||
|  | TOOLS_MOD_DIR := ./internal/tools | ||||||
|  |  | ||||||
|  | # All source code and documents. Used in spell check. | ||||||
|  | ALL_DOCS := $(shell find . -name '*.md' -type f | sort) | ||||||
|  | # All directories with go.mod files related to opentelemetry library. Used for building, testing and linting. | ||||||
|  | ALL_GO_MOD_DIRS := $(filter-out $(TOOLS_MOD_DIR), $(shell find . -type f -name 'go.mod' -exec dirname {} \; | egrep -v '^./example' | sort)) $(shell find ./example -type f -name 'go.mod' -exec dirname {} \; | sort) | ||||||
|  | ALL_COVERAGE_MOD_DIRS := $(shell find . -type f -name 'go.mod' -exec dirname {} \; | egrep -v '^./example|^$(TOOLS_MOD_DIR)' | sort) | ||||||
|  |  | ||||||
|  | # Mac OS Catalina 10.5.x doesn't support 386. Hence skip 386 test | ||||||
|  | SKIP_386_TEST = false | ||||||
|  | UNAME_S := $(shell uname -s) | ||||||
|  | ifeq ($(UNAME_S),Darwin) | ||||||
|  | 	SW_VERS := $(shell sw_vers -productVersion) | ||||||
|  | 	ifeq ($(shell echo $(SW_VERS) | egrep '^(10.1[5-9]|1[1-9]|[2-9])'), $(SW_VERS)) | ||||||
|  | 		SKIP_386_TEST = true | ||||||
|  | 	endif | ||||||
|  | endif | ||||||
|  |  | ||||||
|  | GOTEST_MIN = go test -timeout 30s | ||||||
|  | GOTEST = $(GOTEST_MIN) -race | ||||||
|  | GOTEST_WITH_COVERAGE = $(GOTEST) -coverprofile=coverage.out -covermode=atomic -coverpkg=./... | ||||||
|  |  | ||||||
|  | .DEFAULT_GOAL := precommit | ||||||
|  |  | ||||||
|  | .PHONY: precommit | ||||||
|  |  | ||||||
|  | TOOLS_DIR := $(abspath ./.tools) | ||||||
|  |  | ||||||
|  | $(TOOLS_DIR)/golangci-lint: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go | ||||||
|  | 	cd $(TOOLS_MOD_DIR) && \ | ||||||
|  | 	go build -o $(TOOLS_DIR)/golangci-lint github.com/golangci/golangci-lint/cmd/golangci-lint | ||||||
|  |  | ||||||
|  | $(TOOLS_DIR)/misspell: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go | ||||||
|  | 	cd $(TOOLS_MOD_DIR) && \ | ||||||
|  | 	go build -o $(TOOLS_DIR)/misspell github.com/client9/misspell/cmd/misspell | ||||||
|  |  | ||||||
|  | $(TOOLS_DIR)/stringer: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go | ||||||
|  | 	cd $(TOOLS_MOD_DIR) && \ | ||||||
|  | 	go build -o $(TOOLS_DIR)/stringer golang.org/x/tools/cmd/stringer | ||||||
|  |  | ||||||
|  | $(TOOLS_DIR)/gojq: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go | ||||||
|  | 	cd $(TOOLS_MOD_DIR) && \ | ||||||
|  | 	go build -o $(TOOLS_DIR)/gojq github.com/itchyny/gojq/cmd/gojq | ||||||
|  |  | ||||||
|  | precommit: dependabot-check license-check generate build lint examples test-benchmarks test | ||||||
|  |  | ||||||
|  | .PHONY: test-with-coverage | ||||||
|  | test-with-coverage: | ||||||
|  | 	set -e; \ | ||||||
|  | 	printf "" > coverage.txt; \ | ||||||
|  | 	for dir in $(ALL_COVERAGE_MOD_DIRS); do \ | ||||||
|  | 	  echo "go test ./... + coverage in $${dir}"; \ | ||||||
|  | 	  (cd "$${dir}" && \ | ||||||
|  | 	 	$(GOTEST_WITH_COVERAGE) ./... && \ | ||||||
|  | 		go tool cover -html=coverage.out -o coverage.html); \ | ||||||
|  |       [ -f "$${dir}/coverage.out" ] && cat "$${dir}/coverage.out" >> coverage.txt; \ | ||||||
|  | 	done; \ | ||||||
|  | 	sed -i.bak -e '2,$$ { /^mode: /d; }' coverage.txt | ||||||
|  |  | ||||||
|  |  | ||||||
|  | .PHONY: ci | ||||||
|  | ci: precommit check-clean-work-tree test-with-coverage test-386 | ||||||
|  |  | ||||||
|  | .PHONY: check-clean-work-tree | ||||||
|  | check-clean-work-tree: | ||||||
|  | 	@if ! git diff --quiet; then \ | ||||||
|  | 	  echo; \ | ||||||
|  | 	  echo 'Working tree is not clean, did you forget to run "make precommit"?'; \ | ||||||
|  | 	  echo; \ | ||||||
|  | 	  git status; \ | ||||||
|  | 	  exit 1; \ | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | .PHONY: build | ||||||
|  | build: | ||||||
|  | 	# TODO: Fix this on windows. | ||||||
|  | 	set -e; for dir in $(ALL_GO_MOD_DIRS); do \ | ||||||
|  | 	  echo "compiling all packages in $${dir}"; \ | ||||||
|  | 	  (cd "$${dir}" && \ | ||||||
|  | 	    go build ./... && \ | ||||||
|  | 	    go test -run xxxxxMatchNothingxxxxx ./... >/dev/null); \ | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | .PHONY: test | ||||||
|  | test: | ||||||
|  | 	set -e; for dir in $(ALL_GO_MOD_DIRS); do \ | ||||||
|  | 	  echo "go test ./... + race in $${dir}"; \ | ||||||
|  | 	  (cd "$${dir}" && \ | ||||||
|  | 	    $(GOTEST) ./...); \ | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | .PHONY: test-386 | ||||||
|  | test-386: | ||||||
|  | 	if [ $(SKIP_386_TEST) = true ] ; then \ | ||||||
|  | 	  echo "skipping the test for GOARCH 386 as it is not supported on the current OS"; \ | ||||||
|  | 	else \ | ||||||
|  | 	  set -e; for dir in $(ALL_GO_MOD_DIRS); do \ | ||||||
|  | 	    echo "go test ./... GOARCH 386 in $${dir}"; \ | ||||||
|  | 	    (cd "$${dir}" && \ | ||||||
|  | 	      GOARCH=386 $(GOTEST_MIN) ./...); \ | ||||||
|  | 	  done; \ | ||||||
|  | 	fi | ||||||
|  |  | ||||||
|  | .PHONY: examples | ||||||
|  | examples: | ||||||
|  | 	@set -e; for ex in $(EXAMPLES); do \ | ||||||
|  | 	  echo "Building $${ex}"; \ | ||||||
|  | 	  (cd "$${ex}" && \ | ||||||
|  | 	   go build .); \ | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | .PHONY: test-benchmarks | ||||||
|  | test-benchmarks: | ||||||
|  | 	@set -e; for dir in $(ALL_GO_MOD_DIRS); do \ | ||||||
|  | 	  echo "test benchmarks in $${dir}"; \ | ||||||
|  | 	  (cd "$${dir}" && go test -test.benchtime=1ms -run=NONE -bench=. ./...) > /dev/null; \ | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | .PHONY: lint | ||||||
|  | lint: $(TOOLS_DIR)/golangci-lint $(TOOLS_DIR)/misspell | ||||||
|  | 	set -e; for dir in $(ALL_GO_MOD_DIRS); do \ | ||||||
|  | 	  echo "golangci-lint in $${dir}"; \ | ||||||
|  | 	  (cd "$${dir}" && \ | ||||||
|  | 	    $(TOOLS_DIR)/golangci-lint run --fix && \ | ||||||
|  | 	    $(TOOLS_DIR)/golangci-lint run); \ | ||||||
|  | 	done | ||||||
|  | 	$(TOOLS_DIR)/misspell -w $(ALL_DOCS) | ||||||
|  | 	set -e; for dir in $(ALL_GO_MOD_DIRS) $(TOOLS_MOD_DIR); do \ | ||||||
|  | 	  echo "go mod tidy in $${dir}"; \ | ||||||
|  | 	  (cd "$${dir}" && \ | ||||||
|  | 	    go mod tidy); \ | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | generate: $(TOOLS_DIR)/stringer | ||||||
|  | 	set -e; for dir in $(ALL_GO_MOD_DIRS); do \ | ||||||
|  | 	  echo "running generators in $${dir}"; \ | ||||||
|  | 	  (cd "$${dir}" && \ | ||||||
|  | 	    PATH="$(TOOLS_DIR):$${PATH}" go generate ./...); \ | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | .PHONY: license-check | ||||||
|  | license-check: | ||||||
|  | 	@licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path './vendor/*' ! -path './exporters/otlp/internal/opentelemetry-proto/*') ; do \ | ||||||
|  | 	           awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=3 { found=1; next } END { if (!found) print FILENAME }' $$f; \ | ||||||
|  | 	   done); \ | ||||||
|  | 	   if [ -n "$${licRes}" ]; then \ | ||||||
|  | 	           echo "license header checking failed:"; echo "$${licRes}"; \ | ||||||
|  | 	           exit 1; \ | ||||||
|  | 	   fi | ||||||
|  |  | ||||||
|  | .PHONY: dependabot-check | ||||||
|  | dependabot-check: | ||||||
|  | 	@result=$$( \ | ||||||
|  | 		for f in $$( find . -type f -name go.mod -exec dirname {} \; | sed 's/^.\/\?/\//' ); \ | ||||||
|  | 			do grep -q "$$f" .github/dependabot.yml \ | ||||||
|  | 			|| echo "$$f"; \ | ||||||
|  | 		done; \ | ||||||
|  | 	); \ | ||||||
|  | 	if [ -n "$$result" ]; then \ | ||||||
|  | 		echo "missing go.mod dependabot check:"; echo "$$result"; \ | ||||||
|  | 		exit 1; \ | ||||||
|  | 	fi | ||||||
							
								
								
									
										129
									
								
								vendor/go.opentelemetry.io/otel/Makefile.proto
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								vendor/go.opentelemetry.io/otel/Makefile.proto
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | |||||||
|  | #   -*- mode: makefile; -*- | ||||||
|  | # Copyright The OpenTelemetry Authors | ||||||
|  | # | ||||||
|  | # 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. | ||||||
|  | # | ||||||
|  | # This Makefile.proto has rules to generate go code for otlp | ||||||
|  | # exporter. It does it by copying the proto files from | ||||||
|  | # `exporters/otlp/internal/opentelemetry-proto` (which is a | ||||||
|  | # submodule that needs to be checked out) into `gen/proto`, changing | ||||||
|  | # the go_package option to a valid string, generating the go files and | ||||||
|  | # finally copying the files into the module. The files are not | ||||||
|  | # generated in place, because protoc generates a too-deep directory | ||||||
|  | # structure. | ||||||
|  | # | ||||||
|  | # Currently, all the generated code is in | ||||||
|  | # `exporters/otlp/internal/opentelemetry-proto-gen`. | ||||||
|  | # | ||||||
|  | # Prereqs: wget (for downloading the zip file with protoc binary), | ||||||
|  | # unzip (for unpacking the archive), rsync (for copying back the | ||||||
|  | # generated files). | ||||||
|  |  | ||||||
|  | PROTOC_VERSION := 3.14.0 | ||||||
|  |  | ||||||
|  | TOOLS_DIR                       := $(abspath ./.tools) | ||||||
|  | TOOLS_MOD_DIR                   := ./internal/tools | ||||||
|  | PROTOBUF_VERSION                := v1 | ||||||
|  | OTEL_PROTO_SUBMODULE            := exporters/otlp/internal/opentelemetry-proto | ||||||
|  | GEN_TEMP_DIR                    := gen | ||||||
|  | SUBMODULE_PROTO_FILES           := $(wildcard $(OTEL_PROTO_SUBMODULE)/opentelemetry/proto/*/$(PROTOBUF_VERSION)/*.proto) $(wildcard $(OTEL_PROTO_SUBMODULE)/opentelemetry/proto/collector/*/$(PROTOBUF_VERSION)/*.proto) | ||||||
|  |  | ||||||
|  | ifeq ($(strip $(SUBMODULE_PROTO_FILES)),) | ||||||
|  | $(error Submodule at $(OTEL_PROTO_SUBMODULE) is not checked out, use "git submodule update --init") | ||||||
|  | endif | ||||||
|  |  | ||||||
|  | PROTOBUF_GEN_DIR   := exporters/otlp/internal/opentelemetry-proto-gen | ||||||
|  | PROTOBUF_TEMP_DIR  := $(GEN_TEMP_DIR)/pb-go | ||||||
|  | PROTO_SOURCE_DIR   := $(GEN_TEMP_DIR)/proto | ||||||
|  | SOURCE_PROTO_FILES := $(subst $(OTEL_PROTO_SUBMODULE),$(PROTO_SOURCE_DIR),$(SUBMODULE_PROTO_FILES)) | ||||||
|  |  | ||||||
|  | .DEFAULT_GOAL := protobuf | ||||||
|  |  | ||||||
|  | UNAME_S := $(shell uname -s) | ||||||
|  | UNAME_M := $(shell uname -m) | ||||||
|  |  | ||||||
|  | ifeq ($(UNAME_S),Linux) | ||||||
|  |  | ||||||
|  | PROTOC_OS := linux | ||||||
|  | PROTOC_ARCH := $(UNAME_M) | ||||||
|  |  | ||||||
|  | else ifeq ($(UNAME_S),Darwin) | ||||||
|  |  | ||||||
|  | PROTOC_OS := osx | ||||||
|  | PROTOC_ARCH := x86_64 | ||||||
|  |  | ||||||
|  | endif | ||||||
|  |  | ||||||
|  | PROTOC_ZIP_URL := https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOC_VERSION)/protoc-$(PROTOC_VERSION)-$(PROTOC_OS)-$(PROTOC_ARCH).zip | ||||||
|  |  | ||||||
|  | $(TOOLS_DIR)/PROTOC_$(PROTOC_VERSION): | ||||||
|  | 	@rm -f "$(TOOLS_DIR)"/PROTOC_* && \ | ||||||
|  | 	touch "$@" | ||||||
|  |  | ||||||
|  | # Depend on a versioned file (like PROTOC_3.14.0), so when version | ||||||
|  | # gets bumped, we will depend on a nonexistent file and thus download | ||||||
|  | # a newer version. | ||||||
|  | $(TOOLS_DIR)/protoc/bin/protoc: $(TOOLS_DIR)/PROTOC_$(PROTOC_VERSION) | ||||||
|  | 	echo "Fetching protoc $(PROTOC_VERSION)" && \ | ||||||
|  | 	rm -rf $(TOOLS_DIR)/protoc && \ | ||||||
|  | 	wget -O $(TOOLS_DIR)/protoc.zip $(PROTOC_ZIP_URL) && \ | ||||||
|  | 	unzip $(TOOLS_DIR)/protoc.zip -d $(TOOLS_DIR)/protoc-tmp && \ | ||||||
|  | 	rm $(TOOLS_DIR)/protoc.zip && \ | ||||||
|  | 	touch $(TOOLS_DIR)/protoc-tmp/bin/protoc && \ | ||||||
|  | 	mv $(TOOLS_DIR)/protoc-tmp $(TOOLS_DIR)/protoc | ||||||
|  |  | ||||||
|  | $(TOOLS_DIR)/protoc-gen-gogofast: $(TOOLS_MOD_DIR)/go.mod $(TOOLS_MOD_DIR)/go.sum $(TOOLS_MOD_DIR)/tools.go | ||||||
|  | 	cd $(TOOLS_MOD_DIR) && \ | ||||||
|  | 	go build -o $(TOOLS_DIR)/protoc-gen-gogofast github.com/gogo/protobuf/protoc-gen-gogofast && \ | ||||||
|  | 	go mod tidy | ||||||
|  |  | ||||||
|  | # Return a sed expression for replacing the go_package option in proto | ||||||
|  | # file with a one that's valid for us. | ||||||
|  | # | ||||||
|  | # Example: $(call get-sed-expr,$(PROTOBUF_GEN_DIR)) | ||||||
|  | define get-sed-expr | ||||||
|  | 's,go_package = "github.com/open-telemetry/opentelemetry-proto/gen/go,go_package = "go.opentelemetry.io/otel/$(1),' | ||||||
|  | endef | ||||||
|  |  | ||||||
|  | .PHONY: protobuf | ||||||
|  | protobuf: protobuf-source gen-protobuf copy-protobufs | ||||||
|  |  | ||||||
|  | .PHONY: protobuf-source | ||||||
|  | protobuf-source: $(SOURCE_PROTO_FILES) | ||||||
|  |  | ||||||
|  | # This copies proto files from submodule into $(PROTO_SOURCE_DIR), | ||||||
|  | # thus satisfying the $(SOURCE_PROTO_FILES) prerequisite. The copies | ||||||
|  | # have their package name replaced by go.opentelemetry.io/otel. | ||||||
|  | $(PROTO_SOURCE_DIR)/%.proto: $(OTEL_PROTO_SUBMODULE)/%.proto | ||||||
|  | 	@ \ | ||||||
|  | 	mkdir -p $(@D); \ | ||||||
|  | 	sed -e $(call get-sed-expr,$(PROTOBUF_GEN_DIR)) "$<" >"$@.tmp"; \ | ||||||
|  | 	mv "$@.tmp" "$@" | ||||||
|  |  | ||||||
|  | .PHONY: gen-protobuf | ||||||
|  | gen-protobuf: $(SOURCE_PROTO_FILES) $(TOOLS_DIR)/protoc-gen-gogofast $(TOOLS_DIR)/protoc/bin/protoc | ||||||
|  | 	@ \ | ||||||
|  | 	mkdir -p "$(PROTOBUF_TEMP_DIR)"; \ | ||||||
|  | 	set -e; for f in $^; do \ | ||||||
|  | 	  if [[ "$${f}" == $(TOOLS_DIR)/* ]]; then continue; fi; \ | ||||||
|  | 	  echo "protoc $${f#"$(PROTO_SOURCE_DIR)/"}"; \ | ||||||
|  | 	  PATH="$(TOOLS_DIR):$${PATH}" $(TOOLS_DIR)/protoc/bin/protoc --proto_path="$(PROTO_SOURCE_DIR)" --gogofast_out="plugins=grpc:$(PROTOBUF_TEMP_DIR)" "$${f}"; \ | ||||||
|  | 	done | ||||||
|  |  | ||||||
|  | .PHONY: copy-protobufs | ||||||
|  | copy-protobufs: | ||||||
|  | 	@rsync -a $(PROTOBUF_TEMP_DIR)/go.opentelemetry.io/otel/exporters . | ||||||
|  |  | ||||||
|  | .PHONY: clean | ||||||
|  | clean: | ||||||
|  | 	rm -rf $(GEN_TEMP_DIR) | ||||||
							
								
								
									
										71
									
								
								vendor/go.opentelemetry.io/otel/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								vendor/go.opentelemetry.io/otel/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | # OpenTelemetry-Go | ||||||
|  |  | ||||||
|  | [](https://github.com/open-telemetry/opentelemetry-go/actions?query=workflow%3Aci+branch%3Amaster) | ||||||
|  | [](https://pkg.go.dev/go.opentelemetry.io/otel) | ||||||
|  | [](https://goreportcard.com/report/go.opentelemetry.io/otel) | ||||||
|  | [](https://gitter.im/open-telemetry/opentelemetry-go?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) | ||||||
|  |  | ||||||
|  | The Go [OpenTelemetry](https://opentelemetry.io/) implementation. | ||||||
|  |  | ||||||
|  | ## Project Status | ||||||
|  |  | ||||||
|  | **Warning**: this project is currently in a pre-GA phase. Backwards | ||||||
|  | incompatible changes may be introduced in subsequent minor version releases as | ||||||
|  | we work to track the evolving OpenTelemetry specification and user feedback. | ||||||
|  |  | ||||||
|  | Our progress towards a GA release candidate is tracked in [this project | ||||||
|  | board](https://github.com/orgs/open-telemetry/projects/5). This release | ||||||
|  | candidate will follow semantic versioning and will be released with a major | ||||||
|  | version greater than zero. | ||||||
|  |  | ||||||
|  | Progress and status specific to this repository is tracked in our local | ||||||
|  | [project boards](https://github.com/open-telemetry/opentelemetry-go/projects) | ||||||
|  | and | ||||||
|  | [milestones](https://github.com/open-telemetry/opentelemetry-go/milestones). | ||||||
|  |  | ||||||
|  | Project versioning information and stability guarantees can be found in the | ||||||
|  | [versioning documentation](./VERSIONING.md). | ||||||
|  |  | ||||||
|  | ## Getting Started | ||||||
|  |  | ||||||
|  | You can find a getting started guide on [opentelemetry.io](https://opentelemetry.io/docs/go/getting-started/). | ||||||
|  |  | ||||||
|  | OpenTelemetry's goal is to provide a single set of APIs to capture distributed | ||||||
|  | traces and metrics from your application and send them to an observability | ||||||
|  | platform. This project allows you to do just that for applications written in | ||||||
|  | Go. There are two steps to this process: instrument your application, and | ||||||
|  | configure an exporter. | ||||||
|  |  | ||||||
|  | ### Instrumentation | ||||||
|  |  | ||||||
|  | To start capturing distributed traces and metric events from your application | ||||||
|  | it first needs to be instrumented. The easiest way to do this is by using an | ||||||
|  | instrumentation library for your code. Be sure to check out [the officially | ||||||
|  | supported instrumentation | ||||||
|  | libraries](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/master/instrumentation). | ||||||
|  |  | ||||||
|  | If you need to extend the telemetry an instrumentation library provides or want | ||||||
|  | to build your own instrumentation for your application directly you will need | ||||||
|  | to use the | ||||||
|  | [go.opentelemetry.io/otel/api](https://pkg.go.dev/go.opentelemetry.io/otel/api) | ||||||
|  | package. The included [examples](./example/) are a good way to see some | ||||||
|  | practical uses of this process. | ||||||
|  |  | ||||||
|  | ### Export | ||||||
|  |  | ||||||
|  | Now that your application is instrumented to collect telemetry, it needs an | ||||||
|  | export pipeline to send that telemetry to an observability platform. | ||||||
|  |  | ||||||
|  | You can find officially supported exporters [here](./exporters/) and in the | ||||||
|  | companion [contrib | ||||||
|  | repository](https://github.com/open-telemetry/opentelemetry-go-contrib/tree/master/exporters/metric). | ||||||
|  | Additionally, there are many vendor specific or 3rd party exporters for | ||||||
|  | OpenTelemetry. These exporters are broken down by | ||||||
|  | [trace](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/export/trace?tab=importedby) | ||||||
|  | and | ||||||
|  | [metric](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/export/metric?tab=importedby) | ||||||
|  | support. | ||||||
|  |  | ||||||
|  | ## Contributing | ||||||
|  |  | ||||||
|  | See the [contributing documentation](CONTRIBUTING.md). | ||||||
							
								
								
									
										81
									
								
								vendor/go.opentelemetry.io/otel/RELEASING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								vendor/go.opentelemetry.io/otel/RELEASING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | # Release Process | ||||||
|  |  | ||||||
|  | ## Pre-Release | ||||||
|  |  | ||||||
|  | Update go.mod for submodules to depend on the new release which will happen in the next step. | ||||||
|  |  | ||||||
|  | 1. Run the pre-release script. It creates a branch `pre_release_<new tag>` that will contain all release changes. | ||||||
|  |  | ||||||
|  |     ``` | ||||||
|  |     ./pre_release.sh -t <new tag> | ||||||
|  |     ``` | ||||||
|  |  | ||||||
|  | 2. Verify the changes. | ||||||
|  |  | ||||||
|  |     ``` | ||||||
|  |     git diff master | ||||||
|  |     ``` | ||||||
|  |  | ||||||
|  |     This should have changed the version for all modules to be `<new tag>`. | ||||||
|  |  | ||||||
|  | 3. Update the [Changelog](./CHANGELOG.md). | ||||||
|  |    - Make sure all relevant changes for this release are included and are in language that non-contributors to the project can understand. | ||||||
|  |        To verify this, you can look directly at the commits since the `<last tag>`. | ||||||
|  |  | ||||||
|  |        ``` | ||||||
|  |        git --no-pager log --pretty=oneline "<last tag>..HEAD" | ||||||
|  |        ``` | ||||||
|  |  | ||||||
|  |    - Move all the `Unreleased` changes into a new section following the title scheme (`[<new tag>] - <date of release>`). | ||||||
|  |    - Update all the appropriate links at the bottom. | ||||||
|  |  | ||||||
|  | 4. Push the changes to upstream and create a Pull Request on GitHub. | ||||||
|  |     Be sure to include the curated changes from the [Changelog](./CHANGELOG.md) in the description. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## Tag | ||||||
|  |  | ||||||
|  | Once the Pull Request with all the version changes has been approved and merged it is time to tag the merged commit. | ||||||
|  |  | ||||||
|  | ***IMPORTANT***: It is critical you use the same tag that you used in the Pre-Release step! | ||||||
|  | Failure to do so will leave things in a broken state. | ||||||
|  |  | ||||||
|  | ***IMPORTANT***: [There is currently no way to remove an incorrectly tagged version of a Go module](https://github.com/golang/go/issues/34189). | ||||||
|  | It is critical you make sure the version you push upstream is correct. | ||||||
|  | [Failure to do so will lead to minor emergencies and tough to work around](https://github.com/open-telemetry/opentelemetry-go/issues/331). | ||||||
|  |  | ||||||
|  | 1. Run the tag.sh script using the `<commit-hash>` of the commit on the master branch for the merged Pull Request. | ||||||
|  |  | ||||||
|  |     ``` | ||||||
|  |     ./tag.sh <new tag> <commit-hash> | ||||||
|  |     ``` | ||||||
|  |  | ||||||
|  | 2. Push tags to the upstream remote (not your fork: `github.com/open-telemetry/opentelemetry-go.git`). | ||||||
|  |     Make sure you push all sub-modules as well. | ||||||
|  |  | ||||||
|  |     ``` | ||||||
|  |     git push upstream <new tag> | ||||||
|  |     git push upstream <submodules-path/new tag> | ||||||
|  |     ... | ||||||
|  |     ``` | ||||||
|  |  | ||||||
|  | ## Release | ||||||
|  |  | ||||||
|  | Finally create a Release for the new `<new tag>` on GitHub. | ||||||
|  | The release body should include all the release notes from the Changelog for this release. | ||||||
|  | Additionally, the `tag.sh` script generates commit logs since last release which can be used to supplement the release notes. | ||||||
|  |  | ||||||
|  | ## Verify Examples | ||||||
|  |  | ||||||
|  | After releasing verify that examples build outside of the repository. | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | ./verify_examples.sh | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | The script copies examples into a different directory removes any `replace` declarations in `go.mod` and builds them. | ||||||
|  | This ensures they build with the published release, not the local copy. | ||||||
|  |  | ||||||
|  | ## Contrib Repository | ||||||
|  |  | ||||||
|  | Once verified be sure to [make a release for the `contrib` repository](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/master/RELEASING.md) that uses this release. | ||||||
							
								
								
									
										217
									
								
								vendor/go.opentelemetry.io/otel/VERSIONING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								vendor/go.opentelemetry.io/otel/VERSIONING.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | |||||||
|  | # Versioning | ||||||
|  |  | ||||||
|  | This document describes the versioning policy for this repository. This policy | ||||||
|  | is designed so the following goals can be achieved. | ||||||
|  |  | ||||||
|  | **Users are provided a codebase of value that is stable and secure.** | ||||||
|  |  | ||||||
|  | ## Policy | ||||||
|  |  | ||||||
|  | * Versioning of this project will be idiomatic of a Go project using [Go | ||||||
|  |   modules](https://github.com/golang/go/wiki/Modules). | ||||||
|  |   * [Semantic import | ||||||
|  |     versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning) | ||||||
|  |     will be used. | ||||||
|  |     * Versions will comply with [semver 2.0](https://semver.org/spec/v2.0.0.html). | ||||||
|  |     * If a module is version `v2` or higher, the major version of the module | ||||||
|  |       must be included as a `/vN` at the end of the module paths used in | ||||||
|  |       `go.mod` files (e.g., `module go.opentelemetry.io/otel/v2`, `require | ||||||
|  |       go.opentelemetry.io/otel/v2 v2.0.1`) and in the package import path | ||||||
|  |       (e.g., `import "go.opentelemetry.io/otel/v2/trace"`). This includes the | ||||||
|  |       paths used in `go get` commands (e.g., `go get | ||||||
|  |       go.opentelemetry.io/otel/v2@v2.0.1`.  Note there is both a `/v2` and a | ||||||
|  |       `@v2.0.1` in that example. One way to think about it is that the module | ||||||
|  |       name now includes the `/v2`, so include `/v2` whenever you are using the | ||||||
|  |       module name). | ||||||
|  |     * If a module is version `v0` or `v1`, do not include the major version in | ||||||
|  |       either the module path or the import path. | ||||||
|  |   * Modules will be used to encapsulate signals and components. | ||||||
|  |     * Experimental modules still under active development will be versioned at | ||||||
|  |       `v0` to imply the stability guarantee defined by | ||||||
|  |       [semver](https://semver.org/spec/v2.0.0.html#spec-item-4). | ||||||
|  |  | ||||||
|  |       > Major version zero (0.y.z) is for initial development. Anything MAY | ||||||
|  |       > change at any time. The public API SHOULD NOT be considered stable. | ||||||
|  |  | ||||||
|  |     * Mature modules for which we guarantee a stable public API will be versioned | ||||||
|  |       with a major version greater than `v0`. | ||||||
|  |       * The decision to make a module stable will be made on a case-by-case | ||||||
|  |         basis by the maintainers of this project. | ||||||
|  |     * Experimental modules will start their versioning at `v0.0.0` and will | ||||||
|  |       increment their minor version when backwards incompatible changes are | ||||||
|  |       released and increment their patch version when backwards compatible | ||||||
|  |       changes are released. | ||||||
|  |     * All stable modules that use the same major version number will use the | ||||||
|  |       same entire version number. | ||||||
|  |       * Stable modules may be released with an incremented minor or patch | ||||||
|  |         version even though that module has not been changed, but rather so | ||||||
|  |         that it will remain at the same version as other stable modules that | ||||||
|  |         did undergo change. | ||||||
|  |       * When an experimental module becomes stable a new stable module version | ||||||
|  |         will be released and will include this now stable module. The new | ||||||
|  |         stable module version will be an increment of the minor version number | ||||||
|  |         and will be applied to all existing stable modules as well as the newly | ||||||
|  |         stable module being released. | ||||||
|  | * Versioning of the associated [contrib | ||||||
|  |   repository](https://github.com/open-telemetry/opentelemetry-go-contrib) of | ||||||
|  |   this project will be idiomatic of a Go project using [Go | ||||||
|  |   modules](https://github.com/golang/go/wiki/Modules). | ||||||
|  |   * [Semantic import | ||||||
|  |     versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning) | ||||||
|  |     will be used. | ||||||
|  |     * Versions will comply with [semver 2.0](https://semver.org/spec/v2.0.0.html). | ||||||
|  |     * If a module is version `v2` or higher, the | ||||||
|  |       major version of the module must be included as a `/vN` at the end of the | ||||||
|  |       module paths used in `go.mod` files (e.g., `module | ||||||
|  |       go.opentelemetry.io/contrib/instrumentation/host/v2`, `require | ||||||
|  |       go.opentelemetry.io/contrib/instrumentation/host/v2 v2.0.1`) and in the | ||||||
|  |       package import path (e.g., `import | ||||||
|  |       "go.opentelemetry.io/contrib/instrumentation/host/v2"`). This includes | ||||||
|  |       the paths used in `go get` commands (e.g., `go get | ||||||
|  |       go.opentelemetry.io/contrib/instrumentation/host/v2@v2.0.1`.  Note there | ||||||
|  |       is both a `/v2` and a `@v2.0.1` in that example. One way to think about | ||||||
|  |       it is that the module name now includes the `/v2`, so include `/v2` | ||||||
|  |       whenever you are using the module name). | ||||||
|  |     * If a module is version `v0` or `v1`, do not include the major version | ||||||
|  |       in either the module path or the import path. | ||||||
|  |   * In addition to public APIs, telemetry produced by stable instrumentation | ||||||
|  |     will remain stable and backwards compatible. This is to avoid breaking | ||||||
|  |     alerts and dashboard. | ||||||
|  |   * Modules will be used to encapsulate instrumentation, detectors, exporters, | ||||||
|  |     propagators, and any other independent sets of related components. | ||||||
|  |     * Experimental modules still under active development will be versioned at | ||||||
|  |       `v0` to imply the stability guarantee defined by | ||||||
|  |       [semver](https://semver.org/spec/v2.0.0.html#spec-item-4). | ||||||
|  |  | ||||||
|  |       > Major version zero (0.y.z) is for initial development. Anything MAY | ||||||
|  |       > change at any time. The public API SHOULD NOT be considered stable. | ||||||
|  |  | ||||||
|  |     * Mature modules for which we guarantee a stable public API and telemetry will | ||||||
|  |       be versioned with a major version greater than `v0`. | ||||||
|  |     * Experimental modules will start their versioning at `v0.0.0` and will | ||||||
|  |       increment their minor version when backwards incompatible changes are | ||||||
|  |       released and increment their patch version when backwards compatible | ||||||
|  |       changes are released. | ||||||
|  |     * Stable contrib modules cannot depend on experimental modules from this | ||||||
|  |       project. | ||||||
|  |     * All stable contrib modules of the same major version with this project | ||||||
|  |       will use the same entire version as this project. | ||||||
|  |       * Stable modules may be released with an incremented minor or patch | ||||||
|  |         version even though that module's code has not been changed. Instead | ||||||
|  |         the only change that will have been included is to have updated that | ||||||
|  |         modules dependency on this project's stable APIs. | ||||||
|  |       * When an experimental module in contrib becomes stable a new stable | ||||||
|  |         module version will be released and will include this now stable | ||||||
|  |         module. The new stable module version will be an increment of the minor | ||||||
|  |         version number and will be applied to all existing stable contrib | ||||||
|  |         modules, this project's modules, and the newly stable module being | ||||||
|  |         released. | ||||||
|  |   * Contrib modules will be kept up to date with this project's releases. | ||||||
|  |     * Due to the dependency contrib modules will implicitly have on this | ||||||
|  |       project's modules the release of stable contrib modules to match the | ||||||
|  |       released version number will be staggered after this project's release. | ||||||
|  |       There is no explicit time guarantee for how long after this projects | ||||||
|  |       release the contrib release will be. Effort should be made to keep them | ||||||
|  |       as close in time as possible. | ||||||
|  |     * No additional stable release in this project can be made until the | ||||||
|  |       contrib repository has a matching stable release. | ||||||
|  |     * No release can be made in the contrib repository after this project's | ||||||
|  |       stable release except for a stable release of the contrib repository. | ||||||
|  | * GitHub releases will be made for all releases. | ||||||
|  | * Go modules will be made available at Go package mirrors. | ||||||
|  |  | ||||||
|  | ## Example Versioning Lifecycle | ||||||
|  |  | ||||||
|  | To better understand the implementation of the above policy the following | ||||||
|  | example is provided. This project is simplified to include only the following | ||||||
|  | modules and their versions: | ||||||
|  |  | ||||||
|  | * `otel`: `v0.14.0` | ||||||
|  | * `otel/trace`: `v0.14.0` | ||||||
|  | * `otel/metric`: `v0.14.0` | ||||||
|  | * `otel/baggage`: `v0.14.0` | ||||||
|  | * `otel/sdk/trace`: `v0.14.0` | ||||||
|  | * `otel/sdk/metric`: `v0.14.0` | ||||||
|  |  | ||||||
|  | These modules have been developed to a point where the `otel/trace`, | ||||||
|  | `otel/baggage`, and `otel/sdk/trace` modules have reached a point that they | ||||||
|  | should be considered for a stable release. The `otel/metric` and | ||||||
|  | `otel/sdk/metric` are still under active development and the `otel` module | ||||||
|  | depends on both `otel/trace` and `otel/metric`. | ||||||
|  |  | ||||||
|  | The `otel` package is refactored to remove its dependencies on `otel/metric` so | ||||||
|  | it can be released as stable as well. With that done the following release | ||||||
|  | candidates are made: | ||||||
|  |  | ||||||
|  | * `otel`: `v1.0.0-rc.1` | ||||||
|  | * `otel/trace`: `v1.0.0-rc.1` | ||||||
|  | * `otel/baggage`: `v1.0.0-rc.1` | ||||||
|  | * `otel/sdk/trace`: `v1.0.0-rc.1` | ||||||
|  |  | ||||||
|  | The `otel/metric` and `otel/sdk/metric` modules remain at `v0.14.0`. | ||||||
|  |  | ||||||
|  | A few minor issues are discovered in the `otel/trace` package. These issues are | ||||||
|  | resolved with some minor, but backwards incompatible, changes and are released | ||||||
|  | as a second release candidate: | ||||||
|  |  | ||||||
|  | * `otel`: `v1.0.0-rc.2` | ||||||
|  | * `otel/trace`: `v1.0.0-rc.2` | ||||||
|  | * `otel/baggage`: `v1.0.0-rc.2` | ||||||
|  | * `otel/sdk/trace`: `v1.0.0-rc.2` | ||||||
|  |  | ||||||
|  | Notice that all module version numbers are incremented to adhere to our | ||||||
|  | versioning policy. | ||||||
|  |  | ||||||
|  | After these release candidates have been evaluated to satisfaction, they are | ||||||
|  | released as version `v1.0.0`. | ||||||
|  |  | ||||||
|  | * `otel`: `v1.0.0` | ||||||
|  | * `otel/trace`: `v1.0.0` | ||||||
|  | * `otel/baggage`: `v1.0.0` | ||||||
|  | * `otel/sdk/trace`: `v1.0.0` | ||||||
|  |  | ||||||
|  | Since both the `go` utility and the Go module system support [the semantic | ||||||
|  | versioning definition of | ||||||
|  | precedence](https://semver.org/spec/v2.0.0.html#spec-item-11), this release | ||||||
|  | will correctly be interpreted as the successor to the previous release | ||||||
|  | candidates. | ||||||
|  |  | ||||||
|  | Active development of this project continues. The `otel/metric` module now has | ||||||
|  | backwards incompatible changes to its API that need to be released and the | ||||||
|  | `otel/baggage` module has a minor bug fix that needs to be released. The | ||||||
|  | following release is made: | ||||||
|  |  | ||||||
|  | * `otel`: `v1.0.1` | ||||||
|  | * `otel/trace`: `v1.0.1` | ||||||
|  | * `otel/metric`: `v0.15.0` | ||||||
|  | * `otel/baggage`: `v1.0.1` | ||||||
|  | * `otel/sdk/trace`: `v1.0.1` | ||||||
|  | * `otel/sdk/metric`: `v0.15.0` | ||||||
|  |  | ||||||
|  | Notice that, again, all stable module versions are incremented in unison and | ||||||
|  | the `otel/sdk/metric` package, which depends on the `otel/metric` package, also | ||||||
|  | bumped its version. This bump of the `otel/sdk/metric` package makes sense | ||||||
|  | given their coupling, though it is not explicitly required by our versioning | ||||||
|  | policy. | ||||||
|  |  | ||||||
|  | As we progress, the `otel/metric` and `otel/sdk/metric` packages have reached a | ||||||
|  | point where they should be evaluated for stability. The `otel` module is | ||||||
|  | reintegrated with the `otel/metric` package and the following release is made: | ||||||
|  |  | ||||||
|  | * `otel`: `v1.1.0-rc.1` | ||||||
|  | * `otel/trace`: `v1.1.0-rc.1` | ||||||
|  | * `otel/metric`: `v1.1.0-rc.1` | ||||||
|  | * `otel/baggage`: `v1.1.0-rc.1` | ||||||
|  | * `otel/sdk/trace`: `v1.1.0-rc.1` | ||||||
|  | * `otel/sdk/metric`: `v1.1.0-rc.1` | ||||||
|  |  | ||||||
|  | All the modules are evaluated and determined to a viable stable release. They | ||||||
|  | are then released as version `v1.1.0` (the minor version is incremented to | ||||||
|  | indicate the addition of new signal). | ||||||
|  |  | ||||||
|  | * `otel`: `v1.1.0` | ||||||
|  | * `otel/trace`: `v1.1.0` | ||||||
|  | * `otel/metric`: `v1.1.0` | ||||||
|  | * `otel/baggage`: `v1.1.0` | ||||||
|  | * `otel/sdk/trace`: `v1.1.0` | ||||||
|  | * `otel/sdk/metric`: `v1.1.0` | ||||||
							
								
								
									
										106
									
								
								vendor/go.opentelemetry.io/otel/codes/codes.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								vendor/go.opentelemetry.io/otel/codes/codes.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | package codes // import "go.opentelemetry.io/otel/codes" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// Unset is the default status code. | ||||||
|  | 	Unset Code = 0 | ||||||
|  | 	// Error indicates the operation contains an error. | ||||||
|  | 	Error Code = 1 | ||||||
|  | 	// Ok indicates operation has been validated by an Application developers | ||||||
|  | 	// or Operator to have completed successfully, or contain no error. | ||||||
|  | 	Ok Code = 2 | ||||||
|  |  | ||||||
|  | 	maxCode = 3 | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Code is an 32-bit representation of a status state. | ||||||
|  | type Code uint32 | ||||||
|  |  | ||||||
|  | var codeToStr = map[Code]string{ | ||||||
|  | 	Unset: "Unset", | ||||||
|  | 	Error: "Error", | ||||||
|  | 	Ok:    "Ok", | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var strToCode = map[string]Code{ | ||||||
|  | 	`"Unset"`: Unset, | ||||||
|  | 	`"Error"`: Error, | ||||||
|  | 	`"Ok"`:    Ok, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // String returns the Code as a string. | ||||||
|  | func (c Code) String() string { | ||||||
|  | 	return codeToStr[c] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // UnmarshalJSON unmarshals b into the Code. | ||||||
|  | // | ||||||
|  | // This is based on the functionality in the gRPC codes package: | ||||||
|  | // https://github.com/grpc/grpc-go/blob/bb64fee312b46ebee26be43364a7a966033521b1/codes/codes.go#L218-L244 | ||||||
|  | func (c *Code) UnmarshalJSON(b []byte) error { | ||||||
|  | 	// From json.Unmarshaler: By convention, to approximate the behavior of | ||||||
|  | 	// Unmarshal itself, Unmarshalers implement UnmarshalJSON([]byte("null")) as | ||||||
|  | 	// a no-op. | ||||||
|  | 	if string(b) == "null" { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	if c == nil { | ||||||
|  | 		return fmt.Errorf("nil receiver passed to UnmarshalJSON") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var x interface{} | ||||||
|  | 	if err := json.Unmarshal(b, &x); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	switch x.(type) { | ||||||
|  | 	case string: | ||||||
|  | 		if jc, ok := strToCode[string(b)]; ok { | ||||||
|  | 			*c = jc | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		return fmt.Errorf("invalid code: %q", string(b)) | ||||||
|  | 	case float64: | ||||||
|  | 		if ci, err := strconv.ParseUint(string(b), 10, 32); err == nil { | ||||||
|  | 			if ci >= maxCode { | ||||||
|  | 				return fmt.Errorf("invalid code: %q", ci) | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			*c = Code(ci) | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		return fmt.Errorf("invalid code: %q", string(b)) | ||||||
|  | 	default: | ||||||
|  | 		return fmt.Errorf("invalid code: %q", string(b)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MarshalJSON returns c as the JSON encoding of c. | ||||||
|  | func (c *Code) MarshalJSON() ([]byte, error) { | ||||||
|  | 	if c == nil { | ||||||
|  | 		return []byte("null"), nil | ||||||
|  | 	} | ||||||
|  | 	str, ok := codeToStr[*c] | ||||||
|  | 	if !ok { | ||||||
|  | 		return nil, fmt.Errorf("invalid code: %d", *c) | ||||||
|  | 	} | ||||||
|  | 	return []byte(fmt.Sprintf("%q", str)), nil | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								vendor/go.opentelemetry.io/otel/codes/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								vendor/go.opentelemetry.io/otel/codes/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | Package codes defines the canonical error codes used by OpenTelemetry. | ||||||
|  |  | ||||||
|  | This package is currently in a pre-GA phase. Backwards incompatible changes | ||||||
|  | may be introduced in subsequent minor version releases as we work to track | ||||||
|  | the evolving OpenTelemetry specification and user feedback. | ||||||
|  |  | ||||||
|  | It conforms to [the OpenTelemetry | ||||||
|  | specification](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md#statuscanonicalcode). | ||||||
|  | */ | ||||||
|  | package codes // import "go.opentelemetry.io/otel/codes" | ||||||
							
								
								
									
										38
									
								
								vendor/go.opentelemetry.io/otel/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								vendor/go.opentelemetry.io/otel/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | Package otel provides global access to the OpenTelemetry API. The subpackages of | ||||||
|  | the otel package provide an implementation of the OpenTelemetry API. | ||||||
|  |  | ||||||
|  | This package is currently in a pre-GA phase. Backwards incompatible changes | ||||||
|  | may be introduced in subsequent minor version releases as we work to track the | ||||||
|  | evolving OpenTelemetry specification and user feedback. | ||||||
|  |  | ||||||
|  | The provided API is used to instrument code and measure data about that code's | ||||||
|  | performance and operation. The measured data, by default, is not processed or | ||||||
|  | transmitted anywhere. An implementation of the OpenTelemetry SDK, like the | ||||||
|  | default SDK implementation (go.opentelemetry.io/otel/sdk), and associated | ||||||
|  | exporters are used to process and transport this data. | ||||||
|  |  | ||||||
|  | To read the getting started guide, see https://opentelemetry.io/docs/go/getting-started/. | ||||||
|  |  | ||||||
|  | To read more about tracing, see go.opentelemetry.io/otel/trace. | ||||||
|  |  | ||||||
|  | To read more about metrics, see go.opentelemetry.io/otel/metric. | ||||||
|  |  | ||||||
|  | To read more about propagation, see go.opentelemetry.io/otel/propagation and | ||||||
|  | go.opentelemetry.io/otel/baggage. | ||||||
|  | */ | ||||||
|  | package otel // import "go.opentelemetry.io/otel" | ||||||
							
								
								
									
										22
									
								
								vendor/go.opentelemetry.io/otel/error_handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/go.opentelemetry.io/otel/error_handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | package otel // import "go.opentelemetry.io/otel" | ||||||
|  |  | ||||||
|  | // ErrorHandler handles irremediable events. | ||||||
|  | type ErrorHandler interface { | ||||||
|  | 	// Handle handles any error deemed irremediable by an OpenTelemetry | ||||||
|  | 	// component. | ||||||
|  | 	Handle(error) | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								vendor/go.opentelemetry.io/otel/get_main_pkgs.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/go.opentelemetry.io/otel/get_main_pkgs.sh
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | #!/usr/bin/env bash | ||||||
|  |  | ||||||
|  | # Copyright The OpenTelemetry Authors | ||||||
|  | # | ||||||
|  | # 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. | ||||||
|  |  | ||||||
|  | set -euo pipefail | ||||||
|  |  | ||||||
|  | top_dir='.' | ||||||
|  | if [[ $# -gt 0 ]]; then | ||||||
|  |     top_dir="${1}" | ||||||
|  | fi | ||||||
|  |  | ||||||
|  | p=$(pwd) | ||||||
|  | mod_dirs=() | ||||||
|  |  | ||||||
|  | # Note `mapfile` does not exist in older bash versions: | ||||||
|  | # https://stackoverflow.com/questions/41475261/need-alternative-to-readarray-mapfile-for-script-on-older-version-of-bash | ||||||
|  |  | ||||||
|  | while IFS= read -r line; do | ||||||
|  |     mod_dirs+=("$line") | ||||||
|  | done < <(find "${top_dir}" -type f -name 'go.mod' -exec dirname {} \; | sort) | ||||||
|  |  | ||||||
|  | for mod_dir in "${mod_dirs[@]}"; do | ||||||
|  |     cd "${mod_dir}" | ||||||
|  |  | ||||||
|  |     while IFS= read -r line; do | ||||||
|  |         echo ".${line#${p}}" | ||||||
|  |     done < <(go list --find -f '{{.Name}}|{{.Dir}}' ./... | grep '^main|' | cut -f 2- -d '|') | ||||||
|  |     cd "${p}" | ||||||
|  | done | ||||||
							
								
								
									
										8
									
								
								vendor/go.opentelemetry.io/otel/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/go.opentelemetry.io/otel/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | module go.opentelemetry.io/otel | ||||||
|  |  | ||||||
|  | go 1.14 | ||||||
|  |  | ||||||
|  | require ( | ||||||
|  | 	github.com/google/go-cmp v0.5.4 | ||||||
|  | 	github.com/stretchr/testify v1.6.1 | ||||||
|  | ) | ||||||
							
								
								
									
										15
									
								
								vendor/go.opentelemetry.io/otel/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/go.opentelemetry.io/otel/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||||||
|  | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
|  | github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= | ||||||
|  | github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
|  | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
|  | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||||
|  | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= | ||||||
|  | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||||||
|  | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | ||||||
|  | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
|  | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||||
|  | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
|  | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | ||||||
|  | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
							
								
								
									
										89
									
								
								vendor/go.opentelemetry.io/otel/handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								vendor/go.opentelemetry.io/otel/handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | package otel // import "go.opentelemetry.io/otel" | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | 	"sync" | ||||||
|  | 	"sync/atomic" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	// globalErrorHandler provides an ErrorHandler that can be used | ||||||
|  | 	// throughout an OpenTelemetry instrumented project. When a user | ||||||
|  | 	// specified ErrorHandler is registered (`SetErrorHandler`) all calls to | ||||||
|  | 	// `Handle` and will be delegated to the registered ErrorHandler. | ||||||
|  | 	globalErrorHandler = &loggingErrorHandler{ | ||||||
|  | 		l: log.New(os.Stderr, "", log.LstdFlags), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// delegateErrorHandlerOnce ensures that a user provided ErrorHandler is | ||||||
|  | 	// only ever registered once. | ||||||
|  | 	delegateErrorHandlerOnce sync.Once | ||||||
|  |  | ||||||
|  | 	// Comiple time check that loggingErrorHandler implements ErrorHandler. | ||||||
|  | 	_ ErrorHandler = (*loggingErrorHandler)(nil) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // loggingErrorHandler logs all errors to STDERR. | ||||||
|  | type loggingErrorHandler struct { | ||||||
|  | 	delegate atomic.Value | ||||||
|  |  | ||||||
|  | 	l *log.Logger | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // setDelegate sets the ErrorHandler delegate if one is not already set. | ||||||
|  | func (h *loggingErrorHandler) setDelegate(d ErrorHandler) { | ||||||
|  | 	if h.delegate.Load() != nil { | ||||||
|  | 		// Delegate already registered | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	h.delegate.Store(d) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Handle implements ErrorHandler. | ||||||
|  | func (h *loggingErrorHandler) Handle(err error) { | ||||||
|  | 	if d := h.delegate.Load(); d != nil { | ||||||
|  | 		d.(ErrorHandler).Handle(err) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	h.l.Print(err) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // GetErrorHandler returns the global ErrorHandler instance. If no ErrorHandler | ||||||
|  | // instance has been set (`SetErrorHandler`), the default ErrorHandler which | ||||||
|  | // logs errors to STDERR is returned. | ||||||
|  | func GetErrorHandler() ErrorHandler { | ||||||
|  | 	return globalErrorHandler | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetErrorHandler sets the global ErrorHandler to be h. | ||||||
|  | func SetErrorHandler(h ErrorHandler) { | ||||||
|  | 	delegateErrorHandlerOnce.Do(func() { | ||||||
|  | 		current := GetErrorHandler() | ||||||
|  | 		if current == h { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 		if internalHandler, ok := current.(*loggingErrorHandler); ok { | ||||||
|  | 			internalHandler.setDelegate(h) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Handle is a convience function for ErrorHandler().Handle(err) | ||||||
|  | func Handle(err error) { | ||||||
|  | 	GetErrorHandler().Handle(err) | ||||||
|  | } | ||||||
							
								
								
									
										338
									
								
								vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										338
									
								
								vendor/go.opentelemetry.io/otel/internal/baggage/baggage.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,338 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | // Package baggage provides types and functions to manage W3C Baggage. | ||||||
|  | package baggage | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  |  | ||||||
|  | 	"go.opentelemetry.io/otel/label" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type rawMap map[label.Key]label.Value | ||||||
|  | type keySet map[label.Key]struct{} | ||||||
|  |  | ||||||
|  | // Map is an immutable storage for correlations. | ||||||
|  | type Map struct { | ||||||
|  | 	m rawMap | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MapUpdate contains information about correlation changes to be | ||||||
|  | // made. | ||||||
|  | type MapUpdate struct { | ||||||
|  | 	// DropSingleK contains a single key to be dropped from | ||||||
|  | 	// correlations. Use this to avoid an overhead of a slice | ||||||
|  | 	// allocation if there is only one key to drop. | ||||||
|  | 	DropSingleK label.Key | ||||||
|  | 	// DropMultiK contains all the keys to be dropped from | ||||||
|  | 	// correlations. | ||||||
|  | 	DropMultiK []label.Key | ||||||
|  |  | ||||||
|  | 	// SingleKV contains a single key-value pair to be added to | ||||||
|  | 	// correlations. Use this to avoid an overhead of a slice | ||||||
|  | 	// allocation if there is only one key-value pair to add. | ||||||
|  | 	SingleKV label.KeyValue | ||||||
|  | 	// MultiKV contains all the key-value pairs to be added to | ||||||
|  | 	// correlations. | ||||||
|  | 	MultiKV []label.KeyValue | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newMap(raw rawMap) Map { | ||||||
|  | 	return Map{ | ||||||
|  | 		m: raw, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewEmptyMap creates an empty correlations map. | ||||||
|  | func NewEmptyMap() Map { | ||||||
|  | 	return newMap(nil) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewMap creates a map with the contents of the update applied. In | ||||||
|  | // this function, having an update with DropSingleK or DropMultiK | ||||||
|  | // makes no sense - those fields are effectively ignored. | ||||||
|  | func NewMap(update MapUpdate) Map { | ||||||
|  | 	return NewEmptyMap().Apply(update) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Apply creates a copy of the map with the contents of the update | ||||||
|  | // applied. Apply will first drop the keys from DropSingleK and | ||||||
|  | // DropMultiK, then add key-value pairs from SingleKV and MultiKV. | ||||||
|  | func (m Map) Apply(update MapUpdate) Map { | ||||||
|  | 	delSet, addSet := getModificationSets(update) | ||||||
|  | 	mapSize := getNewMapSize(m.m, delSet, addSet) | ||||||
|  |  | ||||||
|  | 	r := make(rawMap, mapSize) | ||||||
|  | 	for k, v := range m.m { | ||||||
|  | 		// do not copy items we want to drop | ||||||
|  | 		if _, ok := delSet[k]; ok { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		// do not copy items we would overwrite | ||||||
|  | 		if _, ok := addSet[k]; ok { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		r[k] = v | ||||||
|  | 	} | ||||||
|  | 	if update.SingleKV.Key.Defined() { | ||||||
|  | 		r[update.SingleKV.Key] = update.SingleKV.Value | ||||||
|  | 	} | ||||||
|  | 	for _, kv := range update.MultiKV { | ||||||
|  | 		r[kv.Key] = kv.Value | ||||||
|  | 	} | ||||||
|  | 	if len(r) == 0 { | ||||||
|  | 		r = nil | ||||||
|  | 	} | ||||||
|  | 	return newMap(r) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getModificationSets(update MapUpdate) (delSet, addSet keySet) { | ||||||
|  | 	deletionsCount := len(update.DropMultiK) | ||||||
|  | 	if update.DropSingleK.Defined() { | ||||||
|  | 		deletionsCount++ | ||||||
|  | 	} | ||||||
|  | 	if deletionsCount > 0 { | ||||||
|  | 		delSet = make(map[label.Key]struct{}, deletionsCount) | ||||||
|  | 		for _, k := range update.DropMultiK { | ||||||
|  | 			delSet[k] = struct{}{} | ||||||
|  | 		} | ||||||
|  | 		if update.DropSingleK.Defined() { | ||||||
|  | 			delSet[update.DropSingleK] = struct{}{} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	additionsCount := len(update.MultiKV) | ||||||
|  | 	if update.SingleKV.Key.Defined() { | ||||||
|  | 		additionsCount++ | ||||||
|  | 	} | ||||||
|  | 	if additionsCount > 0 { | ||||||
|  | 		addSet = make(map[label.Key]struct{}, additionsCount) | ||||||
|  | 		for _, k := range update.MultiKV { | ||||||
|  | 			addSet[k.Key] = struct{}{} | ||||||
|  | 		} | ||||||
|  | 		if update.SingleKV.Key.Defined() { | ||||||
|  | 			addSet[update.SingleKV.Key] = struct{}{} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func getNewMapSize(m rawMap, delSet, addSet keySet) int { | ||||||
|  | 	mapSizeDiff := 0 | ||||||
|  | 	for k := range addSet { | ||||||
|  | 		if _, ok := m[k]; !ok { | ||||||
|  | 			mapSizeDiff++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	for k := range delSet { | ||||||
|  | 		if _, ok := m[k]; ok { | ||||||
|  | 			if _, inAddSet := addSet[k]; !inAddSet { | ||||||
|  | 				mapSizeDiff-- | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return len(m) + mapSizeDiff | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Value gets a value from correlations map and returns a boolean | ||||||
|  | // value indicating whether the key exist in the map. | ||||||
|  | func (m Map) Value(k label.Key) (label.Value, bool) { | ||||||
|  | 	value, ok := m.m[k] | ||||||
|  | 	return value, ok | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // HasValue returns a boolean value indicating whether the key exist | ||||||
|  | // in the map. | ||||||
|  | func (m Map) HasValue(k label.Key) bool { | ||||||
|  | 	_, has := m.Value(k) | ||||||
|  | 	return has | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Len returns a length of the map. | ||||||
|  | func (m Map) Len() int { | ||||||
|  | 	return len(m.m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Foreach calls a passed callback once on each key-value pair until | ||||||
|  | // all the key-value pairs of the map were iterated or the callback | ||||||
|  | // returns false, whichever happens first. | ||||||
|  | func (m Map) Foreach(f func(label.KeyValue) bool) { | ||||||
|  | 	for k, v := range m.m { | ||||||
|  | 		if !f(label.KeyValue{ | ||||||
|  | 			Key:   k, | ||||||
|  | 			Value: v, | ||||||
|  | 		}) { | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type correlationsType struct{} | ||||||
|  |  | ||||||
|  | // SetHookFunc describes a type of a callback that is called when | ||||||
|  | // storing baggage in the context. | ||||||
|  | type SetHookFunc func(context.Context) context.Context | ||||||
|  |  | ||||||
|  | // GetHookFunc describes a type of a callback that is called when | ||||||
|  | // getting baggage from the context. | ||||||
|  | type GetHookFunc func(context.Context, Map) Map | ||||||
|  |  | ||||||
|  | // value under this key is either of type Map or correlationsData | ||||||
|  | var correlationsKey = &correlationsType{} | ||||||
|  |  | ||||||
|  | type correlationsData struct { | ||||||
|  | 	m       Map | ||||||
|  | 	setHook SetHookFunc | ||||||
|  | 	getHook GetHookFunc | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d correlationsData) isHookless() bool { | ||||||
|  | 	return d.setHook == nil && d.getHook == nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type hookKind int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	hookKindSet hookKind = iota | ||||||
|  | 	hookKindGet | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func (d *correlationsData) overrideHook(kind hookKind, setHook SetHookFunc, getHook GetHookFunc) { | ||||||
|  | 	switch kind { | ||||||
|  | 	case hookKindSet: | ||||||
|  | 		d.setHook = setHook | ||||||
|  | 	case hookKindGet: | ||||||
|  | 		d.getHook = getHook | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContextWithSetHook installs a hook function that will be invoked | ||||||
|  | // every time ContextWithMap is called. To avoid unnecessary callback | ||||||
|  | // invocations (recursive or not), the callback can temporarily clear | ||||||
|  | // the hooks from the context with the ContextWithNoHooks function. | ||||||
|  | // | ||||||
|  | // Note that NewContext also calls ContextWithMap, so the hook will be | ||||||
|  | // invoked. | ||||||
|  | // | ||||||
|  | // Passing nil SetHookFunc creates a context with no set hook to call. | ||||||
|  | // | ||||||
|  | // This function should not be used by applications or libraries. It | ||||||
|  | // is mostly for interoperation with other observability APIs. | ||||||
|  | func ContextWithSetHook(ctx context.Context, hook SetHookFunc) context.Context { | ||||||
|  | 	return contextWithHook(ctx, hookKindSet, hook, nil) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContextWithGetHook installs a hook function that will be invoked | ||||||
|  | // every time MapFromContext is called. To avoid unnecessary callback | ||||||
|  | // invocations (recursive or not), the callback can temporarily clear | ||||||
|  | // the hooks from the context with the ContextWithNoHooks function. | ||||||
|  | // | ||||||
|  | // Note that NewContext also calls MapFromContext, so the hook will be | ||||||
|  | // invoked. | ||||||
|  | // | ||||||
|  | // Passing nil GetHookFunc creates a context with no get hook to call. | ||||||
|  | // | ||||||
|  | // This function should not be used by applications or libraries. It | ||||||
|  | // is mostly for interoperation with other observability APIs. | ||||||
|  | func ContextWithGetHook(ctx context.Context, hook GetHookFunc) context.Context { | ||||||
|  | 	return contextWithHook(ctx, hookKindGet, nil, hook) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func contextWithHook(ctx context.Context, kind hookKind, setHook SetHookFunc, getHook GetHookFunc) context.Context { | ||||||
|  | 	switch v := ctx.Value(correlationsKey).(type) { | ||||||
|  | 	case correlationsData: | ||||||
|  | 		v.overrideHook(kind, setHook, getHook) | ||||||
|  | 		if v.isHookless() { | ||||||
|  | 			return context.WithValue(ctx, correlationsKey, v.m) | ||||||
|  | 		} | ||||||
|  | 		return context.WithValue(ctx, correlationsKey, v) | ||||||
|  | 	case Map: | ||||||
|  | 		return contextWithOneHookAndMap(ctx, kind, setHook, getHook, v) | ||||||
|  | 	default: | ||||||
|  | 		m := NewEmptyMap() | ||||||
|  | 		return contextWithOneHookAndMap(ctx, kind, setHook, getHook, m) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func contextWithOneHookAndMap(ctx context.Context, kind hookKind, setHook SetHookFunc, getHook GetHookFunc, m Map) context.Context { | ||||||
|  | 	d := correlationsData{m: m} | ||||||
|  | 	d.overrideHook(kind, setHook, getHook) | ||||||
|  | 	if d.isHookless() { | ||||||
|  | 		return ctx | ||||||
|  | 	} | ||||||
|  | 	return context.WithValue(ctx, correlationsKey, d) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContextWithNoHooks creates a context with all the hooks | ||||||
|  | // disabled. Also returns old set and get hooks. This function can be | ||||||
|  | // used to temporarily clear the context from hooks and then reinstate | ||||||
|  | // them by calling ContextWithSetHook and ContextWithGetHook functions | ||||||
|  | // passing the hooks returned by this function. | ||||||
|  | // | ||||||
|  | // This function should not be used by applications or libraries. It | ||||||
|  | // is mostly for interoperation with other observability APIs. | ||||||
|  | func ContextWithNoHooks(ctx context.Context) (context.Context, SetHookFunc, GetHookFunc) { | ||||||
|  | 	switch v := ctx.Value(correlationsKey).(type) { | ||||||
|  | 	case correlationsData: | ||||||
|  | 		return context.WithValue(ctx, correlationsKey, v.m), v.setHook, v.getHook | ||||||
|  | 	default: | ||||||
|  | 		return ctx, nil, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContextWithMap returns a context with the Map entered into it. | ||||||
|  | func ContextWithMap(ctx context.Context, m Map) context.Context { | ||||||
|  | 	switch v := ctx.Value(correlationsKey).(type) { | ||||||
|  | 	case correlationsData: | ||||||
|  | 		v.m = m | ||||||
|  | 		ctx = context.WithValue(ctx, correlationsKey, v) | ||||||
|  | 		if v.setHook != nil { | ||||||
|  | 			ctx = v.setHook(ctx) | ||||||
|  | 		} | ||||||
|  | 		return ctx | ||||||
|  | 	default: | ||||||
|  | 		return context.WithValue(ctx, correlationsKey, m) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ContextWithNoCorrelationData returns a context stripped of correlation | ||||||
|  | // data. | ||||||
|  | func ContextWithNoCorrelationData(ctx context.Context) context.Context { | ||||||
|  | 	return context.WithValue(ctx, correlationsKey, nil) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewContext returns a context with the map from passed context | ||||||
|  | // updated with the passed key-value pairs. | ||||||
|  | func NewContext(ctx context.Context, keyvalues ...label.KeyValue) context.Context { | ||||||
|  | 	return ContextWithMap(ctx, MapFromContext(ctx).Apply(MapUpdate{ | ||||||
|  | 		MultiKV: keyvalues, | ||||||
|  | 	})) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MapFromContext gets the current Map from a Context. | ||||||
|  | func MapFromContext(ctx context.Context) Map { | ||||||
|  | 	switch v := ctx.Value(correlationsKey).(type) { | ||||||
|  | 	case correlationsData: | ||||||
|  | 		if v.getHook != nil { | ||||||
|  | 			return v.getHook(ctx, v.m) | ||||||
|  | 		} | ||||||
|  | 		return v.m | ||||||
|  | 	case Map: | ||||||
|  | 		return v | ||||||
|  | 	default: | ||||||
|  | 		return NewEmptyMap() | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										348
									
								
								vendor/go.opentelemetry.io/otel/internal/global/meter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										348
									
								
								vendor/go.opentelemetry.io/otel/internal/global/meter.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,348 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | package global | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"sync" | ||||||
|  | 	"sync/atomic" | ||||||
|  | 	"unsafe" | ||||||
|  |  | ||||||
|  | 	"go.opentelemetry.io/otel/label" | ||||||
|  | 	"go.opentelemetry.io/otel/metric" | ||||||
|  | 	"go.opentelemetry.io/otel/metric/number" | ||||||
|  | 	"go.opentelemetry.io/otel/metric/registry" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // This file contains the forwarding implementation of MeterProvider used as | ||||||
|  | // the default global instance.  Metric events using instruments provided by | ||||||
|  | // this implementation are no-ops until the first Meter implementation is set | ||||||
|  | // as the global provider. | ||||||
|  | // | ||||||
|  | // The implementation here uses Mutexes to maintain a list of active Meters in | ||||||
|  | // the MeterProvider and Instruments in each Meter, under the assumption that | ||||||
|  | // these interfaces are not performance-critical. | ||||||
|  | // | ||||||
|  | // We have the invariant that setDelegate() will be called before a new | ||||||
|  | // MeterProvider implementation is registered as the global provider.  Mutexes | ||||||
|  | // in the MeterProvider and Meters ensure that each instrument has a delegate | ||||||
|  | // before the global provider is set. | ||||||
|  | // | ||||||
|  | // Bound instrument operations are implemented by delegating to the | ||||||
|  | // instrument after it is registered, with a sync.Once initializer to | ||||||
|  | // protect against races with Release(). | ||||||
|  | // | ||||||
|  | // Metric uniqueness checking is implemented by calling the exported | ||||||
|  | // methods of the api/metric/registry package. | ||||||
|  |  | ||||||
|  | type meterKey struct { | ||||||
|  | 	Name, Version string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type meterProvider struct { | ||||||
|  | 	delegate metric.MeterProvider | ||||||
|  |  | ||||||
|  | 	// lock protects `delegate` and `meters`. | ||||||
|  | 	lock sync.Mutex | ||||||
|  |  | ||||||
|  | 	// meters maintains a unique entry for every named Meter | ||||||
|  | 	// that has been registered through the global instance. | ||||||
|  | 	meters map[meterKey]*meterEntry | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type meterImpl struct { | ||||||
|  | 	delegate unsafe.Pointer // (*metric.MeterImpl) | ||||||
|  |  | ||||||
|  | 	lock       sync.Mutex | ||||||
|  | 	syncInsts  []*syncImpl | ||||||
|  | 	asyncInsts []*asyncImpl | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type meterEntry struct { | ||||||
|  | 	unique metric.MeterImpl | ||||||
|  | 	impl   meterImpl | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type instrument struct { | ||||||
|  | 	descriptor metric.Descriptor | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type syncImpl struct { | ||||||
|  | 	delegate unsafe.Pointer // (*metric.SyncImpl) | ||||||
|  |  | ||||||
|  | 	instrument | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type asyncImpl struct { | ||||||
|  | 	delegate unsafe.Pointer // (*metric.AsyncImpl) | ||||||
|  |  | ||||||
|  | 	instrument | ||||||
|  |  | ||||||
|  | 	runner metric.AsyncRunner | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SyncImpler is implemented by all of the sync metric | ||||||
|  | // instruments. | ||||||
|  | type SyncImpler interface { | ||||||
|  | 	SyncImpl() metric.SyncImpl | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // AsyncImpler is implemented by all of the async | ||||||
|  | // metric instruments. | ||||||
|  | type AsyncImpler interface { | ||||||
|  | 	AsyncImpl() metric.AsyncImpl | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type syncHandle struct { | ||||||
|  | 	delegate unsafe.Pointer // (*metric.BoundInstrumentImpl) | ||||||
|  |  | ||||||
|  | 	inst   *syncImpl | ||||||
|  | 	labels []label.KeyValue | ||||||
|  |  | ||||||
|  | 	initialize sync.Once | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var _ metric.MeterProvider = &meterProvider{} | ||||||
|  | var _ metric.MeterImpl = &meterImpl{} | ||||||
|  | var _ metric.InstrumentImpl = &syncImpl{} | ||||||
|  | var _ metric.BoundSyncImpl = &syncHandle{} | ||||||
|  | var _ metric.AsyncImpl = &asyncImpl{} | ||||||
|  |  | ||||||
|  | func (inst *instrument) Descriptor() metric.Descriptor { | ||||||
|  | 	return inst.descriptor | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MeterProvider interface and delegation | ||||||
|  |  | ||||||
|  | func newMeterProvider() *meterProvider { | ||||||
|  | 	return &meterProvider{ | ||||||
|  | 		meters: map[meterKey]*meterEntry{}, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *meterProvider) setDelegate(provider metric.MeterProvider) { | ||||||
|  | 	p.lock.Lock() | ||||||
|  | 	defer p.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	p.delegate = provider | ||||||
|  | 	for key, entry := range p.meters { | ||||||
|  | 		entry.impl.setDelegate(key.Name, key.Version, provider) | ||||||
|  | 	} | ||||||
|  | 	p.meters = nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *meterProvider) Meter(instrumentationName string, opts ...metric.MeterOption) metric.Meter { | ||||||
|  | 	p.lock.Lock() | ||||||
|  | 	defer p.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	if p.delegate != nil { | ||||||
|  | 		return p.delegate.Meter(instrumentationName, opts...) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	key := meterKey{ | ||||||
|  | 		Name:    instrumentationName, | ||||||
|  | 		Version: metric.NewMeterConfig(opts...).InstrumentationVersion, | ||||||
|  | 	} | ||||||
|  | 	entry, ok := p.meters[key] | ||||||
|  | 	if !ok { | ||||||
|  | 		entry = &meterEntry{} | ||||||
|  | 		entry.unique = registry.NewUniqueInstrumentMeterImpl(&entry.impl) | ||||||
|  | 		p.meters[key] = entry | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  | 	return metric.WrapMeterImpl(entry.unique, key.Name, metric.WithInstrumentationVersion(key.Version)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Meter interface and delegation | ||||||
|  |  | ||||||
|  | func (m *meterImpl) setDelegate(name, version string, provider metric.MeterProvider) { | ||||||
|  | 	m.lock.Lock() | ||||||
|  | 	defer m.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	d := new(metric.MeterImpl) | ||||||
|  | 	*d = provider.Meter(name, metric.WithInstrumentationVersion(version)).MeterImpl() | ||||||
|  | 	m.delegate = unsafe.Pointer(d) | ||||||
|  |  | ||||||
|  | 	for _, inst := range m.syncInsts { | ||||||
|  | 		inst.setDelegate(*d) | ||||||
|  | 	} | ||||||
|  | 	m.syncInsts = nil | ||||||
|  | 	for _, obs := range m.asyncInsts { | ||||||
|  | 		obs.setDelegate(*d) | ||||||
|  | 	} | ||||||
|  | 	m.asyncInsts = nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *meterImpl) NewSyncInstrument(desc metric.Descriptor) (metric.SyncImpl, error) { | ||||||
|  | 	m.lock.Lock() | ||||||
|  | 	defer m.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	if meterPtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { | ||||||
|  | 		return (*meterPtr).NewSyncInstrument(desc) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	inst := &syncImpl{ | ||||||
|  | 		instrument: instrument{ | ||||||
|  | 			descriptor: desc, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	m.syncInsts = append(m.syncInsts, inst) | ||||||
|  | 	return inst, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Synchronous delegation | ||||||
|  |  | ||||||
|  | func (inst *syncImpl) setDelegate(d metric.MeterImpl) { | ||||||
|  | 	implPtr := new(metric.SyncImpl) | ||||||
|  |  | ||||||
|  | 	var err error | ||||||
|  | 	*implPtr, err = d.NewSyncInstrument(inst.descriptor) | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		// TODO: There is no standard way to deliver this error to the user. | ||||||
|  | 		// See https://github.com/open-telemetry/opentelemetry-go/issues/514 | ||||||
|  | 		// Note that the default SDK will not generate any errors yet, this is | ||||||
|  | 		// only for added safety. | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	atomic.StorePointer(&inst.delegate, unsafe.Pointer(implPtr)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (inst *syncImpl) Implementation() interface{} { | ||||||
|  | 	if implPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { | ||||||
|  | 		return (*implPtr).Implementation() | ||||||
|  | 	} | ||||||
|  | 	return inst | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (inst *syncImpl) Bind(labels []label.KeyValue) metric.BoundSyncImpl { | ||||||
|  | 	if implPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); implPtr != nil { | ||||||
|  | 		return (*implPtr).Bind(labels) | ||||||
|  | 	} | ||||||
|  | 	return &syncHandle{ | ||||||
|  | 		inst:   inst, | ||||||
|  | 		labels: labels, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (bound *syncHandle) Unbind() { | ||||||
|  | 	bound.initialize.Do(func() {}) | ||||||
|  |  | ||||||
|  | 	implPtr := (*metric.BoundSyncImpl)(atomic.LoadPointer(&bound.delegate)) | ||||||
|  |  | ||||||
|  | 	if implPtr == nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	(*implPtr).Unbind() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Async delegation | ||||||
|  |  | ||||||
|  | func (m *meterImpl) NewAsyncInstrument( | ||||||
|  | 	desc metric.Descriptor, | ||||||
|  | 	runner metric.AsyncRunner, | ||||||
|  | ) (metric.AsyncImpl, error) { | ||||||
|  |  | ||||||
|  | 	m.lock.Lock() | ||||||
|  | 	defer m.lock.Unlock() | ||||||
|  |  | ||||||
|  | 	if meterPtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); meterPtr != nil { | ||||||
|  | 		return (*meterPtr).NewAsyncInstrument(desc, runner) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	inst := &asyncImpl{ | ||||||
|  | 		instrument: instrument{ | ||||||
|  | 			descriptor: desc, | ||||||
|  | 		}, | ||||||
|  | 		runner: runner, | ||||||
|  | 	} | ||||||
|  | 	m.asyncInsts = append(m.asyncInsts, inst) | ||||||
|  | 	return inst, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (obs *asyncImpl) Implementation() interface{} { | ||||||
|  | 	if implPtr := (*metric.AsyncImpl)(atomic.LoadPointer(&obs.delegate)); implPtr != nil { | ||||||
|  | 		return (*implPtr).Implementation() | ||||||
|  | 	} | ||||||
|  | 	return obs | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (obs *asyncImpl) setDelegate(d metric.MeterImpl) { | ||||||
|  | 	implPtr := new(metric.AsyncImpl) | ||||||
|  |  | ||||||
|  | 	var err error | ||||||
|  | 	*implPtr, err = d.NewAsyncInstrument(obs.descriptor, obs.runner) | ||||||
|  |  | ||||||
|  | 	if err != nil { | ||||||
|  | 		// TODO: There is no standard way to deliver this error to the user. | ||||||
|  | 		// See https://github.com/open-telemetry/opentelemetry-go/issues/514 | ||||||
|  | 		// Note that the default SDK will not generate any errors yet, this is | ||||||
|  | 		// only for added safety. | ||||||
|  | 		panic(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	atomic.StorePointer(&obs.delegate, unsafe.Pointer(implPtr)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Metric updates | ||||||
|  |  | ||||||
|  | func (m *meterImpl) RecordBatch(ctx context.Context, labels []label.KeyValue, measurements ...metric.Measurement) { | ||||||
|  | 	if delegatePtr := (*metric.MeterImpl)(atomic.LoadPointer(&m.delegate)); delegatePtr != nil { | ||||||
|  | 		(*delegatePtr).RecordBatch(ctx, labels, measurements...) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (inst *syncImpl) RecordOne(ctx context.Context, number number.Number, labels []label.KeyValue) { | ||||||
|  | 	if instPtr := (*metric.SyncImpl)(atomic.LoadPointer(&inst.delegate)); instPtr != nil { | ||||||
|  | 		(*instPtr).RecordOne(ctx, number, labels) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Bound instrument initialization | ||||||
|  |  | ||||||
|  | func (bound *syncHandle) RecordOne(ctx context.Context, number number.Number) { | ||||||
|  | 	instPtr := (*metric.SyncImpl)(atomic.LoadPointer(&bound.inst.delegate)) | ||||||
|  | 	if instPtr == nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	var implPtr *metric.BoundSyncImpl | ||||||
|  | 	bound.initialize.Do(func() { | ||||||
|  | 		implPtr = new(metric.BoundSyncImpl) | ||||||
|  | 		*implPtr = (*instPtr).Bind(bound.labels) | ||||||
|  | 		atomic.StorePointer(&bound.delegate, unsafe.Pointer(implPtr)) | ||||||
|  | 	}) | ||||||
|  | 	if implPtr == nil { | ||||||
|  | 		implPtr = (*metric.BoundSyncImpl)(atomic.LoadPointer(&bound.delegate)) | ||||||
|  | 	} | ||||||
|  | 	// This may still be nil if instrument was created and bound | ||||||
|  | 	// without a delegate, then the instrument was set to have a | ||||||
|  | 	// delegate and unbound. | ||||||
|  | 	if implPtr == nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	(*implPtr).RecordOne(ctx, number) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func AtomicFieldOffsets() map[string]uintptr { | ||||||
|  | 	return map[string]uintptr{ | ||||||
|  | 		"meterProvider.delegate": unsafe.Offsetof(meterProvider{}.delegate), | ||||||
|  | 		"meterImpl.delegate":     unsafe.Offsetof(meterImpl{}.delegate), | ||||||
|  | 		"syncImpl.delegate":      unsafe.Offsetof(syncImpl{}.delegate), | ||||||
|  | 		"asyncImpl.delegate":     unsafe.Offsetof(asyncImpl{}.delegate), | ||||||
|  | 		"syncHandle.delegate":    unsafe.Offsetof(syncHandle{}.delegate), | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										82
									
								
								vendor/go.opentelemetry.io/otel/internal/global/propagator.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								vendor/go.opentelemetry.io/otel/internal/global/propagator.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | package global | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	"go.opentelemetry.io/otel/propagation" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // textMapPropagator is a default TextMapPropagator that delegates calls to a | ||||||
|  | // registered delegate if one is set, otherwise it defaults to delegating the | ||||||
|  | // calls to a the default no-op propagation.TextMapPropagator. | ||||||
|  | type textMapPropagator struct { | ||||||
|  | 	mtx      sync.Mutex | ||||||
|  | 	once     sync.Once | ||||||
|  | 	delegate propagation.TextMapPropagator | ||||||
|  | 	noop     propagation.TextMapPropagator | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Compile-time guarantee that textMapPropagator implements the | ||||||
|  | // propagation.TextMapPropagator interface. | ||||||
|  | var _ propagation.TextMapPropagator = (*textMapPropagator)(nil) | ||||||
|  |  | ||||||
|  | func newTextMapPropagator() *textMapPropagator { | ||||||
|  | 	return &textMapPropagator{ | ||||||
|  | 		noop: propagation.NewCompositeTextMapPropagator(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetDelegate sets a delegate propagation.TextMapPropagator that all calls are | ||||||
|  | // forwarded to. Delegation can only be performed once, all subsequent calls | ||||||
|  | // perform no delegation. | ||||||
|  | func (p *textMapPropagator) SetDelegate(delegate propagation.TextMapPropagator) { | ||||||
|  | 	if delegate == nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	p.mtx.Lock() | ||||||
|  | 	p.once.Do(func() { p.delegate = delegate }) | ||||||
|  | 	p.mtx.Unlock() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // effectiveDelegate returns the current delegate of p if one is set, | ||||||
|  | // otherwise the default noop TextMapPropagator is returned. This method | ||||||
|  | // can be called concurrently. | ||||||
|  | func (p *textMapPropagator) effectiveDelegate() propagation.TextMapPropagator { | ||||||
|  | 	p.mtx.Lock() | ||||||
|  | 	defer p.mtx.Unlock() | ||||||
|  | 	if p.delegate != nil { | ||||||
|  | 		return p.delegate | ||||||
|  | 	} | ||||||
|  | 	return p.noop | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Inject set cross-cutting concerns from the Context into the carrier. | ||||||
|  | func (p *textMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { | ||||||
|  | 	p.effectiveDelegate().Inject(ctx, carrier) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Extract reads cross-cutting concerns from the carrier into a Context. | ||||||
|  | func (p *textMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { | ||||||
|  | 	return p.effectiveDelegate().Extract(ctx, carrier) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Fields returns the keys whose values are set with Inject. | ||||||
|  | func (p *textMapPropagator) Fields() []string { | ||||||
|  | 	return p.effectiveDelegate().Fields() | ||||||
|  | } | ||||||
							
								
								
									
										143
									
								
								vendor/go.opentelemetry.io/otel/internal/global/state.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										143
									
								
								vendor/go.opentelemetry.io/otel/internal/global/state.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,143 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | package global | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"sync" | ||||||
|  | 	"sync/atomic" | ||||||
|  |  | ||||||
|  | 	"go.opentelemetry.io/otel/metric" | ||||||
|  | 	"go.opentelemetry.io/otel/propagation" | ||||||
|  | 	"go.opentelemetry.io/otel/trace" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type ( | ||||||
|  | 	tracerProviderHolder struct { | ||||||
|  | 		tp trace.TracerProvider | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	meterProviderHolder struct { | ||||||
|  | 		mp metric.MeterProvider | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	propagatorsHolder struct { | ||||||
|  | 		tm propagation.TextMapPropagator | ||||||
|  | 	} | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	globalTracer      = defaultTracerValue() | ||||||
|  | 	globalMeter       = defaultMeterValue() | ||||||
|  | 	globalPropagators = defaultPropagatorsValue() | ||||||
|  |  | ||||||
|  | 	delegateMeterOnce             sync.Once | ||||||
|  | 	delegateTraceOnce             sync.Once | ||||||
|  | 	delegateTextMapPropagatorOnce sync.Once | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // TracerProvider is the internal implementation for global.TracerProvider. | ||||||
|  | func TracerProvider() trace.TracerProvider { | ||||||
|  | 	return globalTracer.Load().(tracerProviderHolder).tp | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetTracerProvider is the internal implementation for global.SetTracerProvider. | ||||||
|  | func SetTracerProvider(tp trace.TracerProvider) { | ||||||
|  | 	delegateTraceOnce.Do(func() { | ||||||
|  | 		current := TracerProvider() | ||||||
|  | 		if current == tp { | ||||||
|  | 			// Setting the provider to the prior default is nonsense, panic. | ||||||
|  | 			// Panic is acceptable because we are likely still early in the | ||||||
|  | 			// process lifetime. | ||||||
|  | 			panic("invalid TracerProvider, the global instance cannot be reinstalled") | ||||||
|  | 		} else if def, ok := current.(*tracerProvider); ok { | ||||||
|  | 			def.setDelegate(tp) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 	}) | ||||||
|  | 	globalTracer.Store(tracerProviderHolder{tp: tp}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // MeterProvider is the internal implementation for global.MeterProvider. | ||||||
|  | func MeterProvider() metric.MeterProvider { | ||||||
|  | 	return globalMeter.Load().(meterProviderHolder).mp | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetMeterProvider is the internal implementation for global.SetMeterProvider. | ||||||
|  | func SetMeterProvider(mp metric.MeterProvider) { | ||||||
|  | 	delegateMeterOnce.Do(func() { | ||||||
|  | 		current := MeterProvider() | ||||||
|  |  | ||||||
|  | 		if current == mp { | ||||||
|  | 			// Setting the provider to the prior default is nonsense, panic. | ||||||
|  | 			// Panic is acceptable because we are likely still early in the | ||||||
|  | 			// process lifetime. | ||||||
|  | 			panic("invalid MeterProvider, the global instance cannot be reinstalled") | ||||||
|  | 		} else if def, ok := current.(*meterProvider); ok { | ||||||
|  | 			def.setDelegate(mp) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	globalMeter.Store(meterProviderHolder{mp: mp}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // TextMapPropagator is the internal implementation for global.TextMapPropagator. | ||||||
|  | func TextMapPropagator() propagation.TextMapPropagator { | ||||||
|  | 	return globalPropagators.Load().(propagatorsHolder).tm | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // SetTextMapPropagator is the internal implementation for global.SetTextMapPropagator. | ||||||
|  | func SetTextMapPropagator(p propagation.TextMapPropagator) { | ||||||
|  | 	// For the textMapPropagator already returned by TextMapPropagator | ||||||
|  | 	// delegate to p. | ||||||
|  | 	delegateTextMapPropagatorOnce.Do(func() { | ||||||
|  | 		if current := TextMapPropagator(); current == p { | ||||||
|  | 			// Setting the provider to the prior default is nonsense, panic. | ||||||
|  | 			// Panic is acceptable because we are likely still early in the | ||||||
|  | 			// process lifetime. | ||||||
|  | 			panic("invalid TextMapPropagator, the global instance cannot be reinstalled") | ||||||
|  | 		} else if def, ok := current.(*textMapPropagator); ok { | ||||||
|  | 			def.SetDelegate(p) | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | 	// Return p when subsequent calls to TextMapPropagator are made. | ||||||
|  | 	globalPropagators.Store(propagatorsHolder{tm: p}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func defaultTracerValue() *atomic.Value { | ||||||
|  | 	v := &atomic.Value{} | ||||||
|  | 	v.Store(tracerProviderHolder{tp: &tracerProvider{}}) | ||||||
|  | 	return v | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func defaultMeterValue() *atomic.Value { | ||||||
|  | 	v := &atomic.Value{} | ||||||
|  | 	v.Store(meterProviderHolder{mp: newMeterProvider()}) | ||||||
|  | 	return v | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func defaultPropagatorsValue() *atomic.Value { | ||||||
|  | 	v := &atomic.Value{} | ||||||
|  | 	v.Store(propagatorsHolder{tm: newTextMapPropagator()}) | ||||||
|  | 	return v | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ResetForTest restores the initial global state, for testing purposes. | ||||||
|  | func ResetForTest() { | ||||||
|  | 	globalTracer = defaultTracerValue() | ||||||
|  | 	globalMeter = defaultMeterValue() | ||||||
|  | 	globalPropagators = defaultPropagatorsValue() | ||||||
|  | 	delegateMeterOnce = sync.Once{} | ||||||
|  | 	delegateTraceOnce = sync.Once{} | ||||||
|  | 	delegateTextMapPropagatorOnce = sync.Once{} | ||||||
|  | } | ||||||
							
								
								
									
										128
									
								
								vendor/go.opentelemetry.io/otel/internal/global/trace.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								vendor/go.opentelemetry.io/otel/internal/global/trace.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | package global | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | This file contains the forwarding implementation of the TracerProvider used as | ||||||
|  | the default global instance. Prior to initialization of an SDK, Tracers | ||||||
|  | returned by the global TracerProvider will provide no-op functionality. This | ||||||
|  | means that all Span created prior to initialization are no-op Spans. | ||||||
|  |  | ||||||
|  | Once an SDK has been initialized, all provided no-op Tracers are swapped for | ||||||
|  | Tracers provided by the SDK defined TracerProvider. However, any Span started | ||||||
|  | prior to this initialization does not change its behavior. Meaning, the Span | ||||||
|  | remains a no-op Span. | ||||||
|  |  | ||||||
|  | The implementation to track and swap Tracers locks all new Tracer creation | ||||||
|  | until the swap is complete. This assumes that this operation is not | ||||||
|  | performance-critical. If that assumption is incorrect, be sure to configure an | ||||||
|  | SDK prior to any Tracer creation. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	"go.opentelemetry.io/otel/internal/trace/noop" | ||||||
|  | 	"go.opentelemetry.io/otel/trace" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // tracerProvider is a placeholder for a configured SDK TracerProvider. | ||||||
|  | // | ||||||
|  | // All TracerProvider functionality is forwarded to a delegate once | ||||||
|  | // configured. | ||||||
|  | type tracerProvider struct { | ||||||
|  | 	mtx     sync.Mutex | ||||||
|  | 	tracers []*tracer | ||||||
|  |  | ||||||
|  | 	delegate trace.TracerProvider | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Compile-time guarantee that tracerProvider implements the TracerProvider | ||||||
|  | // interface. | ||||||
|  | var _ trace.TracerProvider = &tracerProvider{} | ||||||
|  |  | ||||||
|  | // setDelegate configures p to delegate all TracerProvider functionality to | ||||||
|  | // provider. | ||||||
|  | // | ||||||
|  | // All Tracers provided prior to this function call are switched out to be | ||||||
|  | // Tracers provided by provider. | ||||||
|  | // | ||||||
|  | // Delegation only happens on the first call to this method. All subsequent | ||||||
|  | // calls result in no delegation changes. | ||||||
|  | func (p *tracerProvider) setDelegate(provider trace.TracerProvider) { | ||||||
|  | 	if p.delegate != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	p.mtx.Lock() | ||||||
|  | 	defer p.mtx.Unlock() | ||||||
|  |  | ||||||
|  | 	p.delegate = provider | ||||||
|  | 	for _, t := range p.tracers { | ||||||
|  | 		t.setDelegate(provider) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	p.tracers = nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Tracer implements TracerProvider. | ||||||
|  | func (p *tracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { | ||||||
|  | 	p.mtx.Lock() | ||||||
|  | 	defer p.mtx.Unlock() | ||||||
|  |  | ||||||
|  | 	if p.delegate != nil { | ||||||
|  | 		return p.delegate.Tracer(name, opts...) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	t := &tracer{name: name, opts: opts} | ||||||
|  | 	p.tracers = append(p.tracers, t) | ||||||
|  | 	return t | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // tracer is a placeholder for a trace.Tracer. | ||||||
|  | // | ||||||
|  | // All Tracer functionality is forwarded to a delegate once configured. | ||||||
|  | // Otherwise, all functionality is forwarded to a NoopTracer. | ||||||
|  | type tracer struct { | ||||||
|  | 	once sync.Once | ||||||
|  | 	name string | ||||||
|  | 	opts []trace.TracerOption | ||||||
|  |  | ||||||
|  | 	delegate trace.Tracer | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Compile-time guarantee that tracer implements the trace.Tracer interface. | ||||||
|  | var _ trace.Tracer = &tracer{} | ||||||
|  |  | ||||||
|  | // setDelegate configures t to delegate all Tracer functionality to Tracers | ||||||
|  | // created by provider. | ||||||
|  | // | ||||||
|  | // All subsequent calls to the Tracer methods will be passed to the delegate. | ||||||
|  | // | ||||||
|  | // Delegation only happens on the first call to this method. All subsequent | ||||||
|  | // calls result in no delegation changes. | ||||||
|  | func (t *tracer) setDelegate(provider trace.TracerProvider) { | ||||||
|  | 	t.once.Do(func() { t.delegate = provider.Tracer(t.name, t.opts...) }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Start implements trace.Tracer by forwarding the call to t.delegate if | ||||||
|  | // set, otherwise it forwards the call to a NoopTracer. | ||||||
|  | func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanOption) (context.Context, trace.Span) { | ||||||
|  | 	if t.delegate != nil { | ||||||
|  | 		return t.delegate.Start(ctx, name, opts...) | ||||||
|  | 	} | ||||||
|  | 	return noop.Tracer.Start(ctx, name, opts...) | ||||||
|  | } | ||||||
							
								
								
									
										91
									
								
								vendor/go.opentelemetry.io/otel/internal/rawhelpers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								vendor/go.opentelemetry.io/otel/internal/rawhelpers.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | // Copyright The OpenTelemetry Authors | ||||||
|  | // | ||||||
|  | // 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. | ||||||
|  |  | ||||||
|  | package internal | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"math" | ||||||
|  | 	"unsafe" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func BoolToRaw(b bool) uint64 { | ||||||
|  | 	if b { | ||||||
|  | 		return 1 | ||||||
|  | 	} | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawToBool(r uint64) bool { | ||||||
|  | 	return r != 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Int64ToRaw(i int64) uint64 { | ||||||
|  | 	return uint64(i) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawToInt64(r uint64) int64 { | ||||||
|  | 	return int64(r) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Uint64ToRaw(u uint64) uint64 { | ||||||
|  | 	return u | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawToUint64(r uint64) uint64 { | ||||||
|  | 	return r | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Float64ToRaw(f float64) uint64 { | ||||||
|  | 	return math.Float64bits(f) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawToFloat64(r uint64) float64 { | ||||||
|  | 	return math.Float64frombits(r) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Int32ToRaw(i int32) uint64 { | ||||||
|  | 	return uint64(i) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawToInt32(r uint64) int32 { | ||||||
|  | 	return int32(r) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Uint32ToRaw(u uint32) uint64 { | ||||||
|  | 	return uint64(u) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawToUint32(r uint64) uint32 { | ||||||
|  | 	return uint32(r) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Float32ToRaw(f float32) uint64 { | ||||||
|  | 	return Uint32ToRaw(math.Float32bits(f)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawToFloat32(r uint64) float32 { | ||||||
|  | 	return math.Float32frombits(RawToUint32(r)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawPtrToFloat64Ptr(r *uint64) *float64 { | ||||||
|  | 	return (*float64)(unsafe.Pointer(r)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawPtrToInt64Ptr(r *uint64) *int64 { | ||||||
|  | 	return (*int64)(unsafe.Pointer(r)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RawPtrToUint64Ptr(r *uint64) *uint64 { | ||||||
|  | 	return r | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 6543
					6543