forked from gitea/gitea
		
	[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:
		
							parent
							
								
									4cffc46f65
								
							
						
					
					
						commit
						ac97ea573c
					
				
							
								
								
									
										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-git/v5 v5.2.0 | ||||
| 	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-swagger/go-swagger v0.26.0 | ||||
| 	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/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/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-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= | ||||
| @ -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/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= | ||||
| 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/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= | ||||
| 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/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= | ||||
| 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.3.1 h1:L6VrMUGZaMlNIMN8Hj+CHh4U9yodJE3FAt/rgvfaKvE= | ||||
| 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-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-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= | ||||
| @ -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.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.10 h1:5BHISBAXOc/aJK25irLZnx2D3s6WyYaY9D4gmuz9fdE= | ||||
| 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/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.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.6 h1:xZMThgv5SQ7SMbWtKFkCf9bBdvR2iEyw9k3zGZONuys= | ||||
| 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.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.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.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= | ||||
| 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/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.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.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.6/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.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.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.15/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.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.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.11/go.mod h1:UukAYgTaQfqJuAFlNxxMWNvMYiwiXtLsF2VwmoFtbtc= | ||||
| 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.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.9 h1:1IxuqvBUU3S2Bi4YC7tlP9SJF1gVpCvqN0T2Qof4azE= | ||||
| 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.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.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.10 h1:tG3SZ5DC5KF4cyt7nqLVcQXGj5A7mpaYkAcNPlDK+Yk= | ||||
| 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.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-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/v7 v7.4.0 h1:7obg6wUoj05T0EpY0o8B59S9w5yeMWql7sw2kwNW1x4= | ||||
| github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= | ||||
| github.com/go-redis/redis/v8 v8.4.0 h1:J5NCReIgh3QgUJu398hUncxDExN4gMOHI11NVbVicGQ= | ||||
| 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.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= | ||||
| 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/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.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/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 h1:gBeyun7mySAKWg7Fb0GOcv0upX9bdaZScs8QcRo8mEY= | ||||
| 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.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/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= | ||||
| 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/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/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.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= | ||||
| 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/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.1.30 h1:Qww6FseFn8PRfw07jueqIXqodm0JKiiKuK0DeXSqfyo= | ||||
| 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.1 h1:9ojcLbuZ4gXbB2sX53MKn8JUZ0sB/2wfwsEcRw+I08U= | ||||
| 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/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.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= | ||||
| 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.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.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.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.14.2 h1:8mVmC9kjFFmA8H4pKMUhcblgifdkOIXPvbhN1T36q1M= | ||||
| 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.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.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/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/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= | ||||
| @ -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/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/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.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= | ||||
| 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/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= | ||||
| 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/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= | ||||
| @ -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.27/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.3.1 h1:eVwehsLsZlCJCwXyGLgg+Q4iFWE/eTIMG0e8waCmm/I= | ||||
| 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.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | ||||
| 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.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.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | ||||
| 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-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-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-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew= | ||||
| 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-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-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-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-20210126194326-f9ce19ea3013 h1:55H5j7lotzuFCEOKDsMch+fRNUQ9DgtyHOUP31FNqKc= | ||||
| 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-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-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-20210124154548-22da62e12c0c h1:VwygUrnw9jn88c4u8GD3rZQbqrP/tgas88tPUbBxQrk= | ||||
| 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-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= | ||||
| 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.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.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= | ||||
| 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/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-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-20201022035929-9cf592e881e9 h1:sEvmEcJVKBNUvgCUClbUQeHOAa9U0I2Ce1BooMvVCY4= | ||||
| 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-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | ||||
| 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/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.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.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | ||||
| 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/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" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/modules/graceful" | ||||
| 	"code.gitea.io/gitea/modules/nosql" | ||||
| 
 | ||||
| 	"gitea.com/go-chi/cache" | ||||
| 	"github.com/go-redis/redis/v7" | ||||
| 	"github.com/go-redis/redis/v8" | ||||
| 	"github.com/unknwon/com" | ||||
| ) | ||||
| 
 | ||||
| @ -28,7 +29,7 @@ type RedisCacher struct { | ||||
| func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { | ||||
| 	key = c.prefix + key | ||||
| 	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 | ||||
| 		} | ||||
| 	} else { | ||||
| @ -36,7 +37,7 @@ func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { | ||||
| 		if err != nil { | ||||
| 			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 | ||||
| 		} | ||||
| 	} | ||||
| @ -44,12 +45,12 @@ func (c *RedisCacher) Put(key string, val interface{}, expire int64) error { | ||||
| 	if c.occupyMode { | ||||
| 		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. | ||||
| 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 { | ||||
| 		return nil | ||||
| 	} | ||||
| @ -59,14 +60,14 @@ func (c *RedisCacher) Get(key string) interface{} { | ||||
| // Delete deletes cached value by given key. | ||||
| func (c *RedisCacher) Delete(key string) error { | ||||
| 	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 | ||||
| 	} | ||||
| 
 | ||||
| 	if c.occupyMode { | ||||
| 		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. | ||||
| @ -74,7 +75,7 @@ func (c *RedisCacher) Incr(key string) error { | ||||
| 	if !c.IsExist(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. | ||||
| @ -82,17 +83,17 @@ func (c *RedisCacher) Decr(key string) error { | ||||
| 	if !c.IsExist(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. | ||||
| 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 | ||||
| 	} | ||||
| 
 | ||||
| 	if !c.occupyMode { | ||||
| 		c.c.HDel(c.hsetName, c.prefix+key) | ||||
| 		c.c.HDel(graceful.GetManager().HammerContext(), c.hsetName, c.prefix+key) | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| @ -100,17 +101,17 @@ func (c *RedisCacher) IsExist(key string) bool { | ||||
| // Flush deletes all cached data. | ||||
| func (c *RedisCacher) Flush() error { | ||||
| 	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 { | ||||
| 		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 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. | ||||
| @ -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() { | ||||
|  | ||||
| @ -9,7 +9,7 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7" | ||||
| 	"github.com/go-redis/redis/v8" | ||||
| 	"github.com/syndtr/goleveldb/leveldb" | ||||
| ) | ||||
| 
 | ||||
|  | ||||
| @ -10,7 +10,7 @@ import ( | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7" | ||||
| 	"github.com/go-redis/redis/v8" | ||||
| ) | ||||
| 
 | ||||
| var replacer = strings.NewReplacer("_", "", "-", "") | ||||
|  | ||||
| @ -163,6 +163,11 @@ func (q *ByteFIFOQueue) Shutdown() { | ||||
| 	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 | ||||
| func (q *ByteFIFOQueue) Terminate() { | ||||
| 	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) | ||||
| } | ||||
| 
 | ||||
| // IsTerminated returns a channel which is closed when this Queue is terminated | ||||
| func (q *ByteFIFOQueue) IsTerminated() <-chan struct{} { | ||||
| 	return q.terminated | ||||
| } | ||||
| 
 | ||||
| var _ (UniqueQueue) = &ByteFIFOUniqueQueue{} | ||||
| 
 | ||||
| // ByteFIFOUniqueQueue represents a UniqueQueue formed from a UniqueByteFifo | ||||
|  | ||||
| @ -5,10 +5,14 @@ | ||||
| package queue | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/modules/graceful" | ||||
| 	"code.gitea.io/gitea/modules/log" | ||||
| 	"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 | ||||
| @ -43,6 +47,8 @@ func NewRedisQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	byteFIFO.ctx = graceful.NewChannelContext(byteFIFOQueue.IsTerminated(), fmt.Errorf("queue has been terminated")) | ||||
| 
 | ||||
| 	queue := &RedisQueue{ | ||||
| 		ByteFIFOQueue: byteFIFOQueue, | ||||
| 	} | ||||
| @ -53,13 +59,13 @@ func NewRedisQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, error) | ||||
| } | ||||
| 
 | ||||
| type redisClient interface { | ||||
| 	RPush(key string, args ...interface{}) *redis.IntCmd | ||||
| 	LPop(key string) *redis.StringCmd | ||||
| 	LLen(key string) *redis.IntCmd | ||||
| 	SAdd(key string, members ...interface{}) *redis.IntCmd | ||||
| 	SRem(key string, members ...interface{}) *redis.IntCmd | ||||
| 	SIsMember(key string, member interface{}) *redis.BoolCmd | ||||
| 	Ping() *redis.StatusCmd | ||||
| 	RPush(ctx context.Context, key string, args ...interface{}) *redis.IntCmd | ||||
| 	LPop(ctx context.Context, key string) *redis.StringCmd | ||||
| 	LLen(ctx context.Context, key string) *redis.IntCmd | ||||
| 	SAdd(ctx context.Context, key string, members ...interface{}) *redis.IntCmd | ||||
| 	SRem(ctx context.Context, key string, members ...interface{}) *redis.IntCmd | ||||
| 	SIsMember(ctx context.Context, key string, member interface{}) *redis.BoolCmd | ||||
| 	Ping(ctx context.Context) *redis.StatusCmd | ||||
| 	Close() error | ||||
| } | ||||
| 
 | ||||
| @ -67,6 +73,7 @@ var _ (ByteFIFO) = &RedisByteFIFO{} | ||||
| 
 | ||||
| // RedisByteFIFO represents a ByteFIFO formed from a redisClient | ||||
| type RedisByteFIFO struct { | ||||
| 	ctx       context.Context | ||||
| 	client    redisClient | ||||
| 	queueName string | ||||
| } | ||||
| @ -82,8 +89,9 @@ func NewRedisByteFIFO(config RedisByteFIFOConfiguration) (*RedisByteFIFO, error) | ||||
| 	fifo := &RedisByteFIFO{ | ||||
| 		queueName: config.QueueName, | ||||
| 	} | ||||
| 	fifo.ctx = graceful.GetManager().TerminateContext() | ||||
| 	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 fifo, nil | ||||
| @ -96,12 +104,12 @@ func (fifo *RedisByteFIFO) PushFunc(data []byte, fn func() error) error { | ||||
| 			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 | ||||
| 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 { | ||||
| 		return data, nil | ||||
| 	} | ||||
| @ -115,7 +123,7 @@ func (fifo *RedisByteFIFO) Close() error { | ||||
| 
 | ||||
| // Len returns the length of the fifo | ||||
| 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 { | ||||
| 		log.Error("Error whilst getting length of redis queue %s: Error: %v", fifo.queueName, err) | ||||
| 		return -1 | ||||
|  | ||||
| @ -4,7 +4,12 @@ | ||||
| 
 | ||||
| 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 | ||||
| const RedisUniqueQueueType Type = "unique-redis" | ||||
| @ -46,6 +51,8 @@ func NewRedisUniqueQueue(handle HandlerFunc, cfg, exemplar interface{}) (Queue, | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	byteFIFO.ctx = graceful.NewChannelContext(byteFIFOQueue.IsTerminated(), fmt.Errorf("queue has been terminated")) | ||||
| 
 | ||||
| 	queue := &RedisUniqueQueue{ | ||||
| 		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 | ||||
| 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 { | ||||
| 		return err | ||||
| 	} | ||||
| @ -98,12 +105,12 @@ func (fifo *RedisUniqueByteFIFO) PushFunc(data []byte, fn func() error) error { | ||||
| 			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 | ||||
| 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 { | ||||
| 		return data, err | ||||
| 	} | ||||
| @ -112,13 +119,13 @@ func (fifo *RedisUniqueByteFIFO) Pop() ([]byte, error) { | ||||
| 		return data, nil | ||||
| 	} | ||||
| 
 | ||||
| 	err = fifo.client.SRem(fifo.setName, data).Err() | ||||
| 	err = fifo.client.SRem(fifo.ctx, fifo.setName, data).Err() | ||||
| 	return data, err | ||||
| } | ||||
| 
 | ||||
| // Has returns whether the fifo contains this data | ||||
| 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() { | ||||
|  | ||||
| @ -21,10 +21,11 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"code.gitea.io/gitea/modules/graceful" | ||||
| 	"code.gitea.io/gitea/modules/nosql" | ||||
| 
 | ||||
| 	"gitea.com/go-chi/session" | ||||
| 	"github.com/go-redis/redis/v7" | ||||
| 	"github.com/go-redis/redis/v8" | ||||
| ) | ||||
| 
 | ||||
| // RedisStore represents a redis session store implementation. | ||||
| @ -90,7 +91,7 @@ func (s *RedisStore) Release() error { | ||||
| 		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. | ||||
| @ -127,20 +128,20 @@ func (p *RedisProvider) Init(maxlifetime int64, configs string) (err error) { | ||||
| 	} | ||||
| 
 | ||||
| 	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. | ||||
| func (p *RedisProvider) Read(sid string) (session.RawStore, error) { | ||||
| 	psid := p.prefix + 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 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	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 { | ||||
| 		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. | ||||
| 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 | ||||
| } | ||||
| 
 | ||||
| // Destroy deletes a session by session ID. | ||||
| 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. | ||||
| @ -176,17 +177,17 @@ func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err | ||||
| 		return nil, fmt.Errorf("new sid '%s' already exists", sid) | ||||
| 	} else if !p.Exist(oldsid) { | ||||
| 		// 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 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	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 | ||||
| 	} | ||||
| 
 | ||||
| 	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 { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @ -205,7 +206,11 @@ func (p *RedisProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err | ||||
| 
 | ||||
| // Count counts and returns number of sessions. | ||||
| 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. | ||||
|  | ||||
							
								
								
									
										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 | ||||
| testdata/*/ | ||||
| .idea/ | ||||
| @ -7,9 +7,18 @@ linters: | ||||
|   disable: | ||||
|     - funlen | ||||
|     - gochecknoglobals | ||||
|     - gochecknoinits | ||||
|     - gocognit | ||||
|     - goconst | ||||
|     - godox | ||||
|     - gosec | ||||
|     - maligned | ||||
|     - 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 ./... -run=NONE -bench=. -benchmem | ||||
| 	env GOOS=linux GOARCH=386 go test ./... | ||||
| 	go vet | ||||
| 	golangci-lint run | ||||
| 
 | ||||
| testdeps: testdata/redis/src/redis-server | ||||
| @ -18,3 +19,9 @@ testdata/redis: | ||||
| 
 | ||||
| testdata/redis/src/redis-server: testdata/redis | ||||
| 	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" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7/internal/pool" | ||||
| 	"github.com/go-redis/redis/v7/internal/proto" | ||||
| 	"github.com/go-redis/redis/v8/internal/pool" | ||||
| 	"github.com/go-redis/redis/v8/internal/proto" | ||||
| ) | ||||
| 
 | ||||
| var ErrClosed = pool.ErrClosed | ||||
| @ -24,15 +24,16 @@ type Error interface { | ||||
| 
 | ||||
| var _ Error = proto.RedisError("") | ||||
| 
 | ||||
| func isRetryableError(err error, retryTimeout bool) bool { | ||||
| func shouldRetry(err error, retryTimeout bool) bool { | ||||
| 	switch err { | ||||
| 	case io.EOF, io.ErrUnexpectedEOF: | ||||
| 		return true | ||||
| 	case nil, context.Canceled, context.DeadlineExceeded: | ||||
| 		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 true | ||||
| @ -51,6 +52,10 @@ func isRetryableError(err error, retryTimeout bool) bool { | ||||
| 	if strings.HasPrefix(s, "CLUSTERDOWN ") { | ||||
| 		return true | ||||
| 	} | ||||
| 	if strings.HasPrefix(s, "TRYAGAIN ") { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| @ -60,19 +65,25 @@ func isRedisError(err error) bool { | ||||
| } | ||||
| 
 | ||||
| func isBadConn(err error, allowTimeout bool) bool { | ||||
| 	if err == nil { | ||||
| 	switch err { | ||||
| 	case nil: | ||||
| 		return false | ||||
| 	case context.Canceled, context.DeadlineExceeded: | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	if isRedisError(err) { | ||||
| 		// Close connections in read only state in case domain addr is used | ||||
| 		// and domain resolves to a different Redis Server. See #790. | ||||
| 		return isReadOnlyError(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if allowTimeout { | ||||
| 		if netErr, ok := err.(net.Error); ok && netErr.Timeout() { | ||||
| 			return false | ||||
| 			return !netErr.Temporary() | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| } | ||||
| 
 | ||||
| @ -106,3 +117,9 @@ func isLoadingError(err error) bool { | ||||
| func isReadOnlyError(err error) bool { | ||||
| 	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 | ||||
| 
 | ||||
| import ( | ||||
| 	"math/rand" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v8/internal/rand" | ||||
| ) | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"context" | ||||
| 	"net" | ||||
| 	"sync/atomic" | ||||
| 	"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{} | ||||
| 
 | ||||
| type Conn struct { | ||||
| 	usedAt  int64 // atomic | ||||
| 	netConn net.Conn | ||||
| 
 | ||||
| 	rd *proto.Reader | ||||
| 	bw *bufio.Writer | ||||
| 	wr *proto.Writer | ||||
| 
 | ||||
| 	Inited    bool | ||||
| 	pooled    bool | ||||
| 	createdAt time.Time | ||||
| 	usedAt    int64 // atomic | ||||
| } | ||||
| 
 | ||||
| func NewConn(netConn net.Conn) *Conn { | ||||
| @ -29,7 +33,8 @@ func NewConn(netConn net.Conn) *Conn { | ||||
| 		createdAt: time.Now(), | ||||
| 	} | ||||
| 	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()) | ||||
| 	return cn | ||||
| } | ||||
| @ -46,7 +51,7 @@ func (cn *Conn) SetUsedAt(tm time.Time) { | ||||
| func (cn *Conn) SetNetConn(netConn net.Conn) { | ||||
| 	cn.netConn = netConn | ||||
| 	cn.rd.Reset(netConn) | ||||
| 	cn.wr.Reset(netConn) | ||||
| 	cn.bw.Reset(netConn) | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
| 	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 { | ||||
| 	err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return fn(cn.rd) | ||||
| 	return internal.WithSpan(ctx, "redis.with_reader", func(ctx context.Context, span trace.Span) error { | ||||
| 		if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil { | ||||
| 			return internal.RecordError(ctx, span, err) | ||||
| 		} | ||||
| 		if err := fn(cn.rd); err != nil { | ||||
| 			return internal.RecordError(ctx, span, err) | ||||
| 		} | ||||
| 		return nil | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func (cn *Conn) WithWriter( | ||||
| 	ctx context.Context, timeout time.Duration, fn func(wr *proto.Writer) error, | ||||
| ) error { | ||||
| 	err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return internal.WithSpan(ctx, "redis.with_writer", func(ctx context.Context, span trace.Span) error { | ||||
| 		if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil { | ||||
| 			return internal.RecordError(ctx, span, err) | ||||
| 		} | ||||
| 
 | ||||
| 	if cn.wr.Buffered() > 0 { | ||||
| 		cn.wr.Reset(cn.netConn) | ||||
| 	} | ||||
| 		if cn.bw.Buffered() > 0 { | ||||
| 			cn.bw.Reset(cn.netConn) | ||||
| 		} | ||||
| 
 | ||||
| 	err = fn(cn.wr) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 		if err := fn(cn.wr); err != nil { | ||||
| 			return internal.RecordError(ctx, span, 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 { | ||||
| @ -8,11 +8,13 @@ import ( | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7/internal" | ||||
| 	"github.com/go-redis/redis/v8/internal" | ||||
| ) | ||||
| 
 | ||||
| var ErrClosed = errors.New("redis: client is closed") | ||||
| var ErrPoolTimeout = errors.New("redis: connection pool timeout") | ||||
| var ( | ||||
| 	ErrClosed      = errors.New("redis: client is closed") | ||||
| 	ErrPoolTimeout = errors.New("redis: connection pool timeout") | ||||
| ) | ||||
| 
 | ||||
| var timers = sync.Pool{ | ||||
| 	New: func() interface{} { | ||||
| @ -38,8 +40,8 @@ type Pooler interface { | ||||
| 	CloseConn(*Conn) error | ||||
| 
 | ||||
| 	Get(context.Context) (*Conn, error) | ||||
| 	Put(*Conn) | ||||
| 	Remove(*Conn, error) | ||||
| 	Put(context.Context, *Conn) | ||||
| 	Remove(context.Context, *Conn, error) | ||||
| 
 | ||||
| 	Len() int | ||||
| 	IdleLen() int | ||||
| @ -60,13 +62,16 @@ type Options struct { | ||||
| 	IdleCheckFrequency time.Duration | ||||
| } | ||||
| 
 | ||||
| type lastDialErrorWrap struct { | ||||
| 	err error | ||||
| } | ||||
| 
 | ||||
| type ConnPool struct { | ||||
| 	opt *Options | ||||
| 
 | ||||
| 	dialErrorsNum uint32 // atomic | ||||
| 
 | ||||
| 	lastDialErrorMu sync.RWMutex | ||||
| 	lastDialError   error | ||||
| 	lastDialError atomic.Value | ||||
| 
 | ||||
| 	queue chan struct{} | ||||
| 
 | ||||
| @ -158,6 +163,7 @@ func (p *ConnPool) newConn(ctx context.Context, pooled bool) (*Conn, error) { | ||||
| 		} | ||||
| 	} | ||||
| 	p.connsMu.Unlock() | ||||
| 
 | ||||
| 	return cn, nil | ||||
| } | ||||
| 
 | ||||
| @ -179,6 +185,7 @@ func (p *ConnPool) dialConn(ctx context.Context, pooled bool) (*Conn, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	internal.NewConnectionsCounter.Add(ctx, 1) | ||||
| 	cn := NewConn(netConn) | ||||
| 	cn.pooled = pooled | ||||
| 	return cn, nil | ||||
| @ -204,16 +211,15 @@ func (p *ConnPool) tryDial() { | ||||
| } | ||||
| 
 | ||||
| func (p *ConnPool) setLastDialError(err error) { | ||||
| 	p.lastDialErrorMu.Lock() | ||||
| 	p.lastDialError = err | ||||
| 	p.lastDialErrorMu.Unlock() | ||||
| 	p.lastDialError.Store(&lastDialErrorWrap{err: err}) | ||||
| } | ||||
| 
 | ||||
| func (p *ConnPool) getLastDialError() error { | ||||
| 	p.lastDialErrorMu.RLock() | ||||
| 	err := p.lastDialError | ||||
| 	p.lastDialErrorMu.RUnlock() | ||||
| 	return err | ||||
| 	err, _ := p.lastDialError.Load().(*lastDialErrorWrap) | ||||
| 	if err != nil { | ||||
| 		return err.err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // Get returns existed connection from the pool or creates a new one. | ||||
| @ -313,15 +319,15 @@ func (p *ConnPool) popIdle() *Conn { | ||||
| 	return cn | ||||
| } | ||||
| 
 | ||||
| func (p *ConnPool) Put(cn *Conn) { | ||||
| func (p *ConnPool) Put(ctx context.Context, cn *Conn) { | ||||
| 	if cn.rd.Buffered() > 0 { | ||||
| 		internal.Logger.Printf("Conn has unread data") | ||||
| 		p.Remove(cn, BadConnError{}) | ||||
| 		internal.Logger.Printf(ctx, "Conn has unread data") | ||||
| 		p.Remove(ctx, cn, BadConnError{}) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	if !cn.pooled { | ||||
| 		p.Remove(cn, nil) | ||||
| 		p.Remove(ctx, cn, nil) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| @ -332,7 +338,7 @@ func (p *ConnPool) Put(cn *Conn) { | ||||
| 	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.freeTurn() | ||||
| 	_ = p.closeConn(cn) | ||||
| @ -403,8 +409,10 @@ func (p *ConnPool) closed() bool { | ||||
| } | ||||
| 
 | ||||
| func (p *ConnPool) Filter(fn func(*Conn) bool) error { | ||||
| 	var firstErr error | ||||
| 	p.connsMu.Lock() | ||||
| 	defer p.connsMu.Unlock() | ||||
| 
 | ||||
| 	var firstErr error | ||||
| 	for _, cn := range p.conns { | ||||
| 		if fn(cn) { | ||||
| 			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 | ||||
| } | ||||
| 
 | ||||
| @ -453,7 +460,7 @@ func (p *ConnPool) reaper(frequency time.Duration) { | ||||
| 			} | ||||
| 			_, err := p.ReapStaleConns() | ||||
| 			if err != nil { | ||||
| 				internal.Logger.Printf("ReapStaleConns failed: %s", err) | ||||
| 				internal.Logger.Printf(context.Background(), "ReapStaleConns failed: %s", err) | ||||
| 				continue | ||||
| 			} | ||||
| 		case <-p.closedCh: | ||||
| @ -470,6 +477,7 @@ func (p *ConnPool) ReapStaleConns() (int, error) { | ||||
| 		p.connsMu.Lock() | ||||
| 		cn := p.reapStaleConn() | ||||
| 		p.connsMu.Unlock() | ||||
| 
 | ||||
| 		p.freeTurn() | ||||
| 
 | ||||
| 		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 ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"sync/atomic" | ||||
| ) | ||||
| @ -30,9 +31,11 @@ func (e BadConnError) Unwrap() error { | ||||
| 	return e.wrapped | ||||
| } | ||||
| 
 | ||||
| type SingleConnPool struct { | ||||
| 	pool  Pooler | ||||
| 	level int32 // atomic | ||||
| //------------------------------------------------------------------------------ | ||||
| 
 | ||||
| type StickyConnPool struct { | ||||
| 	pool   Pooler | ||||
| 	shared int32 // atomic | ||||
| 
 | ||||
| 	state uint32 // atomic | ||||
| 	ch    chan *Conn | ||||
| @ -40,37 +43,29 @@ type SingleConnPool struct { | ||||
| 	_badConnError atomic.Value | ||||
| } | ||||
| 
 | ||||
| var _ Pooler = (*SingleConnPool)(nil) | ||||
| var _ Pooler = (*StickyConnPool)(nil) | ||||
| 
 | ||||
| func NewSingleConnPool(pool Pooler) *SingleConnPool { | ||||
| 	p, ok := pool.(*SingleConnPool) | ||||
| func NewStickyConnPool(pool Pooler) *StickyConnPool { | ||||
| 	p, ok := pool.(*StickyConnPool) | ||||
| 	if !ok { | ||||
| 		p = &SingleConnPool{ | ||||
| 		p = &StickyConnPool{ | ||||
| 			pool: pool, | ||||
| 			ch:   make(chan *Conn, 1), | ||||
| 		} | ||||
| 	} | ||||
| 	atomic.AddInt32(&p.level, 1) | ||||
| 	atomic.AddInt32(&p.shared, 1) | ||||
| 	return p | ||||
| } | ||||
| 
 | ||||
| func (p *SingleConnPool) SetConn(cn *Conn) { | ||||
| 	if atomic.CompareAndSwapUint32(&p.state, stateDefault, stateInited) { | ||||
| 		p.ch <- cn | ||||
| 	} else { | ||||
| 		panic("not reached") | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (p *SingleConnPool) NewConn(ctx context.Context) (*Conn, error) { | ||||
| func (p *StickyConnPool) NewConn(ctx context.Context) (*Conn, error) { | ||||
| 	return p.pool.NewConn(ctx) | ||||
| } | ||||
| 
 | ||||
| func (p *SingleConnPool) CloseConn(cn *Conn) error { | ||||
| func (p *StickyConnPool) CloseConn(cn *Conn) error { | ||||
| 	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. | ||||
| 	for i := 0; i < 1000; i++ { | ||||
| 		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) { | ||||
| 				return cn, nil | ||||
| 			} | ||||
| 			p.pool.Remove(cn, ErrClosed) | ||||
| 			p.pool.Remove(ctx, cn, ErrClosed) | ||||
| 		case stateInited: | ||||
| 			if err := p.badConnError(); err != nil { | ||||
| 				return nil, err | ||||
| @ -98,60 +93,38 @@ func (p *SingleConnPool) Get(ctx context.Context) (*Conn, error) { | ||||
| 			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() { | ||||
| 		if recover() != nil { | ||||
| 			p.freeConn(cn) | ||||
| 			p.freeConn(ctx, 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 { | ||||
| 		p.pool.Remove(cn, err) | ||||
| 		p.pool.Remove(ctx, cn, err) | ||||
| 	} 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() { | ||||
| 		if recover() != nil { | ||||
| 			p.pool.Remove(cn, ErrClosed) | ||||
| 			p.pool.Remove(ctx, cn, ErrClosed) | ||||
| 		} | ||||
| 	}() | ||||
| 	p._badConnError.Store(BadConnError{wrapped: reason}) | ||||
| 	p.ch <- cn | ||||
| } | ||||
| 
 | ||||
| func (p *SingleConnPool) 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 *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 { | ||||
| func (p *StickyConnPool) Close() error { | ||||
| 	if shared := atomic.AddInt32(&p.shared, -1); shared > 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| @ -164,16 +137,16 @@ func (p *SingleConnPool) Close() error { | ||||
| 			close(p.ch) | ||||
| 			cn, ok := <-p.ch | ||||
| 			if ok { | ||||
| 				p.freeConn(cn) | ||||
| 				p.freeConn(context.TODO(), cn) | ||||
| 			} | ||||
| 			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 { | ||||
| 		return nil | ||||
| 	} | ||||
| @ -183,21 +156,21 @@ func (p *SingleConnPool) Reset() error { | ||||
| 		if !ok { | ||||
| 			return ErrClosed | ||||
| 		} | ||||
| 		p.pool.Remove(cn, ErrClosed) | ||||
| 		p.pool.Remove(ctx, cn, ErrClosed) | ||||
| 		p._badConnError.Store(BadConnError{wrapped: nil}) | ||||
| 	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) { | ||||
| 		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 | ||||
| } | ||||
| 
 | ||||
| func (p *SingleConnPool) badConnError() error { | ||||
| func (p *StickyConnPool) badConnError() error { | ||||
| 	if v := p._badConnError.Load(); v != nil { | ||||
| 		err := v.(BadConnError) | ||||
| 		if err.wrapped != nil { | ||||
| @ -206,3 +179,24 @@ func (p *SingleConnPool) badConnError() error { | ||||
| 	} | ||||
| 	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" | ||||
| 	"io" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7/internal/util" | ||||
| 	"github.com/go-redis/redis/v8/internal/util" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| @ -71,13 +71,25 @@ func (r *Reader) ReadLine() ([]byte, error) { | ||||
| func (r *Reader) readLine() ([]byte, error) { | ||||
| 	b, err := r.rd.ReadSlice('\n') | ||||
| 	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' { | ||||
| 		return nil, fmt.Errorf("redis: invalid reply: %q", b) | ||||
| 	} | ||||
| 	b = b[:len(b)-2] | ||||
| 	return b, nil | ||||
| 	return b[:len(b)-2], nil | ||||
| } | ||||
| 
 | ||||
| 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() | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| @ -190,7 +202,11 @@ func (r *Reader) ReadArrayLen() (int64, error) { | ||||
| 	case ErrorReply: | ||||
| 		return 0, ParseErrorReply(line) | ||||
| 	case ArrayReply: | ||||
| 		return parseArrayLen(line) | ||||
| 		n, err := parseArrayLen(line) | ||||
| 		if err != nil { | ||||
| 			return 0, err | ||||
| 		} | ||||
| 		return int(n), nil | ||||
| 	default: | ||||
| 		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) | ||||
| 	for i := int64(0); i < n; i++ { | ||||
| 
 | ||||
| 	for i := 0; i < n; i++ { | ||||
| 		key, err := r.ReadString() | ||||
| 		if err != nil { | ||||
| 			return nil, 0, err | ||||
| @ -4,10 +4,13 @@ import ( | ||||
| 	"encoding" | ||||
| 	"fmt" | ||||
| 	"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 { | ||||
| 	switch v := v.(type) { | ||||
| 	case nil: | ||||
| @ -99,6 +102,10 @@ func Scan(b []byte, v interface{}) error { | ||||
| 	case *bool: | ||||
| 		*v = len(b) == 1 && b[0] == '1' | ||||
| 		return nil | ||||
| 	case *time.Time: | ||||
| 		var err error | ||||
| 		*v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b)) | ||||
| 		return err | ||||
| 	case encoding.BinaryUnmarshaler: | ||||
| 		return v.UnmarshalBinary(b) | ||||
| 	default: | ||||
| @ -124,7 +131,7 @@ func ScanSlice(data []string, slice interface{}) error { | ||||
| 	for i, s := range data { | ||||
| 		elem := next() | ||||
| 		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 | ||||
| 		} | ||||
| 	} | ||||
| @ -1,26 +1,32 @@ | ||||
| package proto | ||||
| 
 | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"encoding" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 	"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 { | ||||
| 	wr *bufio.Writer | ||||
| 	writer | ||||
| 
 | ||||
| 	lenBuf []byte | ||||
| 	numBuf []byte | ||||
| } | ||||
| 
 | ||||
| func NewWriter(wr io.Writer) *Writer { | ||||
| func NewWriter(wr writer) *Writer { | ||||
| 	return &Writer{ | ||||
| 		wr: bufio.NewWriter(wr), | ||||
| 		writer: wr, | ||||
| 
 | ||||
| 		lenBuf: make([]byte, 64), | ||||
| 		numBuf: make([]byte, 64), | ||||
| @ -28,19 +34,16 @@ func NewWriter(wr io.Writer) *Writer { | ||||
| } | ||||
| 
 | ||||
| func (w *Writer) WriteArgs(args []interface{}) error { | ||||
| 	err := w.wr.WriteByte(ArrayReply) | ||||
| 	if err != nil { | ||||
| 	if err := w.WriteByte(ArrayReply); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = w.writeLen(len(args)) | ||||
| 	if err != nil { | ||||
| 	if err := w.writeLen(len(args)); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	for _, arg := range args { | ||||
| 		err := w.writeArg(arg) | ||||
| 		if err != nil { | ||||
| 		if err := w.WriteArg(arg); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| @ -51,11 +54,11 @@ func (w *Writer) WriteArgs(args []interface{}) error { | ||||
| func (w *Writer) writeLen(n int) error { | ||||
| 	w.lenBuf = strconv.AppendUint(w.lenBuf[:0], uint64(n), 10) | ||||
| 	w.lenBuf = append(w.lenBuf, '\r', '\n') | ||||
| 	_, err := w.wr.Write(w.lenBuf) | ||||
| 	_, err := w.Write(w.lenBuf) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (w *Writer) writeArg(v interface{}) error { | ||||
| func (w *Writer) WriteArg(v interface{}) error { | ||||
| 	switch v := v.(type) { | ||||
| 	case nil: | ||||
| 		return w.string("") | ||||
| @ -93,7 +96,8 @@ func (w *Writer) writeArg(v interface{}) error { | ||||
| 		} | ||||
| 		return w.int(0) | ||||
| 	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: | ||||
| 		b, err := v.MarshalBinary() | ||||
| 		if err != nil { | ||||
| @ -107,18 +111,15 @@ func (w *Writer) writeArg(v interface{}) error { | ||||
| } | ||||
| 
 | ||||
| func (w *Writer) bytes(b []byte) error { | ||||
| 	err := w.wr.WriteByte(StringReply) | ||||
| 	if err != nil { | ||||
| 	if err := w.WriteByte(StringReply); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = w.writeLen(len(b)) | ||||
| 	if err != nil { | ||||
| 	if err := w.writeLen(len(b)); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = w.wr.Write(b) | ||||
| 	if err != nil { | ||||
| 	if _, err := w.Write(b); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| @ -145,21 +146,8 @@ func (w *Writer) float(f float64) error { | ||||
| } | ||||
| 
 | ||||
| func (w *Writer) crlf() error { | ||||
| 	err := w.wr.WriteByte('\r') | ||||
| 	if err != nil { | ||||
| 	if err := w.WriteByte('\r'); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return w.wr.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() | ||||
| 	return w.WriteByte('\n') | ||||
| } | ||||
							
								
								
									
										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 | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"sync" | ||||
| ) | ||||
| 
 | ||||
| @ -21,7 +22,7 @@ func (it *ScanIterator) Err() error { | ||||
| } | ||||
| 
 | ||||
| // 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() | ||||
| 	defer it.mu.Unlock() | ||||
| 
 | ||||
| @ -43,13 +44,14 @@ func (it *ScanIterator) Next() bool { | ||||
| 		} | ||||
| 
 | ||||
| 		// Fetch next page. | ||||
| 		if it.cmd.args[0] == "scan" { | ||||
| 		switch it.cmd.args[0] { | ||||
| 		case "scan", "qscan": | ||||
| 			it.cmd.args[1] = it.cmd.cursor | ||||
| 		} else { | ||||
| 		default: | ||||
| 			it.cmd.args[2] = it.cmd.cursor | ||||
| 		} | ||||
| 
 | ||||
| 		err := it.cmd.process(it.cmd) | ||||
| 		err := it.cmd.process(ctx, it.cmd) | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
| @ -12,7 +12,10 @@ import ( | ||||
| 	"strings" | ||||
| 	"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. | ||||
| @ -26,6 +29,7 @@ type Limiter interface { | ||||
| 	ReportResult(result error) | ||||
| } | ||||
| 
 | ||||
| // Options keeps the settings to setup redis connection. | ||||
| type Options struct { | ||||
| 	// The network type, either tcp or unix. | ||||
| 	// Default is tcp. | ||||
| @ -38,21 +42,23 @@ type Options struct { | ||||
| 	Dialer func(ctx context.Context, network, addr string) (net.Conn, error) | ||||
| 
 | ||||
| 	// 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 | ||||
| 	// list when connecting to a Redis 6.0 instance, or greater, that is using the Redis ACL system. | ||||
| 	// Use the specified Username to authenticate the current connection | ||||
| 	// 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 | ||||
| 
 | ||||
| 	// Optional password. Must match the password specified in the | ||||
| 	// 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 | ||||
| 
 | ||||
| 	// Database to be selected after connecting to the server. | ||||
| 	DB int | ||||
| 
 | ||||
| 	// 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 | ||||
| 	// Minimum backoff between each retry. | ||||
| 	// Default is 8 milliseconds; -1 disables backoff. | ||||
| @ -117,6 +123,9 @@ func (opt *Options) init() { | ||||
| 			opt.Network = "tcp" | ||||
| 		} | ||||
| 	} | ||||
| 	if opt.DialTimeout == 0 { | ||||
| 		opt.DialTimeout = 5 * time.Second | ||||
| 	} | ||||
| 	if opt.Dialer == nil { | ||||
| 		opt.Dialer = func(ctx context.Context, network, addr string) (net.Conn, error) { | ||||
| 			netDialer := &net.Dialer{ | ||||
| @ -132,9 +141,6 @@ func (opt *Options) init() { | ||||
| 	if opt.PoolSize == 0 { | ||||
| 		opt.PoolSize = 10 * runtime.NumCPU() | ||||
| 	} | ||||
| 	if opt.DialTimeout == 0 { | ||||
| 		opt.DialTimeout = 5 * time.Second | ||||
| 	} | ||||
| 	switch opt.ReadTimeout { | ||||
| 	case -1: | ||||
| 		opt.ReadTimeout = 0 | ||||
| @ -159,6 +165,8 @@ func (opt *Options) init() { | ||||
| 
 | ||||
| 	if opt.MaxRetries == -1 { | ||||
| 		opt.MaxRetries = 0 | ||||
| 	} else if opt.MaxRetries == 0 { | ||||
| 		opt.MaxRetries = 3 | ||||
| 	} | ||||
| 	switch opt.MinRetryBackoff { | ||||
| 	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. | ||||
| // 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) { | ||||
| 	o := &Options{Network: "tcp"} | ||||
| 	u, err := url.Parse(redisURL) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if u.Scheme != "redis" && u.Scheme != "rediss" { | ||||
| 		return nil, errors.New("invalid redis URL scheme: " + u.Scheme) | ||||
| 	switch 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 { | ||||
| 		o.Username = u.User.Username() | ||||
| 		if p, ok := u.User.Password(); ok { | ||||
| 			o.Password = p | ||||
| 		} | ||||
| 	} | ||||
| func setupTCPConn(u *url.URL) (*Options, error) { | ||||
| 	o := &Options{Network: "tcp"} | ||||
| 
 | ||||
| 	o.Username, o.Password = getUserPassword(u) | ||||
| 
 | ||||
| 	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) | ||||
| @ -222,22 +239,73 @@ func ParseURL(redisURL string) (*Options, error) { | ||||
| 		o.DB = 0 | ||||
| 	case 1: | ||||
| 		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: | ||||
| 		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" { | ||||
| 		o.TLSConfig = &tls.Config{ServerName: h} | ||||
| 	} | ||||
| 
 | ||||
| 	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 { | ||||
| 	return pool.NewConnPool(&pool.Options{ | ||||
| 		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, | ||||
| 		MinIdleConns:       opt.MinIdleConns, | ||||
| @ -4,7 +4,7 @@ import ( | ||||
| 	"context" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7/internal/pool" | ||||
| 	"github.com/go-redis/redis/v8/internal/pool" | ||||
| ) | ||||
| 
 | ||||
| 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. | ||||
| type Pipeliner interface { | ||||
| 	StatefulCmdable | ||||
| 	Do(args ...interface{}) *Cmd | ||||
| 	Process(cmd Cmder) error | ||||
| 	Do(ctx context.Context, args ...interface{}) *Cmd | ||||
| 	Process(ctx context.Context, cmd Cmder) error | ||||
| 	Close() error | ||||
| 	Discard() error | ||||
| 	Exec() ([]Cmder, error) | ||||
| 	ExecContext(ctx context.Context) ([]Cmder, error) | ||||
| 	Exec(ctx context.Context) ([]Cmder, error) | ||||
| } | ||||
| 
 | ||||
| var _ Pipeliner = (*Pipeline)(nil) | ||||
| @ -54,14 +53,14 @@ func (c *Pipeline) init() { | ||||
| 	c.statefulCmdable = c.Process | ||||
| } | ||||
| 
 | ||||
| func (c *Pipeline) Do(args ...interface{}) *Cmd { | ||||
| 	cmd := NewCmd(args...) | ||||
| 	_ = c.Process(cmd) | ||||
| func (c *Pipeline) Do(ctx context.Context, args ...interface{}) *Cmd { | ||||
| 	cmd := NewCmd(ctx, args...) | ||||
| 	_ = c.Process(ctx, cmd) | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| // 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.cmds = append(c.cmds, cmd) | ||||
| 	c.mu.Unlock() | ||||
| @ -98,11 +97,7 @@ func (c *Pipeline) discard() error { | ||||
| // | ||||
| // Exec always returns list of commands and error of the first failed | ||||
| // command if any. | ||||
| func (c *Pipeline) Exec() ([]Cmder, error) { | ||||
| 	return c.ExecContext(c.ctx) | ||||
| } | ||||
| 
 | ||||
| func (c *Pipeline) ExecContext(ctx context.Context) ([]Cmder, error) { | ||||
| func (c *Pipeline) Exec(ctx context.Context) ([]Cmder, error) { | ||||
| 	c.mu.Lock() | ||||
| 	defer c.mu.Unlock() | ||||
| 
 | ||||
| @ -120,11 +115,11 @@ func (c *Pipeline) ExecContext(ctx context.Context) ([]Cmder, error) { | ||||
| 	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 { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	cmds, err := c.Exec() | ||||
| 	cmds, err := c.Exec(ctx) | ||||
| 	_ = c.Close() | ||||
| 	return cmds, err | ||||
| } | ||||
| @ -133,8 +128,8 @@ func (c *Pipeline) Pipeline() Pipeliner { | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| func (c *Pipeline) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.Pipelined(fn) | ||||
| func (c *Pipeline) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.Pipelined(ctx, fn) | ||||
| } | ||||
| 
 | ||||
| func (c *Pipeline) TxPipeline() Pipeliner { | ||||
| @ -8,12 +8,15 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7/internal" | ||||
| 	"github.com/go-redis/redis/v7/internal/pool" | ||||
| 	"github.com/go-redis/redis/v7/internal/proto" | ||||
| 	"github.com/go-redis/redis/v8/internal" | ||||
| 	"github.com/go-redis/redis/v8/internal/pool" | ||||
| 	"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") | ||||
| 
 | ||||
| @ -26,7 +29,7 @@ var errPingTimeout = errors.New("redis: ping timeout") | ||||
| type PubSub struct { | ||||
| 	opt *Options | ||||
| 
 | ||||
| 	newConn   func([]string) (*pool.Conn, error) | ||||
| 	newConn   func(ctx context.Context, channels []string) (*pool.Conn, error) | ||||
| 	closeConn func(*pool.Conn) error | ||||
| 
 | ||||
| 	mu       sync.Mutex | ||||
| @ -55,14 +58,14 @@ func (c *PubSub) init() { | ||||
| 	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() | ||||
| 	cn, err := c.conn(nil) | ||||
| 	cn, err := c.conn(ctx, nil) | ||||
| 	c.mu.Unlock() | ||||
| 	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 { | ||||
| 		return nil, pool.ErrClosed | ||||
| 	} | ||||
| @ -73,12 +76,12 @@ func (c *PubSub) conn(newChannels []string) (*pool.Conn, error) { | ||||
| 	channels := mapKeys(c.channels) | ||||
| 	channels = append(channels, newChannels...) | ||||
| 
 | ||||
| 	cn, err := c.newConn(channels) | ||||
| 	cn, err := c.newConn(ctx, channels) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := c.resubscribe(cn); err != nil { | ||||
| 	if err := c.resubscribe(ctx, cn); err != nil { | ||||
| 		_ = c.closeConn(cn) | ||||
| 		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 | ||||
| 
 | ||||
| 	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 { | ||||
| 		err := c._subscribe(cn, "psubscribe", mapKeys(c.patterns)) | ||||
| 		err := c._subscribe(ctx, cn, "psubscribe", mapKeys(c.patterns)) | ||||
| 		if err != nil && firstErr == nil { | ||||
| 			firstErr = err | ||||
| 		} | ||||
| @ -121,35 +124,40 @@ func mapKeys(m map[string]struct{}) []string { | ||||
| } | ||||
| 
 | ||||
| func (c *PubSub) _subscribe( | ||||
| 	cn *pool.Conn, redisCmd string, channels []string, | ||||
| 	ctx context.Context, cn *pool.Conn, redisCmd string, channels []string, | ||||
| ) error { | ||||
| 	args := make([]interface{}, 0, 1+len(channels)) | ||||
| 	args = append(args, redisCmd) | ||||
| 	for _, channel := range channels { | ||||
| 		args = append(args, channel) | ||||
| 	} | ||||
| 	cmd := NewSliceCmd(args...) | ||||
| 	return c.writeCmd(context.TODO(), cn, cmd) | ||||
| 	cmd := NewSliceCmd(ctx, args...) | ||||
| 	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.releaseConn(cn, err, allowTimeout) | ||||
| 	c.releaseConn(ctx, cn, err, allowTimeout) | ||||
| 	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 { | ||||
| 		return | ||||
| 	} | ||||
| 	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.conn(nil) | ||||
| 	_, _ = c.conn(ctx, nil) | ||||
| } | ||||
| 
 | ||||
| func (c *PubSub) closeTheCn(reason error) error { | ||||
| @ -157,7 +165,7 @@ func (c *PubSub) closeTheCn(reason error) error { | ||||
| 		return nil | ||||
| 	} | ||||
| 	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) | ||||
| 	c.cn = nil | ||||
| @ -179,11 +187,11 @@ func (c *PubSub) Close() error { | ||||
| 
 | ||||
| // Subscribe the client to the specified channels. It returns | ||||
| // 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() | ||||
| 	defer c.mu.Unlock() | ||||
| 
 | ||||
| 	err := c.subscribe("subscribe", channels...) | ||||
| 	err := c.subscribe(ctx, "subscribe", channels...) | ||||
| 	if c.channels == nil { | ||||
| 		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 | ||||
| // 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() | ||||
| 	defer c.mu.Unlock() | ||||
| 
 | ||||
| 	err := c.subscribe("psubscribe", patterns...) | ||||
| 	err := c.subscribe(ctx, "psubscribe", patterns...) | ||||
| 	if c.patterns == nil { | ||||
| 		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 | ||||
| // 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() | ||||
| 	defer c.mu.Unlock() | ||||
| 
 | ||||
| 	for _, channel := range channels { | ||||
| 		delete(c.channels, channel) | ||||
| 	} | ||||
| 	err := c.subscribe("unsubscribe", channels...) | ||||
| 	err := c.subscribe(ctx, "unsubscribe", channels...) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| // PUnsubscribe the client from the given patterns, or from all of | ||||
| // 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() | ||||
| 	defer c.mu.Unlock() | ||||
| 
 | ||||
| 	for _, pattern := range patterns { | ||||
| 		delete(c.patterns, pattern) | ||||
| 	} | ||||
| 	err := c.subscribe("punsubscribe", patterns...) | ||||
| 	err := c.subscribe(ctx, "punsubscribe", patterns...) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (c *PubSub) subscribe(redisCmd string, channels ...string) error { | ||||
| 	cn, err := c.conn(channels) | ||||
| func (c *PubSub) subscribe(ctx context.Context, redisCmd string, channels ...string) error { | ||||
| 	cn, err := c.conn(ctx, channels) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = c._subscribe(cn, redisCmd, channels) | ||||
| 	c.releaseConn(cn, err, false) | ||||
| 	err = c._subscribe(ctx, cn, redisCmd, channels) | ||||
| 	c.releaseConn(ctx, cn, err, false) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (c *PubSub) Ping(payload ...string) error { | ||||
| func (c *PubSub) Ping(ctx context.Context, payload ...string) error { | ||||
| 	args := []interface{}{"ping"} | ||||
| 	if len(payload) == 1 { | ||||
| 		args = append(args, payload[0]) | ||||
| 	} | ||||
| 	cmd := NewCmd(args...) | ||||
| 	cmd := NewCmd(ctx, args...) | ||||
| 
 | ||||
| 	cn, err := c.connWithLock() | ||||
| 	cn, err := c.connWithLock(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = c.writeCmd(context.TODO(), cn, cmd) | ||||
| 	c.releaseConnWithLock(cn, err, false) | ||||
| 	err = c.writeCmd(ctx, cn, cmd) | ||||
| 	c.releaseConnWithLock(ctx, cn, err, false) | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| @ -279,9 +287,10 @@ func (m *Subscription) String() string { | ||||
| 
 | ||||
| // Message received as result of a PUBLISH command issued by another client. | ||||
| type Message struct { | ||||
| 	Channel string | ||||
| 	Pattern string | ||||
| 	Payload string | ||||
| 	Channel      string | ||||
| 	Pattern      string | ||||
| 	Payload      string | ||||
| 	PayloadSlice []string | ||||
| } | ||||
| 
 | ||||
| func (m *Message) String() string { | ||||
| @ -317,10 +326,24 @@ func (c *PubSub) newMessage(reply interface{}) (interface{}, error) { | ||||
| 				Count:   int(reply[2].(int64)), | ||||
| 			}, nil | ||||
| 		case "message": | ||||
| 			return &Message{ | ||||
| 				Channel: reply[1].(string), | ||||
| 				Payload: reply[2].(string), | ||||
| 			}, nil | ||||
| 			switch payload := reply[2].(type) { | ||||
| 			case string: | ||||
| 				return &Message{ | ||||
| 					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": | ||||
| 			return &Message{ | ||||
| 				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 | ||||
| // is not received in time. This is low-level API and in most cases | ||||
| // 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 { | ||||
| 		c.cmd = NewCmd() | ||||
| 		c.cmd = NewCmd(ctx) | ||||
| 	} | ||||
| 
 | ||||
| 	cn, err := c.connWithLock() | ||||
| 	cn, err := c.connWithLock(ctx) | ||||
| 	if err != nil { | ||||
| 		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) | ||||
| 	}) | ||||
| 
 | ||||
| 	c.releaseConnWithLock(cn, err, timeout > 0) | ||||
| 	c.releaseConnWithLock(ctx, cn, err, timeout > 0) | ||||
| 	if err != nil { | ||||
| 		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. | ||||
| // See PubSub example for details. This is low-level API and in most cases | ||||
| // Channel should be used instead. | ||||
| func (c *PubSub) Receive() (interface{}, error) { | ||||
| 	return c.ReceiveTimeout(0) | ||||
| func (c *PubSub) Receive(ctx context.Context) (interface{}, error) { | ||||
| 	return c.ReceiveTimeout(ctx, 0) | ||||
| } | ||||
| 
 | ||||
| // ReceiveMessage returns a Message or error ignoring Subscription and Pong | ||||
| // messages. This is low-level API and in most cases Channel should be used | ||||
| // instead. | ||||
| func (c *PubSub) ReceiveMessage() (*Message, error) { | ||||
| func (c *PubSub) ReceiveMessage(ctx context.Context) (*Message, error) { | ||||
| 	for { | ||||
| 		msg, err := c.Receive() | ||||
| 		msg, err := c.Receive(ctx) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @ -429,7 +452,7 @@ func (c *PubSub) ChannelSize(size int) <-chan *Message { | ||||
| // reconnections. | ||||
| // | ||||
| // 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.initPing() | ||||
| 		c.initAllChan(size) | ||||
| @ -445,10 +468,18 @@ func (c *PubSub) ChannelWithSubscriptions(size int) <-chan interface{} { | ||||
| 	return c.allCh | ||||
| } | ||||
| 
 | ||||
| func (c *PubSub) getContext() context.Context { | ||||
| 	if c.cmd != nil { | ||||
| 		return c.cmd.ctx | ||||
| 	} | ||||
| 	return context.Background() | ||||
| } | ||||
| 
 | ||||
| func (c *PubSub) initPing() { | ||||
| 	ctx := context.TODO() | ||||
| 	c.ping = make(chan struct{}, 1) | ||||
| 	go func() { | ||||
| 		timer := time.NewTimer(pingTimeout) | ||||
| 		timer := time.NewTimer(time.Minute) | ||||
| 		timer.Stop() | ||||
| 
 | ||||
| 		healthy := true | ||||
| @ -461,7 +492,7 @@ func (c *PubSub) initPing() { | ||||
| 					<-timer.C | ||||
| 				} | ||||
| 			case <-timer.C: | ||||
| 				pingErr := c.Ping() | ||||
| 				pingErr := c.Ping(ctx) | ||||
| 				if healthy { | ||||
| 					healthy = false | ||||
| 				} else { | ||||
| @ -469,7 +500,7 @@ func (c *PubSub) initPing() { | ||||
| 						pingErr = errPingTimeout | ||||
| 					} | ||||
| 					c.mu.Lock() | ||||
| 					c.reconnect(pingErr) | ||||
| 					c.reconnect(ctx, pingErr) | ||||
| 					healthy = true | ||||
| 					c.mu.Unlock() | ||||
| 				} | ||||
| @ -482,21 +513,22 @@ func (c *PubSub) initPing() { | ||||
| 
 | ||||
| // initMsgChan must be in sync with initAllChan. | ||||
| func (c *PubSub) initMsgChan(size int) { | ||||
| 	ctx := context.TODO() | ||||
| 	c.msgCh = make(chan *Message, size) | ||||
| 	go func() { | ||||
| 		timer := time.NewTimer(pingTimeout) | ||||
| 		timer := time.NewTimer(time.Minute) | ||||
| 		timer.Stop() | ||||
| 
 | ||||
| 		var errCount int | ||||
| 		for { | ||||
| 			msg, err := c.Receive() | ||||
| 			msg, err := c.Receive(ctx) | ||||
| 			if err != nil { | ||||
| 				if err == pool.ErrClosed { | ||||
| 					close(c.msgCh) | ||||
| 					return | ||||
| 				} | ||||
| 				if errCount > 0 { | ||||
| 					time.Sleep(c.retryBackoff(errCount)) | ||||
| 					time.Sleep(100 * time.Millisecond) | ||||
| 				} | ||||
| 				errCount++ | ||||
| 				continue | ||||
| @ -516,7 +548,7 @@ func (c *PubSub) initMsgChan(size int) { | ||||
| 			case *Pong: | ||||
| 				// Ignore. | ||||
| 			case *Message: | ||||
| 				timer.Reset(pingTimeout) | ||||
| 				timer.Reset(chanSendTimeout) | ||||
| 				select { | ||||
| 				case c.msgCh <- msg: | ||||
| 					if !timer.Stop() { | ||||
| @ -524,10 +556,14 @@ func (c *PubSub) initMsgChan(size int) { | ||||
| 					} | ||||
| 				case <-timer.C: | ||||
| 					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: | ||||
| 				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. | ||||
| func (c *PubSub) initAllChan(size int) { | ||||
| 	ctx := context.TODO() | ||||
| 	c.allCh = make(chan interface{}, size) | ||||
| 	go func() { | ||||
| 		timer := time.NewTimer(pingTimeout) | ||||
| @ -542,14 +579,14 @@ func (c *PubSub) initAllChan(size int) { | ||||
| 
 | ||||
| 		var errCount int | ||||
| 		for { | ||||
| 			msg, err := c.Receive() | ||||
| 			msg, err := c.Receive(ctx) | ||||
| 			if err != nil { | ||||
| 				if err == pool.ErrClosed { | ||||
| 					close(c.allCh) | ||||
| 					return | ||||
| 				} | ||||
| 				if errCount > 0 { | ||||
| 					time.Sleep(c.retryBackoff(errCount)) | ||||
| 					time.Sleep(100 * time.Millisecond) | ||||
| 				} | ||||
| 				errCount++ | ||||
| 				continue | ||||
| @ -571,7 +608,7 @@ func (c *PubSub) initAllChan(size int) { | ||||
| 			case *Message: | ||||
| 				c.sendMessage(msg, timer) | ||||
| 			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: | ||||
| 		internal.Logger.Printf( | ||||
| 			c.getContext(), | ||||
| 			"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 ( | ||||
| 	"context" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7/internal" | ||||
| 	"github.com/go-redis/redis/v7/internal/pool" | ||||
| 	"github.com/go-redis/redis/v7/internal/proto" | ||||
| 	"github.com/go-redis/redis/v8/internal" | ||||
| 	"github.com/go-redis/redis/v8/internal/pool" | ||||
| 	"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. | ||||
| const Nil = proto.Nil | ||||
| 
 | ||||
| func SetLogger(logger *log.Logger) { | ||||
| func SetLogger(logger internal.Logging) { | ||||
| 	internal.Logger = logger | ||||
| } | ||||
| 
 | ||||
| @ -49,92 +52,88 @@ func (hs *hooks) AddHook(hook Hook) { | ||||
| func (hs hooks) process( | ||||
| 	ctx context.Context, cmd Cmder, fn func(context.Context, Cmder) error, | ||||
| ) error { | ||||
| 	ctx, err := hs.beforeProcess(ctx, cmd) | ||||
| 	if err != nil { | ||||
| 	if len(hs.hooks) == 0 { | ||||
| 		err := hs.withContext(ctx, func() error { | ||||
| 			return fn(ctx, cmd) | ||||
| 		}) | ||||
| 		cmd.SetErr(err) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	cmdErr := fn(ctx, cmd) | ||||
| 	var hookIndex int | ||||
| 	var retErr error | ||||
| 
 | ||||
| 	if err := hs.afterProcess(ctx, cmd); err != nil { | ||||
| 		cmd.SetErr(err) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	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 | ||||
| 	for ; hookIndex < len(hs.hooks) && retErr == nil; hookIndex++ { | ||||
| 		ctx, retErr = hs.hooks[hookIndex].BeforeProcess(ctx, cmd) | ||||
| 		if retErr != nil { | ||||
| 			cmd.SetErr(retErr) | ||||
| 		} | ||||
| 	} | ||||
| 	return ctx, nil | ||||
| } | ||||
| 
 | ||||
| func (hs hooks) afterProcess(ctx context.Context, cmd Cmder) error { | ||||
| 	var firstErr error | ||||
| 	for _, h := range hs.hooks { | ||||
| 		err := h.AfterProcess(ctx, cmd) | ||||
| 		if err != nil && firstErr == nil { | ||||
| 			firstErr = err | ||||
| 	if retErr == nil { | ||||
| 		retErr = hs.withContext(ctx, func() error { | ||||
| 			return fn(ctx, cmd) | ||||
| 		}) | ||||
| 		cmd.SetErr(retErr) | ||||
| 	} | ||||
| 
 | ||||
| 	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( | ||||
| 	ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error, | ||||
| ) error { | ||||
| 	ctx, err := hs.beforeProcessPipeline(ctx, cmds) | ||||
| 	if err != nil { | ||||
| 		setCmdsErr(cmds, err) | ||||
| 	if len(hs.hooks) == 0 { | ||||
| 		err := hs.withContext(ctx, func() error { | ||||
| 			return fn(ctx, cmds) | ||||
| 		}) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	cmdsErr := fn(ctx, cmds) | ||||
| 	var hookIndex int | ||||
| 	var retErr error | ||||
| 
 | ||||
| 	if err := hs.afterProcessPipeline(ctx, cmds); err != nil { | ||||
| 		setCmdsErr(cmds, err) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	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 | ||||
| 	for ; hookIndex < len(hs.hooks) && retErr == nil; hookIndex++ { | ||||
| 		ctx, retErr = hs.hooks[hookIndex].BeforeProcessPipeline(ctx, cmds) | ||||
| 		if retErr != nil { | ||||
| 			setCmdsErr(cmds, retErr) | ||||
| 		} | ||||
| 	} | ||||
| 	return ctx, nil | ||||
| } | ||||
| 
 | ||||
| func (hs hooks) afterProcessPipeline(ctx context.Context, cmds []Cmder) error { | ||||
| 	var firstErr error | ||||
| 	for _, h := range hs.hooks { | ||||
| 		err := h.AfterProcessPipeline(ctx, cmds) | ||||
| 		if err != nil && firstErr == nil { | ||||
| 			firstErr = err | ||||
| 	if retErr == nil { | ||||
| 		retErr = hs.withContext(ctx, func() error { | ||||
| 			return fn(ctx, cmds) | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	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( | ||||
| 	ctx context.Context, cmds []Cmder, fn func(context.Context, []Cmder) error, | ||||
| ) error { | ||||
| 	cmds = wrapMultiExec(cmds) | ||||
| 	cmds = wrapMultiExec(ctx, cmds) | ||||
| 	return hs.processPipeline(ctx, cmds, fn) | ||||
| } | ||||
| 
 | ||||
| func (hs hooks) withContext(ctx context.Context, fn func() error) error { | ||||
| 	return fn() | ||||
| } | ||||
| 
 | ||||
| //------------------------------------------------------------------------------ | ||||
| 
 | ||||
| type baseClient struct { | ||||
| @ -201,6 +200,7 @@ func (c *baseClient) getConn(ctx context.Context) (*pool.Conn, error) { | ||||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return cn, nil | ||||
| } | ||||
| 
 | ||||
| @ -210,10 +210,16 @@ func (c *baseClient) _getConn(ctx context.Context) (*pool.Conn, error) { | ||||
| 		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 { | ||||
| 		c.connPool.Remove(cn, err) | ||||
| 		if err := internal.Unwrap(err); err != nil { | ||||
| 		c.connPool.Remove(ctx, cn, err) | ||||
| 		if err := errors.Unwrap(err); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return nil, err | ||||
| @ -235,25 +241,24 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	connPool := pool.NewSingleConnPool(nil) | ||||
| 	connPool.SetConn(cn) | ||||
| 	connPool := pool.NewSingleConnPool(c.connPool, cn) | ||||
| 	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.Username != "" { | ||||
| 				pipe.AuthACL(c.opt.Username, c.opt.Password) | ||||
| 				pipe.AuthACL(ctx, c.opt.Username, c.opt.Password) | ||||
| 			} else { | ||||
| 				pipe.Auth(c.opt.Password) | ||||
| 				pipe.Auth(ctx, c.opt.Password) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		if c.opt.DB > 0 { | ||||
| 			pipe.Select(c.opt.DB) | ||||
| 			pipe.Select(ctx, c.opt.DB) | ||||
| 		} | ||||
| 
 | ||||
| 		if c.opt.readOnly { | ||||
| 			pipe.ReadOnly() | ||||
| 			pipe.ReadOnly(ctx) | ||||
| 		} | ||||
| 
 | ||||
| 		return nil | ||||
| @ -263,76 +268,107 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error { | ||||
| 	} | ||||
| 
 | ||||
| 	if c.opt.OnConnect != nil { | ||||
| 		return c.opt.OnConnect(conn) | ||||
| 		return c.opt.OnConnect(ctx, conn) | ||||
| 	} | ||||
| 	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 { | ||||
| 		c.opt.Limiter.ReportResult(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if isBadConn(err, false) { | ||||
| 		c.connPool.Remove(cn, err) | ||||
| 		c.connPool.Remove(ctx, cn, err) | ||||
| 	} else { | ||||
| 		c.connPool.Put(cn) | ||||
| 		c.connPool.Put(ctx, cn) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (c *baseClient) withConn( | ||||
| 	ctx context.Context, fn func(context.Context, *pool.Conn) error, | ||||
| ) error { | ||||
| 	cn, err := c.getConn(ctx) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		c.releaseConn(cn, err) | ||||
| 	}() | ||||
| 	return internal.WithSpan(ctx, "redis.with_conn", func(ctx context.Context, span trace.Span) error { | ||||
| 		cn, err := c.getConn(ctx) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 	err = fn(ctx, cn) | ||||
| 	return err | ||||
| 		if span.IsRecording() { | ||||
| 			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 { | ||||
| 	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 | ||||
| 	for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ { | ||||
| 		if attempt > 0 { | ||||
| 			if err := internal.Sleep(ctx, c.retryBackoff(attempt)); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		attempt := attempt | ||||
| 
 | ||||
| 		retryTimeout := true | ||||
| 		lastErr = 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) | ||||
| 		var retry bool | ||||
| 		err := internal.WithSpan(ctx, "redis.process", func(ctx context.Context, span trace.Span) error { | ||||
| 			if attempt > 0 { | ||||
| 				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 { | ||||
| 				return err | ||||
| 			if err == nil { | ||||
| 				return nil | ||||
| 			} | ||||
| 
 | ||||
| 			err = cn.WithReader(ctx, c.cmdTimeout(cmd), cmd.readReply) | ||||
| 			if err != nil { | ||||
| 				retryTimeout = cmd.readTimeout() == nil | ||||
| 				return err | ||||
| 			} | ||||
| 
 | ||||
| 			return nil | ||||
| 			retry = shouldRetry(err, atomic.LoadUint32(&retryTimeout) == 1) | ||||
| 			return err | ||||
| 		}) | ||||
| 		if lastErr == nil || !isRetryableError(lastErr, retryTimeout) { | ||||
| 			return lastErr | ||||
| 		if err == nil || !retry { | ||||
| 			return err | ||||
| 		} | ||||
| 		lastErr = err | ||||
| 	} | ||||
| 	return lastErr | ||||
| } | ||||
| @ -411,7 +447,7 @@ func (c *baseClient) _generalProcessPipeline( | ||||
| 			canRetry, err = p(ctx, cn, cmds) | ||||
| 			return err | ||||
| 		}) | ||||
| 		if lastErr == nil || !canRetry || !isRetryableError(lastErr, true) { | ||||
| 		if lastErr == nil || !canRetry || !shouldRetry(lastErr, true) { | ||||
| 			return lastErr | ||||
| 		} | ||||
| 	} | ||||
| @ -437,6 +473,7 @@ func (c *baseClient) pipelineProcessCmds( | ||||
| func pipelineReadCmds(rd *proto.Reader, cmds []Cmder) error { | ||||
| 	for _, cmd := range cmds { | ||||
| 		err := cmd.readReply(rd) | ||||
| 		cmd.SetErr(err) | ||||
| 		if err != nil && !isRedisError(err) { | ||||
| 			return err | ||||
| 		} | ||||
| @ -469,15 +506,15 @@ func (c *baseClient) txPipelineProcessCmds( | ||||
| 	return false, err | ||||
| } | ||||
| 
 | ||||
| func wrapMultiExec(cmds []Cmder) []Cmder { | ||||
| func wrapMultiExec(ctx context.Context, cmds []Cmder) []Cmder { | ||||
| 	if len(cmds) == 0 { | ||||
| 		panic("not reached") | ||||
| 	} | ||||
| 	cmds = append(cmds, make([]Cmder, 2)...) | ||||
| 	copy(cmds[1:], cmds[:len(cmds)-2]) | ||||
| 	cmds[0] = NewStatusCmd("multi") | ||||
| 	cmds[len(cmds)-1] = NewSliceCmd("exec") | ||||
| 	return cmds | ||||
| 	cmdCopy := make([]Cmder, len(cmds)+2) | ||||
| 	cmdCopy[0] = NewStatusCmd(ctx, "multi") | ||||
| 	copy(cmdCopy[1:], cmds) | ||||
| 	cmdCopy[len(cmdCopy)-1] = NewSliceCmd(ctx, "exec") | ||||
| 	return cmdCopy | ||||
| } | ||||
| 
 | ||||
| func txPipelineReadQueued(rd *proto.Reader, statusCmd *StatusCmd, cmds []Cmder) error { | ||||
| @ -565,26 +602,18 @@ func (c *Client) WithContext(ctx context.Context) *Client { | ||||
| 	return clone | ||||
| } | ||||
| 
 | ||||
| func (c *Client) Conn() *Conn { | ||||
| 	return newConn(c.ctx, c.opt, pool.NewSingleConnPool(c.connPool)) | ||||
| func (c *Client) Conn(ctx context.Context) *Conn { | ||||
| 	return newConn(ctx, c.opt, pool.NewStickyConnPool(c.connPool)) | ||||
| } | ||||
| 
 | ||||
| // Do creates a Cmd from the args and processes the cmd. | ||||
| func (c *Client) Do(args ...interface{}) *Cmd { | ||||
| 	return c.DoContext(c.ctx, args...) | ||||
| } | ||||
| 
 | ||||
| func (c *Client) DoContext(ctx context.Context, args ...interface{}) *Cmd { | ||||
| 	cmd := NewCmd(args...) | ||||
| 	_ = c.ProcessContext(ctx, cmd) | ||||
| func (c *Client) Do(ctx context.Context, args ...interface{}) *Cmd { | ||||
| 	cmd := NewCmd(ctx, args...) | ||||
| 	_ = c.Process(ctx, cmd) | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| func (c *Client) Process(cmd Cmder) error { | ||||
| 	return c.ProcessContext(c.ctx, cmd) | ||||
| } | ||||
| 
 | ||||
| func (c *Client) ProcessContext(ctx context.Context, cmd Cmder) error { | ||||
| func (c *Client) Process(ctx context.Context, cmd Cmder) error { | ||||
| 	return c.hooks.process(ctx, cmd, c.baseClient.process) | ||||
| } | ||||
| 
 | ||||
| @ -609,8 +638,8 @@ func (c *Client) PoolStats() *PoolStats { | ||||
| 	return (*PoolStats)(stats) | ||||
| } | ||||
| 
 | ||||
| func (c *Client) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.Pipeline().Pipelined(fn) | ||||
| func (c *Client) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.Pipeline().Pipelined(ctx, fn) | ||||
| } | ||||
| 
 | ||||
| func (c *Client) Pipeline() Pipeliner { | ||||
| @ -622,8 +651,8 @@ func (c *Client) Pipeline() Pipeliner { | ||||
| 	return &pipe | ||||
| } | ||||
| 
 | ||||
| func (c *Client) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.TxPipeline().Pipelined(fn) | ||||
| func (c *Client) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.TxPipeline().Pipelined(ctx, fn) | ||||
| } | ||||
| 
 | ||||
| // TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. | ||||
| @ -640,8 +669,8 @@ func (c *Client) pubSub() *PubSub { | ||||
| 	pubsub := &PubSub{ | ||||
| 		opt: c.opt, | ||||
| 
 | ||||
| 		newConn: func(channels []string) (*pool.Conn, error) { | ||||
| 			return c.newConn(context.TODO()) | ||||
| 		newConn: func(ctx context.Context, channels []string) (*pool.Conn, error) { | ||||
| 			return c.newConn(ctx) | ||||
| 		}, | ||||
| 		closeConn: c.connPool.CloseConn, | ||||
| 	} | ||||
| @ -675,20 +704,20 @@ func (c *Client) pubSub() *PubSub { | ||||
| //    } | ||||
| // | ||||
| //    ch := sub.Channel() | ||||
| func (c *Client) Subscribe(channels ...string) *PubSub { | ||||
| func (c *Client) Subscribe(ctx context.Context, channels ...string) *PubSub { | ||||
| 	pubsub := c.pubSub() | ||||
| 	if len(channels) > 0 { | ||||
| 		_ = pubsub.Subscribe(channels...) | ||||
| 		_ = pubsub.Subscribe(ctx, channels...) | ||||
| 	} | ||||
| 	return pubsub | ||||
| } | ||||
| 
 | ||||
| // PSubscribe subscribes the client to the given patterns. | ||||
| // 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() | ||||
| 	if len(channels) > 0 { | ||||
| 		_ = pubsub.PSubscribe(channels...) | ||||
| 		_ = pubsub.PSubscribe(ctx, channels...) | ||||
| 	} | ||||
| 	return pubsub | ||||
| } | ||||
| @ -699,6 +728,7 @@ type conn struct { | ||||
| 	baseClient | ||||
| 	cmdable | ||||
| 	statefulCmdable | ||||
| 	hooks // TODO: inherit hooks | ||||
| } | ||||
| 
 | ||||
| // 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 | ||||
| } | ||||
| 
 | ||||
| func (c *Conn) Process(cmd Cmder) error { | ||||
| 	return c.ProcessContext(c.ctx, cmd) | ||||
| func (c *Conn) Process(ctx context.Context, cmd Cmder) error { | ||||
| 	return c.hooks.process(ctx, cmd, c.baseClient.process) | ||||
| } | ||||
| 
 | ||||
| func (c *Conn) ProcessContext(ctx context.Context, cmd Cmder) error { | ||||
| 	return c.baseClient.process(ctx, cmd) | ||||
| func (c *Conn) processPipeline(ctx context.Context, cmds []Cmder) error { | ||||
| 	return c.hooks.processPipeline(ctx, cmds, c.baseClient.processPipeline) | ||||
| } | ||||
| 
 | ||||
| func (c *Conn) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.Pipeline().Pipelined(fn) | ||||
| func (c *Conn) processTxPipeline(ctx context.Context, cmds []Cmder) error { | ||||
| 	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 { | ||||
| @ -743,8 +777,8 @@ func (c *Conn) Pipeline() Pipeliner { | ||||
| 	return &pipe | ||||
| } | ||||
| 
 | ||||
| func (c *Conn) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.TxPipeline().Pipelined(fn) | ||||
| func (c *Conn) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.TxPipeline().Pipelined(ctx, fn) | ||||
| } | ||||
| 
 | ||||
| // TxPipeline acts like Pipeline, but wraps queued commands with MULTI/EXEC. | ||||
| @ -2,7 +2,7 @@ package redis | ||||
| 
 | ||||
| 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 { | ||||
| 	var cmd Cmd | ||||
| 	cmd.val = val | ||||
| @ -10,7 +10,7 @@ func NewCmdResult(val interface{}, err error) *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 { | ||||
| 	var cmd SliceCmd | ||||
| 	cmd.val = val | ||||
| @ -18,7 +18,7 @@ func NewSliceResult(val []interface{}, err error) *SliceCmd { | ||||
| 	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 { | ||||
| 	var cmd StatusCmd | ||||
| 	cmd.val = val | ||||
| @ -26,7 +26,7 @@ func NewStatusResult(val string, err error) *StatusCmd { | ||||
| 	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 { | ||||
| 	var cmd IntCmd | ||||
| 	cmd.val = val | ||||
| @ -34,7 +34,7 @@ func NewIntResult(val int64, err error) *IntCmd { | ||||
| 	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 { | ||||
| 	var cmd DurationCmd | ||||
| 	cmd.val = val | ||||
| @ -42,7 +42,7 @@ func NewDurationResult(val time.Duration, err error) *DurationCmd { | ||||
| 	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 { | ||||
| 	var cmd BoolCmd | ||||
| 	cmd.val = val | ||||
| @ -50,7 +50,7 @@ func NewBoolResult(val bool, err error) *BoolCmd { | ||||
| 	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 { | ||||
| 	var cmd StringCmd | ||||
| 	cmd.val = val | ||||
| @ -58,7 +58,7 @@ func NewStringResult(val string, err error) *StringCmd { | ||||
| 	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 { | ||||
| 	var cmd FloatCmd | ||||
| 	cmd.val = val | ||||
| @ -66,7 +66,7 @@ func NewFloatResult(val float64, err error) *FloatCmd { | ||||
| 	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 { | ||||
| 	var cmd StringSliceCmd | ||||
| 	cmd.val = val | ||||
| @ -74,7 +74,7 @@ func NewStringSliceResult(val []string, err error) *StringSliceCmd { | ||||
| 	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 { | ||||
| 	var cmd BoolSliceCmd | ||||
| 	cmd.val = val | ||||
| @ -82,7 +82,7 @@ func NewBoolSliceResult(val []bool, err error) *BoolSliceCmd { | ||||
| 	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 { | ||||
| 	var cmd StringStringMapCmd | ||||
| 	cmd.val = val | ||||
| @ -90,7 +90,7 @@ func NewStringStringMapResult(val map[string]string, err error) *StringStringMap | ||||
| 	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 { | ||||
| 	var cmd StringIntMapCmd | ||||
| 	cmd.val = val | ||||
| @ -98,7 +98,7 @@ func NewStringIntMapCmdResult(val map[string]int64, err error) *StringIntMapCmd | ||||
| 	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 { | ||||
| 	var cmd TimeCmd | ||||
| 	cmd.val = val | ||||
| @ -106,7 +106,7 @@ func NewTimeCmdResult(val time.Time, err error) *TimeCmd { | ||||
| 	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 { | ||||
| 	var cmd ZSliceCmd | ||||
| 	cmd.val = val | ||||
| @ -114,7 +114,7 @@ func NewZSliceCmdResult(val []Z, err error) *ZSliceCmd { | ||||
| 	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 { | ||||
| 	var cmd ZWithKeyCmd | ||||
| 	cmd.val = val | ||||
| @ -122,7 +122,7 @@ func NewZWithKeyCmdResult(val *ZWithKey, err error) *ZWithKeyCmd { | ||||
| 	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 { | ||||
| 	var cmd ScanCmd | ||||
| 	cmd.page = keys | ||||
| @ -131,7 +131,7 @@ func NewScanCmdResult(keys []string, cursor uint64, err error) *ScanCmd { | ||||
| 	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 { | ||||
| 	var cmd ClusterSlotsCmd | ||||
| 	cmd.val = val | ||||
| @ -139,7 +139,7 @@ func NewClusterSlotsCmdResult(val []ClusterSlot, err error) *ClusterSlotsCmd { | ||||
| 	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 { | ||||
| 	var cmd GeoLocationCmd | ||||
| 	cmd.locations = val | ||||
| @ -147,7 +147,7 @@ func NewGeoLocationCmdResult(val []GeoLocation, err error) *GeoLocationCmd { | ||||
| 	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 { | ||||
| 	var cmd GeoPosCmd | ||||
| 	cmd.val = val | ||||
| @ -155,7 +155,7 @@ func NewGeoPosCmdResult(val []*GeoPos, err error) *GeoPosCmd { | ||||
| 	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 { | ||||
| 	var cmd CommandsInfoCmd | ||||
| 	cmd.val = val | ||||
| @ -163,7 +163,7 @@ func NewCommandsInfoCmdResult(val map[string]*CommandInfo, err error) *CommandsI | ||||
| 	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 { | ||||
| 	var cmd XMessageSliceCmd | ||||
| 	cmd.val = val | ||||
| @ -171,7 +171,7 @@ func NewXMessageSliceCmdResult(val []XMessage, err error) *XMessageSliceCmd { | ||||
| 	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 { | ||||
| 	var cmd XStreamSliceCmd | ||||
| 	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 ( | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"math/rand" | ||||
| 	"net" | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7/internal" | ||||
| 	"github.com/go-redis/redis/v7/internal/consistenthash" | ||||
| 	"github.com/go-redis/redis/v7/internal/hashtag" | ||||
| 	"github.com/go-redis/redis/v7/internal/pool" | ||||
| 	"github.com/cespare/xxhash/v2" | ||||
| 	"github.com/dgryski/go-rendezvous" | ||||
| 	"github.com/go-redis/redis/v8/internal" | ||||
| 	"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") | ||||
| 
 | ||||
| //------------------------------------------------------------------------------ | ||||
| 
 | ||||
| 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 | ||||
| // passed to NewRing. | ||||
| type RingOptions struct { | ||||
| 	// Map of name => host:port addresses of ring shards. | ||||
| 	Addrs map[string]string | ||||
| 
 | ||||
| 	// Map of name => password of ring shards, to allow different shards to have | ||||
| 	// different passwords. It will be ignored if the Password field is set. | ||||
| 	Passwords map[string]string | ||||
| 	// NewClient creates a shard client with provided name and options. | ||||
| 	NewClient func(name string, opt *Options) *Client | ||||
| 
 | ||||
| 	// Frequency of PING commands sent to check shards availability. | ||||
| 	// Shard is considered down after 3 subsequent failed checks. | ||||
| 	HeartbeatFrequency time.Duration | ||||
| 
 | ||||
| 	// Hash function used in consistent hash. | ||||
| 	// Default is crc32.ChecksumIEEE. | ||||
| 	Hash Hash | ||||
| 
 | ||||
| 	// Number of replicas in consistent hash. | ||||
| 	// Default is 100 replicas. | ||||
| 	// NewConsistentHash returns a consistent hash that is used | ||||
| 	// to distribute keys across the shards. | ||||
| 	// | ||||
| 	// Higher number of replicas will provide less deviation, that is keys will be | ||||
| 	// distributed to nodes more evenly. | ||||
| 	// | ||||
| 	// 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) | ||||
| 	// See https://medium.com/@dgryski/consistent-hashing-algorithmic-tradeoffs-ef6b8e2fcae8 | ||||
| 	// for consistent hashing algorithmic tradeoffs. | ||||
| 	NewConsistentHash func(shards []string) ConsistentHash | ||||
| 
 | ||||
| 	// 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 | ||||
| 	DB       int | ||||
| 
 | ||||
| 	MaxRetries      int | ||||
| 	MinRetryBackoff time.Duration | ||||
| @ -83,17 +84,31 @@ type RingOptions struct { | ||||
| 	PoolTimeout        time.Duration | ||||
| 	IdleTimeout        time.Duration | ||||
| 	IdleCheckFrequency time.Duration | ||||
| 
 | ||||
| 	TLSConfig *tls.Config | ||||
| 	Limiter   Limiter | ||||
| } | ||||
| 
 | ||||
| func (opt *RingOptions) init() { | ||||
| 	if opt.NewClient == nil { | ||||
| 		opt.NewClient = func(name string, opt *Options) *Client { | ||||
| 			return NewClient(opt) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if opt.HeartbeatFrequency == 0 { | ||||
| 		opt.HeartbeatFrequency = 500 * time.Millisecond | ||||
| 	} | ||||
| 
 | ||||
| 	if opt.HashReplicas == 0 { | ||||
| 		opt.HashReplicas = 100 | ||||
| 	if opt.NewConsistentHash == nil { | ||||
| 		opt.NewConsistentHash = newRendezvous | ||||
| 	} | ||||
| 
 | ||||
| 	if opt.MaxRetries == -1 { | ||||
| 		opt.MaxRetries = 0 | ||||
| 	} else if opt.MaxRetries == 0 { | ||||
| 		opt.MaxRetries = 3 | ||||
| 	} | ||||
| 	switch opt.MinRetryBackoff { | ||||
| 	case -1: | ||||
| 		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{ | ||||
| 		Dialer:    opt.Dialer, | ||||
| 		OnConnect: opt.OnConnect, | ||||
| 
 | ||||
| 		Username: opt.Username, | ||||
| 		Password: opt.Password, | ||||
| 		DB:       opt.DB, | ||||
| 		Password: opt.getPassword(shard), | ||||
| 
 | ||||
| 		MaxRetries: -1, | ||||
| 
 | ||||
| 		DialTimeout:  opt.DialTimeout, | ||||
| 		ReadTimeout:  opt.ReadTimeout, | ||||
| @ -125,14 +144,10 @@ func (opt *RingOptions) clientOptions(shard string) *Options { | ||||
| 		PoolTimeout:        opt.PoolTimeout, | ||||
| 		IdleTimeout:        opt.IdleTimeout, | ||||
| 		IdleCheckFrequency: opt.IdleCheckFrequency, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (opt *RingOptions) getPassword(shard string) string { | ||||
| 	if opt.Password == "" { | ||||
| 		return opt.Passwords[shard] | ||||
| 		TLSConfig: opt.TLSConfig, | ||||
| 		Limiter:   opt.Limiter, | ||||
| 	} | ||||
| 	return opt.Password | ||||
| } | ||||
| 
 | ||||
| //------------------------------------------------------------------------------ | ||||
| @ -142,6 +157,15 @@ type ringShard struct { | ||||
| 	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 { | ||||
| 	var state string | ||||
| 	if shard.IsUp() { | ||||
| @ -182,41 +206,59 @@ func (shard *ringShard) Vote(up bool) bool { | ||||
| type ringShards struct { | ||||
| 	opt *RingOptions | ||||
| 
 | ||||
| 	mu     sync.RWMutex | ||||
| 	hash   *consistenthash.Map | ||||
| 	shards map[string]*ringShard // read only | ||||
| 	list   []*ringShard          // read only | ||||
| 	len    int | ||||
| 	closed bool | ||||
| 	mu       sync.RWMutex | ||||
| 	hash     ConsistentHash | ||||
| 	shards   map[string]*ringShard // read only | ||||
| 	list     []*ringShard          // read only | ||||
| 	numShard int | ||||
| 	closed   bool | ||||
| } | ||||
| 
 | ||||
| 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, | ||||
| 
 | ||||
| 		hash:   newConsistentHash(opt), | ||||
| 		shards: make(map[string]*ringShard), | ||||
| 		shards: shards, | ||||
| 		list:   list, | ||||
| 	} | ||||
| } | ||||
| 	c.rebalance() | ||||
| 
 | ||||
| func (c *ringShards) Add(name string, cl *Client) { | ||||
| 	shard := &ringShard{Client: cl} | ||||
| 	c.hash.Add(name) | ||||
| 	c.shards[name] = shard | ||||
| 	c.list = append(c.list, shard) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| func (c *ringShards) List() []*ringShard { | ||||
| 	var list []*ringShard | ||||
| 
 | ||||
| 	c.mu.RLock() | ||||
| 	list := c.list | ||||
| 	if !c.closed { | ||||
| 		list = c.list | ||||
| 	} | ||||
| 	c.mu.RUnlock() | ||||
| 
 | ||||
| 	return list | ||||
| } | ||||
| 
 | ||||
| func (c *ringShards) Hash(key string) string { | ||||
| 	key = hashtag.Key(key) | ||||
| 
 | ||||
| 	var hash string | ||||
| 
 | ||||
| 	c.mu.RLock() | ||||
| 	hash := c.hash.Get(key) | ||||
| 	if c.numShard > 0 { | ||||
| 		hash = c.hash.Get(key) | ||||
| 	} | ||||
| 	c.mu.RUnlock() | ||||
| 
 | ||||
| 	return hash | ||||
| } | ||||
| 
 | ||||
| @ -230,6 +272,11 @@ func (c *ringShards) GetByKey(key string) (*ringShard, error) { | ||||
| 		return nil, pool.ErrClosed | ||||
| 	} | ||||
| 
 | ||||
| 	if c.numShard == 0 { | ||||
| 		c.mu.RUnlock() | ||||
| 		return nil, errRingShardsDown | ||||
| 	} | ||||
| 
 | ||||
| 	hash := c.hash.Get(key) | ||||
| 	if hash == "" { | ||||
| 		c.mu.RUnlock() | ||||
| @ -242,13 +289,13 @@ func (c *ringShards) GetByKey(key string) (*ringShard, error) { | ||||
| 	return shard, nil | ||||
| } | ||||
| 
 | ||||
| func (c *ringShards) GetByHash(name string) (*ringShard, error) { | ||||
| 	if name == "" { | ||||
| func (c *ringShards) GetByName(shardName string) (*ringShard, error) { | ||||
| 	if shardName == "" { | ||||
| 		return c.Random() | ||||
| 	} | ||||
| 
 | ||||
| 	c.mu.RLock() | ||||
| 	shard := c.shards[name] | ||||
| 	shard := c.shards[shardName] | ||||
| 	c.mu.RUnlock() | ||||
| 	return shard, nil | ||||
| } | ||||
| @ -261,23 +308,16 @@ func (c *ringShards) Random() (*ringShard, error) { | ||||
| func (c *ringShards) Heartbeat(frequency time.Duration) { | ||||
| 	ticker := time.NewTicker(frequency) | ||||
| 	defer ticker.Stop() | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
| 	for range ticker.C { | ||||
| 		var rebalance bool | ||||
| 
 | ||||
| 		c.mu.RLock() | ||||
| 
 | ||||
| 		if c.closed { | ||||
| 			c.mu.RUnlock() | ||||
| 			break | ||||
| 		} | ||||
| 
 | ||||
| 		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) | ||||
| 		for _, shard := range c.List() { | ||||
| 			err := shard.Client.Ping(ctx).Err() | ||||
| 			isUp := err == nil || err == pool.ErrPoolTimeout | ||||
| 			if shard.Vote(isUp) { | ||||
| 				internal.Logger.Printf(context.Background(), "ring shard state changed: %s", shard) | ||||
| 				rebalance = true | ||||
| 			} | ||||
| 		} | ||||
| @ -294,24 +334,25 @@ func (c *ringShards) rebalance() { | ||||
| 	shards := c.shards | ||||
| 	c.mu.RUnlock() | ||||
| 
 | ||||
| 	hash := newConsistentHash(c.opt) | ||||
| 	var shardsNum int | ||||
| 	liveShards := make([]string, 0, len(shards)) | ||||
| 
 | ||||
| 	for name, shard := range shards { | ||||
| 		if shard.IsUp() { | ||||
| 			hash.Add(name) | ||||
| 			shardsNum++ | ||||
| 			liveShards = append(liveShards, name) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	hash := c.opt.NewConsistentHash(liveShards) | ||||
| 
 | ||||
| 	c.mu.Lock() | ||||
| 	c.hash = hash | ||||
| 	c.len = shardsNum | ||||
| 	c.numShard = len(liveShards) | ||||
| 	c.mu.Unlock() | ||||
| } | ||||
| 
 | ||||
| func (c *ringShards) Len() int { | ||||
| 	c.mu.RLock() | ||||
| 	l := c.len | ||||
| 	l := c.numShard | ||||
| 	c.mu.RUnlock() | ||||
| 	return l | ||||
| } | ||||
| @ -377,34 +418,15 @@ func NewRing(opt *RingOptions) *Ring { | ||||
| 		}, | ||||
| 		ctx: context.Background(), | ||||
| 	} | ||||
| 
 | ||||
| 	ring.cmdsInfoCache = newCmdsInfoCache(ring.cmdsInfo) | ||||
| 	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) | ||||
| 
 | ||||
| 	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 { | ||||
| 	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. | ||||
| func (c *Ring) Do(args ...interface{}) *Cmd { | ||||
| 	return c.DoContext(c.ctx, args...) | ||||
| } | ||||
| 
 | ||||
| func (c *Ring) DoContext(ctx context.Context, args ...interface{}) *Cmd { | ||||
| 	cmd := NewCmd(args...) | ||||
| 	_ = c.ProcessContext(ctx, cmd) | ||||
| func (c *Ring) Do(ctx context.Context, args ...interface{}) *Cmd { | ||||
| 	cmd := NewCmd(ctx, args...) | ||||
| 	_ = c.Process(ctx, cmd) | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| func (c *Ring) Process(cmd Cmder) error { | ||||
| 	return c.ProcessContext(c.ctx, cmd) | ||||
| } | ||||
| 
 | ||||
| func (c *Ring) ProcessContext(ctx context.Context, cmd Cmder) error { | ||||
| func (c *Ring) Process(ctx context.Context, cmd Cmder) error { | ||||
| 	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. | ||||
| func (c *Ring) Subscribe(channels ...string) *PubSub { | ||||
| func (c *Ring) Subscribe(ctx context.Context, channels ...string) *PubSub { | ||||
| 	if len(channels) == 0 { | ||||
| 		panic("at least one channel is required") | ||||
| 	} | ||||
| 
 | ||||
| 	shard, err := c.shards.GetByKey(channels[0]) | ||||
| 	if err != nil { | ||||
| 		//TODO: return PubSub with sticky error | ||||
| 		// TODO: return PubSub with sticky error | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return shard.Client.Subscribe(channels...) | ||||
| 	return shard.Client.Subscribe(ctx, channels...) | ||||
| } | ||||
| 
 | ||||
| // 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 { | ||||
| 		panic("at least one channel is required") | ||||
| 	} | ||||
| 
 | ||||
| 	shard, err := c.shards.GetByKey(channels[0]) | ||||
| 	if err != nil { | ||||
| 		//TODO: return PubSub with sticky error | ||||
| 		// TODO: return PubSub with sticky error | ||||
| 		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. | ||||
| // 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() | ||||
| 	var wg sync.WaitGroup | ||||
| 	errCh := make(chan error, 1) | ||||
| @ -510,7 +527,7 @@ func (c *Ring) ForEachShard(fn func(client *Client) error) error { | ||||
| 		wg.Add(1) | ||||
| 		go func(shard *ringShard) { | ||||
| 			defer wg.Done() | ||||
| 			err := fn(shard.Client) | ||||
| 			err := fn(ctx, shard.Client) | ||||
| 			if err != nil { | ||||
| 				select { | ||||
| 				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() | ||||
| 	firstErr := errRingShardsDown | ||||
| 	var firstErr error | ||||
| 	for _, shard := range shards { | ||||
| 		cmdsInfo, err := shard.Client.Command().Result() | ||||
| 		cmdsInfo, err := shard.Client.Command(ctx).Result() | ||||
| 		if err == nil { | ||||
| 			return cmdsInfo, nil | ||||
| 		} | ||||
| @ -541,23 +558,26 @@ func (c *Ring) cmdsInfo() (map[string]*CommandInfo, error) { | ||||
| 			firstErr = err | ||||
| 		} | ||||
| 	} | ||||
| 	if firstErr == nil { | ||||
| 		return nil, errRingShardsDown | ||||
| 	} | ||||
| 	return nil, firstErr | ||||
| } | ||||
| 
 | ||||
| func (c *Ring) cmdInfo(name string) *CommandInfo { | ||||
| 	cmdsInfo, err := c.cmdsInfoCache.Get() | ||||
| func (c *Ring) cmdInfo(ctx context.Context, name string) *CommandInfo { | ||||
| 	cmdsInfo, err := c.cmdsInfoCache.Get(ctx) | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	info := cmdsInfo[name] | ||||
| 	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 | ||||
| } | ||||
| 
 | ||||
| func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) { | ||||
| 	cmdInfo := c.cmdInfo(cmd.Name()) | ||||
| func (c *Ring) cmdShard(ctx context.Context, cmd Cmder) (*ringShard, error) { | ||||
| 	cmdInfo := c.cmdInfo(ctx, cmd.Name()) | ||||
| 	pos := cmdFirstKeyPos(cmd, cmdInfo) | ||||
| 	if pos == 0 { | ||||
| 		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 { | ||||
| 	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 | ||||
| 	for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ { | ||||
| 		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 { | ||||
| 			return err | ||||
| 		} | ||||
| 
 | ||||
| 		lastErr = shard.Client.ProcessContext(ctx, cmd) | ||||
| 		if lastErr == nil || !isRetryableError(lastErr, cmd.readTimeout() == nil) { | ||||
| 		lastErr = shard.Client.Process(ctx, cmd) | ||||
| 		if lastErr == nil || !shouldRetry(lastErr, cmd.readTimeout() == nil) { | ||||
| 			return lastErr | ||||
| 		} | ||||
| 	} | ||||
| 	return lastErr | ||||
| } | ||||
| 
 | ||||
| func (c *Ring) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.Pipeline().Pipelined(fn) | ||||
| func (c *Ring) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.Pipeline().Pipelined(ctx, fn) | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 	return c.TxPipeline().Pipelined(fn) | ||||
| func (c *Ring) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.TxPipeline().Pipelined(ctx, fn) | ||||
| } | ||||
| 
 | ||||
| func (c *Ring) TxPipeline() Pipeliner { | ||||
| @ -640,10 +651,10 @@ func (c *Ring) generalProcessPipeline( | ||||
| ) error { | ||||
| 	cmdsMap := make(map[string][]Cmder) | ||||
| 	for _, cmd := range cmds { | ||||
| 		cmdInfo := c.cmdInfo(cmd.Name()) | ||||
| 		cmdInfo := c.cmdInfo(ctx, cmd.Name()) | ||||
| 		hash := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo)) | ||||
| 		if hash != "" { | ||||
| 			hash = c.shards.Hash(hashtag.Key(hash)) | ||||
| 			hash = c.shards.Hash(hash) | ||||
| 		} | ||||
| 		cmdsMap[hash] = append(cmdsMap[hash], cmd) | ||||
| 	} | ||||
| @ -665,30 +676,20 @@ func (c *Ring) generalProcessPipeline( | ||||
| func (c *Ring) processShardPipeline( | ||||
| 	ctx context.Context, hash string, cmds []Cmder, tx bool, | ||||
| ) error { | ||||
| 	//TODO: retry? | ||||
| 	shard, err := c.shards.GetByHash(hash) | ||||
| 	// TODO: retry? | ||||
| 	shard, err := c.shards.GetByName(hash) | ||||
| 	if err != nil { | ||||
| 		setCmdsErr(cmds, err) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if tx { | ||||
| 		err = shard.Client.processTxPipeline(ctx, cmds) | ||||
| 	} else { | ||||
| 		err = shard.Client.processPipeline(ctx, cmds) | ||||
| 		return shard.Client.processTxPipeline(ctx, cmds) | ||||
| 	} | ||||
| 	return err | ||||
| 	return shard.Client.processPipeline(ctx, cmds) | ||||
| } | ||||
| 
 | ||||
| // Close closes the ring client, releasing any open resources. | ||||
| // | ||||
| // 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 { | ||||
| func (c *Ring) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error { | ||||
| 	if len(keys) == 0 { | ||||
| 		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 { | ||||
| 	return consistenthash.New(opt.HashReplicas, consistenthash.Hash(opt.Hash)) | ||||
| // Close closes the ring client, releasing any open resources. | ||||
| // | ||||
| // 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 ( | ||||
| 	"context" | ||||
| 
 | ||||
| 	"github.com/go-redis/redis/v7/internal/pool" | ||||
| 	"github.com/go-redis/redis/v7/internal/proto" | ||||
| 	"github.com/go-redis/redis/v8/internal/pool" | ||||
| 	"github.com/go-redis/redis/v8/internal/proto" | ||||
| ) | ||||
| 
 | ||||
| // TxFailedErr transaction redis failed. | ||||
| @ -26,7 +26,7 @@ func (c *Client) newTx(ctx context.Context) *Tx { | ||||
| 	tx := Tx{ | ||||
| 		baseClient: baseClient{ | ||||
| 			opt:      c.opt, | ||||
| 			connPool: pool.NewStickyConnPool(c.connPool.(*pool.ConnPool), true), | ||||
| 			connPool: pool.NewStickyConnPool(c.connPool), | ||||
| 		}, | ||||
| 		hooks: c.hooks.clone(), | ||||
| 		ctx:   ctx, | ||||
| @ -55,11 +55,7 @@ func (c *Tx) WithContext(ctx context.Context) *Tx { | ||||
| 	return &clone | ||||
| } | ||||
| 
 | ||||
| func (c *Tx) Process(cmd Cmder) error { | ||||
| 	return c.ProcessContext(c.ctx, cmd) | ||||
| } | ||||
| 
 | ||||
| func (c *Tx) ProcessContext(ctx context.Context, cmd Cmder) error { | ||||
| func (c *Tx) Process(ctx context.Context, cmd Cmder) error { | ||||
| 	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. | ||||
| // | ||||
| // The transaction is automatically closed when fn exits. | ||||
| func (c *Client) Watch(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 { | ||||
| func (c *Client) Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error { | ||||
| 	tx := c.newTx(ctx) | ||||
| 	defer tx.Close(ctx) | ||||
| 	if len(keys) > 0 { | ||||
| 		if err := tx.Watch(keys...).Err(); err != nil { | ||||
| 			_ = tx.Close() | ||||
| 		if err := tx.Watch(ctx, keys...).Err(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	err := fn(tx) | ||||
| 	_ = tx.Close() | ||||
| 	return err | ||||
| 	return fn(tx) | ||||
| } | ||||
| 
 | ||||
| // Close closes the transaction, releasing any open resources. | ||||
| func (c *Tx) Close() error { | ||||
| 	_ = c.Unwatch().Err() | ||||
| func (c *Tx) Close(ctx context.Context) error { | ||||
| 	_ = c.Unwatch(ctx).Err() | ||||
| 	return c.baseClient.Close() | ||||
| } | ||||
| 
 | ||||
| // Watch marks the keys to be watched for conditional execution | ||||
| // 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[0] = "watch" | ||||
| 	for i, key := range keys { | ||||
| 		args[1+i] = key | ||||
| 	} | ||||
| 	cmd := NewStatusCmd(args...) | ||||
| 	_ = c.Process(cmd) | ||||
| 	cmd := NewStatusCmd(ctx, args...) | ||||
| 	_ = c.Process(ctx, cmd) | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| // 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[0] = "unwatch" | ||||
| 	for i, key := range keys { | ||||
| 		args[1+i] = key | ||||
| 	} | ||||
| 	cmd := NewStatusCmd(args...) | ||||
| 	_ = c.Process(cmd) | ||||
| 	cmd := NewStatusCmd(ctx, args...) | ||||
| 	_ = c.Process(ctx, cmd) | ||||
| 	return cmd | ||||
| } | ||||
| 
 | ||||
| @ -130,8 +119,8 @@ func (c *Tx) Pipeline() Pipeliner { | ||||
| 
 | ||||
| // Pipelined executes commands queued in the fn outside of the transaction. | ||||
| // Use TxPipelined if you need transactional behavior. | ||||
| func (c *Tx) Pipelined(fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.Pipeline().Pipelined(fn) | ||||
| func (c *Tx) Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.Pipeline().Pipelined(ctx, fn) | ||||
| } | ||||
| 
 | ||||
| // 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 | ||||
| // TxFailedErr is returned. Otherwise Exec returns an error of the first | ||||
| // failed command or nil. | ||||
| func (c *Tx) TxPipelined(fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.TxPipeline().Pipelined(fn) | ||||
| func (c *Tx) TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error) { | ||||
| 	return c.TxPipeline().Pipelined(ctx, fn) | ||||
| } | ||||
| 
 | ||||
| // TxPipeline creates a pipeline. Usually it is more convenient to use TxPipelined. | ||||
| @ -20,23 +20,29 @@ type UniversalOptions struct { | ||||
| 
 | ||||
| 	// Common options. | ||||
| 
 | ||||
| 	Dialer             func(ctx context.Context, network, addr string) (net.Conn, error) | ||||
| 	OnConnect          func(*Conn) error | ||||
| 	Username           string | ||||
| 	Password           string | ||||
| 	MaxRetries         int | ||||
| 	MinRetryBackoff    time.Duration | ||||
| 	MaxRetryBackoff    time.Duration | ||||
| 	DialTimeout        time.Duration | ||||
| 	ReadTimeout        time.Duration | ||||
| 	WriteTimeout       time.Duration | ||||
| 	Dialer    func(ctx context.Context, network, addr string) (net.Conn, error) | ||||
| 	OnConnect func(ctx context.Context, cn *Conn) error | ||||
| 
 | ||||
| 	Username         string | ||||
| 	Password         string | ||||
| 	SentinelPassword string | ||||
| 
 | ||||
| 	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 | ||||
| 
 | ||||
| 	TLSConfig *tls.Config | ||||
| 
 | ||||
| 	// Only cluster clients. | ||||
| 
 | ||||
| @ -100,9 +106,10 @@ func (o *UniversalOptions) Failover() *FailoverOptions { | ||||
| 		Dialer:    o.Dialer, | ||||
| 		OnConnect: o.OnConnect, | ||||
| 
 | ||||
| 		DB:       o.DB, | ||||
| 		Username: o.Username, | ||||
| 		Password: o.Password, | ||||
| 		DB:               o.DB, | ||||
| 		Username:         o.Username, | ||||
| 		Password:         o.Password, | ||||
| 		SentinelPassword: o.SentinelPassword, | ||||
| 
 | ||||
| 		MaxRetries:      o.MaxRetries, | ||||
| 		MinRetryBackoff: o.MinRetryBackoff, | ||||
| @ -168,19 +175,20 @@ type UniversalClient interface { | ||||
| 	Cmdable | ||||
| 	Context() context.Context | ||||
| 	AddHook(Hook) | ||||
| 	Watch(fn func(*Tx) error, keys ...string) error | ||||
| 	Do(args ...interface{}) *Cmd | ||||
| 	DoContext(ctx context.Context, args ...interface{}) *Cmd | ||||
| 	Process(cmd Cmder) error | ||||
| 	ProcessContext(ctx context.Context, cmd Cmder) error | ||||
| 	Subscribe(channels ...string) *PubSub | ||||
| 	PSubscribe(channels ...string) *PubSub | ||||
| 	Watch(ctx context.Context, fn func(*Tx) error, keys ...string) error | ||||
| 	Do(ctx context.Context, args ...interface{}) *Cmd | ||||
| 	Process(ctx context.Context, cmd Cmder) error | ||||
| 	Subscribe(ctx context.Context, channels ...string) *PubSub | ||||
| 	PSubscribe(ctx context.Context, channels ...string) *PubSub | ||||
| 	Close() error | ||||
| 	PoolStats() *PoolStats | ||||
| } | ||||
| 
 | ||||
| var _ UniversalClient = (*Client)(nil) | ||||
| var _ UniversalClient = (*ClusterClient)(nil) | ||||
| var _ UniversalClient = (*Ring)(nil) | ||||
| var ( | ||||
| 	_ UniversalClient = (*Client)(nil) | ||||
| 	_ UniversalClient = (*ClusterClient)(nil) | ||||
| 	_ UniversalClient = (*Ring)(nil) | ||||
| ) | ||||
| 
 | ||||
| // NewUniversalClient returns a new multi client. The type of client returned depends | ||||
| // 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
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 6543
						6543