##// END OF EJS Templates
branching: merge stable into default
Raphaël Gomès -
r51712:3ccef790 merge default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,250 +1,251 b''
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
1 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0 iD8DBQBEYmO2ywK+sNU5EO8RAnaYAKCO7x15xUn5mnhqWNXqk/ehlhRt2QCfRDfY0LrUq2q4oK/KypuJYPHgq1A=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
2 2be3001847cb18a23c403439d9e7d0ace30804e9 0 iD8DBQBExUbjywK+sNU5EO8RAhzxAKCtyHAQUzcTSZTqlfJ0by6vhREwWQCghaQFHfkfN0l9/40EowNhuMOKnJk=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
3 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0 iD8DBQBFfL2QywK+sNU5EO8RAjYFAKCoGlaWRTeMsjdmxAjUYx6diZxOBwCfY6IpBYsKvPTwB3oktnPt5Rmrlys=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
4 27230c29bfec36d5540fbe1c976810aefecfd1d2 0 iD8DBQBFheweywK+sNU5EO8RAt7VAKCrqJQWT2/uo2RWf0ZI4bLp6v82jACgjrMdsaTbxRsypcmEsdPhlG6/8F4=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
5 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0 iD8DBQBGgHicywK+sNU5EO8RAgNxAJ0VG8ixAaeudx4sZbhngI1syu49HQCeNUJQfWBgA8bkJ2pvsFpNxwYaX3I=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
6 23889160905a1b09fffe1c07378e9fc1827606eb 0 iD8DBQBHGTzoywK+sNU5EO8RAr/UAJ0Y8s4jQtzgS+G9vM8z6CWBThZ8fwCcCT5XDj2XwxKkz/0s6UELwjsO3LU=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
7 bae2e9c838e90a393bae3973a7850280413e091a 0 iD8DBQBH6DO5ywK+sNU5EO8RAsfrAJ0e4r9c9GF/MJsM7Xjd3NesLRC3+ACffj6+6HXdZf8cswAoFPO+DY00oD0=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
8 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 0 iD8DBQBINdwsywK+sNU5EO8RAjIUAKCPmlFJSpsPAAUKF+iNHAwVnwmzeQCdEXrL27CWclXuUKdbQC8De7LICtE=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
9 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 0 iD8DBQBIo1wpywK+sNU5EO8RAmRNAJ94x3OFt6blbqu/yBoypm/AJ44fuACfUaldXcV5z9tht97hSp22DVTEPGc=
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
10 2a67430f92f15ea5159c26b09ec4839a0c549a26 0 iEYEABECAAYFAkk1hykACgkQywK+sNU5EO85QACeNJNUanjc2tl4wUoPHNuv+lSj0ZMAoIm93wSTc/feyYnO2YCaQ1iyd9Nu
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
11 3773e510d433969e277b1863c317b674cbee2065 0 iEYEABECAAYFAklNbbAACgkQywK+sNU5EO8o+gCfeb2/lfIJZMvyDA1m+G1CsBAxfFsAoIa6iAMG8SBY7hW1Q85Yf/LXEvaE
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
12 11a4eb81fb4f4742451591489e2797dc47903277 0 iEYEABECAAYFAklcAnsACgkQywK+sNU5EO+uXwCbBVHNNsLy1g7BlAyQJwadYVyHOXoAoKvtAVO71+bv7EbVoukwTzT+P4Sx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
13 11efa41037e280d08cfb07c09ad485df30fb0ea8 0 iEYEABECAAYFAkmvJRQACgkQywK+sNU5EO9XZwCeLMgDgPSMWMm6vgjL4lDs2pEc5+0AnRxfiFbpbBfuEFTqKz9nbzeyoBlx
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
14 02981000012e3adf40c4849bd7b3d5618f9ce82d 0 iEYEABECAAYFAknEH3wACgkQywK+sNU5EO+uXwCeI+LbLMmhjU1lKSfU3UWJHjjUC7oAoIZLvYDGOL/tNZFUuatc3RnZ2eje
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
15 196d40e7c885fa6e95f89134809b3ec7bdbca34b 0 iEYEABECAAYFAkpL2X4ACgkQywK+sNU5EO9FOwCfXJycjyKJXsvQqKkHrglwOQhEKS4An36GfKzptfN8b1qNc3+ya/5c2WOM
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
16 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 0 iEYEABECAAYFAkpopLIACgkQywK+sNU5EO8QSgCfZ0ztsd071rOa2lhmp9Fyue/WoI0AoLTei80/xrhRlB8L/rZEf2KBl8dA
17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
17 31ec469f9b556f11819937cf68ee53f2be927ebf 0 iEYEABECAAYFAksBuxAACgkQywK+sNU5EO+mBwCfagB+A0txzWZ6dRpug3LEoK7Z1QsAoKpbk8vsLjv6/oRDicSk/qBu33+m
18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
18 439d7ea6fe3aa4ab9ec274a68846779153789de9 0 iEYEABECAAYFAksVw0kACgkQywK+sNU5EO/oZwCfdfBEkgp38xq6wN2F4nj+SzofrJIAnjmxt04vaJSeOOeHylHvk6lzuQsw
19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
19 296a0b14a68621f6990c54fdba0083f6f20935bf 0 iEYEABECAAYFAks+jCoACgkQywK+sNU5EO9J8wCeMUGF9E/gS2UBsqIz56WS4HMPRPUAoI5J95mwEIK8Clrl7qFRidNI6APq
20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
20 4aa619c4c2c09907034d9824ebb1dd0e878206eb 0 iEYEABECAAYFAktm9IsACgkQywK+sNU5EO9XGgCgk4HclRQhexEtooPE5GcUCdB6M8EAn2ptOhMVbIoO+JncA+tNACPFXh0O
21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
21 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 0 iEYEABECAAYFAkuRoSQACgkQywK+sNU5EO//3QCeJDc5r2uFyFCtAlpSA27DEE5rrxAAn2FSwTy9fhrB3QAdDQlwkEZcQzDh
22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
22 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 0 iEYEABECAAYFAku1IwIACgkQywK+sNU5EO9MjgCdHLVwkTZlNHxhcznZKBL1rjN+J7cAoLLWi9LTL6f/TgBaPSKOy1ublbaW
23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
23 39f725929f0c48c5fb3b90c071fc3066012456ca 0 iEYEABECAAYFAkvclvsACgkQywK+sNU5EO9FSwCeL9i5x8ALW/LE5+lCX6MFEAe4MhwAn1ev5o6SX6GrNdDfKweiemfO2VBk
24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
24 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 0 iEYEABECAAYFAkvsKTkACgkQywK+sNU5EO9qEACgiSiRGvTG2vXGJ65tUSOIYihTuFAAnRzRIqEVSw8M8/RGeUXRps0IzaCO
25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
25 24fe2629c6fd0c74c90bd066e77387c2b02e8437 0 iEYEABECAAYFAkwFLRsACgkQywK+sNU5EO+pJACgp13tPI+pbwKZV+LeMjcQ4H6tCZYAoJebzhd6a8yYx6qiwpJxA9BXZNXy
26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
26 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 0 iEYEABECAAYFAkwsyxcACgkQywK+sNU5EO+crACfUpNAF57PmClkSri9nJcBjb2goN4AniPCNaKvnki7TnUsi1u2oxltpKKL
27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
27 bf1774d95bde614af3956d92b20e2a0c68c5fec7 0 iEYEABECAAYFAkxVwccACgkQywK+sNU5EO+oFQCeJzwZ+we1fIIyBGCddHceOUAN++cAnjvT6A8ZWW0zV21NXIFF1qQmjxJd
28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
28 c00f03a4982e467fb6b6bd45908767db6df4771d 0 iEYEABECAAYFAkxXDqsACgkQywK+sNU5EO/GJACfT9Rz4hZOxPQEs91JwtmfjevO84gAmwSmtfo5mmWSm8gtTUebCcdTv0Kf
29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
29 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 0 iD8DBQBMdo+qywK+sNU5EO8RAqQpAJ975BL2CCAiWMz9SXthNQ9xG181IwCgp4O+KViHPkufZVFn2aTKMNvcr1A=
30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
30 93d8bff78c96fe7e33237b257558ee97290048a4 0 iD8DBQBMpfvdywK+sNU5EO8RAsxVAJ0UaL1XB51C76JUBhafc9GBefuMxwCdEWkTOzwvE0SarJBe9i008jhbqW4=
31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
31 333421b9e0f96c7bc788e5667c146a58a9440a55 0 iD8DBQBMz0HOywK+sNU5EO8RAlsEAJ0USh6yOG7OrWkADGunVt9QimBQnwCbBqeMnKgSbwEw8jZwE3Iz1mdrYlo=
32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
32 4438875ec01bd0fc32be92b0872eb6daeed4d44f 0 iD8DBQBM4WYUywK+sNU5EO8RAhCVAJ0dJswachwFAHALmk1x0RJehxzqPQCbBNskP9n/X689jB+btNTZTyKU/fw=
33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
33 6aff4f144ad356311318b0011df0bb21f2c97429 0 iD8DBQBM9uxXywK+sNU5EO8RAv+4AKCDj4qKP16GdPaq1tP6BUwpM/M1OACfRyzLPp/qiiN8xJTWoWYSe/XjJug=
34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
34 e3bf16703e2601de99e563cdb3a5d50b64e6d320 0 iD8DBQBNH8WqywK+sNU5EO8RAiQTAJ9sBO+TeiGro4si77VVaQaA6jcRUgCfSA28dBbjj0oFoQwvPoZjANiZBH8=
35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
35 a6c855c32ea081da3c3b8ff628f1847ff271482f 0 iD8DBQBNSJJ+ywK+sNU5EO8RAoJaAKCweDEF70fu+r1Zn7pYDXdlk5RuSgCeO9gK/eit8Lin/1n3pO7aYguFLok=
36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
36 2b2155623ee2559caf288fd333f30475966c4525 0 iD8DBQBNSJeBywK+sNU5EO8RAm1KAJ4hW9Cm9nHaaGJguchBaPLlAr+O3wCgqgmMok8bdAS06N6PL60PSTM//Gg=
37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
37 2616325766e3504c8ae7c84bd15ee610901fe91d 0 iD8DBQBNbWy9ywK+sNU5EO8RAlWCAJ4mW8HbzjJj9GpK98muX7k+7EvEHwCfaTLbC/DH3QEsZBhEP+M8tzL6RU4=
38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
38 aa1f3be38ab127280761889d2dca906ca465b5f4 0 iD8DBQBNeQq7ywK+sNU5EO8RAlEOAJ4tlEDdetE9lKfjGgjbkcR8PrC3egCfXCfF3qNVvU/2YYjpgvRwevjvDy0=
39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
39 b032bec2c0a651ca0ddecb65714bfe6770f67d70 0 iD8DBQBNlg5kywK+sNU5EO8RAnGEAJ9gmEx6MfaR4XcG2m/93vwtfyzs3gCgltzx8/YdHPwqDwRX/WbpYgi33is=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
40 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 0 iD8DBQBNvTy4ywK+sNU5EO8RAmp8AJ9QnxK4jTJ7G722MyeBxf0UXEdGwACgtlM7BKtNQfbEH/fOW5y+45W88VI=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
41 733af5d9f6b22387913e1d11350fb8cb7c1487dd 0 iD8DBQBN5q/8ywK+sNU5EO8RArRGAKCNGT94GKIYtSuwZ57z1sQbcw6uLACfffpbMV4NAPMl8womAwg+7ZPKnIU=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
42 de9eb6b1da4fc522b1cab16d86ca166204c24f25 0 iD8DBQBODhfhywK+sNU5EO8RAr2+AJ4ugbAj8ae8/K0bYZzx3sascIAg1QCeK3b+zbbVVqd3b7CDpwFnaX8kTd4=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
43 4a43e23b8c55b4566b8200bf69fe2158485a2634 0 iD8DBQBONzIMywK+sNU5EO8RAj5SAJ0aPS3+JHnyI6bHB2Fl0LImbDmagwCdGbDLp1S7TFobxXudOH49bX45Iik=
44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
44 d629f1e89021103f1753addcef6b310e4435b184 0 iD8DBQBOWAsBywK+sNU5EO8RAht4AJwJl9oNFopuGkj5m8aKuf7bqPkoAQCeNrEm7UhFsZKYT5iUOjnMV7s2LaM=
45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
45 351a9292e430e35766c552066ed3e87c557b803b 0 iD8DBQBOh3zUywK+sNU5EO8RApFMAKCD3Y/u3avDFndznwqfG5UeTHMlvACfUivPIVQZyDZnhZMq0UhC6zhCEQg=
46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
46 384082750f2c51dc917d85a7145748330fa6ef4d 0 iD8DBQBOmd+OywK+sNU5EO8RAgDgAJ9V/X+G7VLwhTpHrZNiOHabzSyzYQCdE2kKfIevJUYB9QLAWCWP6DPwrwI=
47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
47 41453d55b481ddfcc1dacb445179649e24ca861d 0 iD8DBQBOsFhpywK+sNU5EO8RAqM6AKCyfxUae3/zLuiLdQz+JR78690eMACfQ6JTBQib4AbE+rUDdkeFYg9K/+4=
48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
48 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 0 iD8DBQBO1/fWywK+sNU5EO8RAmoPAKCR5lpv1D6JLURHD8KVLSV4GRVEBgCgnd0Sy78ligNfqAMafmACRDvj7vo=
49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
49 6344043924497cd06d781d9014c66802285072e4 0 iD8DBQBPALgmywK+sNU5EO8RAlfhAJ9nYOdWnhfVDHYtDTJAyJtXBAQS9wCgnefoSQt7QABkbGxM+Q85UYEBuD0=
50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
50 db33555eafeaf9df1e18950e29439eaa706d399b 0 iD8DBQBPGdzxywK+sNU5EO8RAppkAJ9jOXhUVE/97CPgiMA0pMGiIYnesQCfengAszcBiSiKGugiI8Okc9ghU+Y=
51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
51 2aa5b51f310fb3befd26bed99c02267f5c12c734 0 iD8DBQBPKZ9bywK+sNU5EO8RAt1TAJ45r1eJ0YqSkInzrrayg4TVCh0SnQCgm0GA/Ua74jnnDwVQ60lAwROuz1Q=
52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
52 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 0 iD8DBQBPT/fvywK+sNU5EO8RAnfYAKCn7d0vwqIb100YfWm1F7nFD5B+FACeM02YHpQLSNsztrBCObtqcnfod7Q=
53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
53 b9bd95e61b49c221c4cca24e6da7c946fc02f992 0 iD8DBQBPeLsIywK+sNU5EO8RAvpNAKCtKe2gitz8dYn52IRF0hFOPCR7AQCfRJL/RWCFweu2T1vH/mUOCf8SXXc=
54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
54 d9e2f09d5488c395ae9ddbb320ceacd24757e055 0 iD8DBQBPju/dywK+sNU5EO8RArBYAJ9xtifdbk+hCOJO8OZa4JfHX8OYZQCeKPMBaBWiT8N/WHoOm1XU0q+iono=
55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
55 00182b3d087909e3c3ae44761efecdde8f319ef3 0 iD8DBQBPoFhIywK+sNU5EO8RAhzhAKCBj1n2jxPTkZNJJ5pSp3soa+XHIgCgsZZpAQxOpXwCp0eCdNGe0+pmxmg=
56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
56 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 0 iD8DBQBPovNWywK+sNU5EO8RAhgiAJ980T91FdPTRMmVONDhpkMsZwVIMACgg3bKvoWSeuCW28llUhAJtUjrMv0=
57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
57 85a358df5bbbe404ca25730c9c459b34263441dc 0 iD8DBQBPyZsWywK+sNU5EO8RAnpLAJ48qrGDJRT+pteS0mSQ11haqHstPwCdG4ccGbk+0JHb7aNy8/NRGAOqn9w=
58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
58 b013baa3898e117959984fc64c29d8c784d2f28b 0 iD8DBQBP8QOPywK+sNU5EO8RAqimAKCFRSx0lvG6y8vne2IhNG062Hn0dACeMLI5/zhpWpHBIVeAAquYfx2XFeA=
59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
59 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 0 iD8DBQBQGiL8ywK+sNU5EO8RAq5oAJ4rMMCPx6O+OuzNXVOexogedWz/QgCeIiIxLd76I4pXO48tdXhr0hQcBuM=
60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
60 072209ae4ddb654eb2d5fd35bff358c738414432 0 iD8DBQBQQkq0ywK+sNU5EO8RArDTAJ9nk5CySnNAjAXYvqvx4uWCw9ThZwCgqmFRehH/l+oTwj3f8nw8u8qTCdc=
61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
61 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 0 iD8DBQBQamltywK+sNU5EO8RAlsqAJ4qF/m6aFu4mJCOKTiAP5RvZFK02ACfawYShUZO6OXEFfveU0aAxDR0M1k=
62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
62 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 0 iD8DBQBQgPV5ywK+sNU5EO8RArylAJ0abcx5NlDjyv3ZDWpAfRIHyRsJtQCgn4TMuEayqgxzrvadQZHdTEU2g38=
63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
63 195ad823b5d58c68903a6153a25e3fb4ed25239d 0 iD8DBQBQkuT9ywK+sNU5EO8RAhB4AKCeerItoK2Jipm2cVf4euGofAa/WACeJj3TVd4pFILpb+ogj7ebweFLJi0=
64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
64 0c10cf8191469e7c3c8844922e17e71a176cb7cb 0 iD8DBQBQvQWoywK+sNU5EO8RAnq3AJoCn98u4geFx5YaQaeh99gFhCd7bQCgjoBwBSUyOvGd0yBy60E3Vv3VZhM=
65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
65 a4765077b65e6ae29ba42bab7834717b5072d5ba 0 iD8DBQBQ486sywK+sNU5EO8RAhmJAJ90aLfLKZhmcZN7kqphigQJxiFOQACeJ5IUZxjGKH4xzi3MrgIcx9n+dB0=
66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
66 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 0 iD8DBQBQ+yuYywK+sNU5EO8RAm9JAJoD/UciWvpGeKBcpGtZJBFJVcL/HACghDXSgQ+xQDjB+6uGrdgAQsRR1Lg=
67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
67 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 0 iD8DBQBRDDROywK+sNU5EO8RAh75AJ9uJCGoCWnP0Lv/+XuYs4hvUl+sAgCcD36QgAnuw8IQXrvv684BAXAnHcA=
68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
68 7511d4df752e61fe7ae4f3682e0a0008573b0402 0 iD8DBQBRFYaoywK+sNU5EO8RAuErAJoDyhXn+lptU3+AevVdwAIeNFyR2gCdHzPHyWd+JDeWCUR+pSOBi8O2ppM=
69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
69 5b7175377babacce80a6c1e12366d8032a6d4340 0 iD8DBQBRMCYgywK+sNU5EO8RAq1/AKCWKlt9ysibyQgYwoxxIOZv5J8rpwCcDSHQaaf1fFZUTnQsOePwcM2Y/Sg=
70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
70 50c922c1b5145dab8baefefb0437d363b6a6c21c 0 iD8DBQBRWnUnywK+sNU5EO8RAuQRAJwM42cJqJPeqJ0jVNdMqKMDqr4dSACeP0cRVGz1gitMuV0x8f3mrZrqc7I=
71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
71 8a7bd2dccd44ed571afe7424cd7f95594f27c092 0 iD8DBQBRXfBvywK+sNU5EO8RAn+LAKCsMmflbuXjYRxlzFwId5ptm8TZcwCdGkyLbZcASBOkzQUm/WW1qfknJHU=
72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
72 292cd385856d98bacb2c3086f8897bc660c2beea 0 iD8DBQBRcM0BywK+sNU5EO8RAjp4AKCJBykQbvXhKuvLSMxKx3a2TBiXcACfbr/kLg5GlZTF/XDPmY+PyHgI/GM=
73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
73 23f785b38af38d2fca6b8f3db56b8007a84cd73a 0 iD8DBQBRgZwNywK+sNU5EO8RAmO4AJ4u2ILGuimRP6MJgE2t65LZ5dAdkACgiENEstIdrlFC80p+sWKD81kKIYI=
74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
74 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 0 iD8DBQBRkswvywK+sNU5EO8RAiYYAJsHTHyHbJeAgmGvBTmDrfcKu4doUgCeLm7eGBjx7yAPUvEtxef8rAkQmXI=
75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
75 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 0 iD8DBQBRqnFLywK+sNU5EO8RAsWNAJ9RR6t+y1DLFc2HeH0eN9VfZAKF9gCeJ8ezvhtKq/LMs0/nvcgKQc/d5jk=
76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
76 009794acc6e37a650f0fae37872e733382ac1c0c 0 iD8DBQBR0guxywK+sNU5EO8RArNkAKCq9pMihVzP8Os5kCmgbWpe5C37wgCgqzuPZTHvAsXF5wTyaSTMVa9Ccq4=
77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
77 f0d7721d7322dcfb5af33599c2543f27335334bb 0 iD8DBQBR8taaywK+sNU5EO8RAqeEAJ4idDhhDuEsgsUjeQgWNj498matHACfT67gSF5w0ylsrBx1Hb52HkGXDm0=
78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
78 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 0 iD8DBQBR+ymFywK+sNU5EO8RAuSdAJkBMcd9DAZ3rWE9WGKPm2YZ8LBoXACfXn/wbEsVy7ZgJoUwiWmHSnQaWCI=
79 335a558f81dc73afeab4d7be63617392b130117f 0 iQIVAwUAUiZrIyBXgaxoKi1yAQK2iw//cquNqqSkc8Re5/TZT9I6NH+lh6DbOKjJP0Xl1Wqq0K+KSIUgZG4G32ovaEb2l5X0uY+3unRPiZ0ebl0YSw4Fb2ZiPIADXLBTOYRrY2Wwd3tpJeGI6wEgZt3SfcITV/g7NJrCjT3FlYoSOIayrExM80InSdcEM0Q3Rx6HKzY2acyxzgZeAtAW5ohFvHilSvY6p5Gcm4+QptMxvw45GPdreUmjeXZxNXNXZ8P+MjMz/QJbai/N7PjmK8lqnhkBsT48Ng/KhhmOkGntNJ2/ImBWLFGcWngSvJ7sfWwnyhndvGhe0Hq1NcCf7I8TjNDxU5TR+m+uW7xjXdLoDbUjBdX4sKXnh8ZjbYiODKBOrrDq25cf8nA/tnpKyE/qsVy60kOk6loY4XKiYmn1V49Ta0emmDx0hqo3HgxHHsHX0NDnGdWGol7cPRET0RzVobKq1A0jnrhPooWidvLh9bPzLonrWDo+ib+DuySoRkuYUK4pgZJ2mbg6daFOBEZygkSyRB8bo1UQUP7EgQDrWe4khb/5GHEfDkrQz3qu/sXvc0Ir1mOUWBFPHC2DjjCn/oMJuUkG1SwM8l2Bfv7h67ssES6YQ2+RjOix4yid7EXS/Ogl45PzCIPSI5+BbNs10JhE0w5uErBHlF53EDTe/TSLc+GU6DB6PP6dH912Njdr3jpNSUQ=
79 335a558f81dc73afeab4d7be63617392b130117f 0 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
@@ -1,266 +1,267 b''
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
1 d40cc5aacc31ed673d9b5b24f98bee78c283062c 0.4f
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
2 1c590d34bf61e2ea12c71738e5a746cd74586157 0.4e
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
3 7eca4cfa8aad5fce9a04f7d8acadcd0452e2f34e 0.4d
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
4 b4d0c3786ad3e47beacf8412157326a32b6d25a4 0.4c
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
5 f40273b0ad7b3a6d3012fd37736d0611f41ecf54 0.5
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
6 0a28dfe59f8fab54a5118c5be4f40da34a53cdb7 0.5b
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
7 12e0fdbc57a0be78f0e817fd1d170a3615cd35da 0.6
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
8 4ccf3de52989b14c3d84e1097f59e39a992e00bd 0.6b
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
9 eac9c8efcd9bd8244e72fb6821f769f450457a32 0.6c
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
10 979c049974485125e1f9357f6bbe9c1b548a64c3 0.7
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
11 3a56574f329a368d645853e0f9e09472aee62349 0.8
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
12 6a03cff2b0f5d30281e6addefe96b993582f2eac 0.8.1
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
13 35fb62a3a673d5322f6274a44ba6456e5e4b3b37 0.9
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
14 2be3001847cb18a23c403439d9e7d0ace30804e9 0.9.1
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
15 36a957364b1b89c150f2d0e60a99befe0ee08bd3 0.9.2
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
16 27230c29bfec36d5540fbe1c976810aefecfd1d2 0.9.3
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
17 fb4b6d5fe100b0886f8bc3d6731ec0e5ed5c4694 0.9.4
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
18 23889160905a1b09fffe1c07378e9fc1827606eb 0.9.5
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
19 bae2e9c838e90a393bae3973a7850280413e091a 1.0
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
20 d5cbbe2c49cee22a9fbeb9ea41daa0ac4e26b846 1.0.1
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
21 d2375bbee6d47e62ba8e415c86e83a465dc4dce9 1.0.2
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
22 2a67430f92f15ea5159c26b09ec4839a0c549a26 1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
23 3773e510d433969e277b1863c317b674cbee2065 1.1.1
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
24 11a4eb81fb4f4742451591489e2797dc47903277 1.1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
25 11efa41037e280d08cfb07c09ad485df30fb0ea8 1.2
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
26 02981000012e3adf40c4849bd7b3d5618f9ce82d 1.2.1
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
27 196d40e7c885fa6e95f89134809b3ec7bdbca34b 1.3
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
28 3ef6c14a1e8e83a31226f5881b7fe6095bbfa6f6 1.3.1
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
29 31ec469f9b556f11819937cf68ee53f2be927ebf 1.4
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
30 439d7ea6fe3aa4ab9ec274a68846779153789de9 1.4.1
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
31 296a0b14a68621f6990c54fdba0083f6f20935bf 1.4.2
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
32 4aa619c4c2c09907034d9824ebb1dd0e878206eb 1.4.3
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
33 ff2704a8ded37fbebd8b6eb5ec733731d725da8a 1.5
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
34 2b01dab594167bc0dd33331dbaa6dca3dca1b3aa 1.5.1
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
35 39f725929f0c48c5fb3b90c071fc3066012456ca 1.5.2
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
36 fdcf80f26604f233dc4d8f0a5ef9d7470e317e8a 1.5.3
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
37 24fe2629c6fd0c74c90bd066e77387c2b02e8437 1.5.4
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
38 f786fc4b8764cd2a5526d259cf2f94d8a66924d9 1.6
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
39 bf1774d95bde614af3956d92b20e2a0c68c5fec7 1.6.1
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
40 c00f03a4982e467fb6b6bd45908767db6df4771d 1.6.2
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
41 ff5cec76b1c5b6be9c3bb923aae8c3c6d079d6b9 1.6.3
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
42 93d8bff78c96fe7e33237b257558ee97290048a4 1.6.4
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
43 333421b9e0f96c7bc788e5667c146a58a9440a55 1.7
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
44 4438875ec01bd0fc32be92b0872eb6daeed4d44f 1.7.1
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
45 6aff4f144ad356311318b0011df0bb21f2c97429 1.7.2
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
46 e3bf16703e2601de99e563cdb3a5d50b64e6d320 1.7.3
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
47 a6c855c32ea081da3c3b8ff628f1847ff271482f 1.7.4
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
48 2b2155623ee2559caf288fd333f30475966c4525 1.7.5
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
49 2616325766e3504c8ae7c84bd15ee610901fe91d 1.8
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
50 aa1f3be38ab127280761889d2dca906ca465b5f4 1.8.1
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
51 b032bec2c0a651ca0ddecb65714bfe6770f67d70 1.8.2
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
52 3cb1e95676ad089596bd81d0937cad37d6e3b7fb 1.8.3
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
53 733af5d9f6b22387913e1d11350fb8cb7c1487dd 1.8.4
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
54 de9eb6b1da4fc522b1cab16d86ca166204c24f25 1.9
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
55 4a43e23b8c55b4566b8200bf69fe2158485a2634 1.9.1
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
56 d629f1e89021103f1753addcef6b310e4435b184 1.9.2
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
57 351a9292e430e35766c552066ed3e87c557b803b 1.9.3
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
58 384082750f2c51dc917d85a7145748330fa6ef4d 2.0-rc
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
59 41453d55b481ddfcc1dacb445179649e24ca861d 2.0
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
60 195dbd1cef0c2f9f8bcf4ea303238105f716bda3 2.0.1
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
61 6344043924497cd06d781d9014c66802285072e4 2.0.2
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
62 db33555eafeaf9df1e18950e29439eaa706d399b 2.1-rc
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
63 2aa5b51f310fb3befd26bed99c02267f5c12c734 2.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
64 53e2cd303ecf8ca7c7eeebd785c34e5ed6b0f4a4 2.1.1
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
65 b9bd95e61b49c221c4cca24e6da7c946fc02f992 2.1.2
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
66 d9e2f09d5488c395ae9ddbb320ceacd24757e055 2.2-rc
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
67 00182b3d087909e3c3ae44761efecdde8f319ef3 2.2
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
68 5983de86462c5a9f42a3ad0f5e90ce5b1d221d25 2.2.1
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
69 85a358df5bbbe404ca25730c9c459b34263441dc 2.2.2
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
70 b013baa3898e117959984fc64c29d8c784d2f28b 2.2.3
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
71 a06e2681dd1786e2354d84a5fa9c1c88dd4fa3e0 2.3-rc
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
72 7f5094bb3f423fc799e471aac2aee81a7ce57a0b 2.3
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
73 072209ae4ddb654eb2d5fd35bff358c738414432 2.3.1
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
74 b3f0f9a39c4e1d0250048cd803ab03542d6f140a 2.3.2
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
75 d118a4f4fd16d9b558ec3f3e87bfee772861d2b7 2.4-rc
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
76 195ad823b5d58c68903a6153a25e3fb4ed25239d 2.4
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
77 0c10cf8191469e7c3c8844922e17e71a176cb7cb 2.4.1
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
78 a4765077b65e6ae29ba42bab7834717b5072d5ba 2.4.2
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
79 f5fbe15ca7449f2c9a3cf817c86d0ae68b307214 2.5-rc
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
80 a6088c05e43a8aee0472ca3a4f6f8d7dd914ebbf 2.5
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
81 7511d4df752e61fe7ae4f3682e0a0008573b0402 2.5.1
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
82 5b7175377babacce80a6c1e12366d8032a6d4340 2.5.2
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
83 50c922c1b5145dab8baefefb0437d363b6a6c21c 2.5.3
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
84 8a7bd2dccd44ed571afe7424cd7f95594f27c092 2.5.4
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
85 292cd385856d98bacb2c3086f8897bc660c2beea 2.6-rc
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
86 23f785b38af38d2fca6b8f3db56b8007a84cd73a 2.6
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
87 ddc7a6be20212d18f3e27d9d7e6f079a66d96f21 2.6.1
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
88 cceaf7af4c9e9e6fa2dbfdcfe9856c5da69c4ffd 2.6.2
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
89 009794acc6e37a650f0fae37872e733382ac1c0c 2.6.3
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
90 f0d7721d7322dcfb5af33599c2543f27335334bb 2.7-rc
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
91 f37b5a17e6a0ee17afde2cdde5393dd74715fb58 2.7
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
92 335a558f81dc73afeab4d7be63617392b130117f 2.7.1
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
93 e7fa36d2ad3a7944a52dca126458d6f482db3524 2.7.2
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
94 1596f2d8f2421314b1ddead8f7d0c91009358994 2.8-rc
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
95 d825e4025e39d1c39db943cdc89818abd0a87c27 2.8
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
96 209e04a06467e2969c0cc6501335be0406d46ef0 2.8.1
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
97 ca387377df7a3a67dbb90b6336b781cdadc3ef41 2.8.2
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
98 8862469e16f9236208581b20de5f96bd13cc039d 2.9-rc
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
99 3cec5134e9c4bceab6a00c60f52a4f80677a78f2 2.9
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
100 b96cb15ec9e04d8ac5ee08b34fcbbe4200588965 2.9.1
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
101 3f83fc5cfe715d292069ee8417c83804f6c6c1e4 2.9.2
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
102 564f55b251224f16508dd1311452db7780dafe2b 3.0-rc
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
103 2195ac506c6ababe86985b932f4948837c0891b5 3.0
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
104 269c80ee5b3cb3684fa8edc61501b3506d02eb10 3.0.1
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
105 2d8cd3d0e83c7336c0cb45a9f88638363f993848 3.0.2
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
106 6c36dc6cd61a0e1b563f1d51e55bdf4dacf12162 3.1-rc
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
107 3178e49892020336491cdc6945885c4de26ffa8b 3.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
108 5dc91146f35369949ea56b40172308158b59063a 3.1.1
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
109 f768c888aaa68d12dd7f509dcc7f01c9584357d0 3.1.2
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
110 7f8d16af8cae246fa5a48e723d48d58b015aed94 3.2-rc
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
111 ced632394371a36953ce4d394f86278ae51a2aae 3.2
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
112 643c58303fb0ec020907af28b9e486be299ba043 3.2.1
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
113 902554884335e5ca3661d63be9978eb4aec3f68a 3.2.2
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
114 6dad422ecc5adb63d9fa649eeb8e05a5f9bc4900 3.2.3
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
115 1265a3a71d75396f5d4cf6935ae7d9ba5407a547 3.2.4
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
116 db8e3f7948b1fdeb9ad12d448fc3525759908b9f 3.3-rc
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
117 fbdd5195528fae4f41feebc1838215c110b25d6a 3.3
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
118 5b4ed033390bf6e2879c8f5c28c84e1ee3b87231 3.3.1
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
119 07a92bbd02e5e3a625e0820389b47786b02b2cea 3.3.2
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
120 2e2e9a0750f91a6fe0ad88e4de34f8efefdcab08 3.3.3
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
121 e89f909edffad558b56f4affa8239e4832f88de0 3.4-rc
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
122 8cc6036bca532e06681c5a8fa37efaa812de67b5 3.4
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
123 ed18f4acf435a2824c6f49fba40f42b9df5da7ad 3.4.1
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
124 540cd0ddac49c1125b2e013aa2ff18ecbd4dd954 3.4.2
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
125 96a38d44ba093bd1d1ecfd34119e94056030278b 3.5-rc
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
126 21aa1c313b05b1a85f8ffa1120d51579ddf6bf24 3.5
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
127 1a45e49a6bed023deb229102a8903234d18054d3 3.5.1
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
128 9a466b9f9792e3ad7ae3fc6c43c3ff2e136b718d 3.5.2
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
129 b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 3.6-rc
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
130 47dd34f2e7272be9e3b2a5a83cd0d20be44293f4 3.6
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
131 1aa5083cbebbe7575c88f3402ab377539b484897 3.6.1
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
132 2d437a0f3355834a9485bbbeb30a52a052c98f19 3.6.2
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
133 ea389970c08449440587712117f178d33bab3f1e 3.6.3
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
134 158bdc8965720ca4061f8f8d806563cfc7cdb62e 3.7-rc
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
135 2408645de650d8a29a6ce9e7dce601d8dd0d1474 3.7
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
136 b698abf971e7377d9b7ec7fc8c52df45255b0329 3.7.1
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
137 d493d64757eb45ada99fcb3693e479a51b7782da 3.7.2
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
138 ae279d4a19e9683214cbd1fe8298cf0b50571432 3.7.3
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
139 740156eedf2c450aee58b1a90b0e826f47c5da64 3.8-rc
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
140 f85de28eae32e7d3064b1a1321309071bbaaa069 3.8
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
141 a56296f55a5e1038ea5016dace2076b693c28a56 3.8.1
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
142 aaabed77791a75968a12b8c43ad263631a23ee81 3.8.2
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
143 a9764ab80e11bcf6a37255db7dd079011f767c6c 3.8.3
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
144 26a5d605b8683a292bb89aea11f37a81b06ac016 3.8.4
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
145 519bb4f9d3a47a6e83c2b414d58811ed38f503c2 3.9-rc
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
146 299546f84e68dbb9bd026f0f3a974ce4bdb93686 3.9
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
147 ccd436f7db6d5d7b9af89715179b911d031d44f1 3.9.1
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
148 149433e68974eb5c63ccb03f794d8b57339a80c4 3.9.2
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
149 438173c415874f6ac653efc1099dec9c9150e90f 4.0-rc
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
150 eab27446995210c334c3d06f1a659e3b9b5da769 4.0
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
151 b3b1ae98f6a0e14c1e1ba806a6c18e193b6dae5c 4.0.1
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
152 e69874dc1f4e142746ff3df91e678a09c6fc208c 4.0.2
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
153 a1dd2c0c479e0550040542e392e87bc91262517e 4.1-rc
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
154 e1526da1e6d84e03146151c9b6e6950fe9a83d7d 4.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
155 25703b624d27e3917d978af56d6ad59331e0464a 4.1.1
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
156 ed5b25874d998ababb181a939dd37a16ea644435 4.1.2
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
157 77eaf9539499a1b8be259ffe7ada787d07857f80 4.1.3
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
158 616e788321cc4ae9975b7f0c54c849f36d82182b 4.2-rc
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
159 bb96d4a497432722623ae60d9bc734a1e360179e 4.2
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
160 c850f0ed54c1d42f9aa079ad528f8127e5775217 4.2.1
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
161 26c49ed51a698ec016d2b4c6b44ca3c3f73cc788 4.2.2
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
162 857876ebaed4e315f63157bd157d6ce553c7ab73 4.3-rc
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
163 5544af8622863796a0027566f6b646e10d522c4c 4.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
164 943c91326b23954e6e1c6960d0239511f9530258 4.2.3
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
165 3fee7f7d2da04226914c2258cc2884dc27384fd7 4.3.1
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
166 920977f72c7b70acfdaf56ab35360584d7845827 4.3.2
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
167 2f427b57bf9019c6dc3750baa539dc22c1be50f6 4.3.3
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
168 1e2454b60e5936f5e77498cab2648db469504487 4.4-rc
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
169 0ccb43d4cf01d013ae05917ec4f305509f851b2d 4.4
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
170 cabc840ffdee8a72f3689fb77dd74d04fdc2bc04 4.4.1
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
171 a92b9f8e11ba330614cdfd6af0e03b15c1ff3797 4.4.2
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
172 27b6df1b5adbdf647cf5c6675b40575e1b197c60 4.5-rc
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
173 d334afc585e29577f271c5eda03378736a16ca6b 4.5
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
174 369aadf7a3264b03c8b09efce715bc41e6ab4a9b 4.5.1
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
175 8bba684efde7f45add05f737952093bb2aa07155 4.5.2
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
176 7de7bd407251af2bc98e5b809c8598ee95830daf 4.5.3
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
177 ed5448edcbfa747b9154099e18630e49024fd47b 4.6rc0
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
178 1ec874717d8a93b19e0d50628443e0ee5efab3a9 4.6rc1
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
179 6614cac550aea66d19c601e45efd1b7bd08d7c40 4.6
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
180 9c5ced5276d6e7d54f7c3dadf5247b7ee98ec79c 4.6.1
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
181 0b63a6743010dfdbf8a8154186e119949bdaa1cc 4.6.2
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
182 e90130af47ce8dd53a3109aed9d15876b3e7dee8 4.7rc0
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
183 33ac6a72308a215e6086fbced347ec10aa963b0a 4.7
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
184 ede3bf31fe63677fdf5bd8db687977d4e3d792ed 4.7.1
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
185 5405cb1a79010ac50c58cd84e6f50c4556bf2a4c 4.7.2
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
186 956ec6f1320df26f3133ec40f3de866ea0695fd7 4.8rc0
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
187 a91a2837150bdcb27ae76b3646e6c93cd6a15904 4.8
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
188 1c8c54cf97256f4468da2eb4dbee24f7f3888e71 4.8.1
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
189 197f092b2cd9691e2a55d198f717b231af9be6f9 4.8.2
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
190 593718ff5844cad7a27ee3eb5adad89ac8550949 4.9rc0
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
191 83377b4b4ae0e9a6b8e579f7b0a693b8cf5c3b10 4.9
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
192 4ea21df312ec7159c5b3633096b6ecf68750b0dd 4.9.1
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
193 4a8d9ed864754837a185a642170cde24392f9abf 5.0rc0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
194 07e479ef7c9639be0029f00e6a722b96dcc05fee 5.0
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
195 c3484ddbdb9621256d597ed86b90d229c59c2af9 5.0.1
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
196 97ada9b8d51bef24c5cb4cdca4243f0db694ab6e 5.0.2
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
197 e386b5f4f8360dbb43a576dd9b1368e386fefa5b 5.1rc0
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
198 e91930d712e8507d1bc1b2dffd96c83edc4cbed3 5.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
199 a4e32fd539ab41489a51b2aa88bda9a73b839562 5.1.1
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
200 181e52f2b62f4768aa0d988936c929dc7c4a41a0 5.1.2
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
201 59338f9561099de77c684c00f76507f11e46ebe8 5.2rc0
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
202 ca3dca416f8d5863ca6f5a4a6a6bb835dcd5feeb 5.2
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
203 a50fecefa691c9b72a99e49aa6fe9dd13943c2bf 5.2.1
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
204 b4c82b70418022e67cc0e69b1aa3c3aa43aa1d29 5.2.2
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
205 84a0102c05c7852c8215ef6cf21d809927586b69 5.3rc0
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
206 e4344e463c0c888a2f437b78b5982ecdf3f6650a 5.3rc1
207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
207 7f5410dfc8a64bb587d19637deb95d378fd1eb5c 5.3
208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
208 6d121acbb82e65fe4dd3c2318a1b61981b958492 5.3.1
209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
209 8fca7e8449a847e3cf1054f2c07b51237699fad3 5.3.2
210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
210 26ce8e7515036d3431a03aaeb7bc72dd96cb1112 5.4rc0
211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
211 cf3e07d7648a4371ce584d15dd692e7a6845792f 5.4
212 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1
212 065704cbdbdbb05dcd6bb814eb9bbdd982211b28 5.4.1
213 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2
213 0ea9c86fac8974cd74dc12ea681c8986eb6da6c4 5.4.2
214 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0
214 28163c5de797e5416f9b588940f4608269b4d50a 5.5rc0
215 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5
215 7fc3c5fbc65f6fe85d70ea63923b8767dda4f2e0 5.5
216 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1
216 f62bb5d07848ca598aa860a517394130b61bf2ee 5.5.1
217 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2
217 07731064ac41dacdf0ec869ebd05c2e848c14fbf 5.5.2
218 0e06a7ab9e0d5c65af4e511aee1e0342998799df 5.6rc0
218 0e06a7ab9e0d5c65af4e511aee1e0342998799df 5.6rc0
219 18c17d63fdabd009e70bf994e5efb7db422f4f7f 5.6
219 18c17d63fdabd009e70bf994e5efb7db422f4f7f 5.6
220 1d5189a57405ceca5aa244052c9f948977f4699b 5.6.1
220 1d5189a57405ceca5aa244052c9f948977f4699b 5.6.1
221 9da65e3cf3706ff41e08b311381c588440c27baf 5.7rc0
221 9da65e3cf3706ff41e08b311381c588440c27baf 5.7rc0
222 0e2e7300f4302b02412b0b734717697049494c4c 5.7
222 0e2e7300f4302b02412b0b734717697049494c4c 5.7
223 d5d9177c0045d206db575bae6daa98e2cb2fe5bc 5.7.1
223 d5d9177c0045d206db575bae6daa98e2cb2fe5bc 5.7.1
224 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 5.8rc0
224 f67b8946bb1b6cfa8328dbf8d6a9128b69ccdcb4 5.8rc0
225 8d2b62d716b095507effaa8d56f87cd27ba659ab 5.8rc1
225 8d2b62d716b095507effaa8d56f87cd27ba659ab 5.8rc1
226 067f2c53fb24506c9e9fb4639871b13b19a85f8a 5.8
226 067f2c53fb24506c9e9fb4639871b13b19a85f8a 5.8
227 411dc27fd9fd076d6a031a08fcaace659afe2fe3 5.8.1
227 411dc27fd9fd076d6a031a08fcaace659afe2fe3 5.8.1
228 d7515d29761d5ada7d9c765f517db67db75dea9a 5.9rc0
228 d7515d29761d5ada7d9c765f517db67db75dea9a 5.9rc0
229 2813d406b03607cdb8c06cb04c44efcc9a79d9a2 5.9rc1
229 2813d406b03607cdb8c06cb04c44efcc9a79d9a2 5.9rc1
230 53221078e0de65d1a821ce5311dec45a7a978301 5.9
230 53221078e0de65d1a821ce5311dec45a7a978301 5.9
231 86a60679cf619e14cee9442f865fcf31b142cb9f 5.9.1
231 86a60679cf619e14cee9442f865fcf31b142cb9f 5.9.1
232 750920b18aaaddd654756be40dec59d90f2643be 5.9.2
232 750920b18aaaddd654756be40dec59d90f2643be 5.9.2
233 6ee0244fc1cf889ae543d2ce0ec45201ae0be6e1 5.9.3
233 6ee0244fc1cf889ae543d2ce0ec45201ae0be6e1 5.9.3
234 a44bb185f6bdbecc754996d8386722e2f0123b0a 6.0rc0
234 a44bb185f6bdbecc754996d8386722e2f0123b0a 6.0rc0
235 5d08b289e2e526259d7d5ea32b70fe76d5b327d7 6.0
235 5d08b289e2e526259d7d5ea32b70fe76d5b327d7 6.0
236 799fdf4cca80cb9ae40537a90995e6bd163ebc0b 6.0.1
236 799fdf4cca80cb9ae40537a90995e6bd163ebc0b 6.0.1
237 75676122c2bf7594ac732b7388db4c74c648b365 6.0.2
237 75676122c2bf7594ac732b7388db4c74c648b365 6.0.2
238 dcec16e799ddb6d33fcd11b04af530250a417a58 6.0.3
238 dcec16e799ddb6d33fcd11b04af530250a417a58 6.0.3
239 c00d3ce4e94bb0ee8d809e25e1dcb2a5fab84e2c 6.1rc0
239 c00d3ce4e94bb0ee8d809e25e1dcb2a5fab84e2c 6.1rc0
240 d4486810a1795fba9521449b8885ced034f3a6dd 6.1
240 d4486810a1795fba9521449b8885ced034f3a6dd 6.1
241 5bd6bcd31dd1ebb63b8914b00064f96297267af7 6.1.1
241 5bd6bcd31dd1ebb63b8914b00064f96297267af7 6.1.1
242 0ddd5e1f5f67438af85d12e4ce6c39021dde9916 6.1.2
242 0ddd5e1f5f67438af85d12e4ce6c39021dde9916 6.1.2
243 6b10151b962108f65bfa12b3918b1021ca334f73 6.1.3
243 6b10151b962108f65bfa12b3918b1021ca334f73 6.1.3
244 0cc5f74ff7f0f4ac2427096bddbe102dbc2453ae 6.1.4
244 0cc5f74ff7f0f4ac2427096bddbe102dbc2453ae 6.1.4
245 288de6f5d724bba7bf1669e2838f196962bb7528 6.2rc0
245 288de6f5d724bba7bf1669e2838f196962bb7528 6.2rc0
246 094a5fa3cf52f936e0de3f1e507c818bee5ece6b 6.2
246 094a5fa3cf52f936e0de3f1e507c818bee5ece6b 6.2
247 f69bffd00abe3a1b94d1032eb2c92e611d16a192 6.2.1
247 f69bffd00abe3a1b94d1032eb2c92e611d16a192 6.2.1
248 b5c8524827d20fe2e0ca8fb1234a0fe35a1a36c7 6.2.2
248 b5c8524827d20fe2e0ca8fb1234a0fe35a1a36c7 6.2.2
249 dbdee8ac3e3fcdda1fa55b90c0a235125b7f8e6f 6.2.3
249 dbdee8ac3e3fcdda1fa55b90c0a235125b7f8e6f 6.2.3
250 a3356ab610fc50000cf0ba55c424a4d96da11db7 6.3rc0
250 a3356ab610fc50000cf0ba55c424a4d96da11db7 6.3rc0
251 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
251 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
252 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3
252 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3
253 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
253 04f1dba53c961dfdb875c8469adc96fa999cfbed 6.3.0
254 0000000000000000000000000000000000000000 6.3.0
254 0000000000000000000000000000000000000000 6.3.0
255 c890d8b8bc59b18e5febf60caada629df5356ee2 6.3.1
255 c890d8b8bc59b18e5febf60caada629df5356ee2 6.3.1
256 59466b13a3ae0e29a5d4f485393e516cfbb057d0 6.3.2
256 59466b13a3ae0e29a5d4f485393e516cfbb057d0 6.3.2
257 8830004967ad865ead89c28a410405a6e71e0796 6.3.3
257 8830004967ad865ead89c28a410405a6e71e0796 6.3.3
258 05de4896508e8ec387b33eb30d8aab78d1c8e9e4 6.4rc0
258 05de4896508e8ec387b33eb30d8aab78d1c8e9e4 6.4rc0
259 f14864fffdcab725d9eac6d4f4c07be05a35f59a 6.4
259 f14864fffdcab725d9eac6d4f4c07be05a35f59a 6.4
260 83ea6ce48b4fd09fb79c4e34cc5750c805699a53 6.4.1
260 83ea6ce48b4fd09fb79c4e34cc5750c805699a53 6.4.1
261 f952be90b0514a576dcc8bbe758ce3847faba9bb 6.4.2
261 f952be90b0514a576dcc8bbe758ce3847faba9bb 6.4.2
262 fc445f8abcf90b33db7c463816a1b3560681767f 6.4.3
262 fc445f8abcf90b33db7c463816a1b3560681767f 6.4.3
263 da372c745e0f053bb7a64e74cccd15810d96341d 6.4.4
263 da372c745e0f053bb7a64e74cccd15810d96341d 6.4.4
264 271a4ab29605ffa0bae5d3208eaa21a95427ff92 6.4.5
264 271a4ab29605ffa0bae5d3208eaa21a95427ff92 6.4.5
265 bb42988c7e156931b0ff1e93732b98173ebbcb7f 6.5rc0
265 bb42988c7e156931b0ff1e93732b98173ebbcb7f 6.5rc0
266 3ffc7209bbae5804a53084c9dc2d41139e88c867 6.5
266 3ffc7209bbae5804a53084c9dc2d41139e88c867 6.5
267 787af4e0e8b787e1b77a8059926b123730a4cd01 6.5.1
@@ -1,4449 +1,4449 b''
1 # perf.py - performance test routines
1 # perf.py - performance test routines
2 '''helper extension to measure performance
2 '''helper extension to measure performance
3
3
4 Configurations
4 Configurations
5 ==============
5 ==============
6
6
7 ``perf``
7 ``perf``
8 --------
8 --------
9
9
10 ``all-timing``
10 ``all-timing``
11 When set, additional statistics will be reported for each benchmark: best,
11 When set, additional statistics will be reported for each benchmark: best,
12 worst, median average. If not set only the best timing is reported
12 worst, median average. If not set only the best timing is reported
13 (default: off).
13 (default: off).
14
14
15 ``presleep``
15 ``presleep``
16 number of second to wait before any group of runs (default: 1)
16 number of second to wait before any group of runs (default: 1)
17
17
18 ``pre-run``
18 ``pre-run``
19 number of run to perform before starting measurement.
19 number of run to perform before starting measurement.
20
20
21 ``profile-benchmark``
21 ``profile-benchmark``
22 Enable profiling for the benchmarked section.
22 Enable profiling for the benchmarked section.
23 (The first iteration is benchmarked)
23 (The first iteration is benchmarked)
24
24
25 ``run-limits``
25 ``run-limits``
26 Control the number of runs each benchmark will perform. The option value
26 Control the number of runs each benchmark will perform. The option value
27 should be a list of `<time>-<numberofrun>` pairs. After each run the
27 should be a list of `<time>-<numberofrun>` pairs. After each run the
28 conditions are considered in order with the following logic:
28 conditions are considered in order with the following logic:
29
29
30 If benchmark has been running for <time> seconds, and we have performed
30 If benchmark has been running for <time> seconds, and we have performed
31 <numberofrun> iterations, stop the benchmark,
31 <numberofrun> iterations, stop the benchmark,
32
32
33 The default value is: `3.0-100, 10.0-3`
33 The default value is: `3.0-100, 10.0-3`
34
34
35 ``stub``
35 ``stub``
36 When set, benchmarks will only be run once, useful for testing
36 When set, benchmarks will only be run once, useful for testing
37 (default: off)
37 (default: off)
38 '''
38 '''
39
39
40 # "historical portability" policy of perf.py:
40 # "historical portability" policy of perf.py:
41 #
41 #
42 # We have to do:
42 # We have to do:
43 # - make perf.py "loadable" with as wide Mercurial version as possible
43 # - make perf.py "loadable" with as wide Mercurial version as possible
44 # This doesn't mean that perf commands work correctly with that Mercurial.
44 # This doesn't mean that perf commands work correctly with that Mercurial.
45 # BTW, perf.py itself has been available since 1.1 (or eb240755386d).
45 # BTW, perf.py itself has been available since 1.1 (or eb240755386d).
46 # - make historical perf command work correctly with as wide Mercurial
46 # - make historical perf command work correctly with as wide Mercurial
47 # version as possible
47 # version as possible
48 #
48 #
49 # We have to do, if possible with reasonable cost:
49 # We have to do, if possible with reasonable cost:
50 # - make recent perf command for historical feature work correctly
50 # - make recent perf command for historical feature work correctly
51 # with early Mercurial
51 # with early Mercurial
52 #
52 #
53 # We don't have to do:
53 # We don't have to do:
54 # - make perf command for recent feature work correctly with early
54 # - make perf command for recent feature work correctly with early
55 # Mercurial
55 # Mercurial
56
56
57 import contextlib
57 import contextlib
58 import functools
58 import functools
59 import gc
59 import gc
60 import os
60 import os
61 import random
61 import random
62 import shutil
62 import shutil
63 import struct
63 import struct
64 import sys
64 import sys
65 import tempfile
65 import tempfile
66 import threading
66 import threading
67 import time
67 import time
68
68
69 import mercurial.revlog
69 import mercurial.revlog
70 from mercurial import (
70 from mercurial import (
71 changegroup,
71 changegroup,
72 cmdutil,
72 cmdutil,
73 commands,
73 commands,
74 copies,
74 copies,
75 error,
75 error,
76 extensions,
76 extensions,
77 hg,
77 hg,
78 mdiff,
78 mdiff,
79 merge,
79 merge,
80 util,
80 util,
81 )
81 )
82
82
83 # for "historical portability":
83 # for "historical portability":
84 # try to import modules separately (in dict order), and ignore
84 # try to import modules separately (in dict order), and ignore
85 # failure, because these aren't available with early Mercurial
85 # failure, because these aren't available with early Mercurial
86 try:
86 try:
87 from mercurial import branchmap # since 2.5 (or bcee63733aad)
87 from mercurial import branchmap # since 2.5 (or bcee63733aad)
88 except ImportError:
88 except ImportError:
89 pass
89 pass
90 try:
90 try:
91 from mercurial import obsolete # since 2.3 (or ad0d6c2b3279)
91 from mercurial import obsolete # since 2.3 (or ad0d6c2b3279)
92 except ImportError:
92 except ImportError:
93 pass
93 pass
94 try:
94 try:
95 from mercurial import registrar # since 3.7 (or 37d50250b696)
95 from mercurial import registrar # since 3.7 (or 37d50250b696)
96
96
97 dir(registrar) # forcibly load it
97 dir(registrar) # forcibly load it
98 except ImportError:
98 except ImportError:
99 registrar = None
99 registrar = None
100 try:
100 try:
101 from mercurial import repoview # since 2.5 (or 3a6ddacb7198)
101 from mercurial import repoview # since 2.5 (or 3a6ddacb7198)
102 except ImportError:
102 except ImportError:
103 pass
103 pass
104 try:
104 try:
105 from mercurial.utils import repoviewutil # since 5.0
105 from mercurial.utils import repoviewutil # since 5.0
106 except ImportError:
106 except ImportError:
107 repoviewutil = None
107 repoviewutil = None
108 try:
108 try:
109 from mercurial import scmutil # since 1.9 (or 8b252e826c68)
109 from mercurial import scmutil # since 1.9 (or 8b252e826c68)
110 except ImportError:
110 except ImportError:
111 pass
111 pass
112 try:
112 try:
113 from mercurial import setdiscovery # since 1.9 (or cb98fed52495)
113 from mercurial import setdiscovery # since 1.9 (or cb98fed52495)
114 except ImportError:
114 except ImportError:
115 pass
115 pass
116
116
117 try:
117 try:
118 from mercurial import profiling
118 from mercurial import profiling
119 except ImportError:
119 except ImportError:
120 profiling = None
120 profiling = None
121
121
122 try:
122 try:
123 from mercurial.revlogutils import constants as revlog_constants
123 from mercurial.revlogutils import constants as revlog_constants
124
124
125 perf_rl_kind = (revlog_constants.KIND_OTHER, b'created-by-perf')
125 perf_rl_kind = (revlog_constants.KIND_OTHER, b'created-by-perf')
126
126
127 def revlog(opener, *args, **kwargs):
127 def revlog(opener, *args, **kwargs):
128 return mercurial.revlog.revlog(opener, perf_rl_kind, *args, **kwargs)
128 return mercurial.revlog.revlog(opener, perf_rl_kind, *args, **kwargs)
129
129
130
130
131 except (ImportError, AttributeError):
131 except (ImportError, AttributeError):
132 perf_rl_kind = None
132 perf_rl_kind = None
133
133
134 def revlog(opener, *args, **kwargs):
134 def revlog(opener, *args, **kwargs):
135 return mercurial.revlog.revlog(opener, *args, **kwargs)
135 return mercurial.revlog.revlog(opener, *args, **kwargs)
136
136
137
137
138 def identity(a):
138 def identity(a):
139 return a
139 return a
140
140
141
141
142 try:
142 try:
143 from mercurial import pycompat
143 from mercurial import pycompat
144
144
145 getargspec = pycompat.getargspec # added to module after 4.5
145 getargspec = pycompat.getargspec # added to module after 4.5
146 _byteskwargs = pycompat.byteskwargs # since 4.1 (or fbc3f73dc802)
146 _byteskwargs = pycompat.byteskwargs # since 4.1 (or fbc3f73dc802)
147 _sysstr = pycompat.sysstr # since 4.0 (or 2219f4f82ede)
147 _sysstr = pycompat.sysstr # since 4.0 (or 2219f4f82ede)
148 _bytestr = pycompat.bytestr # since 4.2 (or b70407bd84d5)
148 _bytestr = pycompat.bytestr # since 4.2 (or b70407bd84d5)
149 _xrange = pycompat.xrange # since 4.8 (or 7eba8f83129b)
149 _xrange = pycompat.xrange # since 4.8 (or 7eba8f83129b)
150 fsencode = pycompat.fsencode # since 3.9 (or f4a5e0e86a7e)
150 fsencode = pycompat.fsencode # since 3.9 (or f4a5e0e86a7e)
151 if pycompat.ispy3:
151 if pycompat.ispy3:
152 _maxint = sys.maxsize # per py3 docs for replacing maxint
152 _maxint = sys.maxsize # per py3 docs for replacing maxint
153 else:
153 else:
154 _maxint = sys.maxint
154 _maxint = sys.maxint
155 except (NameError, ImportError, AttributeError):
155 except (NameError, ImportError, AttributeError):
156 import inspect
156 import inspect
157
157
158 getargspec = inspect.getargspec
158 getargspec = inspect.getargspec
159 _byteskwargs = identity
159 _byteskwargs = identity
160 _bytestr = str
160 _bytestr = str
161 fsencode = identity # no py3 support
161 fsencode = identity # no py3 support
162 _maxint = sys.maxint # no py3 support
162 _maxint = sys.maxint # no py3 support
163 _sysstr = lambda x: x # no py3 support
163 _sysstr = lambda x: x # no py3 support
164 _xrange = xrange
164 _xrange = xrange
165
165
166 try:
166 try:
167 # 4.7+
167 # 4.7+
168 queue = pycompat.queue.Queue
168 queue = pycompat.queue.Queue
169 except (NameError, AttributeError, ImportError):
169 except (NameError, AttributeError, ImportError):
170 # <4.7.
170 # <4.7.
171 try:
171 try:
172 queue = pycompat.queue
172 queue = pycompat.queue
173 except (NameError, AttributeError, ImportError):
173 except (NameError, AttributeError, ImportError):
174 import Queue as queue
174 import Queue as queue
175
175
176 try:
176 try:
177 from mercurial import logcmdutil
177 from mercurial import logcmdutil
178
178
179 makelogtemplater = logcmdutil.maketemplater
179 makelogtemplater = logcmdutil.maketemplater
180 except (AttributeError, ImportError):
180 except (AttributeError, ImportError):
181 try:
181 try:
182 makelogtemplater = cmdutil.makelogtemplater
182 makelogtemplater = cmdutil.makelogtemplater
183 except (AttributeError, ImportError):
183 except (AttributeError, ImportError):
184 makelogtemplater = None
184 makelogtemplater = None
185
185
186 # for "historical portability":
186 # for "historical portability":
187 # define util.safehasattr forcibly, because util.safehasattr has been
187 # define util.safehasattr forcibly, because util.safehasattr has been
188 # available since 1.9.3 (or 94b200a11cf7)
188 # available since 1.9.3 (or 94b200a11cf7)
189 _undefined = object()
189 _undefined = object()
190
190
191
191
192 def safehasattr(thing, attr):
192 def safehasattr(thing, attr):
193 return getattr(thing, _sysstr(attr), _undefined) is not _undefined
193 return getattr(thing, _sysstr(attr), _undefined) is not _undefined
194
194
195
195
196 setattr(util, 'safehasattr', safehasattr)
196 setattr(util, 'safehasattr', safehasattr)
197
197
198 # for "historical portability":
198 # for "historical portability":
199 # define util.timer forcibly, because util.timer has been available
199 # define util.timer forcibly, because util.timer has been available
200 # since ae5d60bb70c9
200 # since ae5d60bb70c9
201 if safehasattr(time, 'perf_counter'):
201 if safehasattr(time, 'perf_counter'):
202 util.timer = time.perf_counter
202 util.timer = time.perf_counter
203 elif os.name == b'nt':
203 elif os.name == b'nt':
204 util.timer = time.clock
204 util.timer = time.clock
205 else:
205 else:
206 util.timer = time.time
206 util.timer = time.time
207
207
208 # for "historical portability":
208 # for "historical portability":
209 # use locally defined empty option list, if formatteropts isn't
209 # use locally defined empty option list, if formatteropts isn't
210 # available, because commands.formatteropts has been available since
210 # available, because commands.formatteropts has been available since
211 # 3.2 (or 7a7eed5176a4), even though formatting itself has been
211 # 3.2 (or 7a7eed5176a4), even though formatting itself has been
212 # available since 2.2 (or ae5f92e154d3)
212 # available since 2.2 (or ae5f92e154d3)
213 formatteropts = getattr(
213 formatteropts = getattr(
214 cmdutil, "formatteropts", getattr(commands, "formatteropts", [])
214 cmdutil, "formatteropts", getattr(commands, "formatteropts", [])
215 )
215 )
216
216
217 # for "historical portability":
217 # for "historical portability":
218 # use locally defined option list, if debugrevlogopts isn't available,
218 # use locally defined option list, if debugrevlogopts isn't available,
219 # because commands.debugrevlogopts has been available since 3.7 (or
219 # because commands.debugrevlogopts has been available since 3.7 (or
220 # 5606f7d0d063), even though cmdutil.openrevlog() has been available
220 # 5606f7d0d063), even though cmdutil.openrevlog() has been available
221 # since 1.9 (or a79fea6b3e77).
221 # since 1.9 (or a79fea6b3e77).
222 revlogopts = getattr(
222 revlogopts = getattr(
223 cmdutil,
223 cmdutil,
224 "debugrevlogopts",
224 "debugrevlogopts",
225 getattr(
225 getattr(
226 commands,
226 commands,
227 "debugrevlogopts",
227 "debugrevlogopts",
228 [
228 [
229 (b'c', b'changelog', False, b'open changelog'),
229 (b'c', b'changelog', False, b'open changelog'),
230 (b'm', b'manifest', False, b'open manifest'),
230 (b'm', b'manifest', False, b'open manifest'),
231 (b'', b'dir', False, b'open directory manifest'),
231 (b'', b'dir', False, b'open directory manifest'),
232 ],
232 ],
233 ),
233 ),
234 )
234 )
235
235
236 cmdtable = {}
236 cmdtable = {}
237
237
238
238
239 # for "historical portability":
239 # for "historical portability":
240 # define parsealiases locally, because cmdutil.parsealiases has been
240 # define parsealiases locally, because cmdutil.parsealiases has been
241 # available since 1.5 (or 6252852b4332)
241 # available since 1.5 (or 6252852b4332)
242 def parsealiases(cmd):
242 def parsealiases(cmd):
243 return cmd.split(b"|")
243 return cmd.split(b"|")
244
244
245
245
246 if safehasattr(registrar, 'command'):
246 if safehasattr(registrar, 'command'):
247 command = registrar.command(cmdtable)
247 command = registrar.command(cmdtable)
248 elif safehasattr(cmdutil, 'command'):
248 elif safehasattr(cmdutil, 'command'):
249 command = cmdutil.command(cmdtable)
249 command = cmdutil.command(cmdtable)
250 if 'norepo' not in getargspec(command).args:
250 if 'norepo' not in getargspec(command).args:
251 # for "historical portability":
251 # for "historical portability":
252 # wrap original cmdutil.command, because "norepo" option has
252 # wrap original cmdutil.command, because "norepo" option has
253 # been available since 3.1 (or 75a96326cecb)
253 # been available since 3.1 (or 75a96326cecb)
254 _command = command
254 _command = command
255
255
256 def command(name, options=(), synopsis=None, norepo=False):
256 def command(name, options=(), synopsis=None, norepo=False):
257 if norepo:
257 if norepo:
258 commands.norepo += b' %s' % b' '.join(parsealiases(name))
258 commands.norepo += b' %s' % b' '.join(parsealiases(name))
259 return _command(name, list(options), synopsis)
259 return _command(name, list(options), synopsis)
260
260
261
261
262 else:
262 else:
263 # for "historical portability":
263 # for "historical portability":
264 # define "@command" annotation locally, because cmdutil.command
264 # define "@command" annotation locally, because cmdutil.command
265 # has been available since 1.9 (or 2daa5179e73f)
265 # has been available since 1.9 (or 2daa5179e73f)
266 def command(name, options=(), synopsis=None, norepo=False):
266 def command(name, options=(), synopsis=None, norepo=False):
267 def decorator(func):
267 def decorator(func):
268 if synopsis:
268 if synopsis:
269 cmdtable[name] = func, list(options), synopsis
269 cmdtable[name] = func, list(options), synopsis
270 else:
270 else:
271 cmdtable[name] = func, list(options)
271 cmdtable[name] = func, list(options)
272 if norepo:
272 if norepo:
273 commands.norepo += b' %s' % b' '.join(parsealiases(name))
273 commands.norepo += b' %s' % b' '.join(parsealiases(name))
274 return func
274 return func
275
275
276 return decorator
276 return decorator
277
277
278
278
279 try:
279 try:
280 import mercurial.registrar
280 import mercurial.registrar
281 import mercurial.configitems
281 import mercurial.configitems
282
282
283 configtable = {}
283 configtable = {}
284 configitem = mercurial.registrar.configitem(configtable)
284 configitem = mercurial.registrar.configitem(configtable)
285 configitem(
285 configitem(
286 b'perf',
286 b'perf',
287 b'presleep',
287 b'presleep',
288 default=mercurial.configitems.dynamicdefault,
288 default=mercurial.configitems.dynamicdefault,
289 experimental=True,
289 experimental=True,
290 )
290 )
291 configitem(
291 configitem(
292 b'perf',
292 b'perf',
293 b'stub',
293 b'stub',
294 default=mercurial.configitems.dynamicdefault,
294 default=mercurial.configitems.dynamicdefault,
295 experimental=True,
295 experimental=True,
296 )
296 )
297 configitem(
297 configitem(
298 b'perf',
298 b'perf',
299 b'parentscount',
299 b'parentscount',
300 default=mercurial.configitems.dynamicdefault,
300 default=mercurial.configitems.dynamicdefault,
301 experimental=True,
301 experimental=True,
302 )
302 )
303 configitem(
303 configitem(
304 b'perf',
304 b'perf',
305 b'all-timing',
305 b'all-timing',
306 default=mercurial.configitems.dynamicdefault,
306 default=mercurial.configitems.dynamicdefault,
307 experimental=True,
307 experimental=True,
308 )
308 )
309 configitem(
309 configitem(
310 b'perf',
310 b'perf',
311 b'pre-run',
311 b'pre-run',
312 default=mercurial.configitems.dynamicdefault,
312 default=mercurial.configitems.dynamicdefault,
313 )
313 )
314 configitem(
314 configitem(
315 b'perf',
315 b'perf',
316 b'profile-benchmark',
316 b'profile-benchmark',
317 default=mercurial.configitems.dynamicdefault,
317 default=mercurial.configitems.dynamicdefault,
318 )
318 )
319 configitem(
319 configitem(
320 b'perf',
320 b'perf',
321 b'run-limits',
321 b'run-limits',
322 default=mercurial.configitems.dynamicdefault,
322 default=mercurial.configitems.dynamicdefault,
323 experimental=True,
323 experimental=True,
324 )
324 )
325 except (ImportError, AttributeError):
325 except (ImportError, AttributeError):
326 pass
326 pass
327 except TypeError:
327 except TypeError:
328 # compatibility fix for a11fd395e83f
328 # compatibility fix for a11fd395e83f
329 # hg version: 5.2
329 # hg version: 5.2
330 configitem(
330 configitem(
331 b'perf',
331 b'perf',
332 b'presleep',
332 b'presleep',
333 default=mercurial.configitems.dynamicdefault,
333 default=mercurial.configitems.dynamicdefault,
334 )
334 )
335 configitem(
335 configitem(
336 b'perf',
336 b'perf',
337 b'stub',
337 b'stub',
338 default=mercurial.configitems.dynamicdefault,
338 default=mercurial.configitems.dynamicdefault,
339 )
339 )
340 configitem(
340 configitem(
341 b'perf',
341 b'perf',
342 b'parentscount',
342 b'parentscount',
343 default=mercurial.configitems.dynamicdefault,
343 default=mercurial.configitems.dynamicdefault,
344 )
344 )
345 configitem(
345 configitem(
346 b'perf',
346 b'perf',
347 b'all-timing',
347 b'all-timing',
348 default=mercurial.configitems.dynamicdefault,
348 default=mercurial.configitems.dynamicdefault,
349 )
349 )
350 configitem(
350 configitem(
351 b'perf',
351 b'perf',
352 b'pre-run',
352 b'pre-run',
353 default=mercurial.configitems.dynamicdefault,
353 default=mercurial.configitems.dynamicdefault,
354 )
354 )
355 configitem(
355 configitem(
356 b'perf',
356 b'perf',
357 b'profile-benchmark',
357 b'profile-benchmark',
358 default=mercurial.configitems.dynamicdefault,
358 default=mercurial.configitems.dynamicdefault,
359 )
359 )
360 configitem(
360 configitem(
361 b'perf',
361 b'perf',
362 b'run-limits',
362 b'run-limits',
363 default=mercurial.configitems.dynamicdefault,
363 default=mercurial.configitems.dynamicdefault,
364 )
364 )
365
365
366
366
367 def getlen(ui):
367 def getlen(ui):
368 if ui.configbool(b"perf", b"stub", False):
368 if ui.configbool(b"perf", b"stub", False):
369 return lambda x: 1
369 return lambda x: 1
370 return len
370 return len
371
371
372
372
373 class noop:
373 class noop:
374 """dummy context manager"""
374 """dummy context manager"""
375
375
376 def __enter__(self):
376 def __enter__(self):
377 pass
377 pass
378
378
379 def __exit__(self, *args):
379 def __exit__(self, *args):
380 pass
380 pass
381
381
382
382
383 NOOPCTX = noop()
383 NOOPCTX = noop()
384
384
385
385
386 def gettimer(ui, opts=None):
386 def gettimer(ui, opts=None):
387 """return a timer function and formatter: (timer, formatter)
387 """return a timer function and formatter: (timer, formatter)
388
388
389 This function exists to gather the creation of formatter in a single
389 This function exists to gather the creation of formatter in a single
390 place instead of duplicating it in all performance commands."""
390 place instead of duplicating it in all performance commands."""
391
391
392 # enforce an idle period before execution to counteract power management
392 # enforce an idle period before execution to counteract power management
393 # experimental config: perf.presleep
393 # experimental config: perf.presleep
394 time.sleep(getint(ui, b"perf", b"presleep", 1))
394 time.sleep(getint(ui, b"perf", b"presleep", 1))
395
395
396 if opts is None:
396 if opts is None:
397 opts = {}
397 opts = {}
398 # redirect all to stderr unless buffer api is in use
398 # redirect all to stderr unless buffer api is in use
399 if not ui._buffers:
399 if not ui._buffers:
400 ui = ui.copy()
400 ui = ui.copy()
401 uifout = safeattrsetter(ui, b'fout', ignoremissing=True)
401 uifout = safeattrsetter(ui, b'fout', ignoremissing=True)
402 if uifout:
402 if uifout:
403 # for "historical portability":
403 # for "historical portability":
404 # ui.fout/ferr have been available since 1.9 (or 4e1ccd4c2b6d)
404 # ui.fout/ferr have been available since 1.9 (or 4e1ccd4c2b6d)
405 uifout.set(ui.ferr)
405 uifout.set(ui.ferr)
406
406
407 # get a formatter
407 # get a formatter
408 uiformatter = getattr(ui, 'formatter', None)
408 uiformatter = getattr(ui, 'formatter', None)
409 if uiformatter:
409 if uiformatter:
410 fm = uiformatter(b'perf', opts)
410 fm = uiformatter(b'perf', opts)
411 else:
411 else:
412 # for "historical portability":
412 # for "historical portability":
413 # define formatter locally, because ui.formatter has been
413 # define formatter locally, because ui.formatter has been
414 # available since 2.2 (or ae5f92e154d3)
414 # available since 2.2 (or ae5f92e154d3)
415 from mercurial import node
415 from mercurial import node
416
416
417 class defaultformatter:
417 class defaultformatter:
418 """Minimized composition of baseformatter and plainformatter"""
418 """Minimized composition of baseformatter and plainformatter"""
419
419
420 def __init__(self, ui, topic, opts):
420 def __init__(self, ui, topic, opts):
421 self._ui = ui
421 self._ui = ui
422 if ui.debugflag:
422 if ui.debugflag:
423 self.hexfunc = node.hex
423 self.hexfunc = node.hex
424 else:
424 else:
425 self.hexfunc = node.short
425 self.hexfunc = node.short
426
426
427 def __nonzero__(self):
427 def __nonzero__(self):
428 return False
428 return False
429
429
430 __bool__ = __nonzero__
430 __bool__ = __nonzero__
431
431
432 def startitem(self):
432 def startitem(self):
433 pass
433 pass
434
434
435 def data(self, **data):
435 def data(self, **data):
436 pass
436 pass
437
437
438 def write(self, fields, deftext, *fielddata, **opts):
438 def write(self, fields, deftext, *fielddata, **opts):
439 self._ui.write(deftext % fielddata, **opts)
439 self._ui.write(deftext % fielddata, **opts)
440
440
441 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
441 def condwrite(self, cond, fields, deftext, *fielddata, **opts):
442 if cond:
442 if cond:
443 self._ui.write(deftext % fielddata, **opts)
443 self._ui.write(deftext % fielddata, **opts)
444
444
445 def plain(self, text, **opts):
445 def plain(self, text, **opts):
446 self._ui.write(text, **opts)
446 self._ui.write(text, **opts)
447
447
448 def end(self):
448 def end(self):
449 pass
449 pass
450
450
451 fm = defaultformatter(ui, b'perf', opts)
451 fm = defaultformatter(ui, b'perf', opts)
452
452
453 # stub function, runs code only once instead of in a loop
453 # stub function, runs code only once instead of in a loop
454 # experimental config: perf.stub
454 # experimental config: perf.stub
455 if ui.configbool(b"perf", b"stub", False):
455 if ui.configbool(b"perf", b"stub", False):
456 return functools.partial(stub_timer, fm), fm
456 return functools.partial(stub_timer, fm), fm
457
457
458 # experimental config: perf.all-timing
458 # experimental config: perf.all-timing
459 displayall = ui.configbool(b"perf", b"all-timing", True)
459 displayall = ui.configbool(b"perf", b"all-timing", True)
460
460
461 # experimental config: perf.run-limits
461 # experimental config: perf.run-limits
462 limitspec = ui.configlist(b"perf", b"run-limits", [])
462 limitspec = ui.configlist(b"perf", b"run-limits", [])
463 limits = []
463 limits = []
464 for item in limitspec:
464 for item in limitspec:
465 parts = item.split(b'-', 1)
465 parts = item.split(b'-', 1)
466 if len(parts) < 2:
466 if len(parts) < 2:
467 ui.warn((b'malformatted run limit entry, missing "-": %s\n' % item))
467 ui.warn((b'malformatted run limit entry, missing "-": %s\n' % item))
468 continue
468 continue
469 try:
469 try:
470 time_limit = float(_sysstr(parts[0]))
470 time_limit = float(_sysstr(parts[0]))
471 except ValueError as e:
471 except ValueError as e:
472 ui.warn(
472 ui.warn(
473 (
473 (
474 b'malformatted run limit entry, %s: %s\n'
474 b'malformatted run limit entry, %s: %s\n'
475 % (_bytestr(e), item)
475 % (_bytestr(e), item)
476 )
476 )
477 )
477 )
478 continue
478 continue
479 try:
479 try:
480 run_limit = int(_sysstr(parts[1]))
480 run_limit = int(_sysstr(parts[1]))
481 except ValueError as e:
481 except ValueError as e:
482 ui.warn(
482 ui.warn(
483 (
483 (
484 b'malformatted run limit entry, %s: %s\n'
484 b'malformatted run limit entry, %s: %s\n'
485 % (_bytestr(e), item)
485 % (_bytestr(e), item)
486 )
486 )
487 )
487 )
488 continue
488 continue
489 limits.append((time_limit, run_limit))
489 limits.append((time_limit, run_limit))
490 if not limits:
490 if not limits:
491 limits = DEFAULTLIMITS
491 limits = DEFAULTLIMITS
492
492
493 profiler = None
493 profiler = None
494 if profiling is not None:
494 if profiling is not None:
495 if ui.configbool(b"perf", b"profile-benchmark", False):
495 if ui.configbool(b"perf", b"profile-benchmark", False):
496 profiler = profiling.profile(ui)
496 profiler = profiling.profile(ui)
497
497
498 prerun = getint(ui, b"perf", b"pre-run", 0)
498 prerun = getint(ui, b"perf", b"pre-run", 0)
499 t = functools.partial(
499 t = functools.partial(
500 _timer,
500 _timer,
501 fm,
501 fm,
502 displayall=displayall,
502 displayall=displayall,
503 limits=limits,
503 limits=limits,
504 prerun=prerun,
504 prerun=prerun,
505 profiler=profiler,
505 profiler=profiler,
506 )
506 )
507 return t, fm
507 return t, fm
508
508
509
509
510 def stub_timer(fm, func, setup=None, title=None):
510 def stub_timer(fm, func, setup=None, title=None):
511 if setup is not None:
511 if setup is not None:
512 setup()
512 setup()
513 func()
513 func()
514
514
515
515
516 @contextlib.contextmanager
516 @contextlib.contextmanager
517 def timeone():
517 def timeone():
518 r = []
518 r = []
519 ostart = os.times()
519 ostart = os.times()
520 cstart = util.timer()
520 cstart = util.timer()
521 yield r
521 yield r
522 cstop = util.timer()
522 cstop = util.timer()
523 ostop = os.times()
523 ostop = os.times()
524 a, b = ostart, ostop
524 a, b = ostart, ostop
525 r.append((cstop - cstart, b[0] - a[0], b[1] - a[1]))
525 r.append((cstop - cstart, b[0] - a[0], b[1] - a[1]))
526
526
527
527
528 # list of stop condition (elapsed time, minimal run count)
528 # list of stop condition (elapsed time, minimal run count)
529 DEFAULTLIMITS = (
529 DEFAULTLIMITS = (
530 (3.0, 100),
530 (3.0, 100),
531 (10.0, 3),
531 (10.0, 3),
532 )
532 )
533
533
534
534
535 @contextlib.contextmanager
535 @contextlib.contextmanager
536 def noop_context():
536 def noop_context():
537 yield
537 yield
538
538
539
539
540 def _timer(
540 def _timer(
541 fm,
541 fm,
542 func,
542 func,
543 setup=None,
543 setup=None,
544 context=noop_context,
544 context=noop_context,
545 title=None,
545 title=None,
546 displayall=False,
546 displayall=False,
547 limits=DEFAULTLIMITS,
547 limits=DEFAULTLIMITS,
548 prerun=0,
548 prerun=0,
549 profiler=None,
549 profiler=None,
550 ):
550 ):
551 gc.collect()
551 gc.collect()
552 results = []
552 results = []
553 begin = util.timer()
553 begin = util.timer()
554 count = 0
554 count = 0
555 if profiler is None:
555 if profiler is None:
556 profiler = NOOPCTX
556 profiler = NOOPCTX
557 for i in range(prerun):
557 for i in range(prerun):
558 if setup is not None:
558 if setup is not None:
559 setup()
559 setup()
560 with context():
560 with context():
561 func()
561 func()
562 keepgoing = True
562 keepgoing = True
563 while keepgoing:
563 while keepgoing:
564 if setup is not None:
564 if setup is not None:
565 setup()
565 setup()
566 with context():
566 with context():
567 with profiler:
567 with profiler:
568 with timeone() as item:
568 with timeone() as item:
569 r = func()
569 r = func()
570 profiler = NOOPCTX
570 profiler = NOOPCTX
571 count += 1
571 count += 1
572 results.append(item[0])
572 results.append(item[0])
573 cstop = util.timer()
573 cstop = util.timer()
574 # Look for a stop condition.
574 # Look for a stop condition.
575 elapsed = cstop - begin
575 elapsed = cstop - begin
576 for t, mincount in limits:
576 for t, mincount in limits:
577 if elapsed >= t and count >= mincount:
577 if elapsed >= t and count >= mincount:
578 keepgoing = False
578 keepgoing = False
579 break
579 break
580
580
581 formatone(fm, results, title=title, result=r, displayall=displayall)
581 formatone(fm, results, title=title, result=r, displayall=displayall)
582
582
583
583
584 def formatone(fm, timings, title=None, result=None, displayall=False):
584 def formatone(fm, timings, title=None, result=None, displayall=False):
585 count = len(timings)
585 count = len(timings)
586
586
587 fm.startitem()
587 fm.startitem()
588
588
589 if title:
589 if title:
590 fm.write(b'title', b'! %s\n', title)
590 fm.write(b'title', b'! %s\n', title)
591 if result:
591 if result:
592 fm.write(b'result', b'! result: %s\n', result)
592 fm.write(b'result', b'! result: %s\n', result)
593
593
594 def display(role, entry):
594 def display(role, entry):
595 prefix = b''
595 prefix = b''
596 if role != b'best':
596 if role != b'best':
597 prefix = b'%s.' % role
597 prefix = b'%s.' % role
598 fm.plain(b'!')
598 fm.plain(b'!')
599 fm.write(prefix + b'wall', b' wall %f', entry[0])
599 fm.write(prefix + b'wall', b' wall %f', entry[0])
600 fm.write(prefix + b'comb', b' comb %f', entry[1] + entry[2])
600 fm.write(prefix + b'comb', b' comb %f', entry[1] + entry[2])
601 fm.write(prefix + b'user', b' user %f', entry[1])
601 fm.write(prefix + b'user', b' user %f', entry[1])
602 fm.write(prefix + b'sys', b' sys %f', entry[2])
602 fm.write(prefix + b'sys', b' sys %f', entry[2])
603 fm.write(prefix + b'count', b' (%s of %%d)' % role, count)
603 fm.write(prefix + b'count', b' (%s of %%d)' % role, count)
604 fm.plain(b'\n')
604 fm.plain(b'\n')
605
605
606 timings.sort()
606 timings.sort()
607 min_val = timings[0]
607 min_val = timings[0]
608 display(b'best', min_val)
608 display(b'best', min_val)
609 if displayall:
609 if displayall:
610 max_val = timings[-1]
610 max_val = timings[-1]
611 display(b'max', max_val)
611 display(b'max', max_val)
612 avg = tuple([sum(x) / count for x in zip(*timings)])
612 avg = tuple([sum(x) / count for x in zip(*timings)])
613 display(b'avg', avg)
613 display(b'avg', avg)
614 median = timings[len(timings) // 2]
614 median = timings[len(timings) // 2]
615 display(b'median', median)
615 display(b'median', median)
616
616
617
617
618 # utilities for historical portability
618 # utilities for historical portability
619
619
620
620
621 def getint(ui, section, name, default):
621 def getint(ui, section, name, default):
622 # for "historical portability":
622 # for "historical portability":
623 # ui.configint has been available since 1.9 (or fa2b596db182)
623 # ui.configint has been available since 1.9 (or fa2b596db182)
624 v = ui.config(section, name, None)
624 v = ui.config(section, name, None)
625 if v is None:
625 if v is None:
626 return default
626 return default
627 try:
627 try:
628 return int(v)
628 return int(v)
629 except ValueError:
629 except ValueError:
630 raise error.ConfigError(
630 raise error.ConfigError(
631 b"%s.%s is not an integer ('%s')" % (section, name, v)
631 b"%s.%s is not an integer ('%s')" % (section, name, v)
632 )
632 )
633
633
634
634
635 def safeattrsetter(obj, name, ignoremissing=False):
635 def safeattrsetter(obj, name, ignoremissing=False):
636 """Ensure that 'obj' has 'name' attribute before subsequent setattr
636 """Ensure that 'obj' has 'name' attribute before subsequent setattr
637
637
638 This function is aborted, if 'obj' doesn't have 'name' attribute
638 This function is aborted, if 'obj' doesn't have 'name' attribute
639 at runtime. This avoids overlooking removal of an attribute, which
639 at runtime. This avoids overlooking removal of an attribute, which
640 breaks assumption of performance measurement, in the future.
640 breaks assumption of performance measurement, in the future.
641
641
642 This function returns the object to (1) assign a new value, and
642 This function returns the object to (1) assign a new value, and
643 (2) restore an original value to the attribute.
643 (2) restore an original value to the attribute.
644
644
645 If 'ignoremissing' is true, missing 'name' attribute doesn't cause
645 If 'ignoremissing' is true, missing 'name' attribute doesn't cause
646 abortion, and this function returns None. This is useful to
646 abortion, and this function returns None. This is useful to
647 examine an attribute, which isn't ensured in all Mercurial
647 examine an attribute, which isn't ensured in all Mercurial
648 versions.
648 versions.
649 """
649 """
650 if not util.safehasattr(obj, name):
650 if not util.safehasattr(obj, name):
651 if ignoremissing:
651 if ignoremissing:
652 return None
652 return None
653 raise error.Abort(
653 raise error.Abort(
654 (
654 (
655 b"missing attribute %s of %s might break assumption"
655 b"missing attribute %s of %s might break assumption"
656 b" of performance measurement"
656 b" of performance measurement"
657 )
657 )
658 % (name, obj)
658 % (name, obj)
659 )
659 )
660
660
661 origvalue = getattr(obj, _sysstr(name))
661 origvalue = getattr(obj, _sysstr(name))
662
662
663 class attrutil:
663 class attrutil:
664 def set(self, newvalue):
664 def set(self, newvalue):
665 setattr(obj, _sysstr(name), newvalue)
665 setattr(obj, _sysstr(name), newvalue)
666
666
667 def restore(self):
667 def restore(self):
668 setattr(obj, _sysstr(name), origvalue)
668 setattr(obj, _sysstr(name), origvalue)
669
669
670 return attrutil()
670 return attrutil()
671
671
672
672
673 # utilities to examine each internal API changes
673 # utilities to examine each internal API changes
674
674
675
675
676 def getbranchmapsubsettable():
676 def getbranchmapsubsettable():
677 # for "historical portability":
677 # for "historical portability":
678 # subsettable is defined in:
678 # subsettable is defined in:
679 # - branchmap since 2.9 (or 175c6fd8cacc)
679 # - branchmap since 2.9 (or 175c6fd8cacc)
680 # - repoview since 2.5 (or 59a9f18d4587)
680 # - repoview since 2.5 (or 59a9f18d4587)
681 # - repoviewutil since 5.0
681 # - repoviewutil since 5.0
682 for mod in (branchmap, repoview, repoviewutil):
682 for mod in (branchmap, repoview, repoviewutil):
683 subsettable = getattr(mod, 'subsettable', None)
683 subsettable = getattr(mod, 'subsettable', None)
684 if subsettable:
684 if subsettable:
685 return subsettable
685 return subsettable
686
686
687 # bisecting in bcee63733aad::59a9f18d4587 can reach here (both
687 # bisecting in bcee63733aad::59a9f18d4587 can reach here (both
688 # branchmap and repoview modules exist, but subsettable attribute
688 # branchmap and repoview modules exist, but subsettable attribute
689 # doesn't)
689 # doesn't)
690 raise error.Abort(
690 raise error.Abort(
691 b"perfbranchmap not available with this Mercurial",
691 b"perfbranchmap not available with this Mercurial",
692 hint=b"use 2.5 or later",
692 hint=b"use 2.5 or later",
693 )
693 )
694
694
695
695
696 def getsvfs(repo):
696 def getsvfs(repo):
697 """Return appropriate object to access files under .hg/store"""
697 """Return appropriate object to access files under .hg/store"""
698 # for "historical portability":
698 # for "historical portability":
699 # repo.svfs has been available since 2.3 (or 7034365089bf)
699 # repo.svfs has been available since 2.3 (or 7034365089bf)
700 svfs = getattr(repo, 'svfs', None)
700 svfs = getattr(repo, 'svfs', None)
701 if svfs:
701 if svfs:
702 return svfs
702 return svfs
703 else:
703 else:
704 return getattr(repo, 'sopener')
704 return getattr(repo, 'sopener')
705
705
706
706
707 def getvfs(repo):
707 def getvfs(repo):
708 """Return appropriate object to access files under .hg"""
708 """Return appropriate object to access files under .hg"""
709 # for "historical portability":
709 # for "historical portability":
710 # repo.vfs has been available since 2.3 (or 7034365089bf)
710 # repo.vfs has been available since 2.3 (or 7034365089bf)
711 vfs = getattr(repo, 'vfs', None)
711 vfs = getattr(repo, 'vfs', None)
712 if vfs:
712 if vfs:
713 return vfs
713 return vfs
714 else:
714 else:
715 return getattr(repo, 'opener')
715 return getattr(repo, 'opener')
716
716
717
717
718 def repocleartagscachefunc(repo):
718 def repocleartagscachefunc(repo):
719 """Return the function to clear tags cache according to repo internal API"""
719 """Return the function to clear tags cache according to repo internal API"""
720 if util.safehasattr(repo, b'_tagscache'): # since 2.0 (or 9dca7653b525)
720 if util.safehasattr(repo, b'_tagscache'): # since 2.0 (or 9dca7653b525)
721 # in this case, setattr(repo, '_tagscache', None) or so isn't
721 # in this case, setattr(repo, '_tagscache', None) or so isn't
722 # correct way to clear tags cache, because existing code paths
722 # correct way to clear tags cache, because existing code paths
723 # expect _tagscache to be a structured object.
723 # expect _tagscache to be a structured object.
724 def clearcache():
724 def clearcache():
725 # _tagscache has been filteredpropertycache since 2.5 (or
725 # _tagscache has been filteredpropertycache since 2.5 (or
726 # 98c867ac1330), and delattr() can't work in such case
726 # 98c867ac1330), and delattr() can't work in such case
727 if '_tagscache' in vars(repo):
727 if '_tagscache' in vars(repo):
728 del repo.__dict__['_tagscache']
728 del repo.__dict__['_tagscache']
729
729
730 return clearcache
730 return clearcache
731
731
732 repotags = safeattrsetter(repo, b'_tags', ignoremissing=True)
732 repotags = safeattrsetter(repo, b'_tags', ignoremissing=True)
733 if repotags: # since 1.4 (or 5614a628d173)
733 if repotags: # since 1.4 (or 5614a628d173)
734 return lambda: repotags.set(None)
734 return lambda: repotags.set(None)
735
735
736 repotagscache = safeattrsetter(repo, b'tagscache', ignoremissing=True)
736 repotagscache = safeattrsetter(repo, b'tagscache', ignoremissing=True)
737 if repotagscache: # since 0.6 (or d7df759d0e97)
737 if repotagscache: # since 0.6 (or d7df759d0e97)
738 return lambda: repotagscache.set(None)
738 return lambda: repotagscache.set(None)
739
739
740 # Mercurial earlier than 0.6 (or d7df759d0e97) logically reaches
740 # Mercurial earlier than 0.6 (or d7df759d0e97) logically reaches
741 # this point, but it isn't so problematic, because:
741 # this point, but it isn't so problematic, because:
742 # - repo.tags of such Mercurial isn't "callable", and repo.tags()
742 # - repo.tags of such Mercurial isn't "callable", and repo.tags()
743 # in perftags() causes failure soon
743 # in perftags() causes failure soon
744 # - perf.py itself has been available since 1.1 (or eb240755386d)
744 # - perf.py itself has been available since 1.1 (or eb240755386d)
745 raise error.Abort(b"tags API of this hg command is unknown")
745 raise error.Abort(b"tags API of this hg command is unknown")
746
746
747
747
748 # utilities to clear cache
748 # utilities to clear cache
749
749
750
750
751 def clearfilecache(obj, attrname):
751 def clearfilecache(obj, attrname):
752 unfiltered = getattr(obj, 'unfiltered', None)
752 unfiltered = getattr(obj, 'unfiltered', None)
753 if unfiltered is not None:
753 if unfiltered is not None:
754 obj = obj.unfiltered()
754 obj = obj.unfiltered()
755 if attrname in vars(obj):
755 if attrname in vars(obj):
756 delattr(obj, attrname)
756 delattr(obj, attrname)
757 obj._filecache.pop(attrname, None)
757 obj._filecache.pop(attrname, None)
758
758
759
759
760 def clearchangelog(repo):
760 def clearchangelog(repo):
761 if repo is not repo.unfiltered():
761 if repo is not repo.unfiltered():
762 object.__setattr__(repo, '_clcachekey', None)
762 object.__setattr__(repo, '_clcachekey', None)
763 object.__setattr__(repo, '_clcache', None)
763 object.__setattr__(repo, '_clcache', None)
764 clearfilecache(repo.unfiltered(), 'changelog')
764 clearfilecache(repo.unfiltered(), 'changelog')
765
765
766
766
767 # perf commands
767 # perf commands
768
768
769
769
770 @command(b'perf::walk|perfwalk', formatteropts)
770 @command(b'perf::walk|perfwalk', formatteropts)
771 def perfwalk(ui, repo, *pats, **opts):
771 def perfwalk(ui, repo, *pats, **opts):
772 opts = _byteskwargs(opts)
772 opts = _byteskwargs(opts)
773 timer, fm = gettimer(ui, opts)
773 timer, fm = gettimer(ui, opts)
774 m = scmutil.match(repo[None], pats, {})
774 m = scmutil.match(repo[None], pats, {})
775 timer(
775 timer(
776 lambda: len(
776 lambda: len(
777 list(
777 list(
778 repo.dirstate.walk(m, subrepos=[], unknown=True, ignored=False)
778 repo.dirstate.walk(m, subrepos=[], unknown=True, ignored=False)
779 )
779 )
780 )
780 )
781 )
781 )
782 fm.end()
782 fm.end()
783
783
784
784
785 @command(b'perf::annotate|perfannotate', formatteropts)
785 @command(b'perf::annotate|perfannotate', formatteropts)
786 def perfannotate(ui, repo, f, **opts):
786 def perfannotate(ui, repo, f, **opts):
787 opts = _byteskwargs(opts)
787 opts = _byteskwargs(opts)
788 timer, fm = gettimer(ui, opts)
788 timer, fm = gettimer(ui, opts)
789 fc = repo[b'.'][f]
789 fc = repo[b'.'][f]
790 timer(lambda: len(fc.annotate(True)))
790 timer(lambda: len(fc.annotate(True)))
791 fm.end()
791 fm.end()
792
792
793
793
794 @command(
794 @command(
795 b'perf::status|perfstatus',
795 b'perf::status|perfstatus',
796 [
796 [
797 (b'u', b'unknown', False, b'ask status to look for unknown files'),
797 (b'u', b'unknown', False, b'ask status to look for unknown files'),
798 (b'', b'dirstate', False, b'benchmark the internal dirstate call'),
798 (b'', b'dirstate', False, b'benchmark the internal dirstate call'),
799 ]
799 ]
800 + formatteropts,
800 + formatteropts,
801 )
801 )
802 def perfstatus(ui, repo, **opts):
802 def perfstatus(ui, repo, **opts):
803 """benchmark the performance of a single status call
803 """benchmark the performance of a single status call
804
804
805 The repository data are preserved between each call.
805 The repository data are preserved between each call.
806
806
807 By default, only the status of the tracked file are requested. If
807 By default, only the status of the tracked file are requested. If
808 `--unknown` is passed, the "unknown" files are also tracked.
808 `--unknown` is passed, the "unknown" files are also tracked.
809 """
809 """
810 opts = _byteskwargs(opts)
810 opts = _byteskwargs(opts)
811 # m = match.always(repo.root, repo.getcwd())
811 # m = match.always(repo.root, repo.getcwd())
812 # timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
812 # timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
813 # False))))
813 # False))))
814 timer, fm = gettimer(ui, opts)
814 timer, fm = gettimer(ui, opts)
815 if opts[b'dirstate']:
815 if opts[b'dirstate']:
816 dirstate = repo.dirstate
816 dirstate = repo.dirstate
817 m = scmutil.matchall(repo)
817 m = scmutil.matchall(repo)
818 unknown = opts[b'unknown']
818 unknown = opts[b'unknown']
819
819
820 def status_dirstate():
820 def status_dirstate():
821 s = dirstate.status(
821 s = dirstate.status(
822 m, subrepos=[], ignored=False, clean=False, unknown=unknown
822 m, subrepos=[], ignored=False, clean=False, unknown=unknown
823 )
823 )
824 sum(map(bool, s))
824 sum(map(bool, s))
825
825
826 if util.safehasattr(dirstate, 'running_status'):
826 if util.safehasattr(dirstate, 'running_status'):
827 with dirstate.running_status(repo):
827 with dirstate.running_status(repo):
828 timer(status_dirstate)
828 timer(status_dirstate)
829 dirstate.invalidate()
829 dirstate.invalidate()
830 else:
830 else:
831 timer(status_dirstate)
831 timer(status_dirstate)
832 else:
832 else:
833 timer(lambda: sum(map(len, repo.status(unknown=opts[b'unknown']))))
833 timer(lambda: sum(map(len, repo.status(unknown=opts[b'unknown']))))
834 fm.end()
834 fm.end()
835
835
836
836
837 @command(b'perf::addremove|perfaddremove', formatteropts)
837 @command(b'perf::addremove|perfaddremove', formatteropts)
838 def perfaddremove(ui, repo, **opts):
838 def perfaddremove(ui, repo, **opts):
839 opts = _byteskwargs(opts)
839 opts = _byteskwargs(opts)
840 timer, fm = gettimer(ui, opts)
840 timer, fm = gettimer(ui, opts)
841 try:
841 try:
842 oldquiet = repo.ui.quiet
842 oldquiet = repo.ui.quiet
843 repo.ui.quiet = True
843 repo.ui.quiet = True
844 matcher = scmutil.match(repo[None])
844 matcher = scmutil.match(repo[None])
845 opts[b'dry_run'] = True
845 opts[b'dry_run'] = True
846 if 'uipathfn' in getargspec(scmutil.addremove).args:
846 if 'uipathfn' in getargspec(scmutil.addremove).args:
847 uipathfn = scmutil.getuipathfn(repo)
847 uipathfn = scmutil.getuipathfn(repo)
848 timer(lambda: scmutil.addremove(repo, matcher, b"", uipathfn, opts))
848 timer(lambda: scmutil.addremove(repo, matcher, b"", uipathfn, opts))
849 else:
849 else:
850 timer(lambda: scmutil.addremove(repo, matcher, b"", opts))
850 timer(lambda: scmutil.addremove(repo, matcher, b"", opts))
851 finally:
851 finally:
852 repo.ui.quiet = oldquiet
852 repo.ui.quiet = oldquiet
853 fm.end()
853 fm.end()
854
854
855
855
856 def clearcaches(cl):
856 def clearcaches(cl):
857 # behave somewhat consistently across internal API changes
857 # behave somewhat consistently across internal API changes
858 if util.safehasattr(cl, b'clearcaches'):
858 if util.safehasattr(cl, b'clearcaches'):
859 cl.clearcaches()
859 cl.clearcaches()
860 elif util.safehasattr(cl, b'_nodecache'):
860 elif util.safehasattr(cl, b'_nodecache'):
861 # <= hg-5.2
861 # <= hg-5.2
862 from mercurial.node import nullid, nullrev
862 from mercurial.node import nullid, nullrev
863
863
864 cl._nodecache = {nullid: nullrev}
864 cl._nodecache = {nullid: nullrev}
865 cl._nodepos = None
865 cl._nodepos = None
866
866
867
867
868 @command(b'perf::heads|perfheads', formatteropts)
868 @command(b'perf::heads|perfheads', formatteropts)
869 def perfheads(ui, repo, **opts):
869 def perfheads(ui, repo, **opts):
870 """benchmark the computation of a changelog heads"""
870 """benchmark the computation of a changelog heads"""
871 opts = _byteskwargs(opts)
871 opts = _byteskwargs(opts)
872 timer, fm = gettimer(ui, opts)
872 timer, fm = gettimer(ui, opts)
873 cl = repo.changelog
873 cl = repo.changelog
874
874
875 def s():
875 def s():
876 clearcaches(cl)
876 clearcaches(cl)
877
877
878 def d():
878 def d():
879 len(cl.headrevs())
879 len(cl.headrevs())
880
880
881 timer(d, setup=s)
881 timer(d, setup=s)
882 fm.end()
882 fm.end()
883
883
884
884
885 @command(
885 @command(
886 b'perf::tags|perftags',
886 b'perf::tags|perftags',
887 formatteropts
887 formatteropts
888 + [
888 + [
889 (b'', b'clear-revlogs', False, b'refresh changelog and manifest'),
889 (b'', b'clear-revlogs', False, b'refresh changelog and manifest'),
890 ],
890 ],
891 )
891 )
892 def perftags(ui, repo, **opts):
892 def perftags(ui, repo, **opts):
893 opts = _byteskwargs(opts)
893 opts = _byteskwargs(opts)
894 timer, fm = gettimer(ui, opts)
894 timer, fm = gettimer(ui, opts)
895 repocleartagscache = repocleartagscachefunc(repo)
895 repocleartagscache = repocleartagscachefunc(repo)
896 clearrevlogs = opts[b'clear_revlogs']
896 clearrevlogs = opts[b'clear_revlogs']
897
897
898 def s():
898 def s():
899 if clearrevlogs:
899 if clearrevlogs:
900 clearchangelog(repo)
900 clearchangelog(repo)
901 clearfilecache(repo.unfiltered(), 'manifest')
901 clearfilecache(repo.unfiltered(), 'manifest')
902 repocleartagscache()
902 repocleartagscache()
903
903
904 def t():
904 def t():
905 return len(repo.tags())
905 len(repo.tags())
906
906
907 timer(t, setup=s)
907 timer(t, setup=s)
908 fm.end()
908 fm.end()
909
909
910
910
911 @command(b'perf::ancestors|perfancestors', formatteropts)
911 @command(b'perf::ancestors|perfancestors', formatteropts)
912 def perfancestors(ui, repo, **opts):
912 def perfancestors(ui, repo, **opts):
913 opts = _byteskwargs(opts)
913 opts = _byteskwargs(opts)
914 timer, fm = gettimer(ui, opts)
914 timer, fm = gettimer(ui, opts)
915 heads = repo.changelog.headrevs()
915 heads = repo.changelog.headrevs()
916
916
917 def d():
917 def d():
918 for a in repo.changelog.ancestors(heads):
918 for a in repo.changelog.ancestors(heads):
919 pass
919 pass
920
920
921 timer(d)
921 timer(d)
922 fm.end()
922 fm.end()
923
923
924
924
925 @command(b'perf::ancestorset|perfancestorset', formatteropts)
925 @command(b'perf::ancestorset|perfancestorset', formatteropts)
926 def perfancestorset(ui, repo, revset, **opts):
926 def perfancestorset(ui, repo, revset, **opts):
927 opts = _byteskwargs(opts)
927 opts = _byteskwargs(opts)
928 timer, fm = gettimer(ui, opts)
928 timer, fm = gettimer(ui, opts)
929 revs = repo.revs(revset)
929 revs = repo.revs(revset)
930 heads = repo.changelog.headrevs()
930 heads = repo.changelog.headrevs()
931
931
932 def d():
932 def d():
933 s = repo.changelog.ancestors(heads)
933 s = repo.changelog.ancestors(heads)
934 for rev in revs:
934 for rev in revs:
935 rev in s
935 rev in s
936
936
937 timer(d)
937 timer(d)
938 fm.end()
938 fm.end()
939
939
940
940
941 @command(
941 @command(
942 b'perf::delta-find',
942 b'perf::delta-find',
943 revlogopts + formatteropts,
943 revlogopts + formatteropts,
944 b'-c|-m|FILE REV',
944 b'-c|-m|FILE REV',
945 )
945 )
946 def perf_delta_find(ui, repo, arg_1, arg_2=None, **opts):
946 def perf_delta_find(ui, repo, arg_1, arg_2=None, **opts):
947 """benchmark the process of finding a valid delta for a revlog revision
947 """benchmark the process of finding a valid delta for a revlog revision
948
948
949 When a revlog receives a new revision (e.g. from a commit, or from an
949 When a revlog receives a new revision (e.g. from a commit, or from an
950 incoming bundle), it searches for a suitable delta-base to produce a delta.
950 incoming bundle), it searches for a suitable delta-base to produce a delta.
951 This perf command measures how much time we spend in this process. It
951 This perf command measures how much time we spend in this process. It
952 operates on an already stored revision.
952 operates on an already stored revision.
953
953
954 See `hg help debug-delta-find` for another related command.
954 See `hg help debug-delta-find` for another related command.
955 """
955 """
956 from mercurial import revlogutils
956 from mercurial import revlogutils
957 import mercurial.revlogutils.deltas as deltautil
957 import mercurial.revlogutils.deltas as deltautil
958
958
959 opts = _byteskwargs(opts)
959 opts = _byteskwargs(opts)
960 if arg_2 is None:
960 if arg_2 is None:
961 file_ = None
961 file_ = None
962 rev = arg_1
962 rev = arg_1
963 else:
963 else:
964 file_ = arg_1
964 file_ = arg_1
965 rev = arg_2
965 rev = arg_2
966
966
967 repo = repo.unfiltered()
967 repo = repo.unfiltered()
968
968
969 timer, fm = gettimer(ui, opts)
969 timer, fm = gettimer(ui, opts)
970
970
971 rev = int(rev)
971 rev = int(rev)
972
972
973 revlog = cmdutil.openrevlog(repo, b'perf::delta-find', file_, opts)
973 revlog = cmdutil.openrevlog(repo, b'perf::delta-find', file_, opts)
974
974
975 deltacomputer = deltautil.deltacomputer(revlog)
975 deltacomputer = deltautil.deltacomputer(revlog)
976
976
977 node = revlog.node(rev)
977 node = revlog.node(rev)
978 p1r, p2r = revlog.parentrevs(rev)
978 p1r, p2r = revlog.parentrevs(rev)
979 p1 = revlog.node(p1r)
979 p1 = revlog.node(p1r)
980 p2 = revlog.node(p2r)
980 p2 = revlog.node(p2r)
981 full_text = revlog.revision(rev)
981 full_text = revlog.revision(rev)
982 textlen = len(full_text)
982 textlen = len(full_text)
983 cachedelta = None
983 cachedelta = None
984 flags = revlog.flags(rev)
984 flags = revlog.flags(rev)
985
985
986 revinfo = revlogutils.revisioninfo(
986 revinfo = revlogutils.revisioninfo(
987 node,
987 node,
988 p1,
988 p1,
989 p2,
989 p2,
990 [full_text], # btext
990 [full_text], # btext
991 textlen,
991 textlen,
992 cachedelta,
992 cachedelta,
993 flags,
993 flags,
994 )
994 )
995
995
996 # Note: we should probably purge the potential caches (like the full
996 # Note: we should probably purge the potential caches (like the full
997 # manifest cache) between runs.
997 # manifest cache) between runs.
998 def find_one():
998 def find_one():
999 with revlog._datafp() as fh:
999 with revlog._datafp() as fh:
1000 deltacomputer.finddeltainfo(revinfo, fh, target_rev=rev)
1000 deltacomputer.finddeltainfo(revinfo, fh, target_rev=rev)
1001
1001
1002 timer(find_one)
1002 timer(find_one)
1003 fm.end()
1003 fm.end()
1004
1004
1005
1005
1006 @command(b'perf::discovery|perfdiscovery', formatteropts, b'PATH')
1006 @command(b'perf::discovery|perfdiscovery', formatteropts, b'PATH')
1007 def perfdiscovery(ui, repo, path, **opts):
1007 def perfdiscovery(ui, repo, path, **opts):
1008 """benchmark discovery between local repo and the peer at given path"""
1008 """benchmark discovery between local repo and the peer at given path"""
1009 repos = [repo, None]
1009 repos = [repo, None]
1010 timer, fm = gettimer(ui, opts)
1010 timer, fm = gettimer(ui, opts)
1011
1011
1012 try:
1012 try:
1013 from mercurial.utils.urlutil import get_unique_pull_path_obj
1013 from mercurial.utils.urlutil import get_unique_pull_path_obj
1014
1014
1015 path = get_unique_pull_path_obj(b'perfdiscovery', ui, path)
1015 path = get_unique_pull_path_obj(b'perfdiscovery', ui, path)
1016 except ImportError:
1016 except ImportError:
1017 try:
1017 try:
1018 from mercurial.utils.urlutil import get_unique_pull_path
1018 from mercurial.utils.urlutil import get_unique_pull_path
1019
1019
1020 path = get_unique_pull_path(b'perfdiscovery', repo, ui, path)[0]
1020 path = get_unique_pull_path(b'perfdiscovery', repo, ui, path)[0]
1021 except ImportError:
1021 except ImportError:
1022 path = ui.expandpath(path)
1022 path = ui.expandpath(path)
1023
1023
1024 def s():
1024 def s():
1025 repos[1] = hg.peer(ui, opts, path)
1025 repos[1] = hg.peer(ui, opts, path)
1026
1026
1027 def d():
1027 def d():
1028 setdiscovery.findcommonheads(ui, *repos)
1028 setdiscovery.findcommonheads(ui, *repos)
1029
1029
1030 timer(d, setup=s)
1030 timer(d, setup=s)
1031 fm.end()
1031 fm.end()
1032
1032
1033
1033
1034 @command(
1034 @command(
1035 b'perf::bookmarks|perfbookmarks',
1035 b'perf::bookmarks|perfbookmarks',
1036 formatteropts
1036 formatteropts
1037 + [
1037 + [
1038 (b'', b'clear-revlogs', False, b'refresh changelog and manifest'),
1038 (b'', b'clear-revlogs', False, b'refresh changelog and manifest'),
1039 ],
1039 ],
1040 )
1040 )
1041 def perfbookmarks(ui, repo, **opts):
1041 def perfbookmarks(ui, repo, **opts):
1042 """benchmark parsing bookmarks from disk to memory"""
1042 """benchmark parsing bookmarks from disk to memory"""
1043 opts = _byteskwargs(opts)
1043 opts = _byteskwargs(opts)
1044 timer, fm = gettimer(ui, opts)
1044 timer, fm = gettimer(ui, opts)
1045
1045
1046 clearrevlogs = opts[b'clear_revlogs']
1046 clearrevlogs = opts[b'clear_revlogs']
1047
1047
1048 def s():
1048 def s():
1049 if clearrevlogs:
1049 if clearrevlogs:
1050 clearchangelog(repo)
1050 clearchangelog(repo)
1051 clearfilecache(repo, b'_bookmarks')
1051 clearfilecache(repo, b'_bookmarks')
1052
1052
1053 def d():
1053 def d():
1054 repo._bookmarks
1054 repo._bookmarks
1055
1055
1056 timer(d, setup=s)
1056 timer(d, setup=s)
1057 fm.end()
1057 fm.end()
1058
1058
1059
1059
1060 @command(
1060 @command(
1061 b'perf::bundle',
1061 b'perf::bundle',
1062 [
1062 [
1063 (
1063 (
1064 b'r',
1064 b'r',
1065 b'rev',
1065 b'rev',
1066 [],
1066 [],
1067 b'changesets to bundle',
1067 b'changesets to bundle',
1068 b'REV',
1068 b'REV',
1069 ),
1069 ),
1070 (
1070 (
1071 b't',
1071 b't',
1072 b'type',
1072 b'type',
1073 b'none',
1073 b'none',
1074 b'bundlespec to use (see `hg help bundlespec`)',
1074 b'bundlespec to use (see `hg help bundlespec`)',
1075 b'TYPE',
1075 b'TYPE',
1076 ),
1076 ),
1077 ]
1077 ]
1078 + formatteropts,
1078 + formatteropts,
1079 b'REVS',
1079 b'REVS',
1080 )
1080 )
1081 def perfbundle(ui, repo, *revs, **opts):
1081 def perfbundle(ui, repo, *revs, **opts):
1082 """benchmark the creation of a bundle from a repository
1082 """benchmark the creation of a bundle from a repository
1083
1083
1084 For now, this only supports "none" compression.
1084 For now, this only supports "none" compression.
1085 """
1085 """
1086 try:
1086 try:
1087 from mercurial import bundlecaches
1087 from mercurial import bundlecaches
1088
1088
1089 parsebundlespec = bundlecaches.parsebundlespec
1089 parsebundlespec = bundlecaches.parsebundlespec
1090 except ImportError:
1090 except ImportError:
1091 from mercurial import exchange
1091 from mercurial import exchange
1092
1092
1093 parsebundlespec = exchange.parsebundlespec
1093 parsebundlespec = exchange.parsebundlespec
1094
1094
1095 from mercurial import discovery
1095 from mercurial import discovery
1096 from mercurial import bundle2
1096 from mercurial import bundle2
1097
1097
1098 opts = _byteskwargs(opts)
1098 opts = _byteskwargs(opts)
1099 timer, fm = gettimer(ui, opts)
1099 timer, fm = gettimer(ui, opts)
1100
1100
1101 cl = repo.changelog
1101 cl = repo.changelog
1102 revs = list(revs)
1102 revs = list(revs)
1103 revs.extend(opts.get(b'rev', ()))
1103 revs.extend(opts.get(b'rev', ()))
1104 revs = scmutil.revrange(repo, revs)
1104 revs = scmutil.revrange(repo, revs)
1105 if not revs:
1105 if not revs:
1106 raise error.Abort(b"not revision specified")
1106 raise error.Abort(b"not revision specified")
1107 # make it a consistent set (ie: without topological gaps)
1107 # make it a consistent set (ie: without topological gaps)
1108 old_len = len(revs)
1108 old_len = len(revs)
1109 revs = list(repo.revs(b"%ld::%ld", revs, revs))
1109 revs = list(repo.revs(b"%ld::%ld", revs, revs))
1110 if old_len != len(revs):
1110 if old_len != len(revs):
1111 new_count = len(revs) - old_len
1111 new_count = len(revs) - old_len
1112 msg = b"add %d new revisions to make it a consistent set\n"
1112 msg = b"add %d new revisions to make it a consistent set\n"
1113 ui.write_err(msg % new_count)
1113 ui.write_err(msg % new_count)
1114
1114
1115 targets = [cl.node(r) for r in repo.revs(b"heads(::%ld)", revs)]
1115 targets = [cl.node(r) for r in repo.revs(b"heads(::%ld)", revs)]
1116 bases = [cl.node(r) for r in repo.revs(b"heads(::%ld - %ld)", revs, revs)]
1116 bases = [cl.node(r) for r in repo.revs(b"heads(::%ld - %ld)", revs, revs)]
1117 outgoing = discovery.outgoing(repo, bases, targets)
1117 outgoing = discovery.outgoing(repo, bases, targets)
1118
1118
1119 bundle_spec = opts.get(b'type')
1119 bundle_spec = opts.get(b'type')
1120
1120
1121 bundle_spec = parsebundlespec(repo, bundle_spec, strict=False)
1121 bundle_spec = parsebundlespec(repo, bundle_spec, strict=False)
1122
1122
1123 cgversion = bundle_spec.params.get(b"cg.version")
1123 cgversion = bundle_spec.params.get(b"cg.version")
1124 if cgversion is None:
1124 if cgversion is None:
1125 if bundle_spec.version == b'v1':
1125 if bundle_spec.version == b'v1':
1126 cgversion = b'01'
1126 cgversion = b'01'
1127 if bundle_spec.version == b'v2':
1127 if bundle_spec.version == b'v2':
1128 cgversion = b'02'
1128 cgversion = b'02'
1129 if cgversion not in changegroup.supportedoutgoingversions(repo):
1129 if cgversion not in changegroup.supportedoutgoingversions(repo):
1130 err = b"repository does not support bundle version %s"
1130 err = b"repository does not support bundle version %s"
1131 raise error.Abort(err % cgversion)
1131 raise error.Abort(err % cgversion)
1132
1132
1133 if cgversion == b'01': # bundle1
1133 if cgversion == b'01': # bundle1
1134 bversion = b'HG10' + bundle_spec.wirecompression
1134 bversion = b'HG10' + bundle_spec.wirecompression
1135 bcompression = None
1135 bcompression = None
1136 elif cgversion in (b'02', b'03'):
1136 elif cgversion in (b'02', b'03'):
1137 bversion = b'HG20'
1137 bversion = b'HG20'
1138 bcompression = bundle_spec.wirecompression
1138 bcompression = bundle_spec.wirecompression
1139 else:
1139 else:
1140 err = b'perf::bundle: unexpected changegroup version %s'
1140 err = b'perf::bundle: unexpected changegroup version %s'
1141 raise error.ProgrammingError(err % cgversion)
1141 raise error.ProgrammingError(err % cgversion)
1142
1142
1143 if bcompression is None:
1143 if bcompression is None:
1144 bcompression = b'UN'
1144 bcompression = b'UN'
1145
1145
1146 if bcompression != b'UN':
1146 if bcompression != b'UN':
1147 err = b'perf::bundle: compression currently unsupported: %s'
1147 err = b'perf::bundle: compression currently unsupported: %s'
1148 raise error.ProgrammingError(err % bcompression)
1148 raise error.ProgrammingError(err % bcompression)
1149
1149
1150 def do_bundle():
1150 def do_bundle():
1151 bundle2.writenewbundle(
1151 bundle2.writenewbundle(
1152 ui,
1152 ui,
1153 repo,
1153 repo,
1154 b'perf::bundle',
1154 b'perf::bundle',
1155 os.devnull,
1155 os.devnull,
1156 bversion,
1156 bversion,
1157 outgoing,
1157 outgoing,
1158 bundle_spec.params,
1158 bundle_spec.params,
1159 )
1159 )
1160
1160
1161 timer(do_bundle)
1161 timer(do_bundle)
1162 fm.end()
1162 fm.end()
1163
1163
1164
1164
1165 @command(b'perf::bundleread|perfbundleread', formatteropts, b'BUNDLE')
1165 @command(b'perf::bundleread|perfbundleread', formatteropts, b'BUNDLE')
1166 def perfbundleread(ui, repo, bundlepath, **opts):
1166 def perfbundleread(ui, repo, bundlepath, **opts):
1167 """Benchmark reading of bundle files.
1167 """Benchmark reading of bundle files.
1168
1168
1169 This command is meant to isolate the I/O part of bundle reading as
1169 This command is meant to isolate the I/O part of bundle reading as
1170 much as possible.
1170 much as possible.
1171 """
1171 """
1172 from mercurial import (
1172 from mercurial import (
1173 bundle2,
1173 bundle2,
1174 exchange,
1174 exchange,
1175 streamclone,
1175 streamclone,
1176 )
1176 )
1177
1177
1178 opts = _byteskwargs(opts)
1178 opts = _byteskwargs(opts)
1179
1179
1180 def makebench(fn):
1180 def makebench(fn):
1181 def run():
1181 def run():
1182 with open(bundlepath, b'rb') as fh:
1182 with open(bundlepath, b'rb') as fh:
1183 bundle = exchange.readbundle(ui, fh, bundlepath)
1183 bundle = exchange.readbundle(ui, fh, bundlepath)
1184 fn(bundle)
1184 fn(bundle)
1185
1185
1186 return run
1186 return run
1187
1187
1188 def makereadnbytes(size):
1188 def makereadnbytes(size):
1189 def run():
1189 def run():
1190 with open(bundlepath, b'rb') as fh:
1190 with open(bundlepath, b'rb') as fh:
1191 bundle = exchange.readbundle(ui, fh, bundlepath)
1191 bundle = exchange.readbundle(ui, fh, bundlepath)
1192 while bundle.read(size):
1192 while bundle.read(size):
1193 pass
1193 pass
1194
1194
1195 return run
1195 return run
1196
1196
1197 def makestdioread(size):
1197 def makestdioread(size):
1198 def run():
1198 def run():
1199 with open(bundlepath, b'rb') as fh:
1199 with open(bundlepath, b'rb') as fh:
1200 while fh.read(size):
1200 while fh.read(size):
1201 pass
1201 pass
1202
1202
1203 return run
1203 return run
1204
1204
1205 # bundle1
1205 # bundle1
1206
1206
1207 def deltaiter(bundle):
1207 def deltaiter(bundle):
1208 for delta in bundle.deltaiter():
1208 for delta in bundle.deltaiter():
1209 pass
1209 pass
1210
1210
1211 def iterchunks(bundle):
1211 def iterchunks(bundle):
1212 for chunk in bundle.getchunks():
1212 for chunk in bundle.getchunks():
1213 pass
1213 pass
1214
1214
1215 # bundle2
1215 # bundle2
1216
1216
1217 def forwardchunks(bundle):
1217 def forwardchunks(bundle):
1218 for chunk in bundle._forwardchunks():
1218 for chunk in bundle._forwardchunks():
1219 pass
1219 pass
1220
1220
1221 def iterparts(bundle):
1221 def iterparts(bundle):
1222 for part in bundle.iterparts():
1222 for part in bundle.iterparts():
1223 pass
1223 pass
1224
1224
1225 def iterpartsseekable(bundle):
1225 def iterpartsseekable(bundle):
1226 for part in bundle.iterparts(seekable=True):
1226 for part in bundle.iterparts(seekable=True):
1227 pass
1227 pass
1228
1228
1229 def seek(bundle):
1229 def seek(bundle):
1230 for part in bundle.iterparts(seekable=True):
1230 for part in bundle.iterparts(seekable=True):
1231 part.seek(0, os.SEEK_END)
1231 part.seek(0, os.SEEK_END)
1232
1232
1233 def makepartreadnbytes(size):
1233 def makepartreadnbytes(size):
1234 def run():
1234 def run():
1235 with open(bundlepath, b'rb') as fh:
1235 with open(bundlepath, b'rb') as fh:
1236 bundle = exchange.readbundle(ui, fh, bundlepath)
1236 bundle = exchange.readbundle(ui, fh, bundlepath)
1237 for part in bundle.iterparts():
1237 for part in bundle.iterparts():
1238 while part.read(size):
1238 while part.read(size):
1239 pass
1239 pass
1240
1240
1241 return run
1241 return run
1242
1242
1243 benches = [
1243 benches = [
1244 (makestdioread(8192), b'read(8k)'),
1244 (makestdioread(8192), b'read(8k)'),
1245 (makestdioread(16384), b'read(16k)'),
1245 (makestdioread(16384), b'read(16k)'),
1246 (makestdioread(32768), b'read(32k)'),
1246 (makestdioread(32768), b'read(32k)'),
1247 (makestdioread(131072), b'read(128k)'),
1247 (makestdioread(131072), b'read(128k)'),
1248 ]
1248 ]
1249
1249
1250 with open(bundlepath, b'rb') as fh:
1250 with open(bundlepath, b'rb') as fh:
1251 bundle = exchange.readbundle(ui, fh, bundlepath)
1251 bundle = exchange.readbundle(ui, fh, bundlepath)
1252
1252
1253 if isinstance(bundle, changegroup.cg1unpacker):
1253 if isinstance(bundle, changegroup.cg1unpacker):
1254 benches.extend(
1254 benches.extend(
1255 [
1255 [
1256 (makebench(deltaiter), b'cg1 deltaiter()'),
1256 (makebench(deltaiter), b'cg1 deltaiter()'),
1257 (makebench(iterchunks), b'cg1 getchunks()'),
1257 (makebench(iterchunks), b'cg1 getchunks()'),
1258 (makereadnbytes(8192), b'cg1 read(8k)'),
1258 (makereadnbytes(8192), b'cg1 read(8k)'),
1259 (makereadnbytes(16384), b'cg1 read(16k)'),
1259 (makereadnbytes(16384), b'cg1 read(16k)'),
1260 (makereadnbytes(32768), b'cg1 read(32k)'),
1260 (makereadnbytes(32768), b'cg1 read(32k)'),
1261 (makereadnbytes(131072), b'cg1 read(128k)'),
1261 (makereadnbytes(131072), b'cg1 read(128k)'),
1262 ]
1262 ]
1263 )
1263 )
1264 elif isinstance(bundle, bundle2.unbundle20):
1264 elif isinstance(bundle, bundle2.unbundle20):
1265 benches.extend(
1265 benches.extend(
1266 [
1266 [
1267 (makebench(forwardchunks), b'bundle2 forwardchunks()'),
1267 (makebench(forwardchunks), b'bundle2 forwardchunks()'),
1268 (makebench(iterparts), b'bundle2 iterparts()'),
1268 (makebench(iterparts), b'bundle2 iterparts()'),
1269 (
1269 (
1270 makebench(iterpartsseekable),
1270 makebench(iterpartsseekable),
1271 b'bundle2 iterparts() seekable',
1271 b'bundle2 iterparts() seekable',
1272 ),
1272 ),
1273 (makebench(seek), b'bundle2 part seek()'),
1273 (makebench(seek), b'bundle2 part seek()'),
1274 (makepartreadnbytes(8192), b'bundle2 part read(8k)'),
1274 (makepartreadnbytes(8192), b'bundle2 part read(8k)'),
1275 (makepartreadnbytes(16384), b'bundle2 part read(16k)'),
1275 (makepartreadnbytes(16384), b'bundle2 part read(16k)'),
1276 (makepartreadnbytes(32768), b'bundle2 part read(32k)'),
1276 (makepartreadnbytes(32768), b'bundle2 part read(32k)'),
1277 (makepartreadnbytes(131072), b'bundle2 part read(128k)'),
1277 (makepartreadnbytes(131072), b'bundle2 part read(128k)'),
1278 ]
1278 ]
1279 )
1279 )
1280 elif isinstance(bundle, streamclone.streamcloneapplier):
1280 elif isinstance(bundle, streamclone.streamcloneapplier):
1281 raise error.Abort(b'stream clone bundles not supported')
1281 raise error.Abort(b'stream clone bundles not supported')
1282 else:
1282 else:
1283 raise error.Abort(b'unhandled bundle type: %s' % type(bundle))
1283 raise error.Abort(b'unhandled bundle type: %s' % type(bundle))
1284
1284
1285 for fn, title in benches:
1285 for fn, title in benches:
1286 timer, fm = gettimer(ui, opts)
1286 timer, fm = gettimer(ui, opts)
1287 timer(fn, title=title)
1287 timer(fn, title=title)
1288 fm.end()
1288 fm.end()
1289
1289
1290
1290
1291 @command(
1291 @command(
1292 b'perf::changegroupchangelog|perfchangegroupchangelog',
1292 b'perf::changegroupchangelog|perfchangegroupchangelog',
1293 formatteropts
1293 formatteropts
1294 + [
1294 + [
1295 (b'', b'cgversion', b'02', b'changegroup version'),
1295 (b'', b'cgversion', b'02', b'changegroup version'),
1296 (b'r', b'rev', b'', b'revisions to add to changegroup'),
1296 (b'r', b'rev', b'', b'revisions to add to changegroup'),
1297 ],
1297 ],
1298 )
1298 )
1299 def perfchangegroupchangelog(ui, repo, cgversion=b'02', rev=None, **opts):
1299 def perfchangegroupchangelog(ui, repo, cgversion=b'02', rev=None, **opts):
1300 """Benchmark producing a changelog group for a changegroup.
1300 """Benchmark producing a changelog group for a changegroup.
1301
1301
1302 This measures the time spent processing the changelog during a
1302 This measures the time spent processing the changelog during a
1303 bundle operation. This occurs during `hg bundle` and on a server
1303 bundle operation. This occurs during `hg bundle` and on a server
1304 processing a `getbundle` wire protocol request (handles clones
1304 processing a `getbundle` wire protocol request (handles clones
1305 and pull requests).
1305 and pull requests).
1306
1306
1307 By default, all revisions are added to the changegroup.
1307 By default, all revisions are added to the changegroup.
1308 """
1308 """
1309 opts = _byteskwargs(opts)
1309 opts = _byteskwargs(opts)
1310 cl = repo.changelog
1310 cl = repo.changelog
1311 nodes = [cl.lookup(r) for r in repo.revs(rev or b'all()')]
1311 nodes = [cl.lookup(r) for r in repo.revs(rev or b'all()')]
1312 bundler = changegroup.getbundler(cgversion, repo)
1312 bundler = changegroup.getbundler(cgversion, repo)
1313
1313
1314 def d():
1314 def d():
1315 state, chunks = bundler._generatechangelog(cl, nodes)
1315 state, chunks = bundler._generatechangelog(cl, nodes)
1316 for chunk in chunks:
1316 for chunk in chunks:
1317 pass
1317 pass
1318
1318
1319 timer, fm = gettimer(ui, opts)
1319 timer, fm = gettimer(ui, opts)
1320
1320
1321 # Terminal printing can interfere with timing. So disable it.
1321 # Terminal printing can interfere with timing. So disable it.
1322 with ui.configoverride({(b'progress', b'disable'): True}):
1322 with ui.configoverride({(b'progress', b'disable'): True}):
1323 timer(d)
1323 timer(d)
1324
1324
1325 fm.end()
1325 fm.end()
1326
1326
1327
1327
1328 @command(b'perf::dirs|perfdirs', formatteropts)
1328 @command(b'perf::dirs|perfdirs', formatteropts)
1329 def perfdirs(ui, repo, **opts):
1329 def perfdirs(ui, repo, **opts):
1330 opts = _byteskwargs(opts)
1330 opts = _byteskwargs(opts)
1331 timer, fm = gettimer(ui, opts)
1331 timer, fm = gettimer(ui, opts)
1332 dirstate = repo.dirstate
1332 dirstate = repo.dirstate
1333 b'a' in dirstate
1333 b'a' in dirstate
1334
1334
1335 def d():
1335 def d():
1336 dirstate.hasdir(b'a')
1336 dirstate.hasdir(b'a')
1337 try:
1337 try:
1338 del dirstate._map._dirs
1338 del dirstate._map._dirs
1339 except AttributeError:
1339 except AttributeError:
1340 pass
1340 pass
1341
1341
1342 timer(d)
1342 timer(d)
1343 fm.end()
1343 fm.end()
1344
1344
1345
1345
1346 @command(
1346 @command(
1347 b'perf::dirstate|perfdirstate',
1347 b'perf::dirstate|perfdirstate',
1348 [
1348 [
1349 (
1349 (
1350 b'',
1350 b'',
1351 b'iteration',
1351 b'iteration',
1352 None,
1352 None,
1353 b'benchmark a full iteration for the dirstate',
1353 b'benchmark a full iteration for the dirstate',
1354 ),
1354 ),
1355 (
1355 (
1356 b'',
1356 b'',
1357 b'contains',
1357 b'contains',
1358 None,
1358 None,
1359 b'benchmark a large amount of `nf in dirstate` calls',
1359 b'benchmark a large amount of `nf in dirstate` calls',
1360 ),
1360 ),
1361 ]
1361 ]
1362 + formatteropts,
1362 + formatteropts,
1363 )
1363 )
1364 def perfdirstate(ui, repo, **opts):
1364 def perfdirstate(ui, repo, **opts):
1365 """benchmap the time of various distate operations
1365 """benchmap the time of various distate operations
1366
1366
1367 By default benchmark the time necessary to load a dirstate from scratch.
1367 By default benchmark the time necessary to load a dirstate from scratch.
1368 The dirstate is loaded to the point were a "contains" request can be
1368 The dirstate is loaded to the point were a "contains" request can be
1369 answered.
1369 answered.
1370 """
1370 """
1371 opts = _byteskwargs(opts)
1371 opts = _byteskwargs(opts)
1372 timer, fm = gettimer(ui, opts)
1372 timer, fm = gettimer(ui, opts)
1373 b"a" in repo.dirstate
1373 b"a" in repo.dirstate
1374
1374
1375 if opts[b'iteration'] and opts[b'contains']:
1375 if opts[b'iteration'] and opts[b'contains']:
1376 msg = b'only specify one of --iteration or --contains'
1376 msg = b'only specify one of --iteration or --contains'
1377 raise error.Abort(msg)
1377 raise error.Abort(msg)
1378
1378
1379 if opts[b'iteration']:
1379 if opts[b'iteration']:
1380 setup = None
1380 setup = None
1381 dirstate = repo.dirstate
1381 dirstate = repo.dirstate
1382
1382
1383 def d():
1383 def d():
1384 for f in dirstate:
1384 for f in dirstate:
1385 pass
1385 pass
1386
1386
1387 elif opts[b'contains']:
1387 elif opts[b'contains']:
1388 setup = None
1388 setup = None
1389 dirstate = repo.dirstate
1389 dirstate = repo.dirstate
1390 allfiles = list(dirstate)
1390 allfiles = list(dirstate)
1391 # also add file path that will be "missing" from the dirstate
1391 # also add file path that will be "missing" from the dirstate
1392 allfiles.extend([f[::-1] for f in allfiles])
1392 allfiles.extend([f[::-1] for f in allfiles])
1393
1393
1394 def d():
1394 def d():
1395 for f in allfiles:
1395 for f in allfiles:
1396 f in dirstate
1396 f in dirstate
1397
1397
1398 else:
1398 else:
1399
1399
1400 def setup():
1400 def setup():
1401 repo.dirstate.invalidate()
1401 repo.dirstate.invalidate()
1402
1402
1403 def d():
1403 def d():
1404 b"a" in repo.dirstate
1404 b"a" in repo.dirstate
1405
1405
1406 timer(d, setup=setup)
1406 timer(d, setup=setup)
1407 fm.end()
1407 fm.end()
1408
1408
1409
1409
1410 @command(b'perf::dirstatedirs|perfdirstatedirs', formatteropts)
1410 @command(b'perf::dirstatedirs|perfdirstatedirs', formatteropts)
1411 def perfdirstatedirs(ui, repo, **opts):
1411 def perfdirstatedirs(ui, repo, **opts):
1412 """benchmap a 'dirstate.hasdir' call from an empty `dirs` cache"""
1412 """benchmap a 'dirstate.hasdir' call from an empty `dirs` cache"""
1413 opts = _byteskwargs(opts)
1413 opts = _byteskwargs(opts)
1414 timer, fm = gettimer(ui, opts)
1414 timer, fm = gettimer(ui, opts)
1415 repo.dirstate.hasdir(b"a")
1415 repo.dirstate.hasdir(b"a")
1416
1416
1417 def setup():
1417 def setup():
1418 try:
1418 try:
1419 del repo.dirstate._map._dirs
1419 del repo.dirstate._map._dirs
1420 except AttributeError:
1420 except AttributeError:
1421 pass
1421 pass
1422
1422
1423 def d():
1423 def d():
1424 repo.dirstate.hasdir(b"a")
1424 repo.dirstate.hasdir(b"a")
1425
1425
1426 timer(d, setup=setup)
1426 timer(d, setup=setup)
1427 fm.end()
1427 fm.end()
1428
1428
1429
1429
1430 @command(b'perf::dirstatefoldmap|perfdirstatefoldmap', formatteropts)
1430 @command(b'perf::dirstatefoldmap|perfdirstatefoldmap', formatteropts)
1431 def perfdirstatefoldmap(ui, repo, **opts):
1431 def perfdirstatefoldmap(ui, repo, **opts):
1432 """benchmap a `dirstate._map.filefoldmap.get()` request
1432 """benchmap a `dirstate._map.filefoldmap.get()` request
1433
1433
1434 The dirstate filefoldmap cache is dropped between every request.
1434 The dirstate filefoldmap cache is dropped between every request.
1435 """
1435 """
1436 opts = _byteskwargs(opts)
1436 opts = _byteskwargs(opts)
1437 timer, fm = gettimer(ui, opts)
1437 timer, fm = gettimer(ui, opts)
1438 dirstate = repo.dirstate
1438 dirstate = repo.dirstate
1439 dirstate._map.filefoldmap.get(b'a')
1439 dirstate._map.filefoldmap.get(b'a')
1440
1440
1441 def setup():
1441 def setup():
1442 del dirstate._map.filefoldmap
1442 del dirstate._map.filefoldmap
1443
1443
1444 def d():
1444 def d():
1445 dirstate._map.filefoldmap.get(b'a')
1445 dirstate._map.filefoldmap.get(b'a')
1446
1446
1447 timer(d, setup=setup)
1447 timer(d, setup=setup)
1448 fm.end()
1448 fm.end()
1449
1449
1450
1450
1451 @command(b'perf::dirfoldmap|perfdirfoldmap', formatteropts)
1451 @command(b'perf::dirfoldmap|perfdirfoldmap', formatteropts)
1452 def perfdirfoldmap(ui, repo, **opts):
1452 def perfdirfoldmap(ui, repo, **opts):
1453 """benchmap a `dirstate._map.dirfoldmap.get()` request
1453 """benchmap a `dirstate._map.dirfoldmap.get()` request
1454
1454
1455 The dirstate dirfoldmap cache is dropped between every request.
1455 The dirstate dirfoldmap cache is dropped between every request.
1456 """
1456 """
1457 opts = _byteskwargs(opts)
1457 opts = _byteskwargs(opts)
1458 timer, fm = gettimer(ui, opts)
1458 timer, fm = gettimer(ui, opts)
1459 dirstate = repo.dirstate
1459 dirstate = repo.dirstate
1460 dirstate._map.dirfoldmap.get(b'a')
1460 dirstate._map.dirfoldmap.get(b'a')
1461
1461
1462 def setup():
1462 def setup():
1463 del dirstate._map.dirfoldmap
1463 del dirstate._map.dirfoldmap
1464 try:
1464 try:
1465 del dirstate._map._dirs
1465 del dirstate._map._dirs
1466 except AttributeError:
1466 except AttributeError:
1467 pass
1467 pass
1468
1468
1469 def d():
1469 def d():
1470 dirstate._map.dirfoldmap.get(b'a')
1470 dirstate._map.dirfoldmap.get(b'a')
1471
1471
1472 timer(d, setup=setup)
1472 timer(d, setup=setup)
1473 fm.end()
1473 fm.end()
1474
1474
1475
1475
1476 @command(b'perf::dirstatewrite|perfdirstatewrite', formatteropts)
1476 @command(b'perf::dirstatewrite|perfdirstatewrite', formatteropts)
1477 def perfdirstatewrite(ui, repo, **opts):
1477 def perfdirstatewrite(ui, repo, **opts):
1478 """benchmap the time it take to write a dirstate on disk"""
1478 """benchmap the time it take to write a dirstate on disk"""
1479 opts = _byteskwargs(opts)
1479 opts = _byteskwargs(opts)
1480 timer, fm = gettimer(ui, opts)
1480 timer, fm = gettimer(ui, opts)
1481 ds = repo.dirstate
1481 ds = repo.dirstate
1482 b"a" in ds
1482 b"a" in ds
1483
1483
1484 def setup():
1484 def setup():
1485 ds._dirty = True
1485 ds._dirty = True
1486
1486
1487 def d():
1487 def d():
1488 ds.write(repo.currenttransaction())
1488 ds.write(repo.currenttransaction())
1489
1489
1490 with repo.wlock():
1490 with repo.wlock():
1491 timer(d, setup=setup)
1491 timer(d, setup=setup)
1492 fm.end()
1492 fm.end()
1493
1493
1494
1494
1495 def _getmergerevs(repo, opts):
1495 def _getmergerevs(repo, opts):
1496 """parse command argument to return rev involved in merge
1496 """parse command argument to return rev involved in merge
1497
1497
1498 input: options dictionnary with `rev`, `from` and `bse`
1498 input: options dictionnary with `rev`, `from` and `bse`
1499 output: (localctx, otherctx, basectx)
1499 output: (localctx, otherctx, basectx)
1500 """
1500 """
1501 if opts[b'from']:
1501 if opts[b'from']:
1502 fromrev = scmutil.revsingle(repo, opts[b'from'])
1502 fromrev = scmutil.revsingle(repo, opts[b'from'])
1503 wctx = repo[fromrev]
1503 wctx = repo[fromrev]
1504 else:
1504 else:
1505 wctx = repo[None]
1505 wctx = repo[None]
1506 # we don't want working dir files to be stat'd in the benchmark, so
1506 # we don't want working dir files to be stat'd in the benchmark, so
1507 # prime that cache
1507 # prime that cache
1508 wctx.dirty()
1508 wctx.dirty()
1509 rctx = scmutil.revsingle(repo, opts[b'rev'], opts[b'rev'])
1509 rctx = scmutil.revsingle(repo, opts[b'rev'], opts[b'rev'])
1510 if opts[b'base']:
1510 if opts[b'base']:
1511 fromrev = scmutil.revsingle(repo, opts[b'base'])
1511 fromrev = scmutil.revsingle(repo, opts[b'base'])
1512 ancestor = repo[fromrev]
1512 ancestor = repo[fromrev]
1513 else:
1513 else:
1514 ancestor = wctx.ancestor(rctx)
1514 ancestor = wctx.ancestor(rctx)
1515 return (wctx, rctx, ancestor)
1515 return (wctx, rctx, ancestor)
1516
1516
1517
1517
1518 @command(
1518 @command(
1519 b'perf::mergecalculate|perfmergecalculate',
1519 b'perf::mergecalculate|perfmergecalculate',
1520 [
1520 [
1521 (b'r', b'rev', b'.', b'rev to merge against'),
1521 (b'r', b'rev', b'.', b'rev to merge against'),
1522 (b'', b'from', b'', b'rev to merge from'),
1522 (b'', b'from', b'', b'rev to merge from'),
1523 (b'', b'base', b'', b'the revision to use as base'),
1523 (b'', b'base', b'', b'the revision to use as base'),
1524 ]
1524 ]
1525 + formatteropts,
1525 + formatteropts,
1526 )
1526 )
1527 def perfmergecalculate(ui, repo, **opts):
1527 def perfmergecalculate(ui, repo, **opts):
1528 opts = _byteskwargs(opts)
1528 opts = _byteskwargs(opts)
1529 timer, fm = gettimer(ui, opts)
1529 timer, fm = gettimer(ui, opts)
1530
1530
1531 wctx, rctx, ancestor = _getmergerevs(repo, opts)
1531 wctx, rctx, ancestor = _getmergerevs(repo, opts)
1532
1532
1533 def d():
1533 def d():
1534 # acceptremote is True because we don't want prompts in the middle of
1534 # acceptremote is True because we don't want prompts in the middle of
1535 # our benchmark
1535 # our benchmark
1536 merge.calculateupdates(
1536 merge.calculateupdates(
1537 repo,
1537 repo,
1538 wctx,
1538 wctx,
1539 rctx,
1539 rctx,
1540 [ancestor],
1540 [ancestor],
1541 branchmerge=False,
1541 branchmerge=False,
1542 force=False,
1542 force=False,
1543 acceptremote=True,
1543 acceptremote=True,
1544 followcopies=True,
1544 followcopies=True,
1545 )
1545 )
1546
1546
1547 timer(d)
1547 timer(d)
1548 fm.end()
1548 fm.end()
1549
1549
1550
1550
1551 @command(
1551 @command(
1552 b'perf::mergecopies|perfmergecopies',
1552 b'perf::mergecopies|perfmergecopies',
1553 [
1553 [
1554 (b'r', b'rev', b'.', b'rev to merge against'),
1554 (b'r', b'rev', b'.', b'rev to merge against'),
1555 (b'', b'from', b'', b'rev to merge from'),
1555 (b'', b'from', b'', b'rev to merge from'),
1556 (b'', b'base', b'', b'the revision to use as base'),
1556 (b'', b'base', b'', b'the revision to use as base'),
1557 ]
1557 ]
1558 + formatteropts,
1558 + formatteropts,
1559 )
1559 )
1560 def perfmergecopies(ui, repo, **opts):
1560 def perfmergecopies(ui, repo, **opts):
1561 """measure runtime of `copies.mergecopies`"""
1561 """measure runtime of `copies.mergecopies`"""
1562 opts = _byteskwargs(opts)
1562 opts = _byteskwargs(opts)
1563 timer, fm = gettimer(ui, opts)
1563 timer, fm = gettimer(ui, opts)
1564 wctx, rctx, ancestor = _getmergerevs(repo, opts)
1564 wctx, rctx, ancestor = _getmergerevs(repo, opts)
1565
1565
1566 def d():
1566 def d():
1567 # acceptremote is True because we don't want prompts in the middle of
1567 # acceptremote is True because we don't want prompts in the middle of
1568 # our benchmark
1568 # our benchmark
1569 copies.mergecopies(repo, wctx, rctx, ancestor)
1569 copies.mergecopies(repo, wctx, rctx, ancestor)
1570
1570
1571 timer(d)
1571 timer(d)
1572 fm.end()
1572 fm.end()
1573
1573
1574
1574
1575 @command(b'perf::pathcopies|perfpathcopies', [], b"REV REV")
1575 @command(b'perf::pathcopies|perfpathcopies', [], b"REV REV")
1576 def perfpathcopies(ui, repo, rev1, rev2, **opts):
1576 def perfpathcopies(ui, repo, rev1, rev2, **opts):
1577 """benchmark the copy tracing logic"""
1577 """benchmark the copy tracing logic"""
1578 opts = _byteskwargs(opts)
1578 opts = _byteskwargs(opts)
1579 timer, fm = gettimer(ui, opts)
1579 timer, fm = gettimer(ui, opts)
1580 ctx1 = scmutil.revsingle(repo, rev1, rev1)
1580 ctx1 = scmutil.revsingle(repo, rev1, rev1)
1581 ctx2 = scmutil.revsingle(repo, rev2, rev2)
1581 ctx2 = scmutil.revsingle(repo, rev2, rev2)
1582
1582
1583 def d():
1583 def d():
1584 copies.pathcopies(ctx1, ctx2)
1584 copies.pathcopies(ctx1, ctx2)
1585
1585
1586 timer(d)
1586 timer(d)
1587 fm.end()
1587 fm.end()
1588
1588
1589
1589
1590 @command(
1590 @command(
1591 b'perf::phases|perfphases',
1591 b'perf::phases|perfphases',
1592 [
1592 [
1593 (b'', b'full', False, b'include file reading time too'),
1593 (b'', b'full', False, b'include file reading time too'),
1594 ],
1594 ],
1595 b"",
1595 b"",
1596 )
1596 )
1597 def perfphases(ui, repo, **opts):
1597 def perfphases(ui, repo, **opts):
1598 """benchmark phasesets computation"""
1598 """benchmark phasesets computation"""
1599 opts = _byteskwargs(opts)
1599 opts = _byteskwargs(opts)
1600 timer, fm = gettimer(ui, opts)
1600 timer, fm = gettimer(ui, opts)
1601 _phases = repo._phasecache
1601 _phases = repo._phasecache
1602 full = opts.get(b'full')
1602 full = opts.get(b'full')
1603
1603
1604 def d():
1604 def d():
1605 phases = _phases
1605 phases = _phases
1606 if full:
1606 if full:
1607 clearfilecache(repo, b'_phasecache')
1607 clearfilecache(repo, b'_phasecache')
1608 phases = repo._phasecache
1608 phases = repo._phasecache
1609 phases.invalidate()
1609 phases.invalidate()
1610 phases.loadphaserevs(repo)
1610 phases.loadphaserevs(repo)
1611
1611
1612 timer(d)
1612 timer(d)
1613 fm.end()
1613 fm.end()
1614
1614
1615
1615
1616 @command(b'perf::phasesremote|perfphasesremote', [], b"[DEST]")
1616 @command(b'perf::phasesremote|perfphasesremote', [], b"[DEST]")
1617 def perfphasesremote(ui, repo, dest=None, **opts):
1617 def perfphasesremote(ui, repo, dest=None, **opts):
1618 """benchmark time needed to analyse phases of the remote server"""
1618 """benchmark time needed to analyse phases of the remote server"""
1619 from mercurial.node import bin
1619 from mercurial.node import bin
1620 from mercurial import (
1620 from mercurial import (
1621 exchange,
1621 exchange,
1622 hg,
1622 hg,
1623 phases,
1623 phases,
1624 )
1624 )
1625
1625
1626 opts = _byteskwargs(opts)
1626 opts = _byteskwargs(opts)
1627 timer, fm = gettimer(ui, opts)
1627 timer, fm = gettimer(ui, opts)
1628
1628
1629 path = ui.getpath(dest, default=(b'default-push', b'default'))
1629 path = ui.getpath(dest, default=(b'default-push', b'default'))
1630 if not path:
1630 if not path:
1631 raise error.Abort(
1631 raise error.Abort(
1632 b'default repository not configured!',
1632 b'default repository not configured!',
1633 hint=b"see 'hg help config.paths'",
1633 hint=b"see 'hg help config.paths'",
1634 )
1634 )
1635 if util.safehasattr(path, 'main_path'):
1635 if util.safehasattr(path, 'main_path'):
1636 path = path.get_push_variant()
1636 path = path.get_push_variant()
1637 dest = path.loc
1637 dest = path.loc
1638 else:
1638 else:
1639 dest = path.pushloc or path.loc
1639 dest = path.pushloc or path.loc
1640 ui.statusnoi18n(b'analysing phase of %s\n' % util.hidepassword(dest))
1640 ui.statusnoi18n(b'analysing phase of %s\n' % util.hidepassword(dest))
1641 other = hg.peer(repo, opts, dest)
1641 other = hg.peer(repo, opts, dest)
1642
1642
1643 # easier to perform discovery through the operation
1643 # easier to perform discovery through the operation
1644 op = exchange.pushoperation(repo, other)
1644 op = exchange.pushoperation(repo, other)
1645 exchange._pushdiscoverychangeset(op)
1645 exchange._pushdiscoverychangeset(op)
1646
1646
1647 remotesubset = op.fallbackheads
1647 remotesubset = op.fallbackheads
1648
1648
1649 with other.commandexecutor() as e:
1649 with other.commandexecutor() as e:
1650 remotephases = e.callcommand(
1650 remotephases = e.callcommand(
1651 b'listkeys', {b'namespace': b'phases'}
1651 b'listkeys', {b'namespace': b'phases'}
1652 ).result()
1652 ).result()
1653 del other
1653 del other
1654 publishing = remotephases.get(b'publishing', False)
1654 publishing = remotephases.get(b'publishing', False)
1655 if publishing:
1655 if publishing:
1656 ui.statusnoi18n(b'publishing: yes\n')
1656 ui.statusnoi18n(b'publishing: yes\n')
1657 else:
1657 else:
1658 ui.statusnoi18n(b'publishing: no\n')
1658 ui.statusnoi18n(b'publishing: no\n')
1659
1659
1660 has_node = getattr(repo.changelog.index, 'has_node', None)
1660 has_node = getattr(repo.changelog.index, 'has_node', None)
1661 if has_node is None:
1661 if has_node is None:
1662 has_node = repo.changelog.nodemap.__contains__
1662 has_node = repo.changelog.nodemap.__contains__
1663 nonpublishroots = 0
1663 nonpublishroots = 0
1664 for nhex, phase in remotephases.iteritems():
1664 for nhex, phase in remotephases.iteritems():
1665 if nhex == b'publishing': # ignore data related to publish option
1665 if nhex == b'publishing': # ignore data related to publish option
1666 continue
1666 continue
1667 node = bin(nhex)
1667 node = bin(nhex)
1668 if has_node(node) and int(phase):
1668 if has_node(node) and int(phase):
1669 nonpublishroots += 1
1669 nonpublishroots += 1
1670 ui.statusnoi18n(b'number of roots: %d\n' % len(remotephases))
1670 ui.statusnoi18n(b'number of roots: %d\n' % len(remotephases))
1671 ui.statusnoi18n(b'number of known non public roots: %d\n' % nonpublishroots)
1671 ui.statusnoi18n(b'number of known non public roots: %d\n' % nonpublishroots)
1672
1672
1673 def d():
1673 def d():
1674 phases.remotephasessummary(repo, remotesubset, remotephases)
1674 phases.remotephasessummary(repo, remotesubset, remotephases)
1675
1675
1676 timer(d)
1676 timer(d)
1677 fm.end()
1677 fm.end()
1678
1678
1679
1679
1680 @command(
1680 @command(
1681 b'perf::manifest|perfmanifest',
1681 b'perf::manifest|perfmanifest',
1682 [
1682 [
1683 (b'm', b'manifest-rev', False, b'Look up a manifest node revision'),
1683 (b'm', b'manifest-rev', False, b'Look up a manifest node revision'),
1684 (b'', b'clear-disk', False, b'clear on-disk caches too'),
1684 (b'', b'clear-disk', False, b'clear on-disk caches too'),
1685 ]
1685 ]
1686 + formatteropts,
1686 + formatteropts,
1687 b'REV|NODE',
1687 b'REV|NODE',
1688 )
1688 )
1689 def perfmanifest(ui, repo, rev, manifest_rev=False, clear_disk=False, **opts):
1689 def perfmanifest(ui, repo, rev, manifest_rev=False, clear_disk=False, **opts):
1690 """benchmark the time to read a manifest from disk and return a usable
1690 """benchmark the time to read a manifest from disk and return a usable
1691 dict-like object
1691 dict-like object
1692
1692
1693 Manifest caches are cleared before retrieval."""
1693 Manifest caches are cleared before retrieval."""
1694 opts = _byteskwargs(opts)
1694 opts = _byteskwargs(opts)
1695 timer, fm = gettimer(ui, opts)
1695 timer, fm = gettimer(ui, opts)
1696 if not manifest_rev:
1696 if not manifest_rev:
1697 ctx = scmutil.revsingle(repo, rev, rev)
1697 ctx = scmutil.revsingle(repo, rev, rev)
1698 t = ctx.manifestnode()
1698 t = ctx.manifestnode()
1699 else:
1699 else:
1700 from mercurial.node import bin
1700 from mercurial.node import bin
1701
1701
1702 if len(rev) == 40:
1702 if len(rev) == 40:
1703 t = bin(rev)
1703 t = bin(rev)
1704 else:
1704 else:
1705 try:
1705 try:
1706 rev = int(rev)
1706 rev = int(rev)
1707
1707
1708 if util.safehasattr(repo.manifestlog, b'getstorage'):
1708 if util.safehasattr(repo.manifestlog, b'getstorage'):
1709 t = repo.manifestlog.getstorage(b'').node(rev)
1709 t = repo.manifestlog.getstorage(b'').node(rev)
1710 else:
1710 else:
1711 t = repo.manifestlog._revlog.lookup(rev)
1711 t = repo.manifestlog._revlog.lookup(rev)
1712 except ValueError:
1712 except ValueError:
1713 raise error.Abort(
1713 raise error.Abort(
1714 b'manifest revision must be integer or full node'
1714 b'manifest revision must be integer or full node'
1715 )
1715 )
1716
1716
1717 def d():
1717 def d():
1718 repo.manifestlog.clearcaches(clear_persisted_data=clear_disk)
1718 repo.manifestlog.clearcaches(clear_persisted_data=clear_disk)
1719 repo.manifestlog[t].read()
1719 repo.manifestlog[t].read()
1720
1720
1721 timer(d)
1721 timer(d)
1722 fm.end()
1722 fm.end()
1723
1723
1724
1724
1725 @command(b'perf::changeset|perfchangeset', formatteropts)
1725 @command(b'perf::changeset|perfchangeset', formatteropts)
1726 def perfchangeset(ui, repo, rev, **opts):
1726 def perfchangeset(ui, repo, rev, **opts):
1727 opts = _byteskwargs(opts)
1727 opts = _byteskwargs(opts)
1728 timer, fm = gettimer(ui, opts)
1728 timer, fm = gettimer(ui, opts)
1729 n = scmutil.revsingle(repo, rev).node()
1729 n = scmutil.revsingle(repo, rev).node()
1730
1730
1731 def d():
1731 def d():
1732 repo.changelog.read(n)
1732 repo.changelog.read(n)
1733 # repo.changelog._cache = None
1733 # repo.changelog._cache = None
1734
1734
1735 timer(d)
1735 timer(d)
1736 fm.end()
1736 fm.end()
1737
1737
1738
1738
1739 @command(b'perf::ignore|perfignore', formatteropts)
1739 @command(b'perf::ignore|perfignore', formatteropts)
1740 def perfignore(ui, repo, **opts):
1740 def perfignore(ui, repo, **opts):
1741 """benchmark operation related to computing ignore"""
1741 """benchmark operation related to computing ignore"""
1742 opts = _byteskwargs(opts)
1742 opts = _byteskwargs(opts)
1743 timer, fm = gettimer(ui, opts)
1743 timer, fm = gettimer(ui, opts)
1744 dirstate = repo.dirstate
1744 dirstate = repo.dirstate
1745
1745
1746 def setupone():
1746 def setupone():
1747 dirstate.invalidate()
1747 dirstate.invalidate()
1748 clearfilecache(dirstate, b'_ignore')
1748 clearfilecache(dirstate, b'_ignore')
1749
1749
1750 def runone():
1750 def runone():
1751 dirstate._ignore
1751 dirstate._ignore
1752
1752
1753 timer(runone, setup=setupone, title=b"load")
1753 timer(runone, setup=setupone, title=b"load")
1754 fm.end()
1754 fm.end()
1755
1755
1756
1756
1757 @command(
1757 @command(
1758 b'perf::index|perfindex',
1758 b'perf::index|perfindex',
1759 [
1759 [
1760 (b'', b'rev', [], b'revision to be looked up (default tip)'),
1760 (b'', b'rev', [], b'revision to be looked up (default tip)'),
1761 (b'', b'no-lookup', None, b'do not revision lookup post creation'),
1761 (b'', b'no-lookup', None, b'do not revision lookup post creation'),
1762 ]
1762 ]
1763 + formatteropts,
1763 + formatteropts,
1764 )
1764 )
1765 def perfindex(ui, repo, **opts):
1765 def perfindex(ui, repo, **opts):
1766 """benchmark index creation time followed by a lookup
1766 """benchmark index creation time followed by a lookup
1767
1767
1768 The default is to look `tip` up. Depending on the index implementation,
1768 The default is to look `tip` up. Depending on the index implementation,
1769 the revision looked up can matters. For example, an implementation
1769 the revision looked up can matters. For example, an implementation
1770 scanning the index will have a faster lookup time for `--rev tip` than for
1770 scanning the index will have a faster lookup time for `--rev tip` than for
1771 `--rev 0`. The number of looked up revisions and their order can also
1771 `--rev 0`. The number of looked up revisions and their order can also
1772 matters.
1772 matters.
1773
1773
1774 Example of useful set to test:
1774 Example of useful set to test:
1775
1775
1776 * tip
1776 * tip
1777 * 0
1777 * 0
1778 * -10:
1778 * -10:
1779 * :10
1779 * :10
1780 * -10: + :10
1780 * -10: + :10
1781 * :10: + -10:
1781 * :10: + -10:
1782 * -10000:
1782 * -10000:
1783 * -10000: + 0
1783 * -10000: + 0
1784
1784
1785 It is not currently possible to check for lookup of a missing node. For
1785 It is not currently possible to check for lookup of a missing node. For
1786 deeper lookup benchmarking, checkout the `perfnodemap` command."""
1786 deeper lookup benchmarking, checkout the `perfnodemap` command."""
1787 import mercurial.revlog
1787 import mercurial.revlog
1788
1788
1789 opts = _byteskwargs(opts)
1789 opts = _byteskwargs(opts)
1790 timer, fm = gettimer(ui, opts)
1790 timer, fm = gettimer(ui, opts)
1791 mercurial.revlog._prereadsize = 2 ** 24 # disable lazy parser in old hg
1791 mercurial.revlog._prereadsize = 2 ** 24 # disable lazy parser in old hg
1792 if opts[b'no_lookup']:
1792 if opts[b'no_lookup']:
1793 if opts['rev']:
1793 if opts['rev']:
1794 raise error.Abort('--no-lookup and --rev are mutually exclusive')
1794 raise error.Abort('--no-lookup and --rev are mutually exclusive')
1795 nodes = []
1795 nodes = []
1796 elif not opts[b'rev']:
1796 elif not opts[b'rev']:
1797 nodes = [repo[b"tip"].node()]
1797 nodes = [repo[b"tip"].node()]
1798 else:
1798 else:
1799 revs = scmutil.revrange(repo, opts[b'rev'])
1799 revs = scmutil.revrange(repo, opts[b'rev'])
1800 cl = repo.changelog
1800 cl = repo.changelog
1801 nodes = [cl.node(r) for r in revs]
1801 nodes = [cl.node(r) for r in revs]
1802
1802
1803 unfi = repo.unfiltered()
1803 unfi = repo.unfiltered()
1804 # find the filecache func directly
1804 # find the filecache func directly
1805 # This avoid polluting the benchmark with the filecache logic
1805 # This avoid polluting the benchmark with the filecache logic
1806 makecl = unfi.__class__.changelog.func
1806 makecl = unfi.__class__.changelog.func
1807
1807
1808 def setup():
1808 def setup():
1809 # probably not necessary, but for good measure
1809 # probably not necessary, but for good measure
1810 clearchangelog(unfi)
1810 clearchangelog(unfi)
1811
1811
1812 def d():
1812 def d():
1813 cl = makecl(unfi)
1813 cl = makecl(unfi)
1814 for n in nodes:
1814 for n in nodes:
1815 cl.rev(n)
1815 cl.rev(n)
1816
1816
1817 timer(d, setup=setup)
1817 timer(d, setup=setup)
1818 fm.end()
1818 fm.end()
1819
1819
1820
1820
1821 @command(
1821 @command(
1822 b'perf::nodemap|perfnodemap',
1822 b'perf::nodemap|perfnodemap',
1823 [
1823 [
1824 (b'', b'rev', [], b'revision to be looked up (default tip)'),
1824 (b'', b'rev', [], b'revision to be looked up (default tip)'),
1825 (b'', b'clear-caches', True, b'clear revlog cache between calls'),
1825 (b'', b'clear-caches', True, b'clear revlog cache between calls'),
1826 ]
1826 ]
1827 + formatteropts,
1827 + formatteropts,
1828 )
1828 )
1829 def perfnodemap(ui, repo, **opts):
1829 def perfnodemap(ui, repo, **opts):
1830 """benchmark the time necessary to look up revision from a cold nodemap
1830 """benchmark the time necessary to look up revision from a cold nodemap
1831
1831
1832 Depending on the implementation, the amount and order of revision we look
1832 Depending on the implementation, the amount and order of revision we look
1833 up can varies. Example of useful set to test:
1833 up can varies. Example of useful set to test:
1834 * tip
1834 * tip
1835 * 0
1835 * 0
1836 * -10:
1836 * -10:
1837 * :10
1837 * :10
1838 * -10: + :10
1838 * -10: + :10
1839 * :10: + -10:
1839 * :10: + -10:
1840 * -10000:
1840 * -10000:
1841 * -10000: + 0
1841 * -10000: + 0
1842
1842
1843 The command currently focus on valid binary lookup. Benchmarking for
1843 The command currently focus on valid binary lookup. Benchmarking for
1844 hexlookup, prefix lookup and missing lookup would also be valuable.
1844 hexlookup, prefix lookup and missing lookup would also be valuable.
1845 """
1845 """
1846 import mercurial.revlog
1846 import mercurial.revlog
1847
1847
1848 opts = _byteskwargs(opts)
1848 opts = _byteskwargs(opts)
1849 timer, fm = gettimer(ui, opts)
1849 timer, fm = gettimer(ui, opts)
1850 mercurial.revlog._prereadsize = 2 ** 24 # disable lazy parser in old hg
1850 mercurial.revlog._prereadsize = 2 ** 24 # disable lazy parser in old hg
1851
1851
1852 unfi = repo.unfiltered()
1852 unfi = repo.unfiltered()
1853 clearcaches = opts[b'clear_caches']
1853 clearcaches = opts[b'clear_caches']
1854 # find the filecache func directly
1854 # find the filecache func directly
1855 # This avoid polluting the benchmark with the filecache logic
1855 # This avoid polluting the benchmark with the filecache logic
1856 makecl = unfi.__class__.changelog.func
1856 makecl = unfi.__class__.changelog.func
1857 if not opts[b'rev']:
1857 if not opts[b'rev']:
1858 raise error.Abort(b'use --rev to specify revisions to look up')
1858 raise error.Abort(b'use --rev to specify revisions to look up')
1859 revs = scmutil.revrange(repo, opts[b'rev'])
1859 revs = scmutil.revrange(repo, opts[b'rev'])
1860 cl = repo.changelog
1860 cl = repo.changelog
1861 nodes = [cl.node(r) for r in revs]
1861 nodes = [cl.node(r) for r in revs]
1862
1862
1863 # use a list to pass reference to a nodemap from one closure to the next
1863 # use a list to pass reference to a nodemap from one closure to the next
1864 nodeget = [None]
1864 nodeget = [None]
1865
1865
1866 def setnodeget():
1866 def setnodeget():
1867 # probably not necessary, but for good measure
1867 # probably not necessary, but for good measure
1868 clearchangelog(unfi)
1868 clearchangelog(unfi)
1869 cl = makecl(unfi)
1869 cl = makecl(unfi)
1870 if util.safehasattr(cl.index, 'get_rev'):
1870 if util.safehasattr(cl.index, 'get_rev'):
1871 nodeget[0] = cl.index.get_rev
1871 nodeget[0] = cl.index.get_rev
1872 else:
1872 else:
1873 nodeget[0] = cl.nodemap.get
1873 nodeget[0] = cl.nodemap.get
1874
1874
1875 def d():
1875 def d():
1876 get = nodeget[0]
1876 get = nodeget[0]
1877 for n in nodes:
1877 for n in nodes:
1878 get(n)
1878 get(n)
1879
1879
1880 setup = None
1880 setup = None
1881 if clearcaches:
1881 if clearcaches:
1882
1882
1883 def setup():
1883 def setup():
1884 setnodeget()
1884 setnodeget()
1885
1885
1886 else:
1886 else:
1887 setnodeget()
1887 setnodeget()
1888 d() # prewarm the data structure
1888 d() # prewarm the data structure
1889 timer(d, setup=setup)
1889 timer(d, setup=setup)
1890 fm.end()
1890 fm.end()
1891
1891
1892
1892
1893 @command(b'perf::startup|perfstartup', formatteropts)
1893 @command(b'perf::startup|perfstartup', formatteropts)
1894 def perfstartup(ui, repo, **opts):
1894 def perfstartup(ui, repo, **opts):
1895 opts = _byteskwargs(opts)
1895 opts = _byteskwargs(opts)
1896 timer, fm = gettimer(ui, opts)
1896 timer, fm = gettimer(ui, opts)
1897
1897
1898 def d():
1898 def d():
1899 if os.name != 'nt':
1899 if os.name != 'nt':
1900 os.system(
1900 os.system(
1901 b"HGRCPATH= %s version -q > /dev/null" % fsencode(sys.argv[0])
1901 b"HGRCPATH= %s version -q > /dev/null" % fsencode(sys.argv[0])
1902 )
1902 )
1903 else:
1903 else:
1904 os.environ['HGRCPATH'] = r' '
1904 os.environ['HGRCPATH'] = r' '
1905 os.system("%s version -q > NUL" % sys.argv[0])
1905 os.system("%s version -q > NUL" % sys.argv[0])
1906
1906
1907 timer(d)
1907 timer(d)
1908 fm.end()
1908 fm.end()
1909
1909
1910
1910
1911 def _find_stream_generator(version):
1911 def _find_stream_generator(version):
1912 """find the proper generator function for this stream version"""
1912 """find the proper generator function for this stream version"""
1913 import mercurial.streamclone
1913 import mercurial.streamclone
1914
1914
1915 available = {}
1915 available = {}
1916
1916
1917 # try to fetch a v1 generator
1917 # try to fetch a v1 generator
1918 generatev1 = getattr(mercurial.streamclone, "generatev1", None)
1918 generatev1 = getattr(mercurial.streamclone, "generatev1", None)
1919 if generatev1 is not None:
1919 if generatev1 is not None:
1920
1920
1921 def generate(repo):
1921 def generate(repo):
1922 entries, bytes, data = generatev2(repo, None, None, True)
1922 entries, bytes, data = generatev2(repo, None, None, True)
1923 return data
1923 return data
1924
1924
1925 available[b'v1'] = generatev1
1925 available[b'v1'] = generatev1
1926 # try to fetch a v2 generator
1926 # try to fetch a v2 generator
1927 generatev2 = getattr(mercurial.streamclone, "generatev2", None)
1927 generatev2 = getattr(mercurial.streamclone, "generatev2", None)
1928 if generatev2 is not None:
1928 if generatev2 is not None:
1929
1929
1930 def generate(repo):
1930 def generate(repo):
1931 entries, bytes, data = generatev2(repo, None, None, True)
1931 entries, bytes, data = generatev2(repo, None, None, True)
1932 return data
1932 return data
1933
1933
1934 available[b'v2'] = generate
1934 available[b'v2'] = generate
1935 # try to fetch a v3 generator
1935 # try to fetch a v3 generator
1936 generatev3 = getattr(mercurial.streamclone, "generatev3", None)
1936 generatev3 = getattr(mercurial.streamclone, "generatev3", None)
1937 if generatev3 is not None:
1937 if generatev3 is not None:
1938
1938
1939 def generate(repo):
1939 def generate(repo):
1940 entries, bytes, data = generatev3(repo, None, None, True)
1940 entries, bytes, data = generatev3(repo, None, None, True)
1941 return data
1941 return data
1942
1942
1943 available[b'v3-exp'] = generate
1943 available[b'v3-exp'] = generate
1944
1944
1945 # resolve the request
1945 # resolve the request
1946 if version == b"latest":
1946 if version == b"latest":
1947 # latest is the highest non experimental version
1947 # latest is the highest non experimental version
1948 latest_key = max(v for v in available if b'-exp' not in v)
1948 latest_key = max(v for v in available if b'-exp' not in v)
1949 return available[latest_key]
1949 return available[latest_key]
1950 elif version in available:
1950 elif version in available:
1951 return available[version]
1951 return available[version]
1952 else:
1952 else:
1953 msg = b"unkown or unavailable version: %s"
1953 msg = b"unkown or unavailable version: %s"
1954 msg %= version
1954 msg %= version
1955 hint = b"available versions: %s"
1955 hint = b"available versions: %s"
1956 hint %= b', '.join(sorted(available))
1956 hint %= b', '.join(sorted(available))
1957 raise error.Abort(msg, hint=hint)
1957 raise error.Abort(msg, hint=hint)
1958
1958
1959
1959
1960 @command(
1960 @command(
1961 b'perf::stream-locked-section',
1961 b'perf::stream-locked-section',
1962 [
1962 [
1963 (
1963 (
1964 b'',
1964 b'',
1965 b'stream-version',
1965 b'stream-version',
1966 b'latest',
1966 b'latest',
1967 b'stream version to use ("v1", "v2", "v3" or "latest", (the default))',
1967 b'stream version to use ("v1", "v2", "v3" or "latest", (the default))',
1968 ),
1968 ),
1969 ]
1969 ]
1970 + formatteropts,
1970 + formatteropts,
1971 )
1971 )
1972 def perf_stream_clone_scan(ui, repo, stream_version, **opts):
1972 def perf_stream_clone_scan(ui, repo, stream_version, **opts):
1973 """benchmark the initial, repo-locked, section of a stream-clone"""
1973 """benchmark the initial, repo-locked, section of a stream-clone"""
1974
1974
1975 opts = _byteskwargs(opts)
1975 opts = _byteskwargs(opts)
1976 timer, fm = gettimer(ui, opts)
1976 timer, fm = gettimer(ui, opts)
1977
1977
1978 # deletion of the generator may trigger some cleanup that we do not want to
1978 # deletion of the generator may trigger some cleanup that we do not want to
1979 # measure
1979 # measure
1980 result_holder = [None]
1980 result_holder = [None]
1981
1981
1982 def setupone():
1982 def setupone():
1983 result_holder[0] = None
1983 result_holder[0] = None
1984
1984
1985 generate = _find_stream_generator(stream_version)
1985 generate = _find_stream_generator(stream_version)
1986
1986
1987 def runone():
1987 def runone():
1988 # the lock is held for the duration the initialisation
1988 # the lock is held for the duration the initialisation
1989 result_holder[0] = generate(repo)
1989 result_holder[0] = generate(repo)
1990
1990
1991 timer(runone, setup=setupone, title=b"load")
1991 timer(runone, setup=setupone, title=b"load")
1992 fm.end()
1992 fm.end()
1993
1993
1994
1994
1995 @command(
1995 @command(
1996 b'perf::stream-generate',
1996 b'perf::stream-generate',
1997 [
1997 [
1998 (
1998 (
1999 b'',
1999 b'',
2000 b'stream-version',
2000 b'stream-version',
2001 b'latest',
2001 b'latest',
2002 b'stream version to us ("v1", "v2" or "latest", (the default))',
2002 b'stream version to us ("v1", "v2" or "latest", (the default))',
2003 ),
2003 ),
2004 ]
2004 ]
2005 + formatteropts,
2005 + formatteropts,
2006 )
2006 )
2007 def perf_stream_clone_generate(ui, repo, stream_version, **opts):
2007 def perf_stream_clone_generate(ui, repo, stream_version, **opts):
2008 """benchmark the full generation of a stream clone"""
2008 """benchmark the full generation of a stream clone"""
2009
2009
2010 opts = _byteskwargs(opts)
2010 opts = _byteskwargs(opts)
2011 timer, fm = gettimer(ui, opts)
2011 timer, fm = gettimer(ui, opts)
2012
2012
2013 # deletion of the generator may trigger some cleanup that we do not want to
2013 # deletion of the generator may trigger some cleanup that we do not want to
2014 # measure
2014 # measure
2015
2015
2016 generate = _find_stream_generator(stream_version)
2016 generate = _find_stream_generator(stream_version)
2017
2017
2018 def runone():
2018 def runone():
2019 # the lock is held for the duration the initialisation
2019 # the lock is held for the duration the initialisation
2020 for chunk in generate(repo):
2020 for chunk in generate(repo):
2021 pass
2021 pass
2022
2022
2023 timer(runone, title=b"generate")
2023 timer(runone, title=b"generate")
2024 fm.end()
2024 fm.end()
2025
2025
2026
2026
2027 @command(
2027 @command(
2028 b'perf::stream-consume',
2028 b'perf::stream-consume',
2029 formatteropts,
2029 formatteropts,
2030 )
2030 )
2031 def perf_stream_clone_consume(ui, repo, filename, **opts):
2031 def perf_stream_clone_consume(ui, repo, filename, **opts):
2032 """benchmark the full application of a stream clone
2032 """benchmark the full application of a stream clone
2033
2033
2034 This include the creation of the repository
2034 This include the creation of the repository
2035 """
2035 """
2036 # try except to appease check code
2036 # try except to appease check code
2037 msg = b"mercurial too old, missing necessary module: %s"
2037 msg = b"mercurial too old, missing necessary module: %s"
2038 try:
2038 try:
2039 from mercurial import bundle2
2039 from mercurial import bundle2
2040 except ImportError as exc:
2040 except ImportError as exc:
2041 msg %= _bytestr(exc)
2041 msg %= _bytestr(exc)
2042 raise error.Abort(msg)
2042 raise error.Abort(msg)
2043 try:
2043 try:
2044 from mercurial import exchange
2044 from mercurial import exchange
2045 except ImportError as exc:
2045 except ImportError as exc:
2046 msg %= _bytestr(exc)
2046 msg %= _bytestr(exc)
2047 raise error.Abort(msg)
2047 raise error.Abort(msg)
2048 try:
2048 try:
2049 from mercurial import hg
2049 from mercurial import hg
2050 except ImportError as exc:
2050 except ImportError as exc:
2051 msg %= _bytestr(exc)
2051 msg %= _bytestr(exc)
2052 raise error.Abort(msg)
2052 raise error.Abort(msg)
2053 try:
2053 try:
2054 from mercurial import localrepo
2054 from mercurial import localrepo
2055 except ImportError as exc:
2055 except ImportError as exc:
2056 msg %= _bytestr(exc)
2056 msg %= _bytestr(exc)
2057 raise error.Abort(msg)
2057 raise error.Abort(msg)
2058
2058
2059 opts = _byteskwargs(opts)
2059 opts = _byteskwargs(opts)
2060 timer, fm = gettimer(ui, opts)
2060 timer, fm = gettimer(ui, opts)
2061
2061
2062 # deletion of the generator may trigger some cleanup that we do not want to
2062 # deletion of the generator may trigger some cleanup that we do not want to
2063 # measure
2063 # measure
2064 if not (os.path.isfile(filename) and os.access(filename, os.R_OK)):
2064 if not (os.path.isfile(filename) and os.access(filename, os.R_OK)):
2065 raise error.Abort("not a readable file: %s" % filename)
2065 raise error.Abort("not a readable file: %s" % filename)
2066
2066
2067 run_variables = [None, None]
2067 run_variables = [None, None]
2068
2068
2069 @contextlib.contextmanager
2069 @contextlib.contextmanager
2070 def context():
2070 def context():
2071 with open(filename, mode='rb') as bundle:
2071 with open(filename, mode='rb') as bundle:
2072 with tempfile.TemporaryDirectory() as tmp_dir:
2072 with tempfile.TemporaryDirectory() as tmp_dir:
2073 tmp_dir = fsencode(tmp_dir)
2073 tmp_dir = fsencode(tmp_dir)
2074 run_variables[0] = bundle
2074 run_variables[0] = bundle
2075 run_variables[1] = tmp_dir
2075 run_variables[1] = tmp_dir
2076 yield
2076 yield
2077 run_variables[0] = None
2077 run_variables[0] = None
2078 run_variables[1] = None
2078 run_variables[1] = None
2079
2079
2080 def runone():
2080 def runone():
2081 bundle = run_variables[0]
2081 bundle = run_variables[0]
2082 tmp_dir = run_variables[1]
2082 tmp_dir = run_variables[1]
2083 # only pass ui when no srcrepo
2083 # only pass ui when no srcrepo
2084 localrepo.createrepository(
2084 localrepo.createrepository(
2085 repo.ui, tmp_dir, requirements=repo.requirements
2085 repo.ui, tmp_dir, requirements=repo.requirements
2086 )
2086 )
2087 target = hg.repository(repo.ui, tmp_dir)
2087 target = hg.repository(repo.ui, tmp_dir)
2088 gen = exchange.readbundle(target.ui, bundle, bundle.name)
2088 gen = exchange.readbundle(target.ui, bundle, bundle.name)
2089 # stream v1
2089 # stream v1
2090 if util.safehasattr(gen, 'apply'):
2090 if util.safehasattr(gen, 'apply'):
2091 gen.apply(target)
2091 gen.apply(target)
2092 else:
2092 else:
2093 with target.transaction(b"perf::stream-consume") as tr:
2093 with target.transaction(b"perf::stream-consume") as tr:
2094 bundle2.applybundle(
2094 bundle2.applybundle(
2095 target,
2095 target,
2096 gen,
2096 gen,
2097 tr,
2097 tr,
2098 source=b'unbundle',
2098 source=b'unbundle',
2099 url=filename,
2099 url=filename,
2100 )
2100 )
2101
2101
2102 timer(runone, context=context, title=b"consume")
2102 timer(runone, context=context, title=b"consume")
2103 fm.end()
2103 fm.end()
2104
2104
2105
2105
2106 @command(b'perf::parents|perfparents', formatteropts)
2106 @command(b'perf::parents|perfparents', formatteropts)
2107 def perfparents(ui, repo, **opts):
2107 def perfparents(ui, repo, **opts):
2108 """benchmark the time necessary to fetch one changeset's parents.
2108 """benchmark the time necessary to fetch one changeset's parents.
2109
2109
2110 The fetch is done using the `node identifier`, traversing all object layers
2110 The fetch is done using the `node identifier`, traversing all object layers
2111 from the repository object. The first N revisions will be used for this
2111 from the repository object. The first N revisions will be used for this
2112 benchmark. N is controlled by the ``perf.parentscount`` config option
2112 benchmark. N is controlled by the ``perf.parentscount`` config option
2113 (default: 1000).
2113 (default: 1000).
2114 """
2114 """
2115 opts = _byteskwargs(opts)
2115 opts = _byteskwargs(opts)
2116 timer, fm = gettimer(ui, opts)
2116 timer, fm = gettimer(ui, opts)
2117 # control the number of commits perfparents iterates over
2117 # control the number of commits perfparents iterates over
2118 # experimental config: perf.parentscount
2118 # experimental config: perf.parentscount
2119 count = getint(ui, b"perf", b"parentscount", 1000)
2119 count = getint(ui, b"perf", b"parentscount", 1000)
2120 if len(repo.changelog) < count:
2120 if len(repo.changelog) < count:
2121 raise error.Abort(b"repo needs %d commits for this test" % count)
2121 raise error.Abort(b"repo needs %d commits for this test" % count)
2122 repo = repo.unfiltered()
2122 repo = repo.unfiltered()
2123 nl = [repo.changelog.node(i) for i in _xrange(count)]
2123 nl = [repo.changelog.node(i) for i in _xrange(count)]
2124
2124
2125 def d():
2125 def d():
2126 for n in nl:
2126 for n in nl:
2127 repo.changelog.parents(n)
2127 repo.changelog.parents(n)
2128
2128
2129 timer(d)
2129 timer(d)
2130 fm.end()
2130 fm.end()
2131
2131
2132
2132
2133 @command(b'perf::ctxfiles|perfctxfiles', formatteropts)
2133 @command(b'perf::ctxfiles|perfctxfiles', formatteropts)
2134 def perfctxfiles(ui, repo, x, **opts):
2134 def perfctxfiles(ui, repo, x, **opts):
2135 opts = _byteskwargs(opts)
2135 opts = _byteskwargs(opts)
2136 x = int(x)
2136 x = int(x)
2137 timer, fm = gettimer(ui, opts)
2137 timer, fm = gettimer(ui, opts)
2138
2138
2139 def d():
2139 def d():
2140 len(repo[x].files())
2140 len(repo[x].files())
2141
2141
2142 timer(d)
2142 timer(d)
2143 fm.end()
2143 fm.end()
2144
2144
2145
2145
2146 @command(b'perf::rawfiles|perfrawfiles', formatteropts)
2146 @command(b'perf::rawfiles|perfrawfiles', formatteropts)
2147 def perfrawfiles(ui, repo, x, **opts):
2147 def perfrawfiles(ui, repo, x, **opts):
2148 opts = _byteskwargs(opts)
2148 opts = _byteskwargs(opts)
2149 x = int(x)
2149 x = int(x)
2150 timer, fm = gettimer(ui, opts)
2150 timer, fm = gettimer(ui, opts)
2151 cl = repo.changelog
2151 cl = repo.changelog
2152
2152
2153 def d():
2153 def d():
2154 len(cl.read(x)[3])
2154 len(cl.read(x)[3])
2155
2155
2156 timer(d)
2156 timer(d)
2157 fm.end()
2157 fm.end()
2158
2158
2159
2159
2160 @command(b'perf::lookup|perflookup', formatteropts)
2160 @command(b'perf::lookup|perflookup', formatteropts)
2161 def perflookup(ui, repo, rev, **opts):
2161 def perflookup(ui, repo, rev, **opts):
2162 opts = _byteskwargs(opts)
2162 opts = _byteskwargs(opts)
2163 timer, fm = gettimer(ui, opts)
2163 timer, fm = gettimer(ui, opts)
2164 timer(lambda: len(repo.lookup(rev)))
2164 timer(lambda: len(repo.lookup(rev)))
2165 fm.end()
2165 fm.end()
2166
2166
2167
2167
2168 @command(
2168 @command(
2169 b'perf::linelogedits|perflinelogedits',
2169 b'perf::linelogedits|perflinelogedits',
2170 [
2170 [
2171 (b'n', b'edits', 10000, b'number of edits'),
2171 (b'n', b'edits', 10000, b'number of edits'),
2172 (b'', b'max-hunk-lines', 10, b'max lines in a hunk'),
2172 (b'', b'max-hunk-lines', 10, b'max lines in a hunk'),
2173 ],
2173 ],
2174 norepo=True,
2174 norepo=True,
2175 )
2175 )
2176 def perflinelogedits(ui, **opts):
2176 def perflinelogedits(ui, **opts):
2177 from mercurial import linelog
2177 from mercurial import linelog
2178
2178
2179 opts = _byteskwargs(opts)
2179 opts = _byteskwargs(opts)
2180
2180
2181 edits = opts[b'edits']
2181 edits = opts[b'edits']
2182 maxhunklines = opts[b'max_hunk_lines']
2182 maxhunklines = opts[b'max_hunk_lines']
2183
2183
2184 maxb1 = 100000
2184 maxb1 = 100000
2185 random.seed(0)
2185 random.seed(0)
2186 randint = random.randint
2186 randint = random.randint
2187 currentlines = 0
2187 currentlines = 0
2188 arglist = []
2188 arglist = []
2189 for rev in _xrange(edits):
2189 for rev in _xrange(edits):
2190 a1 = randint(0, currentlines)
2190 a1 = randint(0, currentlines)
2191 a2 = randint(a1, min(currentlines, a1 + maxhunklines))
2191 a2 = randint(a1, min(currentlines, a1 + maxhunklines))
2192 b1 = randint(0, maxb1)
2192 b1 = randint(0, maxb1)
2193 b2 = randint(b1, b1 + maxhunklines)
2193 b2 = randint(b1, b1 + maxhunklines)
2194 currentlines += (b2 - b1) - (a2 - a1)
2194 currentlines += (b2 - b1) - (a2 - a1)
2195 arglist.append((rev, a1, a2, b1, b2))
2195 arglist.append((rev, a1, a2, b1, b2))
2196
2196
2197 def d():
2197 def d():
2198 ll = linelog.linelog()
2198 ll = linelog.linelog()
2199 for args in arglist:
2199 for args in arglist:
2200 ll.replacelines(*args)
2200 ll.replacelines(*args)
2201
2201
2202 timer, fm = gettimer(ui, opts)
2202 timer, fm = gettimer(ui, opts)
2203 timer(d)
2203 timer(d)
2204 fm.end()
2204 fm.end()
2205
2205
2206
2206
2207 @command(b'perf::revrange|perfrevrange', formatteropts)
2207 @command(b'perf::revrange|perfrevrange', formatteropts)
2208 def perfrevrange(ui, repo, *specs, **opts):
2208 def perfrevrange(ui, repo, *specs, **opts):
2209 opts = _byteskwargs(opts)
2209 opts = _byteskwargs(opts)
2210 timer, fm = gettimer(ui, opts)
2210 timer, fm = gettimer(ui, opts)
2211 revrange = scmutil.revrange
2211 revrange = scmutil.revrange
2212 timer(lambda: len(revrange(repo, specs)))
2212 timer(lambda: len(revrange(repo, specs)))
2213 fm.end()
2213 fm.end()
2214
2214
2215
2215
2216 @command(b'perf::nodelookup|perfnodelookup', formatteropts)
2216 @command(b'perf::nodelookup|perfnodelookup', formatteropts)
2217 def perfnodelookup(ui, repo, rev, **opts):
2217 def perfnodelookup(ui, repo, rev, **opts):
2218 opts = _byteskwargs(opts)
2218 opts = _byteskwargs(opts)
2219 timer, fm = gettimer(ui, opts)
2219 timer, fm = gettimer(ui, opts)
2220 import mercurial.revlog
2220 import mercurial.revlog
2221
2221
2222 mercurial.revlog._prereadsize = 2 ** 24 # disable lazy parser in old hg
2222 mercurial.revlog._prereadsize = 2 ** 24 # disable lazy parser in old hg
2223 n = scmutil.revsingle(repo, rev).node()
2223 n = scmutil.revsingle(repo, rev).node()
2224
2224
2225 try:
2225 try:
2226 cl = revlog(getsvfs(repo), radix=b"00changelog")
2226 cl = revlog(getsvfs(repo), radix=b"00changelog")
2227 except TypeError:
2227 except TypeError:
2228 cl = revlog(getsvfs(repo), indexfile=b"00changelog.i")
2228 cl = revlog(getsvfs(repo), indexfile=b"00changelog.i")
2229
2229
2230 def d():
2230 def d():
2231 cl.rev(n)
2231 cl.rev(n)
2232 clearcaches(cl)
2232 clearcaches(cl)
2233
2233
2234 timer(d)
2234 timer(d)
2235 fm.end()
2235 fm.end()
2236
2236
2237
2237
2238 @command(
2238 @command(
2239 b'perf::log|perflog',
2239 b'perf::log|perflog',
2240 [(b'', b'rename', False, b'ask log to follow renames')] + formatteropts,
2240 [(b'', b'rename', False, b'ask log to follow renames')] + formatteropts,
2241 )
2241 )
2242 def perflog(ui, repo, rev=None, **opts):
2242 def perflog(ui, repo, rev=None, **opts):
2243 opts = _byteskwargs(opts)
2243 opts = _byteskwargs(opts)
2244 if rev is None:
2244 if rev is None:
2245 rev = []
2245 rev = []
2246 timer, fm = gettimer(ui, opts)
2246 timer, fm = gettimer(ui, opts)
2247 ui.pushbuffer()
2247 ui.pushbuffer()
2248 timer(
2248 timer(
2249 lambda: commands.log(
2249 lambda: commands.log(
2250 ui, repo, rev=rev, date=b'', user=b'', copies=opts.get(b'rename')
2250 ui, repo, rev=rev, date=b'', user=b'', copies=opts.get(b'rename')
2251 )
2251 )
2252 )
2252 )
2253 ui.popbuffer()
2253 ui.popbuffer()
2254 fm.end()
2254 fm.end()
2255
2255
2256
2256
2257 @command(b'perf::moonwalk|perfmoonwalk', formatteropts)
2257 @command(b'perf::moonwalk|perfmoonwalk', formatteropts)
2258 def perfmoonwalk(ui, repo, **opts):
2258 def perfmoonwalk(ui, repo, **opts):
2259 """benchmark walking the changelog backwards
2259 """benchmark walking the changelog backwards
2260
2260
2261 This also loads the changelog data for each revision in the changelog.
2261 This also loads the changelog data for each revision in the changelog.
2262 """
2262 """
2263 opts = _byteskwargs(opts)
2263 opts = _byteskwargs(opts)
2264 timer, fm = gettimer(ui, opts)
2264 timer, fm = gettimer(ui, opts)
2265
2265
2266 def moonwalk():
2266 def moonwalk():
2267 for i in repo.changelog.revs(start=(len(repo) - 1), stop=-1):
2267 for i in repo.changelog.revs(start=(len(repo) - 1), stop=-1):
2268 ctx = repo[i]
2268 ctx = repo[i]
2269 ctx.branch() # read changelog data (in addition to the index)
2269 ctx.branch() # read changelog data (in addition to the index)
2270
2270
2271 timer(moonwalk)
2271 timer(moonwalk)
2272 fm.end()
2272 fm.end()
2273
2273
2274
2274
2275 @command(
2275 @command(
2276 b'perf::templating|perftemplating',
2276 b'perf::templating|perftemplating',
2277 [
2277 [
2278 (b'r', b'rev', [], b'revisions to run the template on'),
2278 (b'r', b'rev', [], b'revisions to run the template on'),
2279 ]
2279 ]
2280 + formatteropts,
2280 + formatteropts,
2281 )
2281 )
2282 def perftemplating(ui, repo, testedtemplate=None, **opts):
2282 def perftemplating(ui, repo, testedtemplate=None, **opts):
2283 """test the rendering time of a given template"""
2283 """test the rendering time of a given template"""
2284 if makelogtemplater is None:
2284 if makelogtemplater is None:
2285 raise error.Abort(
2285 raise error.Abort(
2286 b"perftemplating not available with this Mercurial",
2286 b"perftemplating not available with this Mercurial",
2287 hint=b"use 4.3 or later",
2287 hint=b"use 4.3 or later",
2288 )
2288 )
2289
2289
2290 opts = _byteskwargs(opts)
2290 opts = _byteskwargs(opts)
2291
2291
2292 nullui = ui.copy()
2292 nullui = ui.copy()
2293 nullui.fout = open(os.devnull, 'wb')
2293 nullui.fout = open(os.devnull, 'wb')
2294 nullui.disablepager()
2294 nullui.disablepager()
2295 revs = opts.get(b'rev')
2295 revs = opts.get(b'rev')
2296 if not revs:
2296 if not revs:
2297 revs = [b'all()']
2297 revs = [b'all()']
2298 revs = list(scmutil.revrange(repo, revs))
2298 revs = list(scmutil.revrange(repo, revs))
2299
2299
2300 defaulttemplate = (
2300 defaulttemplate = (
2301 b'{date|shortdate} [{rev}:{node|short}]'
2301 b'{date|shortdate} [{rev}:{node|short}]'
2302 b' {author|person}: {desc|firstline}\n'
2302 b' {author|person}: {desc|firstline}\n'
2303 )
2303 )
2304 if testedtemplate is None:
2304 if testedtemplate is None:
2305 testedtemplate = defaulttemplate
2305 testedtemplate = defaulttemplate
2306 displayer = makelogtemplater(nullui, repo, testedtemplate)
2306 displayer = makelogtemplater(nullui, repo, testedtemplate)
2307
2307
2308 def format():
2308 def format():
2309 for r in revs:
2309 for r in revs:
2310 ctx = repo[r]
2310 ctx = repo[r]
2311 displayer.show(ctx)
2311 displayer.show(ctx)
2312 displayer.flush(ctx)
2312 displayer.flush(ctx)
2313
2313
2314 timer, fm = gettimer(ui, opts)
2314 timer, fm = gettimer(ui, opts)
2315 timer(format)
2315 timer(format)
2316 fm.end()
2316 fm.end()
2317
2317
2318
2318
2319 def _displaystats(ui, opts, entries, data):
2319 def _displaystats(ui, opts, entries, data):
2320 # use a second formatter because the data are quite different, not sure
2320 # use a second formatter because the data are quite different, not sure
2321 # how it flies with the templater.
2321 # how it flies with the templater.
2322 fm = ui.formatter(b'perf-stats', opts)
2322 fm = ui.formatter(b'perf-stats', opts)
2323 for key, title in entries:
2323 for key, title in entries:
2324 values = data[key]
2324 values = data[key]
2325 nbvalues = len(data)
2325 nbvalues = len(data)
2326 values.sort()
2326 values.sort()
2327 stats = {
2327 stats = {
2328 'key': key,
2328 'key': key,
2329 'title': title,
2329 'title': title,
2330 'nbitems': len(values),
2330 'nbitems': len(values),
2331 'min': values[0][0],
2331 'min': values[0][0],
2332 '10%': values[(nbvalues * 10) // 100][0],
2332 '10%': values[(nbvalues * 10) // 100][0],
2333 '25%': values[(nbvalues * 25) // 100][0],
2333 '25%': values[(nbvalues * 25) // 100][0],
2334 '50%': values[(nbvalues * 50) // 100][0],
2334 '50%': values[(nbvalues * 50) // 100][0],
2335 '75%': values[(nbvalues * 75) // 100][0],
2335 '75%': values[(nbvalues * 75) // 100][0],
2336 '80%': values[(nbvalues * 80) // 100][0],
2336 '80%': values[(nbvalues * 80) // 100][0],
2337 '85%': values[(nbvalues * 85) // 100][0],
2337 '85%': values[(nbvalues * 85) // 100][0],
2338 '90%': values[(nbvalues * 90) // 100][0],
2338 '90%': values[(nbvalues * 90) // 100][0],
2339 '95%': values[(nbvalues * 95) // 100][0],
2339 '95%': values[(nbvalues * 95) // 100][0],
2340 '99%': values[(nbvalues * 99) // 100][0],
2340 '99%': values[(nbvalues * 99) // 100][0],
2341 'max': values[-1][0],
2341 'max': values[-1][0],
2342 }
2342 }
2343 fm.startitem()
2343 fm.startitem()
2344 fm.data(**stats)
2344 fm.data(**stats)
2345 # make node pretty for the human output
2345 # make node pretty for the human output
2346 fm.plain('### %s (%d items)\n' % (title, len(values)))
2346 fm.plain('### %s (%d items)\n' % (title, len(values)))
2347 lines = [
2347 lines = [
2348 'min',
2348 'min',
2349 '10%',
2349 '10%',
2350 '25%',
2350 '25%',
2351 '50%',
2351 '50%',
2352 '75%',
2352 '75%',
2353 '80%',
2353 '80%',
2354 '85%',
2354 '85%',
2355 '90%',
2355 '90%',
2356 '95%',
2356 '95%',
2357 '99%',
2357 '99%',
2358 'max',
2358 'max',
2359 ]
2359 ]
2360 for l in lines:
2360 for l in lines:
2361 fm.plain('%s: %s\n' % (l, stats[l]))
2361 fm.plain('%s: %s\n' % (l, stats[l]))
2362 fm.end()
2362 fm.end()
2363
2363
2364
2364
2365 @command(
2365 @command(
2366 b'perf::helper-mergecopies|perfhelper-mergecopies',
2366 b'perf::helper-mergecopies|perfhelper-mergecopies',
2367 formatteropts
2367 formatteropts
2368 + [
2368 + [
2369 (b'r', b'revs', [], b'restrict search to these revisions'),
2369 (b'r', b'revs', [], b'restrict search to these revisions'),
2370 (b'', b'timing', False, b'provides extra data (costly)'),
2370 (b'', b'timing', False, b'provides extra data (costly)'),
2371 (b'', b'stats', False, b'provides statistic about the measured data'),
2371 (b'', b'stats', False, b'provides statistic about the measured data'),
2372 ],
2372 ],
2373 )
2373 )
2374 def perfhelpermergecopies(ui, repo, revs=[], **opts):
2374 def perfhelpermergecopies(ui, repo, revs=[], **opts):
2375 """find statistics about potential parameters for `perfmergecopies`
2375 """find statistics about potential parameters for `perfmergecopies`
2376
2376
2377 This command find (base, p1, p2) triplet relevant for copytracing
2377 This command find (base, p1, p2) triplet relevant for copytracing
2378 benchmarking in the context of a merge. It reports values for some of the
2378 benchmarking in the context of a merge. It reports values for some of the
2379 parameters that impact merge copy tracing time during merge.
2379 parameters that impact merge copy tracing time during merge.
2380
2380
2381 If `--timing` is set, rename detection is run and the associated timing
2381 If `--timing` is set, rename detection is run and the associated timing
2382 will be reported. The extra details come at the cost of slower command
2382 will be reported. The extra details come at the cost of slower command
2383 execution.
2383 execution.
2384
2384
2385 Since rename detection is only run once, other factors might easily
2385 Since rename detection is only run once, other factors might easily
2386 affect the precision of the timing. However it should give a good
2386 affect the precision of the timing. However it should give a good
2387 approximation of which revision triplets are very costly.
2387 approximation of which revision triplets are very costly.
2388 """
2388 """
2389 opts = _byteskwargs(opts)
2389 opts = _byteskwargs(opts)
2390 fm = ui.formatter(b'perf', opts)
2390 fm = ui.formatter(b'perf', opts)
2391 dotiming = opts[b'timing']
2391 dotiming = opts[b'timing']
2392 dostats = opts[b'stats']
2392 dostats = opts[b'stats']
2393
2393
2394 output_template = [
2394 output_template = [
2395 ("base", "%(base)12s"),
2395 ("base", "%(base)12s"),
2396 ("p1", "%(p1.node)12s"),
2396 ("p1", "%(p1.node)12s"),
2397 ("p2", "%(p2.node)12s"),
2397 ("p2", "%(p2.node)12s"),
2398 ("p1.nb-revs", "%(p1.nbrevs)12d"),
2398 ("p1.nb-revs", "%(p1.nbrevs)12d"),
2399 ("p1.nb-files", "%(p1.nbmissingfiles)12d"),
2399 ("p1.nb-files", "%(p1.nbmissingfiles)12d"),
2400 ("p1.renames", "%(p1.renamedfiles)12d"),
2400 ("p1.renames", "%(p1.renamedfiles)12d"),
2401 ("p1.time", "%(p1.time)12.3f"),
2401 ("p1.time", "%(p1.time)12.3f"),
2402 ("p2.nb-revs", "%(p2.nbrevs)12d"),
2402 ("p2.nb-revs", "%(p2.nbrevs)12d"),
2403 ("p2.nb-files", "%(p2.nbmissingfiles)12d"),
2403 ("p2.nb-files", "%(p2.nbmissingfiles)12d"),
2404 ("p2.renames", "%(p2.renamedfiles)12d"),
2404 ("p2.renames", "%(p2.renamedfiles)12d"),
2405 ("p2.time", "%(p2.time)12.3f"),
2405 ("p2.time", "%(p2.time)12.3f"),
2406 ("renames", "%(nbrenamedfiles)12d"),
2406 ("renames", "%(nbrenamedfiles)12d"),
2407 ("total.time", "%(time)12.3f"),
2407 ("total.time", "%(time)12.3f"),
2408 ]
2408 ]
2409 if not dotiming:
2409 if not dotiming:
2410 output_template = [
2410 output_template = [
2411 i
2411 i
2412 for i in output_template
2412 for i in output_template
2413 if not ('time' in i[0] or 'renames' in i[0])
2413 if not ('time' in i[0] or 'renames' in i[0])
2414 ]
2414 ]
2415 header_names = [h for (h, v) in output_template]
2415 header_names = [h for (h, v) in output_template]
2416 output = ' '.join([v for (h, v) in output_template]) + '\n'
2416 output = ' '.join([v for (h, v) in output_template]) + '\n'
2417 header = ' '.join(['%12s'] * len(header_names)) + '\n'
2417 header = ' '.join(['%12s'] * len(header_names)) + '\n'
2418 fm.plain(header % tuple(header_names))
2418 fm.plain(header % tuple(header_names))
2419
2419
2420 if not revs:
2420 if not revs:
2421 revs = ['all()']
2421 revs = ['all()']
2422 revs = scmutil.revrange(repo, revs)
2422 revs = scmutil.revrange(repo, revs)
2423
2423
2424 if dostats:
2424 if dostats:
2425 alldata = {
2425 alldata = {
2426 'nbrevs': [],
2426 'nbrevs': [],
2427 'nbmissingfiles': [],
2427 'nbmissingfiles': [],
2428 }
2428 }
2429 if dotiming:
2429 if dotiming:
2430 alldata['parentnbrenames'] = []
2430 alldata['parentnbrenames'] = []
2431 alldata['totalnbrenames'] = []
2431 alldata['totalnbrenames'] = []
2432 alldata['parenttime'] = []
2432 alldata['parenttime'] = []
2433 alldata['totaltime'] = []
2433 alldata['totaltime'] = []
2434
2434
2435 roi = repo.revs('merge() and %ld', revs)
2435 roi = repo.revs('merge() and %ld', revs)
2436 for r in roi:
2436 for r in roi:
2437 ctx = repo[r]
2437 ctx = repo[r]
2438 p1 = ctx.p1()
2438 p1 = ctx.p1()
2439 p2 = ctx.p2()
2439 p2 = ctx.p2()
2440 bases = repo.changelog._commonancestorsheads(p1.rev(), p2.rev())
2440 bases = repo.changelog._commonancestorsheads(p1.rev(), p2.rev())
2441 for b in bases:
2441 for b in bases:
2442 b = repo[b]
2442 b = repo[b]
2443 p1missing = copies._computeforwardmissing(b, p1)
2443 p1missing = copies._computeforwardmissing(b, p1)
2444 p2missing = copies._computeforwardmissing(b, p2)
2444 p2missing = copies._computeforwardmissing(b, p2)
2445 data = {
2445 data = {
2446 b'base': b.hex(),
2446 b'base': b.hex(),
2447 b'p1.node': p1.hex(),
2447 b'p1.node': p1.hex(),
2448 b'p1.nbrevs': len(repo.revs('only(%d, %d)', p1.rev(), b.rev())),
2448 b'p1.nbrevs': len(repo.revs('only(%d, %d)', p1.rev(), b.rev())),
2449 b'p1.nbmissingfiles': len(p1missing),
2449 b'p1.nbmissingfiles': len(p1missing),
2450 b'p2.node': p2.hex(),
2450 b'p2.node': p2.hex(),
2451 b'p2.nbrevs': len(repo.revs('only(%d, %d)', p2.rev(), b.rev())),
2451 b'p2.nbrevs': len(repo.revs('only(%d, %d)', p2.rev(), b.rev())),
2452 b'p2.nbmissingfiles': len(p2missing),
2452 b'p2.nbmissingfiles': len(p2missing),
2453 }
2453 }
2454 if dostats:
2454 if dostats:
2455 if p1missing:
2455 if p1missing:
2456 alldata['nbrevs'].append(
2456 alldata['nbrevs'].append(
2457 (data['p1.nbrevs'], b.hex(), p1.hex())
2457 (data['p1.nbrevs'], b.hex(), p1.hex())
2458 )
2458 )
2459 alldata['nbmissingfiles'].append(
2459 alldata['nbmissingfiles'].append(
2460 (data['p1.nbmissingfiles'], b.hex(), p1.hex())
2460 (data['p1.nbmissingfiles'], b.hex(), p1.hex())
2461 )
2461 )
2462 if p2missing:
2462 if p2missing:
2463 alldata['nbrevs'].append(
2463 alldata['nbrevs'].append(
2464 (data['p2.nbrevs'], b.hex(), p2.hex())
2464 (data['p2.nbrevs'], b.hex(), p2.hex())
2465 )
2465 )
2466 alldata['nbmissingfiles'].append(
2466 alldata['nbmissingfiles'].append(
2467 (data['p2.nbmissingfiles'], b.hex(), p2.hex())
2467 (data['p2.nbmissingfiles'], b.hex(), p2.hex())
2468 )
2468 )
2469 if dotiming:
2469 if dotiming:
2470 begin = util.timer()
2470 begin = util.timer()
2471 mergedata = copies.mergecopies(repo, p1, p2, b)
2471 mergedata = copies.mergecopies(repo, p1, p2, b)
2472 end = util.timer()
2472 end = util.timer()
2473 # not very stable timing since we did only one run
2473 # not very stable timing since we did only one run
2474 data['time'] = end - begin
2474 data['time'] = end - begin
2475 # mergedata contains five dicts: "copy", "movewithdir",
2475 # mergedata contains five dicts: "copy", "movewithdir",
2476 # "diverge", "renamedelete" and "dirmove".
2476 # "diverge", "renamedelete" and "dirmove".
2477 # The first 4 are about renamed file so lets count that.
2477 # The first 4 are about renamed file so lets count that.
2478 renames = len(mergedata[0])
2478 renames = len(mergedata[0])
2479 renames += len(mergedata[1])
2479 renames += len(mergedata[1])
2480 renames += len(mergedata[2])
2480 renames += len(mergedata[2])
2481 renames += len(mergedata[3])
2481 renames += len(mergedata[3])
2482 data['nbrenamedfiles'] = renames
2482 data['nbrenamedfiles'] = renames
2483 begin = util.timer()
2483 begin = util.timer()
2484 p1renames = copies.pathcopies(b, p1)
2484 p1renames = copies.pathcopies(b, p1)
2485 end = util.timer()
2485 end = util.timer()
2486 data['p1.time'] = end - begin
2486 data['p1.time'] = end - begin
2487 begin = util.timer()
2487 begin = util.timer()
2488 p2renames = copies.pathcopies(b, p2)
2488 p2renames = copies.pathcopies(b, p2)
2489 end = util.timer()
2489 end = util.timer()
2490 data['p2.time'] = end - begin
2490 data['p2.time'] = end - begin
2491 data['p1.renamedfiles'] = len(p1renames)
2491 data['p1.renamedfiles'] = len(p1renames)
2492 data['p2.renamedfiles'] = len(p2renames)
2492 data['p2.renamedfiles'] = len(p2renames)
2493
2493
2494 if dostats:
2494 if dostats:
2495 if p1missing:
2495 if p1missing:
2496 alldata['parentnbrenames'].append(
2496 alldata['parentnbrenames'].append(
2497 (data['p1.renamedfiles'], b.hex(), p1.hex())
2497 (data['p1.renamedfiles'], b.hex(), p1.hex())
2498 )
2498 )
2499 alldata['parenttime'].append(
2499 alldata['parenttime'].append(
2500 (data['p1.time'], b.hex(), p1.hex())
2500 (data['p1.time'], b.hex(), p1.hex())
2501 )
2501 )
2502 if p2missing:
2502 if p2missing:
2503 alldata['parentnbrenames'].append(
2503 alldata['parentnbrenames'].append(
2504 (data['p2.renamedfiles'], b.hex(), p2.hex())
2504 (data['p2.renamedfiles'], b.hex(), p2.hex())
2505 )
2505 )
2506 alldata['parenttime'].append(
2506 alldata['parenttime'].append(
2507 (data['p2.time'], b.hex(), p2.hex())
2507 (data['p2.time'], b.hex(), p2.hex())
2508 )
2508 )
2509 if p1missing or p2missing:
2509 if p1missing or p2missing:
2510 alldata['totalnbrenames'].append(
2510 alldata['totalnbrenames'].append(
2511 (
2511 (
2512 data['nbrenamedfiles'],
2512 data['nbrenamedfiles'],
2513 b.hex(),
2513 b.hex(),
2514 p1.hex(),
2514 p1.hex(),
2515 p2.hex(),
2515 p2.hex(),
2516 )
2516 )
2517 )
2517 )
2518 alldata['totaltime'].append(
2518 alldata['totaltime'].append(
2519 (data['time'], b.hex(), p1.hex(), p2.hex())
2519 (data['time'], b.hex(), p1.hex(), p2.hex())
2520 )
2520 )
2521 fm.startitem()
2521 fm.startitem()
2522 fm.data(**data)
2522 fm.data(**data)
2523 # make node pretty for the human output
2523 # make node pretty for the human output
2524 out = data.copy()
2524 out = data.copy()
2525 out['base'] = fm.hexfunc(b.node())
2525 out['base'] = fm.hexfunc(b.node())
2526 out['p1.node'] = fm.hexfunc(p1.node())
2526 out['p1.node'] = fm.hexfunc(p1.node())
2527 out['p2.node'] = fm.hexfunc(p2.node())
2527 out['p2.node'] = fm.hexfunc(p2.node())
2528 fm.plain(output % out)
2528 fm.plain(output % out)
2529
2529
2530 fm.end()
2530 fm.end()
2531 if dostats:
2531 if dostats:
2532 # use a second formatter because the data are quite different, not sure
2532 # use a second formatter because the data are quite different, not sure
2533 # how it flies with the templater.
2533 # how it flies with the templater.
2534 entries = [
2534 entries = [
2535 ('nbrevs', 'number of revision covered'),
2535 ('nbrevs', 'number of revision covered'),
2536 ('nbmissingfiles', 'number of missing files at head'),
2536 ('nbmissingfiles', 'number of missing files at head'),
2537 ]
2537 ]
2538 if dotiming:
2538 if dotiming:
2539 entries.append(
2539 entries.append(
2540 ('parentnbrenames', 'rename from one parent to base')
2540 ('parentnbrenames', 'rename from one parent to base')
2541 )
2541 )
2542 entries.append(('totalnbrenames', 'total number of renames'))
2542 entries.append(('totalnbrenames', 'total number of renames'))
2543 entries.append(('parenttime', 'time for one parent'))
2543 entries.append(('parenttime', 'time for one parent'))
2544 entries.append(('totaltime', 'time for both parents'))
2544 entries.append(('totaltime', 'time for both parents'))
2545 _displaystats(ui, opts, entries, alldata)
2545 _displaystats(ui, opts, entries, alldata)
2546
2546
2547
2547
2548 @command(
2548 @command(
2549 b'perf::helper-pathcopies|perfhelper-pathcopies',
2549 b'perf::helper-pathcopies|perfhelper-pathcopies',
2550 formatteropts
2550 formatteropts
2551 + [
2551 + [
2552 (b'r', b'revs', [], b'restrict search to these revisions'),
2552 (b'r', b'revs', [], b'restrict search to these revisions'),
2553 (b'', b'timing', False, b'provides extra data (costly)'),
2553 (b'', b'timing', False, b'provides extra data (costly)'),
2554 (b'', b'stats', False, b'provides statistic about the measured data'),
2554 (b'', b'stats', False, b'provides statistic about the measured data'),
2555 ],
2555 ],
2556 )
2556 )
2557 def perfhelperpathcopies(ui, repo, revs=[], **opts):
2557 def perfhelperpathcopies(ui, repo, revs=[], **opts):
2558 """find statistic about potential parameters for the `perftracecopies`
2558 """find statistic about potential parameters for the `perftracecopies`
2559
2559
2560 This command find source-destination pair relevant for copytracing testing.
2560 This command find source-destination pair relevant for copytracing testing.
2561 It report value for some of the parameters that impact copy tracing time.
2561 It report value for some of the parameters that impact copy tracing time.
2562
2562
2563 If `--timing` is set, rename detection is run and the associated timing
2563 If `--timing` is set, rename detection is run and the associated timing
2564 will be reported. The extra details comes at the cost of a slower command
2564 will be reported. The extra details comes at the cost of a slower command
2565 execution.
2565 execution.
2566
2566
2567 Since the rename detection is only run once, other factors might easily
2567 Since the rename detection is only run once, other factors might easily
2568 affect the precision of the timing. However it should give a good
2568 affect the precision of the timing. However it should give a good
2569 approximation of which revision pairs are very costly.
2569 approximation of which revision pairs are very costly.
2570 """
2570 """
2571 opts = _byteskwargs(opts)
2571 opts = _byteskwargs(opts)
2572 fm = ui.formatter(b'perf', opts)
2572 fm = ui.formatter(b'perf', opts)
2573 dotiming = opts[b'timing']
2573 dotiming = opts[b'timing']
2574 dostats = opts[b'stats']
2574 dostats = opts[b'stats']
2575
2575
2576 if dotiming:
2576 if dotiming:
2577 header = '%12s %12s %12s %12s %12s %12s\n'
2577 header = '%12s %12s %12s %12s %12s %12s\n'
2578 output = (
2578 output = (
2579 "%(source)12s %(destination)12s "
2579 "%(source)12s %(destination)12s "
2580 "%(nbrevs)12d %(nbmissingfiles)12d "
2580 "%(nbrevs)12d %(nbmissingfiles)12d "
2581 "%(nbrenamedfiles)12d %(time)18.5f\n"
2581 "%(nbrenamedfiles)12d %(time)18.5f\n"
2582 )
2582 )
2583 header_names = (
2583 header_names = (
2584 "source",
2584 "source",
2585 "destination",
2585 "destination",
2586 "nb-revs",
2586 "nb-revs",
2587 "nb-files",
2587 "nb-files",
2588 "nb-renames",
2588 "nb-renames",
2589 "time",
2589 "time",
2590 )
2590 )
2591 fm.plain(header % header_names)
2591 fm.plain(header % header_names)
2592 else:
2592 else:
2593 header = '%12s %12s %12s %12s\n'
2593 header = '%12s %12s %12s %12s\n'
2594 output = (
2594 output = (
2595 "%(source)12s %(destination)12s "
2595 "%(source)12s %(destination)12s "
2596 "%(nbrevs)12d %(nbmissingfiles)12d\n"
2596 "%(nbrevs)12d %(nbmissingfiles)12d\n"
2597 )
2597 )
2598 fm.plain(header % ("source", "destination", "nb-revs", "nb-files"))
2598 fm.plain(header % ("source", "destination", "nb-revs", "nb-files"))
2599
2599
2600 if not revs:
2600 if not revs:
2601 revs = ['all()']
2601 revs = ['all()']
2602 revs = scmutil.revrange(repo, revs)
2602 revs = scmutil.revrange(repo, revs)
2603
2603
2604 if dostats:
2604 if dostats:
2605 alldata = {
2605 alldata = {
2606 'nbrevs': [],
2606 'nbrevs': [],
2607 'nbmissingfiles': [],
2607 'nbmissingfiles': [],
2608 }
2608 }
2609 if dotiming:
2609 if dotiming:
2610 alldata['nbrenames'] = []
2610 alldata['nbrenames'] = []
2611 alldata['time'] = []
2611 alldata['time'] = []
2612
2612
2613 roi = repo.revs('merge() and %ld', revs)
2613 roi = repo.revs('merge() and %ld', revs)
2614 for r in roi:
2614 for r in roi:
2615 ctx = repo[r]
2615 ctx = repo[r]
2616 p1 = ctx.p1().rev()
2616 p1 = ctx.p1().rev()
2617 p2 = ctx.p2().rev()
2617 p2 = ctx.p2().rev()
2618 bases = repo.changelog._commonancestorsheads(p1, p2)
2618 bases = repo.changelog._commonancestorsheads(p1, p2)
2619 for p in (p1, p2):
2619 for p in (p1, p2):
2620 for b in bases:
2620 for b in bases:
2621 base = repo[b]
2621 base = repo[b]
2622 parent = repo[p]
2622 parent = repo[p]
2623 missing = copies._computeforwardmissing(base, parent)
2623 missing = copies._computeforwardmissing(base, parent)
2624 if not missing:
2624 if not missing:
2625 continue
2625 continue
2626 data = {
2626 data = {
2627 b'source': base.hex(),
2627 b'source': base.hex(),
2628 b'destination': parent.hex(),
2628 b'destination': parent.hex(),
2629 b'nbrevs': len(repo.revs('only(%d, %d)', p, b)),
2629 b'nbrevs': len(repo.revs('only(%d, %d)', p, b)),
2630 b'nbmissingfiles': len(missing),
2630 b'nbmissingfiles': len(missing),
2631 }
2631 }
2632 if dostats:
2632 if dostats:
2633 alldata['nbrevs'].append(
2633 alldata['nbrevs'].append(
2634 (
2634 (
2635 data['nbrevs'],
2635 data['nbrevs'],
2636 base.hex(),
2636 base.hex(),
2637 parent.hex(),
2637 parent.hex(),
2638 )
2638 )
2639 )
2639 )
2640 alldata['nbmissingfiles'].append(
2640 alldata['nbmissingfiles'].append(
2641 (
2641 (
2642 data['nbmissingfiles'],
2642 data['nbmissingfiles'],
2643 base.hex(),
2643 base.hex(),
2644 parent.hex(),
2644 parent.hex(),
2645 )
2645 )
2646 )
2646 )
2647 if dotiming:
2647 if dotiming:
2648 begin = util.timer()
2648 begin = util.timer()
2649 renames = copies.pathcopies(base, parent)
2649 renames = copies.pathcopies(base, parent)
2650 end = util.timer()
2650 end = util.timer()
2651 # not very stable timing since we did only one run
2651 # not very stable timing since we did only one run
2652 data['time'] = end - begin
2652 data['time'] = end - begin
2653 data['nbrenamedfiles'] = len(renames)
2653 data['nbrenamedfiles'] = len(renames)
2654 if dostats:
2654 if dostats:
2655 alldata['time'].append(
2655 alldata['time'].append(
2656 (
2656 (
2657 data['time'],
2657 data['time'],
2658 base.hex(),
2658 base.hex(),
2659 parent.hex(),
2659 parent.hex(),
2660 )
2660 )
2661 )
2661 )
2662 alldata['nbrenames'].append(
2662 alldata['nbrenames'].append(
2663 (
2663 (
2664 data['nbrenamedfiles'],
2664 data['nbrenamedfiles'],
2665 base.hex(),
2665 base.hex(),
2666 parent.hex(),
2666 parent.hex(),
2667 )
2667 )
2668 )
2668 )
2669 fm.startitem()
2669 fm.startitem()
2670 fm.data(**data)
2670 fm.data(**data)
2671 out = data.copy()
2671 out = data.copy()
2672 out['source'] = fm.hexfunc(base.node())
2672 out['source'] = fm.hexfunc(base.node())
2673 out['destination'] = fm.hexfunc(parent.node())
2673 out['destination'] = fm.hexfunc(parent.node())
2674 fm.plain(output % out)
2674 fm.plain(output % out)
2675
2675
2676 fm.end()
2676 fm.end()
2677 if dostats:
2677 if dostats:
2678 entries = [
2678 entries = [
2679 ('nbrevs', 'number of revision covered'),
2679 ('nbrevs', 'number of revision covered'),
2680 ('nbmissingfiles', 'number of missing files at head'),
2680 ('nbmissingfiles', 'number of missing files at head'),
2681 ]
2681 ]
2682 if dotiming:
2682 if dotiming:
2683 entries.append(('nbrenames', 'renamed files'))
2683 entries.append(('nbrenames', 'renamed files'))
2684 entries.append(('time', 'time'))
2684 entries.append(('time', 'time'))
2685 _displaystats(ui, opts, entries, alldata)
2685 _displaystats(ui, opts, entries, alldata)
2686
2686
2687
2687
2688 @command(b'perf::cca|perfcca', formatteropts)
2688 @command(b'perf::cca|perfcca', formatteropts)
2689 def perfcca(ui, repo, **opts):
2689 def perfcca(ui, repo, **opts):
2690 opts = _byteskwargs(opts)
2690 opts = _byteskwargs(opts)
2691 timer, fm = gettimer(ui, opts)
2691 timer, fm = gettimer(ui, opts)
2692 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
2692 timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
2693 fm.end()
2693 fm.end()
2694
2694
2695
2695
2696 @command(b'perf::fncacheload|perffncacheload', formatteropts)
2696 @command(b'perf::fncacheload|perffncacheload', formatteropts)
2697 def perffncacheload(ui, repo, **opts):
2697 def perffncacheload(ui, repo, **opts):
2698 opts = _byteskwargs(opts)
2698 opts = _byteskwargs(opts)
2699 timer, fm = gettimer(ui, opts)
2699 timer, fm = gettimer(ui, opts)
2700 s = repo.store
2700 s = repo.store
2701
2701
2702 def d():
2702 def d():
2703 s.fncache._load()
2703 s.fncache._load()
2704
2704
2705 timer(d)
2705 timer(d)
2706 fm.end()
2706 fm.end()
2707
2707
2708
2708
2709 @command(b'perf::fncachewrite|perffncachewrite', formatteropts)
2709 @command(b'perf::fncachewrite|perffncachewrite', formatteropts)
2710 def perffncachewrite(ui, repo, **opts):
2710 def perffncachewrite(ui, repo, **opts):
2711 opts = _byteskwargs(opts)
2711 opts = _byteskwargs(opts)
2712 timer, fm = gettimer(ui, opts)
2712 timer, fm = gettimer(ui, opts)
2713 s = repo.store
2713 s = repo.store
2714 lock = repo.lock()
2714 lock = repo.lock()
2715 s.fncache._load()
2715 s.fncache._load()
2716 tr = repo.transaction(b'perffncachewrite')
2716 tr = repo.transaction(b'perffncachewrite')
2717 tr.addbackup(b'fncache')
2717 tr.addbackup(b'fncache')
2718
2718
2719 def d():
2719 def d():
2720 s.fncache._dirty = True
2720 s.fncache._dirty = True
2721 s.fncache.write(tr)
2721 s.fncache.write(tr)
2722
2722
2723 timer(d)
2723 timer(d)
2724 tr.close()
2724 tr.close()
2725 lock.release()
2725 lock.release()
2726 fm.end()
2726 fm.end()
2727
2727
2728
2728
2729 @command(b'perf::fncacheencode|perffncacheencode', formatteropts)
2729 @command(b'perf::fncacheencode|perffncacheencode', formatteropts)
2730 def perffncacheencode(ui, repo, **opts):
2730 def perffncacheencode(ui, repo, **opts):
2731 opts = _byteskwargs(opts)
2731 opts = _byteskwargs(opts)
2732 timer, fm = gettimer(ui, opts)
2732 timer, fm = gettimer(ui, opts)
2733 s = repo.store
2733 s = repo.store
2734 s.fncache._load()
2734 s.fncache._load()
2735
2735
2736 def d():
2736 def d():
2737 for p in s.fncache.entries:
2737 for p in s.fncache.entries:
2738 s.encode(p)
2738 s.encode(p)
2739
2739
2740 timer(d)
2740 timer(d)
2741 fm.end()
2741 fm.end()
2742
2742
2743
2743
2744 def _bdiffworker(q, blocks, xdiff, ready, done):
2744 def _bdiffworker(q, blocks, xdiff, ready, done):
2745 while not done.is_set():
2745 while not done.is_set():
2746 pair = q.get()
2746 pair = q.get()
2747 while pair is not None:
2747 while pair is not None:
2748 if xdiff:
2748 if xdiff:
2749 mdiff.bdiff.xdiffblocks(*pair)
2749 mdiff.bdiff.xdiffblocks(*pair)
2750 elif blocks:
2750 elif blocks:
2751 mdiff.bdiff.blocks(*pair)
2751 mdiff.bdiff.blocks(*pair)
2752 else:
2752 else:
2753 mdiff.textdiff(*pair)
2753 mdiff.textdiff(*pair)
2754 q.task_done()
2754 q.task_done()
2755 pair = q.get()
2755 pair = q.get()
2756 q.task_done() # for the None one
2756 q.task_done() # for the None one
2757 with ready:
2757 with ready:
2758 ready.wait()
2758 ready.wait()
2759
2759
2760
2760
2761 def _manifestrevision(repo, mnode):
2761 def _manifestrevision(repo, mnode):
2762 ml = repo.manifestlog
2762 ml = repo.manifestlog
2763
2763
2764 if util.safehasattr(ml, b'getstorage'):
2764 if util.safehasattr(ml, b'getstorage'):
2765 store = ml.getstorage(b'')
2765 store = ml.getstorage(b'')
2766 else:
2766 else:
2767 store = ml._revlog
2767 store = ml._revlog
2768
2768
2769 return store.revision(mnode)
2769 return store.revision(mnode)
2770
2770
2771
2771
2772 @command(
2772 @command(
2773 b'perf::bdiff|perfbdiff',
2773 b'perf::bdiff|perfbdiff',
2774 revlogopts
2774 revlogopts
2775 + formatteropts
2775 + formatteropts
2776 + [
2776 + [
2777 (
2777 (
2778 b'',
2778 b'',
2779 b'count',
2779 b'count',
2780 1,
2780 1,
2781 b'number of revisions to test (when using --startrev)',
2781 b'number of revisions to test (when using --startrev)',
2782 ),
2782 ),
2783 (b'', b'alldata', False, b'test bdiffs for all associated revisions'),
2783 (b'', b'alldata', False, b'test bdiffs for all associated revisions'),
2784 (b'', b'threads', 0, b'number of thread to use (disable with 0)'),
2784 (b'', b'threads', 0, b'number of thread to use (disable with 0)'),
2785 (b'', b'blocks', False, b'test computing diffs into blocks'),
2785 (b'', b'blocks', False, b'test computing diffs into blocks'),
2786 (b'', b'xdiff', False, b'use xdiff algorithm'),
2786 (b'', b'xdiff', False, b'use xdiff algorithm'),
2787 ],
2787 ],
2788 b'-c|-m|FILE REV',
2788 b'-c|-m|FILE REV',
2789 )
2789 )
2790 def perfbdiff(ui, repo, file_, rev=None, count=None, threads=0, **opts):
2790 def perfbdiff(ui, repo, file_, rev=None, count=None, threads=0, **opts):
2791 """benchmark a bdiff between revisions
2791 """benchmark a bdiff between revisions
2792
2792
2793 By default, benchmark a bdiff between its delta parent and itself.
2793 By default, benchmark a bdiff between its delta parent and itself.
2794
2794
2795 With ``--count``, benchmark bdiffs between delta parents and self for N
2795 With ``--count``, benchmark bdiffs between delta parents and self for N
2796 revisions starting at the specified revision.
2796 revisions starting at the specified revision.
2797
2797
2798 With ``--alldata``, assume the requested revision is a changeset and
2798 With ``--alldata``, assume the requested revision is a changeset and
2799 measure bdiffs for all changes related to that changeset (manifest
2799 measure bdiffs for all changes related to that changeset (manifest
2800 and filelogs).
2800 and filelogs).
2801 """
2801 """
2802 opts = _byteskwargs(opts)
2802 opts = _byteskwargs(opts)
2803
2803
2804 if opts[b'xdiff'] and not opts[b'blocks']:
2804 if opts[b'xdiff'] and not opts[b'blocks']:
2805 raise error.CommandError(b'perfbdiff', b'--xdiff requires --blocks')
2805 raise error.CommandError(b'perfbdiff', b'--xdiff requires --blocks')
2806
2806
2807 if opts[b'alldata']:
2807 if opts[b'alldata']:
2808 opts[b'changelog'] = True
2808 opts[b'changelog'] = True
2809
2809
2810 if opts.get(b'changelog') or opts.get(b'manifest'):
2810 if opts.get(b'changelog') or opts.get(b'manifest'):
2811 file_, rev = None, file_
2811 file_, rev = None, file_
2812 elif rev is None:
2812 elif rev is None:
2813 raise error.CommandError(b'perfbdiff', b'invalid arguments')
2813 raise error.CommandError(b'perfbdiff', b'invalid arguments')
2814
2814
2815 blocks = opts[b'blocks']
2815 blocks = opts[b'blocks']
2816 xdiff = opts[b'xdiff']
2816 xdiff = opts[b'xdiff']
2817 textpairs = []
2817 textpairs = []
2818
2818
2819 r = cmdutil.openrevlog(repo, b'perfbdiff', file_, opts)
2819 r = cmdutil.openrevlog(repo, b'perfbdiff', file_, opts)
2820
2820
2821 startrev = r.rev(r.lookup(rev))
2821 startrev = r.rev(r.lookup(rev))
2822 for rev in range(startrev, min(startrev + count, len(r) - 1)):
2822 for rev in range(startrev, min(startrev + count, len(r) - 1)):
2823 if opts[b'alldata']:
2823 if opts[b'alldata']:
2824 # Load revisions associated with changeset.
2824 # Load revisions associated with changeset.
2825 ctx = repo[rev]
2825 ctx = repo[rev]
2826 mtext = _manifestrevision(repo, ctx.manifestnode())
2826 mtext = _manifestrevision(repo, ctx.manifestnode())
2827 for pctx in ctx.parents():
2827 for pctx in ctx.parents():
2828 pman = _manifestrevision(repo, pctx.manifestnode())
2828 pman = _manifestrevision(repo, pctx.manifestnode())
2829 textpairs.append((pman, mtext))
2829 textpairs.append((pman, mtext))
2830
2830
2831 # Load filelog revisions by iterating manifest delta.
2831 # Load filelog revisions by iterating manifest delta.
2832 man = ctx.manifest()
2832 man = ctx.manifest()
2833 pman = ctx.p1().manifest()
2833 pman = ctx.p1().manifest()
2834 for filename, change in pman.diff(man).items():
2834 for filename, change in pman.diff(man).items():
2835 fctx = repo.file(filename)
2835 fctx = repo.file(filename)
2836 f1 = fctx.revision(change[0][0] or -1)
2836 f1 = fctx.revision(change[0][0] or -1)
2837 f2 = fctx.revision(change[1][0] or -1)
2837 f2 = fctx.revision(change[1][0] or -1)
2838 textpairs.append((f1, f2))
2838 textpairs.append((f1, f2))
2839 else:
2839 else:
2840 dp = r.deltaparent(rev)
2840 dp = r.deltaparent(rev)
2841 textpairs.append((r.revision(dp), r.revision(rev)))
2841 textpairs.append((r.revision(dp), r.revision(rev)))
2842
2842
2843 withthreads = threads > 0
2843 withthreads = threads > 0
2844 if not withthreads:
2844 if not withthreads:
2845
2845
2846 def d():
2846 def d():
2847 for pair in textpairs:
2847 for pair in textpairs:
2848 if xdiff:
2848 if xdiff:
2849 mdiff.bdiff.xdiffblocks(*pair)
2849 mdiff.bdiff.xdiffblocks(*pair)
2850 elif blocks:
2850 elif blocks:
2851 mdiff.bdiff.blocks(*pair)
2851 mdiff.bdiff.blocks(*pair)
2852 else:
2852 else:
2853 mdiff.textdiff(*pair)
2853 mdiff.textdiff(*pair)
2854
2854
2855 else:
2855 else:
2856 q = queue()
2856 q = queue()
2857 for i in _xrange(threads):
2857 for i in _xrange(threads):
2858 q.put(None)
2858 q.put(None)
2859 ready = threading.Condition()
2859 ready = threading.Condition()
2860 done = threading.Event()
2860 done = threading.Event()
2861 for i in _xrange(threads):
2861 for i in _xrange(threads):
2862 threading.Thread(
2862 threading.Thread(
2863 target=_bdiffworker, args=(q, blocks, xdiff, ready, done)
2863 target=_bdiffworker, args=(q, blocks, xdiff, ready, done)
2864 ).start()
2864 ).start()
2865 q.join()
2865 q.join()
2866
2866
2867 def d():
2867 def d():
2868 for pair in textpairs:
2868 for pair in textpairs:
2869 q.put(pair)
2869 q.put(pair)
2870 for i in _xrange(threads):
2870 for i in _xrange(threads):
2871 q.put(None)
2871 q.put(None)
2872 with ready:
2872 with ready:
2873 ready.notify_all()
2873 ready.notify_all()
2874 q.join()
2874 q.join()
2875
2875
2876 timer, fm = gettimer(ui, opts)
2876 timer, fm = gettimer(ui, opts)
2877 timer(d)
2877 timer(d)
2878 fm.end()
2878 fm.end()
2879
2879
2880 if withthreads:
2880 if withthreads:
2881 done.set()
2881 done.set()
2882 for i in _xrange(threads):
2882 for i in _xrange(threads):
2883 q.put(None)
2883 q.put(None)
2884 with ready:
2884 with ready:
2885 ready.notify_all()
2885 ready.notify_all()
2886
2886
2887
2887
2888 @command(
2888 @command(
2889 b'perf::unbundle',
2889 b'perf::unbundle',
2890 formatteropts,
2890 formatteropts,
2891 b'BUNDLE_FILE',
2891 b'BUNDLE_FILE',
2892 )
2892 )
2893 def perf_unbundle(ui, repo, fname, **opts):
2893 def perf_unbundle(ui, repo, fname, **opts):
2894 """benchmark application of a bundle in a repository.
2894 """benchmark application of a bundle in a repository.
2895
2895
2896 This does not include the final transaction processing"""
2896 This does not include the final transaction processing"""
2897
2897
2898 from mercurial import exchange
2898 from mercurial import exchange
2899 from mercurial import bundle2
2899 from mercurial import bundle2
2900 from mercurial import transaction
2900 from mercurial import transaction
2901
2901
2902 opts = _byteskwargs(opts)
2902 opts = _byteskwargs(opts)
2903
2903
2904 ### some compatibility hotfix
2904 ### some compatibility hotfix
2905 #
2905 #
2906 # the data attribute is dropped in 63edc384d3b7 a changeset introducing a
2906 # the data attribute is dropped in 63edc384d3b7 a changeset introducing a
2907 # critical regression that break transaction rollback for files that are
2907 # critical regression that break transaction rollback for files that are
2908 # de-inlined.
2908 # de-inlined.
2909 method = transaction.transaction._addentry
2909 method = transaction.transaction._addentry
2910 pre_63edc384d3b7 = "data" in getargspec(method).args
2910 pre_63edc384d3b7 = "data" in getargspec(method).args
2911 # the `detailed_exit_code` attribute is introduced in 33c0c25d0b0f
2911 # the `detailed_exit_code` attribute is introduced in 33c0c25d0b0f
2912 # a changeset that is a close descendant of 18415fc918a1, the changeset
2912 # a changeset that is a close descendant of 18415fc918a1, the changeset
2913 # that conclude the fix run for the bug introduced in 63edc384d3b7.
2913 # that conclude the fix run for the bug introduced in 63edc384d3b7.
2914 args = getargspec(error.Abort.__init__).args
2914 args = getargspec(error.Abort.__init__).args
2915 post_18415fc918a1 = "detailed_exit_code" in args
2915 post_18415fc918a1 = "detailed_exit_code" in args
2916
2916
2917 old_max_inline = None
2917 old_max_inline = None
2918 try:
2918 try:
2919 if not (pre_63edc384d3b7 or post_18415fc918a1):
2919 if not (pre_63edc384d3b7 or post_18415fc918a1):
2920 # disable inlining
2920 # disable inlining
2921 old_max_inline = mercurial.revlog._maxinline
2921 old_max_inline = mercurial.revlog._maxinline
2922 # large enough to never happen
2922 # large enough to never happen
2923 mercurial.revlog._maxinline = 2 ** 50
2923 mercurial.revlog._maxinline = 2 ** 50
2924
2924
2925 with repo.lock():
2925 with repo.lock():
2926 bundle = [None, None]
2926 bundle = [None, None]
2927 orig_quiet = repo.ui.quiet
2927 orig_quiet = repo.ui.quiet
2928 try:
2928 try:
2929 repo.ui.quiet = True
2929 repo.ui.quiet = True
2930 with open(fname, mode="rb") as f:
2930 with open(fname, mode="rb") as f:
2931
2931
2932 def noop_report(*args, **kwargs):
2932 def noop_report(*args, **kwargs):
2933 pass
2933 pass
2934
2934
2935 def setup():
2935 def setup():
2936 gen, tr = bundle
2936 gen, tr = bundle
2937 if tr is not None:
2937 if tr is not None:
2938 tr.abort()
2938 tr.abort()
2939 bundle[:] = [None, None]
2939 bundle[:] = [None, None]
2940 f.seek(0)
2940 f.seek(0)
2941 bundle[0] = exchange.readbundle(ui, f, fname)
2941 bundle[0] = exchange.readbundle(ui, f, fname)
2942 bundle[1] = repo.transaction(b'perf::unbundle')
2942 bundle[1] = repo.transaction(b'perf::unbundle')
2943 # silence the transaction
2943 # silence the transaction
2944 bundle[1]._report = noop_report
2944 bundle[1]._report = noop_report
2945
2945
2946 def apply():
2946 def apply():
2947 gen, tr = bundle
2947 gen, tr = bundle
2948 bundle2.applybundle(
2948 bundle2.applybundle(
2949 repo,
2949 repo,
2950 gen,
2950 gen,
2951 tr,
2951 tr,
2952 source=b'perf::unbundle',
2952 source=b'perf::unbundle',
2953 url=fname,
2953 url=fname,
2954 )
2954 )
2955
2955
2956 timer, fm = gettimer(ui, opts)
2956 timer, fm = gettimer(ui, opts)
2957 timer(apply, setup=setup)
2957 timer(apply, setup=setup)
2958 fm.end()
2958 fm.end()
2959 finally:
2959 finally:
2960 repo.ui.quiet == orig_quiet
2960 repo.ui.quiet == orig_quiet
2961 gen, tr = bundle
2961 gen, tr = bundle
2962 if tr is not None:
2962 if tr is not None:
2963 tr.abort()
2963 tr.abort()
2964 finally:
2964 finally:
2965 if old_max_inline is not None:
2965 if old_max_inline is not None:
2966 mercurial.revlog._maxinline = old_max_inline
2966 mercurial.revlog._maxinline = old_max_inline
2967
2967
2968
2968
2969 @command(
2969 @command(
2970 b'perf::unidiff|perfunidiff',
2970 b'perf::unidiff|perfunidiff',
2971 revlogopts
2971 revlogopts
2972 + formatteropts
2972 + formatteropts
2973 + [
2973 + [
2974 (
2974 (
2975 b'',
2975 b'',
2976 b'count',
2976 b'count',
2977 1,
2977 1,
2978 b'number of revisions to test (when using --startrev)',
2978 b'number of revisions to test (when using --startrev)',
2979 ),
2979 ),
2980 (b'', b'alldata', False, b'test unidiffs for all associated revisions'),
2980 (b'', b'alldata', False, b'test unidiffs for all associated revisions'),
2981 ],
2981 ],
2982 b'-c|-m|FILE REV',
2982 b'-c|-m|FILE REV',
2983 )
2983 )
2984 def perfunidiff(ui, repo, file_, rev=None, count=None, **opts):
2984 def perfunidiff(ui, repo, file_, rev=None, count=None, **opts):
2985 """benchmark a unified diff between revisions
2985 """benchmark a unified diff between revisions
2986
2986
2987 This doesn't include any copy tracing - it's just a unified diff
2987 This doesn't include any copy tracing - it's just a unified diff
2988 of the texts.
2988 of the texts.
2989
2989
2990 By default, benchmark a diff between its delta parent and itself.
2990 By default, benchmark a diff between its delta parent and itself.
2991
2991
2992 With ``--count``, benchmark diffs between delta parents and self for N
2992 With ``--count``, benchmark diffs between delta parents and self for N
2993 revisions starting at the specified revision.
2993 revisions starting at the specified revision.
2994
2994
2995 With ``--alldata``, assume the requested revision is a changeset and
2995 With ``--alldata``, assume the requested revision is a changeset and
2996 measure diffs for all changes related to that changeset (manifest
2996 measure diffs for all changes related to that changeset (manifest
2997 and filelogs).
2997 and filelogs).
2998 """
2998 """
2999 opts = _byteskwargs(opts)
2999 opts = _byteskwargs(opts)
3000 if opts[b'alldata']:
3000 if opts[b'alldata']:
3001 opts[b'changelog'] = True
3001 opts[b'changelog'] = True
3002
3002
3003 if opts.get(b'changelog') or opts.get(b'manifest'):
3003 if opts.get(b'changelog') or opts.get(b'manifest'):
3004 file_, rev = None, file_
3004 file_, rev = None, file_
3005 elif rev is None:
3005 elif rev is None:
3006 raise error.CommandError(b'perfunidiff', b'invalid arguments')
3006 raise error.CommandError(b'perfunidiff', b'invalid arguments')
3007
3007
3008 textpairs = []
3008 textpairs = []
3009
3009
3010 r = cmdutil.openrevlog(repo, b'perfunidiff', file_, opts)
3010 r = cmdutil.openrevlog(repo, b'perfunidiff', file_, opts)
3011
3011
3012 startrev = r.rev(r.lookup(rev))
3012 startrev = r.rev(r.lookup(rev))
3013 for rev in range(startrev, min(startrev + count, len(r) - 1)):
3013 for rev in range(startrev, min(startrev + count, len(r) - 1)):
3014 if opts[b'alldata']:
3014 if opts[b'alldata']:
3015 # Load revisions associated with changeset.
3015 # Load revisions associated with changeset.
3016 ctx = repo[rev]
3016 ctx = repo[rev]
3017 mtext = _manifestrevision(repo, ctx.manifestnode())
3017 mtext = _manifestrevision(repo, ctx.manifestnode())
3018 for pctx in ctx.parents():
3018 for pctx in ctx.parents():
3019 pman = _manifestrevision(repo, pctx.manifestnode())
3019 pman = _manifestrevision(repo, pctx.manifestnode())
3020 textpairs.append((pman, mtext))
3020 textpairs.append((pman, mtext))
3021
3021
3022 # Load filelog revisions by iterating manifest delta.
3022 # Load filelog revisions by iterating manifest delta.
3023 man = ctx.manifest()
3023 man = ctx.manifest()
3024 pman = ctx.p1().manifest()
3024 pman = ctx.p1().manifest()
3025 for filename, change in pman.diff(man).items():
3025 for filename, change in pman.diff(man).items():
3026 fctx = repo.file(filename)
3026 fctx = repo.file(filename)
3027 f1 = fctx.revision(change[0][0] or -1)
3027 f1 = fctx.revision(change[0][0] or -1)
3028 f2 = fctx.revision(change[1][0] or -1)
3028 f2 = fctx.revision(change[1][0] or -1)
3029 textpairs.append((f1, f2))
3029 textpairs.append((f1, f2))
3030 else:
3030 else:
3031 dp = r.deltaparent(rev)
3031 dp = r.deltaparent(rev)
3032 textpairs.append((r.revision(dp), r.revision(rev)))
3032 textpairs.append((r.revision(dp), r.revision(rev)))
3033
3033
3034 def d():
3034 def d():
3035 for left, right in textpairs:
3035 for left, right in textpairs:
3036 # The date strings don't matter, so we pass empty strings.
3036 # The date strings don't matter, so we pass empty strings.
3037 headerlines, hunks = mdiff.unidiff(
3037 headerlines, hunks = mdiff.unidiff(
3038 left, b'', right, b'', b'left', b'right', binary=False
3038 left, b'', right, b'', b'left', b'right', binary=False
3039 )
3039 )
3040 # consume iterators in roughly the way patch.py does
3040 # consume iterators in roughly the way patch.py does
3041 b'\n'.join(headerlines)
3041 b'\n'.join(headerlines)
3042 b''.join(sum((list(hlines) for hrange, hlines in hunks), []))
3042 b''.join(sum((list(hlines) for hrange, hlines in hunks), []))
3043
3043
3044 timer, fm = gettimer(ui, opts)
3044 timer, fm = gettimer(ui, opts)
3045 timer(d)
3045 timer(d)
3046 fm.end()
3046 fm.end()
3047
3047
3048
3048
3049 @command(b'perf::diffwd|perfdiffwd', formatteropts)
3049 @command(b'perf::diffwd|perfdiffwd', formatteropts)
3050 def perfdiffwd(ui, repo, **opts):
3050 def perfdiffwd(ui, repo, **opts):
3051 """Profile diff of working directory changes"""
3051 """Profile diff of working directory changes"""
3052 opts = _byteskwargs(opts)
3052 opts = _byteskwargs(opts)
3053 timer, fm = gettimer(ui, opts)
3053 timer, fm = gettimer(ui, opts)
3054 options = {
3054 options = {
3055 'w': 'ignore_all_space',
3055 'w': 'ignore_all_space',
3056 'b': 'ignore_space_change',
3056 'b': 'ignore_space_change',
3057 'B': 'ignore_blank_lines',
3057 'B': 'ignore_blank_lines',
3058 }
3058 }
3059
3059
3060 for diffopt in ('', 'w', 'b', 'B', 'wB'):
3060 for diffopt in ('', 'w', 'b', 'B', 'wB'):
3061 opts = {options[c]: b'1' for c in diffopt}
3061 opts = {options[c]: b'1' for c in diffopt}
3062
3062
3063 def d():
3063 def d():
3064 ui.pushbuffer()
3064 ui.pushbuffer()
3065 commands.diff(ui, repo, **opts)
3065 commands.diff(ui, repo, **opts)
3066 ui.popbuffer()
3066 ui.popbuffer()
3067
3067
3068 diffopt = diffopt.encode('ascii')
3068 diffopt = diffopt.encode('ascii')
3069 title = b'diffopts: %s' % (diffopt and (b'-' + diffopt) or b'none')
3069 title = b'diffopts: %s' % (diffopt and (b'-' + diffopt) or b'none')
3070 timer(d, title=title)
3070 timer(d, title=title)
3071 fm.end()
3071 fm.end()
3072
3072
3073
3073
3074 @command(
3074 @command(
3075 b'perf::revlogindex|perfrevlogindex',
3075 b'perf::revlogindex|perfrevlogindex',
3076 revlogopts + formatteropts,
3076 revlogopts + formatteropts,
3077 b'-c|-m|FILE',
3077 b'-c|-m|FILE',
3078 )
3078 )
3079 def perfrevlogindex(ui, repo, file_=None, **opts):
3079 def perfrevlogindex(ui, repo, file_=None, **opts):
3080 """Benchmark operations against a revlog index.
3080 """Benchmark operations against a revlog index.
3081
3081
3082 This tests constructing a revlog instance, reading index data,
3082 This tests constructing a revlog instance, reading index data,
3083 parsing index data, and performing various operations related to
3083 parsing index data, and performing various operations related to
3084 index data.
3084 index data.
3085 """
3085 """
3086
3086
3087 opts = _byteskwargs(opts)
3087 opts = _byteskwargs(opts)
3088
3088
3089 rl = cmdutil.openrevlog(repo, b'perfrevlogindex', file_, opts)
3089 rl = cmdutil.openrevlog(repo, b'perfrevlogindex', file_, opts)
3090
3090
3091 opener = getattr(rl, 'opener') # trick linter
3091 opener = getattr(rl, 'opener') # trick linter
3092 # compat with hg <= 5.8
3092 # compat with hg <= 5.8
3093 radix = getattr(rl, 'radix', None)
3093 radix = getattr(rl, 'radix', None)
3094 indexfile = getattr(rl, '_indexfile', None)
3094 indexfile = getattr(rl, '_indexfile', None)
3095 if indexfile is None:
3095 if indexfile is None:
3096 # compatibility with <= hg-5.8
3096 # compatibility with <= hg-5.8
3097 indexfile = getattr(rl, 'indexfile')
3097 indexfile = getattr(rl, 'indexfile')
3098 data = opener.read(indexfile)
3098 data = opener.read(indexfile)
3099
3099
3100 header = struct.unpack(b'>I', data[0:4])[0]
3100 header = struct.unpack(b'>I', data[0:4])[0]
3101 version = header & 0xFFFF
3101 version = header & 0xFFFF
3102 if version == 1:
3102 if version == 1:
3103 inline = header & (1 << 16)
3103 inline = header & (1 << 16)
3104 else:
3104 else:
3105 raise error.Abort(b'unsupported revlog version: %d' % version)
3105 raise error.Abort(b'unsupported revlog version: %d' % version)
3106
3106
3107 parse_index_v1 = getattr(mercurial.revlog, 'parse_index_v1', None)
3107 parse_index_v1 = getattr(mercurial.revlog, 'parse_index_v1', None)
3108 if parse_index_v1 is None:
3108 if parse_index_v1 is None:
3109 parse_index_v1 = mercurial.revlog.revlogio().parseindex
3109 parse_index_v1 = mercurial.revlog.revlogio().parseindex
3110
3110
3111 rllen = len(rl)
3111 rllen = len(rl)
3112
3112
3113 node0 = rl.node(0)
3113 node0 = rl.node(0)
3114 node25 = rl.node(rllen // 4)
3114 node25 = rl.node(rllen // 4)
3115 node50 = rl.node(rllen // 2)
3115 node50 = rl.node(rllen // 2)
3116 node75 = rl.node(rllen // 4 * 3)
3116 node75 = rl.node(rllen // 4 * 3)
3117 node100 = rl.node(rllen - 1)
3117 node100 = rl.node(rllen - 1)
3118
3118
3119 allrevs = range(rllen)
3119 allrevs = range(rllen)
3120 allrevsrev = list(reversed(allrevs))
3120 allrevsrev = list(reversed(allrevs))
3121 allnodes = [rl.node(rev) for rev in range(rllen)]
3121 allnodes = [rl.node(rev) for rev in range(rllen)]
3122 allnodesrev = list(reversed(allnodes))
3122 allnodesrev = list(reversed(allnodes))
3123
3123
3124 def constructor():
3124 def constructor():
3125 if radix is not None:
3125 if radix is not None:
3126 revlog(opener, radix=radix)
3126 revlog(opener, radix=radix)
3127 else:
3127 else:
3128 # hg <= 5.8
3128 # hg <= 5.8
3129 revlog(opener, indexfile=indexfile)
3129 revlog(opener, indexfile=indexfile)
3130
3130
3131 def read():
3131 def read():
3132 with opener(indexfile) as fh:
3132 with opener(indexfile) as fh:
3133 fh.read()
3133 fh.read()
3134
3134
3135 def parseindex():
3135 def parseindex():
3136 parse_index_v1(data, inline)
3136 parse_index_v1(data, inline)
3137
3137
3138 def getentry(revornode):
3138 def getentry(revornode):
3139 index = parse_index_v1(data, inline)[0]
3139 index = parse_index_v1(data, inline)[0]
3140 index[revornode]
3140 index[revornode]
3141
3141
3142 def getentries(revs, count=1):
3142 def getentries(revs, count=1):
3143 index = parse_index_v1(data, inline)[0]
3143 index = parse_index_v1(data, inline)[0]
3144
3144
3145 for i in range(count):
3145 for i in range(count):
3146 for rev in revs:
3146 for rev in revs:
3147 index[rev]
3147 index[rev]
3148
3148
3149 def resolvenode(node):
3149 def resolvenode(node):
3150 index = parse_index_v1(data, inline)[0]
3150 index = parse_index_v1(data, inline)[0]
3151 rev = getattr(index, 'rev', None)
3151 rev = getattr(index, 'rev', None)
3152 if rev is None:
3152 if rev is None:
3153 nodemap = getattr(parse_index_v1(data, inline)[0], 'nodemap', None)
3153 nodemap = getattr(parse_index_v1(data, inline)[0], 'nodemap', None)
3154 # This only works for the C code.
3154 # This only works for the C code.
3155 if nodemap is None:
3155 if nodemap is None:
3156 return
3156 return
3157 rev = nodemap.__getitem__
3157 rev = nodemap.__getitem__
3158
3158
3159 try:
3159 try:
3160 rev(node)
3160 rev(node)
3161 except error.RevlogError:
3161 except error.RevlogError:
3162 pass
3162 pass
3163
3163
3164 def resolvenodes(nodes, count=1):
3164 def resolvenodes(nodes, count=1):
3165 index = parse_index_v1(data, inline)[0]
3165 index = parse_index_v1(data, inline)[0]
3166 rev = getattr(index, 'rev', None)
3166 rev = getattr(index, 'rev', None)
3167 if rev is None:
3167 if rev is None:
3168 nodemap = getattr(parse_index_v1(data, inline)[0], 'nodemap', None)
3168 nodemap = getattr(parse_index_v1(data, inline)[0], 'nodemap', None)
3169 # This only works for the C code.
3169 # This only works for the C code.
3170 if nodemap is None:
3170 if nodemap is None:
3171 return
3171 return
3172 rev = nodemap.__getitem__
3172 rev = nodemap.__getitem__
3173
3173
3174 for i in range(count):
3174 for i in range(count):
3175 for node in nodes:
3175 for node in nodes:
3176 try:
3176 try:
3177 rev(node)
3177 rev(node)
3178 except error.RevlogError:
3178 except error.RevlogError:
3179 pass
3179 pass
3180
3180
3181 benches = [
3181 benches = [
3182 (constructor, b'revlog constructor'),
3182 (constructor, b'revlog constructor'),
3183 (read, b'read'),
3183 (read, b'read'),
3184 (parseindex, b'create index object'),
3184 (parseindex, b'create index object'),
3185 (lambda: getentry(0), b'retrieve index entry for rev 0'),
3185 (lambda: getentry(0), b'retrieve index entry for rev 0'),
3186 (lambda: resolvenode(b'a' * 20), b'look up missing node'),
3186 (lambda: resolvenode(b'a' * 20), b'look up missing node'),
3187 (lambda: resolvenode(node0), b'look up node at rev 0'),
3187 (lambda: resolvenode(node0), b'look up node at rev 0'),
3188 (lambda: resolvenode(node25), b'look up node at 1/4 len'),
3188 (lambda: resolvenode(node25), b'look up node at 1/4 len'),
3189 (lambda: resolvenode(node50), b'look up node at 1/2 len'),
3189 (lambda: resolvenode(node50), b'look up node at 1/2 len'),
3190 (lambda: resolvenode(node75), b'look up node at 3/4 len'),
3190 (lambda: resolvenode(node75), b'look up node at 3/4 len'),
3191 (lambda: resolvenode(node100), b'look up node at tip'),
3191 (lambda: resolvenode(node100), b'look up node at tip'),
3192 # 2x variation is to measure caching impact.
3192 # 2x variation is to measure caching impact.
3193 (lambda: resolvenodes(allnodes), b'look up all nodes (forward)'),
3193 (lambda: resolvenodes(allnodes), b'look up all nodes (forward)'),
3194 (lambda: resolvenodes(allnodes, 2), b'look up all nodes 2x (forward)'),
3194 (lambda: resolvenodes(allnodes, 2), b'look up all nodes 2x (forward)'),
3195 (lambda: resolvenodes(allnodesrev), b'look up all nodes (reverse)'),
3195 (lambda: resolvenodes(allnodesrev), b'look up all nodes (reverse)'),
3196 (
3196 (
3197 lambda: resolvenodes(allnodesrev, 2),
3197 lambda: resolvenodes(allnodesrev, 2),
3198 b'look up all nodes 2x (reverse)',
3198 b'look up all nodes 2x (reverse)',
3199 ),
3199 ),
3200 (lambda: getentries(allrevs), b'retrieve all index entries (forward)'),
3200 (lambda: getentries(allrevs), b'retrieve all index entries (forward)'),
3201 (
3201 (
3202 lambda: getentries(allrevs, 2),
3202 lambda: getentries(allrevs, 2),
3203 b'retrieve all index entries 2x (forward)',
3203 b'retrieve all index entries 2x (forward)',
3204 ),
3204 ),
3205 (
3205 (
3206 lambda: getentries(allrevsrev),
3206 lambda: getentries(allrevsrev),
3207 b'retrieve all index entries (reverse)',
3207 b'retrieve all index entries (reverse)',
3208 ),
3208 ),
3209 (
3209 (
3210 lambda: getentries(allrevsrev, 2),
3210 lambda: getentries(allrevsrev, 2),
3211 b'retrieve all index entries 2x (reverse)',
3211 b'retrieve all index entries 2x (reverse)',
3212 ),
3212 ),
3213 ]
3213 ]
3214
3214
3215 for fn, title in benches:
3215 for fn, title in benches:
3216 timer, fm = gettimer(ui, opts)
3216 timer, fm = gettimer(ui, opts)
3217 timer(fn, title=title)
3217 timer(fn, title=title)
3218 fm.end()
3218 fm.end()
3219
3219
3220
3220
3221 @command(
3221 @command(
3222 b'perf::revlogrevisions|perfrevlogrevisions',
3222 b'perf::revlogrevisions|perfrevlogrevisions',
3223 revlogopts
3223 revlogopts
3224 + formatteropts
3224 + formatteropts
3225 + [
3225 + [
3226 (b'd', b'dist', 100, b'distance between the revisions'),
3226 (b'd', b'dist', 100, b'distance between the revisions'),
3227 (b's', b'startrev', 0, b'revision to start reading at'),
3227 (b's', b'startrev', 0, b'revision to start reading at'),
3228 (b'', b'reverse', False, b'read in reverse'),
3228 (b'', b'reverse', False, b'read in reverse'),
3229 ],
3229 ],
3230 b'-c|-m|FILE',
3230 b'-c|-m|FILE',
3231 )
3231 )
3232 def perfrevlogrevisions(
3232 def perfrevlogrevisions(
3233 ui, repo, file_=None, startrev=0, reverse=False, **opts
3233 ui, repo, file_=None, startrev=0, reverse=False, **opts
3234 ):
3234 ):
3235 """Benchmark reading a series of revisions from a revlog.
3235 """Benchmark reading a series of revisions from a revlog.
3236
3236
3237 By default, we read every ``-d/--dist`` revision from 0 to tip of
3237 By default, we read every ``-d/--dist`` revision from 0 to tip of
3238 the specified revlog.
3238 the specified revlog.
3239
3239
3240 The start revision can be defined via ``-s/--startrev``.
3240 The start revision can be defined via ``-s/--startrev``.
3241 """
3241 """
3242 opts = _byteskwargs(opts)
3242 opts = _byteskwargs(opts)
3243
3243
3244 rl = cmdutil.openrevlog(repo, b'perfrevlogrevisions', file_, opts)
3244 rl = cmdutil.openrevlog(repo, b'perfrevlogrevisions', file_, opts)
3245 rllen = getlen(ui)(rl)
3245 rllen = getlen(ui)(rl)
3246
3246
3247 if startrev < 0:
3247 if startrev < 0:
3248 startrev = rllen + startrev
3248 startrev = rllen + startrev
3249
3249
3250 def d():
3250 def d():
3251 rl.clearcaches()
3251 rl.clearcaches()
3252
3252
3253 beginrev = startrev
3253 beginrev = startrev
3254 endrev = rllen
3254 endrev = rllen
3255 dist = opts[b'dist']
3255 dist = opts[b'dist']
3256
3256
3257 if reverse:
3257 if reverse:
3258 beginrev, endrev = endrev - 1, beginrev - 1
3258 beginrev, endrev = endrev - 1, beginrev - 1
3259 dist = -1 * dist
3259 dist = -1 * dist
3260
3260
3261 for x in _xrange(beginrev, endrev, dist):
3261 for x in _xrange(beginrev, endrev, dist):
3262 # Old revisions don't support passing int.
3262 # Old revisions don't support passing int.
3263 n = rl.node(x)
3263 n = rl.node(x)
3264 rl.revision(n)
3264 rl.revision(n)
3265
3265
3266 timer, fm = gettimer(ui, opts)
3266 timer, fm = gettimer(ui, opts)
3267 timer(d)
3267 timer(d)
3268 fm.end()
3268 fm.end()
3269
3269
3270
3270
3271 @command(
3271 @command(
3272 b'perf::revlogwrite|perfrevlogwrite',
3272 b'perf::revlogwrite|perfrevlogwrite',
3273 revlogopts
3273 revlogopts
3274 + formatteropts
3274 + formatteropts
3275 + [
3275 + [
3276 (b's', b'startrev', 1000, b'revision to start writing at'),
3276 (b's', b'startrev', 1000, b'revision to start writing at'),
3277 (b'', b'stoprev', -1, b'last revision to write'),
3277 (b'', b'stoprev', -1, b'last revision to write'),
3278 (b'', b'count', 3, b'number of passes to perform'),
3278 (b'', b'count', 3, b'number of passes to perform'),
3279 (b'', b'details', False, b'print timing for every revisions tested'),
3279 (b'', b'details', False, b'print timing for every revisions tested'),
3280 (b'', b'source', b'full', b'the kind of data feed in the revlog'),
3280 (b'', b'source', b'full', b'the kind of data feed in the revlog'),
3281 (b'', b'lazydeltabase', True, b'try the provided delta first'),
3281 (b'', b'lazydeltabase', True, b'try the provided delta first'),
3282 (b'', b'clear-caches', True, b'clear revlog cache between calls'),
3282 (b'', b'clear-caches', True, b'clear revlog cache between calls'),
3283 ],
3283 ],
3284 b'-c|-m|FILE',
3284 b'-c|-m|FILE',
3285 )
3285 )
3286 def perfrevlogwrite(ui, repo, file_=None, startrev=1000, stoprev=-1, **opts):
3286 def perfrevlogwrite(ui, repo, file_=None, startrev=1000, stoprev=-1, **opts):
3287 """Benchmark writing a series of revisions to a revlog.
3287 """Benchmark writing a series of revisions to a revlog.
3288
3288
3289 Possible source values are:
3289 Possible source values are:
3290 * `full`: add from a full text (default).
3290 * `full`: add from a full text (default).
3291 * `parent-1`: add from a delta to the first parent
3291 * `parent-1`: add from a delta to the first parent
3292 * `parent-2`: add from a delta to the second parent if it exists
3292 * `parent-2`: add from a delta to the second parent if it exists
3293 (use a delta from the first parent otherwise)
3293 (use a delta from the first parent otherwise)
3294 * `parent-smallest`: add from the smallest delta (either p1 or p2)
3294 * `parent-smallest`: add from the smallest delta (either p1 or p2)
3295 * `storage`: add from the existing precomputed deltas
3295 * `storage`: add from the existing precomputed deltas
3296
3296
3297 Note: This performance command measures performance in a custom way. As a
3297 Note: This performance command measures performance in a custom way. As a
3298 result some of the global configuration of the 'perf' command does not
3298 result some of the global configuration of the 'perf' command does not
3299 apply to it:
3299 apply to it:
3300
3300
3301 * ``pre-run``: disabled
3301 * ``pre-run``: disabled
3302
3302
3303 * ``profile-benchmark``: disabled
3303 * ``profile-benchmark``: disabled
3304
3304
3305 * ``run-limits``: disabled use --count instead
3305 * ``run-limits``: disabled use --count instead
3306 """
3306 """
3307 opts = _byteskwargs(opts)
3307 opts = _byteskwargs(opts)
3308
3308
3309 rl = cmdutil.openrevlog(repo, b'perfrevlogwrite', file_, opts)
3309 rl = cmdutil.openrevlog(repo, b'perfrevlogwrite', file_, opts)
3310 rllen = getlen(ui)(rl)
3310 rllen = getlen(ui)(rl)
3311 if startrev < 0:
3311 if startrev < 0:
3312 startrev = rllen + startrev
3312 startrev = rllen + startrev
3313 if stoprev < 0:
3313 if stoprev < 0:
3314 stoprev = rllen + stoprev
3314 stoprev = rllen + stoprev
3315
3315
3316 lazydeltabase = opts['lazydeltabase']
3316 lazydeltabase = opts['lazydeltabase']
3317 source = opts['source']
3317 source = opts['source']
3318 clearcaches = opts['clear_caches']
3318 clearcaches = opts['clear_caches']
3319 validsource = (
3319 validsource = (
3320 b'full',
3320 b'full',
3321 b'parent-1',
3321 b'parent-1',
3322 b'parent-2',
3322 b'parent-2',
3323 b'parent-smallest',
3323 b'parent-smallest',
3324 b'storage',
3324 b'storage',
3325 )
3325 )
3326 if source not in validsource:
3326 if source not in validsource:
3327 raise error.Abort('invalid source type: %s' % source)
3327 raise error.Abort('invalid source type: %s' % source)
3328
3328
3329 ### actually gather results
3329 ### actually gather results
3330 count = opts['count']
3330 count = opts['count']
3331 if count <= 0:
3331 if count <= 0:
3332 raise error.Abort('invalide run count: %d' % count)
3332 raise error.Abort('invalide run count: %d' % count)
3333 allresults = []
3333 allresults = []
3334 for c in range(count):
3334 for c in range(count):
3335 timing = _timeonewrite(
3335 timing = _timeonewrite(
3336 ui,
3336 ui,
3337 rl,
3337 rl,
3338 source,
3338 source,
3339 startrev,
3339 startrev,
3340 stoprev,
3340 stoprev,
3341 c + 1,
3341 c + 1,
3342 lazydeltabase=lazydeltabase,
3342 lazydeltabase=lazydeltabase,
3343 clearcaches=clearcaches,
3343 clearcaches=clearcaches,
3344 )
3344 )
3345 allresults.append(timing)
3345 allresults.append(timing)
3346
3346
3347 ### consolidate the results in a single list
3347 ### consolidate the results in a single list
3348 results = []
3348 results = []
3349 for idx, (rev, t) in enumerate(allresults[0]):
3349 for idx, (rev, t) in enumerate(allresults[0]):
3350 ts = [t]
3350 ts = [t]
3351 for other in allresults[1:]:
3351 for other in allresults[1:]:
3352 orev, ot = other[idx]
3352 orev, ot = other[idx]
3353 assert orev == rev
3353 assert orev == rev
3354 ts.append(ot)
3354 ts.append(ot)
3355 results.append((rev, ts))
3355 results.append((rev, ts))
3356 resultcount = len(results)
3356 resultcount = len(results)
3357
3357
3358 ### Compute and display relevant statistics
3358 ### Compute and display relevant statistics
3359
3359
3360 # get a formatter
3360 # get a formatter
3361 fm = ui.formatter(b'perf', opts)
3361 fm = ui.formatter(b'perf', opts)
3362 displayall = ui.configbool(b"perf", b"all-timing", True)
3362 displayall = ui.configbool(b"perf", b"all-timing", True)
3363
3363
3364 # print individual details if requested
3364 # print individual details if requested
3365 if opts['details']:
3365 if opts['details']:
3366 for idx, item in enumerate(results, 1):
3366 for idx, item in enumerate(results, 1):
3367 rev, data = item
3367 rev, data = item
3368 title = 'revisions #%d of %d, rev %d' % (idx, resultcount, rev)
3368 title = 'revisions #%d of %d, rev %d' % (idx, resultcount, rev)
3369 formatone(fm, data, title=title, displayall=displayall)
3369 formatone(fm, data, title=title, displayall=displayall)
3370
3370
3371 # sorts results by median time
3371 # sorts results by median time
3372 results.sort(key=lambda x: sorted(x[1])[len(x[1]) // 2])
3372 results.sort(key=lambda x: sorted(x[1])[len(x[1]) // 2])
3373 # list of (name, index) to display)
3373 # list of (name, index) to display)
3374 relevants = [
3374 relevants = [
3375 ("min", 0),
3375 ("min", 0),
3376 ("10%", resultcount * 10 // 100),
3376 ("10%", resultcount * 10 // 100),
3377 ("25%", resultcount * 25 // 100),
3377 ("25%", resultcount * 25 // 100),
3378 ("50%", resultcount * 70 // 100),
3378 ("50%", resultcount * 70 // 100),
3379 ("75%", resultcount * 75 // 100),
3379 ("75%", resultcount * 75 // 100),
3380 ("90%", resultcount * 90 // 100),
3380 ("90%", resultcount * 90 // 100),
3381 ("95%", resultcount * 95 // 100),
3381 ("95%", resultcount * 95 // 100),
3382 ("99%", resultcount * 99 // 100),
3382 ("99%", resultcount * 99 // 100),
3383 ("99.9%", resultcount * 999 // 1000),
3383 ("99.9%", resultcount * 999 // 1000),
3384 ("99.99%", resultcount * 9999 // 10000),
3384 ("99.99%", resultcount * 9999 // 10000),
3385 ("99.999%", resultcount * 99999 // 100000),
3385 ("99.999%", resultcount * 99999 // 100000),
3386 ("max", -1),
3386 ("max", -1),
3387 ]
3387 ]
3388 if not ui.quiet:
3388 if not ui.quiet:
3389 for name, idx in relevants:
3389 for name, idx in relevants:
3390 data = results[idx]
3390 data = results[idx]
3391 title = '%s of %d, rev %d' % (name, resultcount, data[0])
3391 title = '%s of %d, rev %d' % (name, resultcount, data[0])
3392 formatone(fm, data[1], title=title, displayall=displayall)
3392 formatone(fm, data[1], title=title, displayall=displayall)
3393
3393
3394 # XXX summing that many float will not be very precise, we ignore this fact
3394 # XXX summing that many float will not be very precise, we ignore this fact
3395 # for now
3395 # for now
3396 totaltime = []
3396 totaltime = []
3397 for item in allresults:
3397 for item in allresults:
3398 totaltime.append(
3398 totaltime.append(
3399 (
3399 (
3400 sum(x[1][0] for x in item),
3400 sum(x[1][0] for x in item),
3401 sum(x[1][1] for x in item),
3401 sum(x[1][1] for x in item),
3402 sum(x[1][2] for x in item),
3402 sum(x[1][2] for x in item),
3403 )
3403 )
3404 )
3404 )
3405 formatone(
3405 formatone(
3406 fm,
3406 fm,
3407 totaltime,
3407 totaltime,
3408 title="total time (%d revs)" % resultcount,
3408 title="total time (%d revs)" % resultcount,
3409 displayall=displayall,
3409 displayall=displayall,
3410 )
3410 )
3411 fm.end()
3411 fm.end()
3412
3412
3413
3413
3414 class _faketr:
3414 class _faketr:
3415 def add(s, x, y, z=None):
3415 def add(s, x, y, z=None):
3416 return None
3416 return None
3417
3417
3418
3418
3419 def _timeonewrite(
3419 def _timeonewrite(
3420 ui,
3420 ui,
3421 orig,
3421 orig,
3422 source,
3422 source,
3423 startrev,
3423 startrev,
3424 stoprev,
3424 stoprev,
3425 runidx=None,
3425 runidx=None,
3426 lazydeltabase=True,
3426 lazydeltabase=True,
3427 clearcaches=True,
3427 clearcaches=True,
3428 ):
3428 ):
3429 timings = []
3429 timings = []
3430 tr = _faketr()
3430 tr = _faketr()
3431 with _temprevlog(ui, orig, startrev) as dest:
3431 with _temprevlog(ui, orig, startrev) as dest:
3432 dest._lazydeltabase = lazydeltabase
3432 dest._lazydeltabase = lazydeltabase
3433 revs = list(orig.revs(startrev, stoprev))
3433 revs = list(orig.revs(startrev, stoprev))
3434 total = len(revs)
3434 total = len(revs)
3435 topic = 'adding'
3435 topic = 'adding'
3436 if runidx is not None:
3436 if runidx is not None:
3437 topic += ' (run #%d)' % runidx
3437 topic += ' (run #%d)' % runidx
3438 # Support both old and new progress API
3438 # Support both old and new progress API
3439 if util.safehasattr(ui, 'makeprogress'):
3439 if util.safehasattr(ui, 'makeprogress'):
3440 progress = ui.makeprogress(topic, unit='revs', total=total)
3440 progress = ui.makeprogress(topic, unit='revs', total=total)
3441
3441
3442 def updateprogress(pos):
3442 def updateprogress(pos):
3443 progress.update(pos)
3443 progress.update(pos)
3444
3444
3445 def completeprogress():
3445 def completeprogress():
3446 progress.complete()
3446 progress.complete()
3447
3447
3448 else:
3448 else:
3449
3449
3450 def updateprogress(pos):
3450 def updateprogress(pos):
3451 ui.progress(topic, pos, unit='revs', total=total)
3451 ui.progress(topic, pos, unit='revs', total=total)
3452
3452
3453 def completeprogress():
3453 def completeprogress():
3454 ui.progress(topic, None, unit='revs', total=total)
3454 ui.progress(topic, None, unit='revs', total=total)
3455
3455
3456 for idx, rev in enumerate(revs):
3456 for idx, rev in enumerate(revs):
3457 updateprogress(idx)
3457 updateprogress(idx)
3458 addargs, addkwargs = _getrevisionseed(orig, rev, tr, source)
3458 addargs, addkwargs = _getrevisionseed(orig, rev, tr, source)
3459 if clearcaches:
3459 if clearcaches:
3460 dest.index.clearcaches()
3460 dest.index.clearcaches()
3461 dest.clearcaches()
3461 dest.clearcaches()
3462 with timeone() as r:
3462 with timeone() as r:
3463 dest.addrawrevision(*addargs, **addkwargs)
3463 dest.addrawrevision(*addargs, **addkwargs)
3464 timings.append((rev, r[0]))
3464 timings.append((rev, r[0]))
3465 updateprogress(total)
3465 updateprogress(total)
3466 completeprogress()
3466 completeprogress()
3467 return timings
3467 return timings
3468
3468
3469
3469
3470 def _getrevisionseed(orig, rev, tr, source):
3470 def _getrevisionseed(orig, rev, tr, source):
3471 from mercurial.node import nullid
3471 from mercurial.node import nullid
3472
3472
3473 linkrev = orig.linkrev(rev)
3473 linkrev = orig.linkrev(rev)
3474 node = orig.node(rev)
3474 node = orig.node(rev)
3475 p1, p2 = orig.parents(node)
3475 p1, p2 = orig.parents(node)
3476 flags = orig.flags(rev)
3476 flags = orig.flags(rev)
3477 cachedelta = None
3477 cachedelta = None
3478 text = None
3478 text = None
3479
3479
3480 if source == b'full':
3480 if source == b'full':
3481 text = orig.revision(rev)
3481 text = orig.revision(rev)
3482 elif source == b'parent-1':
3482 elif source == b'parent-1':
3483 baserev = orig.rev(p1)
3483 baserev = orig.rev(p1)
3484 cachedelta = (baserev, orig.revdiff(p1, rev))
3484 cachedelta = (baserev, orig.revdiff(p1, rev))
3485 elif source == b'parent-2':
3485 elif source == b'parent-2':
3486 parent = p2
3486 parent = p2
3487 if p2 == nullid:
3487 if p2 == nullid:
3488 parent = p1
3488 parent = p1
3489 baserev = orig.rev(parent)
3489 baserev = orig.rev(parent)
3490 cachedelta = (baserev, orig.revdiff(parent, rev))
3490 cachedelta = (baserev, orig.revdiff(parent, rev))
3491 elif source == b'parent-smallest':
3491 elif source == b'parent-smallest':
3492 p1diff = orig.revdiff(p1, rev)
3492 p1diff = orig.revdiff(p1, rev)
3493 parent = p1
3493 parent = p1
3494 diff = p1diff
3494 diff = p1diff
3495 if p2 != nullid:
3495 if p2 != nullid:
3496 p2diff = orig.revdiff(p2, rev)
3496 p2diff = orig.revdiff(p2, rev)
3497 if len(p1diff) > len(p2diff):
3497 if len(p1diff) > len(p2diff):
3498 parent = p2
3498 parent = p2
3499 diff = p2diff
3499 diff = p2diff
3500 baserev = orig.rev(parent)
3500 baserev = orig.rev(parent)
3501 cachedelta = (baserev, diff)
3501 cachedelta = (baserev, diff)
3502 elif source == b'storage':
3502 elif source == b'storage':
3503 baserev = orig.deltaparent(rev)
3503 baserev = orig.deltaparent(rev)
3504 cachedelta = (baserev, orig.revdiff(orig.node(baserev), rev))
3504 cachedelta = (baserev, orig.revdiff(orig.node(baserev), rev))
3505
3505
3506 return (
3506 return (
3507 (text, tr, linkrev, p1, p2),
3507 (text, tr, linkrev, p1, p2),
3508 {'node': node, 'flags': flags, 'cachedelta': cachedelta},
3508 {'node': node, 'flags': flags, 'cachedelta': cachedelta},
3509 )
3509 )
3510
3510
3511
3511
3512 @contextlib.contextmanager
3512 @contextlib.contextmanager
3513 def _temprevlog(ui, orig, truncaterev):
3513 def _temprevlog(ui, orig, truncaterev):
3514 from mercurial import vfs as vfsmod
3514 from mercurial import vfs as vfsmod
3515
3515
3516 if orig._inline:
3516 if orig._inline:
3517 raise error.Abort('not supporting inline revlog (yet)')
3517 raise error.Abort('not supporting inline revlog (yet)')
3518 revlogkwargs = {}
3518 revlogkwargs = {}
3519 k = 'upperboundcomp'
3519 k = 'upperboundcomp'
3520 if util.safehasattr(orig, k):
3520 if util.safehasattr(orig, k):
3521 revlogkwargs[k] = getattr(orig, k)
3521 revlogkwargs[k] = getattr(orig, k)
3522
3522
3523 indexfile = getattr(orig, '_indexfile', None)
3523 indexfile = getattr(orig, '_indexfile', None)
3524 if indexfile is None:
3524 if indexfile is None:
3525 # compatibility with <= hg-5.8
3525 # compatibility with <= hg-5.8
3526 indexfile = getattr(orig, 'indexfile')
3526 indexfile = getattr(orig, 'indexfile')
3527 origindexpath = orig.opener.join(indexfile)
3527 origindexpath = orig.opener.join(indexfile)
3528
3528
3529 datafile = getattr(orig, '_datafile', getattr(orig, 'datafile'))
3529 datafile = getattr(orig, '_datafile', getattr(orig, 'datafile'))
3530 origdatapath = orig.opener.join(datafile)
3530 origdatapath = orig.opener.join(datafile)
3531 radix = b'revlog'
3531 radix = b'revlog'
3532 indexname = b'revlog.i'
3532 indexname = b'revlog.i'
3533 dataname = b'revlog.d'
3533 dataname = b'revlog.d'
3534
3534
3535 tmpdir = tempfile.mkdtemp(prefix='tmp-hgperf-')
3535 tmpdir = tempfile.mkdtemp(prefix='tmp-hgperf-')
3536 try:
3536 try:
3537 # copy the data file in a temporary directory
3537 # copy the data file in a temporary directory
3538 ui.debug('copying data in %s\n' % tmpdir)
3538 ui.debug('copying data in %s\n' % tmpdir)
3539 destindexpath = os.path.join(tmpdir, 'revlog.i')
3539 destindexpath = os.path.join(tmpdir, 'revlog.i')
3540 destdatapath = os.path.join(tmpdir, 'revlog.d')
3540 destdatapath = os.path.join(tmpdir, 'revlog.d')
3541 shutil.copyfile(origindexpath, destindexpath)
3541 shutil.copyfile(origindexpath, destindexpath)
3542 shutil.copyfile(origdatapath, destdatapath)
3542 shutil.copyfile(origdatapath, destdatapath)
3543
3543
3544 # remove the data we want to add again
3544 # remove the data we want to add again
3545 ui.debug('truncating data to be rewritten\n')
3545 ui.debug('truncating data to be rewritten\n')
3546 with open(destindexpath, 'ab') as index:
3546 with open(destindexpath, 'ab') as index:
3547 index.seek(0)
3547 index.seek(0)
3548 index.truncate(truncaterev * orig._io.size)
3548 index.truncate(truncaterev * orig._io.size)
3549 with open(destdatapath, 'ab') as data:
3549 with open(destdatapath, 'ab') as data:
3550 data.seek(0)
3550 data.seek(0)
3551 data.truncate(orig.start(truncaterev))
3551 data.truncate(orig.start(truncaterev))
3552
3552
3553 # instantiate a new revlog from the temporary copy
3553 # instantiate a new revlog from the temporary copy
3554 ui.debug('truncating adding to be rewritten\n')
3554 ui.debug('truncating adding to be rewritten\n')
3555 vfs = vfsmod.vfs(tmpdir)
3555 vfs = vfsmod.vfs(tmpdir)
3556 vfs.options = getattr(orig.opener, 'options', None)
3556 vfs.options = getattr(orig.opener, 'options', None)
3557
3557
3558 try:
3558 try:
3559 dest = revlog(vfs, radix=radix, **revlogkwargs)
3559 dest = revlog(vfs, radix=radix, **revlogkwargs)
3560 except TypeError:
3560 except TypeError:
3561 dest = revlog(
3561 dest = revlog(
3562 vfs, indexfile=indexname, datafile=dataname, **revlogkwargs
3562 vfs, indexfile=indexname, datafile=dataname, **revlogkwargs
3563 )
3563 )
3564 if dest._inline:
3564 if dest._inline:
3565 raise error.Abort('not supporting inline revlog (yet)')
3565 raise error.Abort('not supporting inline revlog (yet)')
3566 # make sure internals are initialized
3566 # make sure internals are initialized
3567 dest.revision(len(dest) - 1)
3567 dest.revision(len(dest) - 1)
3568 yield dest
3568 yield dest
3569 del dest, vfs
3569 del dest, vfs
3570 finally:
3570 finally:
3571 shutil.rmtree(tmpdir, True)
3571 shutil.rmtree(tmpdir, True)
3572
3572
3573
3573
3574 @command(
3574 @command(
3575 b'perf::revlogchunks|perfrevlogchunks',
3575 b'perf::revlogchunks|perfrevlogchunks',
3576 revlogopts
3576 revlogopts
3577 + formatteropts
3577 + formatteropts
3578 + [
3578 + [
3579 (b'e', b'engines', b'', b'compression engines to use'),
3579 (b'e', b'engines', b'', b'compression engines to use'),
3580 (b's', b'startrev', 0, b'revision to start at'),
3580 (b's', b'startrev', 0, b'revision to start at'),
3581 ],
3581 ],
3582 b'-c|-m|FILE',
3582 b'-c|-m|FILE',
3583 )
3583 )
3584 def perfrevlogchunks(ui, repo, file_=None, engines=None, startrev=0, **opts):
3584 def perfrevlogchunks(ui, repo, file_=None, engines=None, startrev=0, **opts):
3585 """Benchmark operations on revlog chunks.
3585 """Benchmark operations on revlog chunks.
3586
3586
3587 Logically, each revlog is a collection of fulltext revisions. However,
3587 Logically, each revlog is a collection of fulltext revisions. However,
3588 stored within each revlog are "chunks" of possibly compressed data. This
3588 stored within each revlog are "chunks" of possibly compressed data. This
3589 data needs to be read and decompressed or compressed and written.
3589 data needs to be read and decompressed or compressed and written.
3590
3590
3591 This command measures the time it takes to read+decompress and recompress
3591 This command measures the time it takes to read+decompress and recompress
3592 chunks in a revlog. It effectively isolates I/O and compression performance.
3592 chunks in a revlog. It effectively isolates I/O and compression performance.
3593 For measurements of higher-level operations like resolving revisions,
3593 For measurements of higher-level operations like resolving revisions,
3594 see ``perfrevlogrevisions`` and ``perfrevlogrevision``.
3594 see ``perfrevlogrevisions`` and ``perfrevlogrevision``.
3595 """
3595 """
3596 opts = _byteskwargs(opts)
3596 opts = _byteskwargs(opts)
3597
3597
3598 rl = cmdutil.openrevlog(repo, b'perfrevlogchunks', file_, opts)
3598 rl = cmdutil.openrevlog(repo, b'perfrevlogchunks', file_, opts)
3599
3599
3600 # _chunkraw was renamed to _getsegmentforrevs.
3600 # _chunkraw was renamed to _getsegmentforrevs.
3601 try:
3601 try:
3602 segmentforrevs = rl._getsegmentforrevs
3602 segmentforrevs = rl._getsegmentforrevs
3603 except AttributeError:
3603 except AttributeError:
3604 segmentforrevs = rl._chunkraw
3604 segmentforrevs = rl._chunkraw
3605
3605
3606 # Verify engines argument.
3606 # Verify engines argument.
3607 if engines:
3607 if engines:
3608 engines = {e.strip() for e in engines.split(b',')}
3608 engines = {e.strip() for e in engines.split(b',')}
3609 for engine in engines:
3609 for engine in engines:
3610 try:
3610 try:
3611 util.compressionengines[engine]
3611 util.compressionengines[engine]
3612 except KeyError:
3612 except KeyError:
3613 raise error.Abort(b'unknown compression engine: %s' % engine)
3613 raise error.Abort(b'unknown compression engine: %s' % engine)
3614 else:
3614 else:
3615 engines = []
3615 engines = []
3616 for e in util.compengines:
3616 for e in util.compengines:
3617 engine = util.compengines[e]
3617 engine = util.compengines[e]
3618 try:
3618 try:
3619 if engine.available():
3619 if engine.available():
3620 engine.revlogcompressor().compress(b'dummy')
3620 engine.revlogcompressor().compress(b'dummy')
3621 engines.append(e)
3621 engines.append(e)
3622 except NotImplementedError:
3622 except NotImplementedError:
3623 pass
3623 pass
3624
3624
3625 revs = list(rl.revs(startrev, len(rl) - 1))
3625 revs = list(rl.revs(startrev, len(rl) - 1))
3626
3626
3627 def rlfh(rl):
3627 def rlfh(rl):
3628 if rl._inline:
3628 if rl._inline:
3629 indexfile = getattr(rl, '_indexfile', None)
3629 indexfile = getattr(rl, '_indexfile', None)
3630 if indexfile is None:
3630 if indexfile is None:
3631 # compatibility with <= hg-5.8
3631 # compatibility with <= hg-5.8
3632 indexfile = getattr(rl, 'indexfile')
3632 indexfile = getattr(rl, 'indexfile')
3633 return getsvfs(repo)(indexfile)
3633 return getsvfs(repo)(indexfile)
3634 else:
3634 else:
3635 datafile = getattr(rl, 'datafile', getattr(rl, 'datafile'))
3635 datafile = getattr(rl, 'datafile', getattr(rl, 'datafile'))
3636 return getsvfs(repo)(datafile)
3636 return getsvfs(repo)(datafile)
3637
3637
3638 def doread():
3638 def doread():
3639 rl.clearcaches()
3639 rl.clearcaches()
3640 for rev in revs:
3640 for rev in revs:
3641 segmentforrevs(rev, rev)
3641 segmentforrevs(rev, rev)
3642
3642
3643 def doreadcachedfh():
3643 def doreadcachedfh():
3644 rl.clearcaches()
3644 rl.clearcaches()
3645 fh = rlfh(rl)
3645 fh = rlfh(rl)
3646 for rev in revs:
3646 for rev in revs:
3647 segmentforrevs(rev, rev, df=fh)
3647 segmentforrevs(rev, rev, df=fh)
3648
3648
3649 def doreadbatch():
3649 def doreadbatch():
3650 rl.clearcaches()
3650 rl.clearcaches()
3651 segmentforrevs(revs[0], revs[-1])
3651 segmentforrevs(revs[0], revs[-1])
3652
3652
3653 def doreadbatchcachedfh():
3653 def doreadbatchcachedfh():
3654 rl.clearcaches()
3654 rl.clearcaches()
3655 fh = rlfh(rl)
3655 fh = rlfh(rl)
3656 segmentforrevs(revs[0], revs[-1], df=fh)
3656 segmentforrevs(revs[0], revs[-1], df=fh)
3657
3657
3658 def dochunk():
3658 def dochunk():
3659 rl.clearcaches()
3659 rl.clearcaches()
3660 fh = rlfh(rl)
3660 fh = rlfh(rl)
3661 for rev in revs:
3661 for rev in revs:
3662 rl._chunk(rev, df=fh)
3662 rl._chunk(rev, df=fh)
3663
3663
3664 chunks = [None]
3664 chunks = [None]
3665
3665
3666 def dochunkbatch():
3666 def dochunkbatch():
3667 rl.clearcaches()
3667 rl.clearcaches()
3668 fh = rlfh(rl)
3668 fh = rlfh(rl)
3669 # Save chunks as a side-effect.
3669 # Save chunks as a side-effect.
3670 chunks[0] = rl._chunks(revs, df=fh)
3670 chunks[0] = rl._chunks(revs, df=fh)
3671
3671
3672 def docompress(compressor):
3672 def docompress(compressor):
3673 rl.clearcaches()
3673 rl.clearcaches()
3674
3674
3675 try:
3675 try:
3676 # Swap in the requested compression engine.
3676 # Swap in the requested compression engine.
3677 oldcompressor = rl._compressor
3677 oldcompressor = rl._compressor
3678 rl._compressor = compressor
3678 rl._compressor = compressor
3679 for chunk in chunks[0]:
3679 for chunk in chunks[0]:
3680 rl.compress(chunk)
3680 rl.compress(chunk)
3681 finally:
3681 finally:
3682 rl._compressor = oldcompressor
3682 rl._compressor = oldcompressor
3683
3683
3684 benches = [
3684 benches = [
3685 (lambda: doread(), b'read'),
3685 (lambda: doread(), b'read'),
3686 (lambda: doreadcachedfh(), b'read w/ reused fd'),
3686 (lambda: doreadcachedfh(), b'read w/ reused fd'),
3687 (lambda: doreadbatch(), b'read batch'),
3687 (lambda: doreadbatch(), b'read batch'),
3688 (lambda: doreadbatchcachedfh(), b'read batch w/ reused fd'),
3688 (lambda: doreadbatchcachedfh(), b'read batch w/ reused fd'),
3689 (lambda: dochunk(), b'chunk'),
3689 (lambda: dochunk(), b'chunk'),
3690 (lambda: dochunkbatch(), b'chunk batch'),
3690 (lambda: dochunkbatch(), b'chunk batch'),
3691 ]
3691 ]
3692
3692
3693 for engine in sorted(engines):
3693 for engine in sorted(engines):
3694 compressor = util.compengines[engine].revlogcompressor()
3694 compressor = util.compengines[engine].revlogcompressor()
3695 benches.append(
3695 benches.append(
3696 (
3696 (
3697 functools.partial(docompress, compressor),
3697 functools.partial(docompress, compressor),
3698 b'compress w/ %s' % engine,
3698 b'compress w/ %s' % engine,
3699 )
3699 )
3700 )
3700 )
3701
3701
3702 for fn, title in benches:
3702 for fn, title in benches:
3703 timer, fm = gettimer(ui, opts)
3703 timer, fm = gettimer(ui, opts)
3704 timer(fn, title=title)
3704 timer(fn, title=title)
3705 fm.end()
3705 fm.end()
3706
3706
3707
3707
3708 @command(
3708 @command(
3709 b'perf::revlogrevision|perfrevlogrevision',
3709 b'perf::revlogrevision|perfrevlogrevision',
3710 revlogopts
3710 revlogopts
3711 + formatteropts
3711 + formatteropts
3712 + [(b'', b'cache', False, b'use caches instead of clearing')],
3712 + [(b'', b'cache', False, b'use caches instead of clearing')],
3713 b'-c|-m|FILE REV',
3713 b'-c|-m|FILE REV',
3714 )
3714 )
3715 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
3715 def perfrevlogrevision(ui, repo, file_, rev=None, cache=None, **opts):
3716 """Benchmark obtaining a revlog revision.
3716 """Benchmark obtaining a revlog revision.
3717
3717
3718 Obtaining a revlog revision consists of roughly the following steps:
3718 Obtaining a revlog revision consists of roughly the following steps:
3719
3719
3720 1. Compute the delta chain
3720 1. Compute the delta chain
3721 2. Slice the delta chain if applicable
3721 2. Slice the delta chain if applicable
3722 3. Obtain the raw chunks for that delta chain
3722 3. Obtain the raw chunks for that delta chain
3723 4. Decompress each raw chunk
3723 4. Decompress each raw chunk
3724 5. Apply binary patches to obtain fulltext
3724 5. Apply binary patches to obtain fulltext
3725 6. Verify hash of fulltext
3725 6. Verify hash of fulltext
3726
3726
3727 This command measures the time spent in each of these phases.
3727 This command measures the time spent in each of these phases.
3728 """
3728 """
3729 opts = _byteskwargs(opts)
3729 opts = _byteskwargs(opts)
3730
3730
3731 if opts.get(b'changelog') or opts.get(b'manifest'):
3731 if opts.get(b'changelog') or opts.get(b'manifest'):
3732 file_, rev = None, file_
3732 file_, rev = None, file_
3733 elif rev is None:
3733 elif rev is None:
3734 raise error.CommandError(b'perfrevlogrevision', b'invalid arguments')
3734 raise error.CommandError(b'perfrevlogrevision', b'invalid arguments')
3735
3735
3736 r = cmdutil.openrevlog(repo, b'perfrevlogrevision', file_, opts)
3736 r = cmdutil.openrevlog(repo, b'perfrevlogrevision', file_, opts)
3737
3737
3738 # _chunkraw was renamed to _getsegmentforrevs.
3738 # _chunkraw was renamed to _getsegmentforrevs.
3739 try:
3739 try:
3740 segmentforrevs = r._getsegmentforrevs
3740 segmentforrevs = r._getsegmentforrevs
3741 except AttributeError:
3741 except AttributeError:
3742 segmentforrevs = r._chunkraw
3742 segmentforrevs = r._chunkraw
3743
3743
3744 node = r.lookup(rev)
3744 node = r.lookup(rev)
3745 rev = r.rev(node)
3745 rev = r.rev(node)
3746
3746
3747 def getrawchunks(data, chain):
3747 def getrawchunks(data, chain):
3748 start = r.start
3748 start = r.start
3749 length = r.length
3749 length = r.length
3750 inline = r._inline
3750 inline = r._inline
3751 try:
3751 try:
3752 iosize = r.index.entry_size
3752 iosize = r.index.entry_size
3753 except AttributeError:
3753 except AttributeError:
3754 iosize = r._io.size
3754 iosize = r._io.size
3755 buffer = util.buffer
3755 buffer = util.buffer
3756
3756
3757 chunks = []
3757 chunks = []
3758 ladd = chunks.append
3758 ladd = chunks.append
3759 for idx, item in enumerate(chain):
3759 for idx, item in enumerate(chain):
3760 offset = start(item[0])
3760 offset = start(item[0])
3761 bits = data[idx]
3761 bits = data[idx]
3762 for rev in item:
3762 for rev in item:
3763 chunkstart = start(rev)
3763 chunkstart = start(rev)
3764 if inline:
3764 if inline:
3765 chunkstart += (rev + 1) * iosize
3765 chunkstart += (rev + 1) * iosize
3766 chunklength = length(rev)
3766 chunklength = length(rev)
3767 ladd(buffer(bits, chunkstart - offset, chunklength))
3767 ladd(buffer(bits, chunkstart - offset, chunklength))
3768
3768
3769 return chunks
3769 return chunks
3770
3770
3771 def dodeltachain(rev):
3771 def dodeltachain(rev):
3772 if not cache:
3772 if not cache:
3773 r.clearcaches()
3773 r.clearcaches()
3774 r._deltachain(rev)
3774 r._deltachain(rev)
3775
3775
3776 def doread(chain):
3776 def doread(chain):
3777 if not cache:
3777 if not cache:
3778 r.clearcaches()
3778 r.clearcaches()
3779 for item in slicedchain:
3779 for item in slicedchain:
3780 segmentforrevs(item[0], item[-1])
3780 segmentforrevs(item[0], item[-1])
3781
3781
3782 def doslice(r, chain, size):
3782 def doslice(r, chain, size):
3783 for s in slicechunk(r, chain, targetsize=size):
3783 for s in slicechunk(r, chain, targetsize=size):
3784 pass
3784 pass
3785
3785
3786 def dorawchunks(data, chain):
3786 def dorawchunks(data, chain):
3787 if not cache:
3787 if not cache:
3788 r.clearcaches()
3788 r.clearcaches()
3789 getrawchunks(data, chain)
3789 getrawchunks(data, chain)
3790
3790
3791 def dodecompress(chunks):
3791 def dodecompress(chunks):
3792 decomp = r.decompress
3792 decomp = r.decompress
3793 for chunk in chunks:
3793 for chunk in chunks:
3794 decomp(chunk)
3794 decomp(chunk)
3795
3795
3796 def dopatch(text, bins):
3796 def dopatch(text, bins):
3797 if not cache:
3797 if not cache:
3798 r.clearcaches()
3798 r.clearcaches()
3799 mdiff.patches(text, bins)
3799 mdiff.patches(text, bins)
3800
3800
3801 def dohash(text):
3801 def dohash(text):
3802 if not cache:
3802 if not cache:
3803 r.clearcaches()
3803 r.clearcaches()
3804 r.checkhash(text, node, rev=rev)
3804 r.checkhash(text, node, rev=rev)
3805
3805
3806 def dorevision():
3806 def dorevision():
3807 if not cache:
3807 if not cache:
3808 r.clearcaches()
3808 r.clearcaches()
3809 r.revision(node)
3809 r.revision(node)
3810
3810
3811 try:
3811 try:
3812 from mercurial.revlogutils.deltas import slicechunk
3812 from mercurial.revlogutils.deltas import slicechunk
3813 except ImportError:
3813 except ImportError:
3814 slicechunk = getattr(revlog, '_slicechunk', None)
3814 slicechunk = getattr(revlog, '_slicechunk', None)
3815
3815
3816 size = r.length(rev)
3816 size = r.length(rev)
3817 chain = r._deltachain(rev)[0]
3817 chain = r._deltachain(rev)[0]
3818 if not getattr(r, '_withsparseread', False):
3818 if not getattr(r, '_withsparseread', False):
3819 slicedchain = (chain,)
3819 slicedchain = (chain,)
3820 else:
3820 else:
3821 slicedchain = tuple(slicechunk(r, chain, targetsize=size))
3821 slicedchain = tuple(slicechunk(r, chain, targetsize=size))
3822 data = [segmentforrevs(seg[0], seg[-1])[1] for seg in slicedchain]
3822 data = [segmentforrevs(seg[0], seg[-1])[1] for seg in slicedchain]
3823 rawchunks = getrawchunks(data, slicedchain)
3823 rawchunks = getrawchunks(data, slicedchain)
3824 bins = r._chunks(chain)
3824 bins = r._chunks(chain)
3825 text = bytes(bins[0])
3825 text = bytes(bins[0])
3826 bins = bins[1:]
3826 bins = bins[1:]
3827 text = mdiff.patches(text, bins)
3827 text = mdiff.patches(text, bins)
3828
3828
3829 benches = [
3829 benches = [
3830 (lambda: dorevision(), b'full'),
3830 (lambda: dorevision(), b'full'),
3831 (lambda: dodeltachain(rev), b'deltachain'),
3831 (lambda: dodeltachain(rev), b'deltachain'),
3832 (lambda: doread(chain), b'read'),
3832 (lambda: doread(chain), b'read'),
3833 ]
3833 ]
3834
3834
3835 if getattr(r, '_withsparseread', False):
3835 if getattr(r, '_withsparseread', False):
3836 slicing = (lambda: doslice(r, chain, size), b'slice-sparse-chain')
3836 slicing = (lambda: doslice(r, chain, size), b'slice-sparse-chain')
3837 benches.append(slicing)
3837 benches.append(slicing)
3838
3838
3839 benches.extend(
3839 benches.extend(
3840 [
3840 [
3841 (lambda: dorawchunks(data, slicedchain), b'rawchunks'),
3841 (lambda: dorawchunks(data, slicedchain), b'rawchunks'),
3842 (lambda: dodecompress(rawchunks), b'decompress'),
3842 (lambda: dodecompress(rawchunks), b'decompress'),
3843 (lambda: dopatch(text, bins), b'patch'),
3843 (lambda: dopatch(text, bins), b'patch'),
3844 (lambda: dohash(text), b'hash'),
3844 (lambda: dohash(text), b'hash'),
3845 ]
3845 ]
3846 )
3846 )
3847
3847
3848 timer, fm = gettimer(ui, opts)
3848 timer, fm = gettimer(ui, opts)
3849 for fn, title in benches:
3849 for fn, title in benches:
3850 timer(fn, title=title)
3850 timer(fn, title=title)
3851 fm.end()
3851 fm.end()
3852
3852
3853
3853
3854 @command(
3854 @command(
3855 b'perf::revset|perfrevset',
3855 b'perf::revset|perfrevset',
3856 [
3856 [
3857 (b'C', b'clear', False, b'clear volatile cache between each call.'),
3857 (b'C', b'clear', False, b'clear volatile cache between each call.'),
3858 (b'', b'contexts', False, b'obtain changectx for each revision'),
3858 (b'', b'contexts', False, b'obtain changectx for each revision'),
3859 ]
3859 ]
3860 + formatteropts,
3860 + formatteropts,
3861 b"REVSET",
3861 b"REVSET",
3862 )
3862 )
3863 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
3863 def perfrevset(ui, repo, expr, clear=False, contexts=False, **opts):
3864 """benchmark the execution time of a revset
3864 """benchmark the execution time of a revset
3865
3865
3866 Use the --clean option if need to evaluate the impact of build volatile
3866 Use the --clean option if need to evaluate the impact of build volatile
3867 revisions set cache on the revset execution. Volatile cache hold filtered
3867 revisions set cache on the revset execution. Volatile cache hold filtered
3868 and obsolete related cache."""
3868 and obsolete related cache."""
3869 opts = _byteskwargs(opts)
3869 opts = _byteskwargs(opts)
3870
3870
3871 timer, fm = gettimer(ui, opts)
3871 timer, fm = gettimer(ui, opts)
3872
3872
3873 def d():
3873 def d():
3874 if clear:
3874 if clear:
3875 repo.invalidatevolatilesets()
3875 repo.invalidatevolatilesets()
3876 if contexts:
3876 if contexts:
3877 for ctx in repo.set(expr):
3877 for ctx in repo.set(expr):
3878 pass
3878 pass
3879 else:
3879 else:
3880 for r in repo.revs(expr):
3880 for r in repo.revs(expr):
3881 pass
3881 pass
3882
3882
3883 timer(d)
3883 timer(d)
3884 fm.end()
3884 fm.end()
3885
3885
3886
3886
3887 @command(
3887 @command(
3888 b'perf::volatilesets|perfvolatilesets',
3888 b'perf::volatilesets|perfvolatilesets',
3889 [
3889 [
3890 (b'', b'clear-obsstore', False, b'drop obsstore between each call.'),
3890 (b'', b'clear-obsstore', False, b'drop obsstore between each call.'),
3891 ]
3891 ]
3892 + formatteropts,
3892 + formatteropts,
3893 )
3893 )
3894 def perfvolatilesets(ui, repo, *names, **opts):
3894 def perfvolatilesets(ui, repo, *names, **opts):
3895 """benchmark the computation of various volatile set
3895 """benchmark the computation of various volatile set
3896
3896
3897 Volatile set computes element related to filtering and obsolescence."""
3897 Volatile set computes element related to filtering and obsolescence."""
3898 opts = _byteskwargs(opts)
3898 opts = _byteskwargs(opts)
3899 timer, fm = gettimer(ui, opts)
3899 timer, fm = gettimer(ui, opts)
3900 repo = repo.unfiltered()
3900 repo = repo.unfiltered()
3901
3901
3902 def getobs(name):
3902 def getobs(name):
3903 def d():
3903 def d():
3904 repo.invalidatevolatilesets()
3904 repo.invalidatevolatilesets()
3905 if opts[b'clear_obsstore']:
3905 if opts[b'clear_obsstore']:
3906 clearfilecache(repo, b'obsstore')
3906 clearfilecache(repo, b'obsstore')
3907 obsolete.getrevs(repo, name)
3907 obsolete.getrevs(repo, name)
3908
3908
3909 return d
3909 return d
3910
3910
3911 allobs = sorted(obsolete.cachefuncs)
3911 allobs = sorted(obsolete.cachefuncs)
3912 if names:
3912 if names:
3913 allobs = [n for n in allobs if n in names]
3913 allobs = [n for n in allobs if n in names]
3914
3914
3915 for name in allobs:
3915 for name in allobs:
3916 timer(getobs(name), title=name)
3916 timer(getobs(name), title=name)
3917
3917
3918 def getfiltered(name):
3918 def getfiltered(name):
3919 def d():
3919 def d():
3920 repo.invalidatevolatilesets()
3920 repo.invalidatevolatilesets()
3921 if opts[b'clear_obsstore']:
3921 if opts[b'clear_obsstore']:
3922 clearfilecache(repo, b'obsstore')
3922 clearfilecache(repo, b'obsstore')
3923 repoview.filterrevs(repo, name)
3923 repoview.filterrevs(repo, name)
3924
3924
3925 return d
3925 return d
3926
3926
3927 allfilter = sorted(repoview.filtertable)
3927 allfilter = sorted(repoview.filtertable)
3928 if names:
3928 if names:
3929 allfilter = [n for n in allfilter if n in names]
3929 allfilter = [n for n in allfilter if n in names]
3930
3930
3931 for name in allfilter:
3931 for name in allfilter:
3932 timer(getfiltered(name), title=name)
3932 timer(getfiltered(name), title=name)
3933 fm.end()
3933 fm.end()
3934
3934
3935
3935
3936 @command(
3936 @command(
3937 b'perf::branchmap|perfbranchmap',
3937 b'perf::branchmap|perfbranchmap',
3938 [
3938 [
3939 (b'f', b'full', False, b'Includes build time of subset'),
3939 (b'f', b'full', False, b'Includes build time of subset'),
3940 (
3940 (
3941 b'',
3941 b'',
3942 b'clear-revbranch',
3942 b'clear-revbranch',
3943 False,
3943 False,
3944 b'purge the revbranch cache between computation',
3944 b'purge the revbranch cache between computation',
3945 ),
3945 ),
3946 ]
3946 ]
3947 + formatteropts,
3947 + formatteropts,
3948 )
3948 )
3949 def perfbranchmap(ui, repo, *filternames, **opts):
3949 def perfbranchmap(ui, repo, *filternames, **opts):
3950 """benchmark the update of a branchmap
3950 """benchmark the update of a branchmap
3951
3951
3952 This benchmarks the full repo.branchmap() call with read and write disabled
3952 This benchmarks the full repo.branchmap() call with read and write disabled
3953 """
3953 """
3954 opts = _byteskwargs(opts)
3954 opts = _byteskwargs(opts)
3955 full = opts.get(b"full", False)
3955 full = opts.get(b"full", False)
3956 clear_revbranch = opts.get(b"clear_revbranch", False)
3956 clear_revbranch = opts.get(b"clear_revbranch", False)
3957 timer, fm = gettimer(ui, opts)
3957 timer, fm = gettimer(ui, opts)
3958
3958
3959 def getbranchmap(filtername):
3959 def getbranchmap(filtername):
3960 """generate a benchmark function for the filtername"""
3960 """generate a benchmark function for the filtername"""
3961 if filtername is None:
3961 if filtername is None:
3962 view = repo
3962 view = repo
3963 else:
3963 else:
3964 view = repo.filtered(filtername)
3964 view = repo.filtered(filtername)
3965 if util.safehasattr(view._branchcaches, '_per_filter'):
3965 if util.safehasattr(view._branchcaches, '_per_filter'):
3966 filtered = view._branchcaches._per_filter
3966 filtered = view._branchcaches._per_filter
3967 else:
3967 else:
3968 # older versions
3968 # older versions
3969 filtered = view._branchcaches
3969 filtered = view._branchcaches
3970
3970
3971 def d():
3971 def d():
3972 if clear_revbranch:
3972 if clear_revbranch:
3973 repo.revbranchcache()._clear()
3973 repo.revbranchcache()._clear()
3974 if full:
3974 if full:
3975 view._branchcaches.clear()
3975 view._branchcaches.clear()
3976 else:
3976 else:
3977 filtered.pop(filtername, None)
3977 filtered.pop(filtername, None)
3978 view.branchmap()
3978 view.branchmap()
3979
3979
3980 return d
3980 return d
3981
3981
3982 # add filter in smaller subset to bigger subset
3982 # add filter in smaller subset to bigger subset
3983 possiblefilters = set(repoview.filtertable)
3983 possiblefilters = set(repoview.filtertable)
3984 if filternames:
3984 if filternames:
3985 possiblefilters &= set(filternames)
3985 possiblefilters &= set(filternames)
3986 subsettable = getbranchmapsubsettable()
3986 subsettable = getbranchmapsubsettable()
3987 allfilters = []
3987 allfilters = []
3988 while possiblefilters:
3988 while possiblefilters:
3989 for name in possiblefilters:
3989 for name in possiblefilters:
3990 subset = subsettable.get(name)
3990 subset = subsettable.get(name)
3991 if subset not in possiblefilters:
3991 if subset not in possiblefilters:
3992 break
3992 break
3993 else:
3993 else:
3994 assert False, b'subset cycle %s!' % possiblefilters
3994 assert False, b'subset cycle %s!' % possiblefilters
3995 allfilters.append(name)
3995 allfilters.append(name)
3996 possiblefilters.remove(name)
3996 possiblefilters.remove(name)
3997
3997
3998 # warm the cache
3998 # warm the cache
3999 if not full:
3999 if not full:
4000 for name in allfilters:
4000 for name in allfilters:
4001 repo.filtered(name).branchmap()
4001 repo.filtered(name).branchmap()
4002 if not filternames or b'unfiltered' in filternames:
4002 if not filternames or b'unfiltered' in filternames:
4003 # add unfiltered
4003 # add unfiltered
4004 allfilters.append(None)
4004 allfilters.append(None)
4005
4005
4006 if util.safehasattr(branchmap.branchcache, 'fromfile'):
4006 if util.safehasattr(branchmap.branchcache, 'fromfile'):
4007 branchcacheread = safeattrsetter(branchmap.branchcache, b'fromfile')
4007 branchcacheread = safeattrsetter(branchmap.branchcache, b'fromfile')
4008 branchcacheread.set(classmethod(lambda *args: None))
4008 branchcacheread.set(classmethod(lambda *args: None))
4009 else:
4009 else:
4010 # older versions
4010 # older versions
4011 branchcacheread = safeattrsetter(branchmap, b'read')
4011 branchcacheread = safeattrsetter(branchmap, b'read')
4012 branchcacheread.set(lambda *args: None)
4012 branchcacheread.set(lambda *args: None)
4013 branchcachewrite = safeattrsetter(branchmap.branchcache, b'write')
4013 branchcachewrite = safeattrsetter(branchmap.branchcache, b'write')
4014 branchcachewrite.set(lambda *args: None)
4014 branchcachewrite.set(lambda *args: None)
4015 try:
4015 try:
4016 for name in allfilters:
4016 for name in allfilters:
4017 printname = name
4017 printname = name
4018 if name is None:
4018 if name is None:
4019 printname = b'unfiltered'
4019 printname = b'unfiltered'
4020 timer(getbranchmap(name), title=printname)
4020 timer(getbranchmap(name), title=printname)
4021 finally:
4021 finally:
4022 branchcacheread.restore()
4022 branchcacheread.restore()
4023 branchcachewrite.restore()
4023 branchcachewrite.restore()
4024 fm.end()
4024 fm.end()
4025
4025
4026
4026
4027 @command(
4027 @command(
4028 b'perf::branchmapupdate|perfbranchmapupdate',
4028 b'perf::branchmapupdate|perfbranchmapupdate',
4029 [
4029 [
4030 (b'', b'base', [], b'subset of revision to start from'),
4030 (b'', b'base', [], b'subset of revision to start from'),
4031 (b'', b'target', [], b'subset of revision to end with'),
4031 (b'', b'target', [], b'subset of revision to end with'),
4032 (b'', b'clear-caches', False, b'clear cache between each runs'),
4032 (b'', b'clear-caches', False, b'clear cache between each runs'),
4033 ]
4033 ]
4034 + formatteropts,
4034 + formatteropts,
4035 )
4035 )
4036 def perfbranchmapupdate(ui, repo, base=(), target=(), **opts):
4036 def perfbranchmapupdate(ui, repo, base=(), target=(), **opts):
4037 """benchmark branchmap update from for <base> revs to <target> revs
4037 """benchmark branchmap update from for <base> revs to <target> revs
4038
4038
4039 If `--clear-caches` is passed, the following items will be reset before
4039 If `--clear-caches` is passed, the following items will be reset before
4040 each update:
4040 each update:
4041 * the changelog instance and associated indexes
4041 * the changelog instance and associated indexes
4042 * the rev-branch-cache instance
4042 * the rev-branch-cache instance
4043
4043
4044 Examples:
4044 Examples:
4045
4045
4046 # update for the one last revision
4046 # update for the one last revision
4047 $ hg perfbranchmapupdate --base 'not tip' --target 'tip'
4047 $ hg perfbranchmapupdate --base 'not tip' --target 'tip'
4048
4048
4049 $ update for change coming with a new branch
4049 $ update for change coming with a new branch
4050 $ hg perfbranchmapupdate --base 'stable' --target 'default'
4050 $ hg perfbranchmapupdate --base 'stable' --target 'default'
4051 """
4051 """
4052 from mercurial import branchmap
4052 from mercurial import branchmap
4053 from mercurial import repoview
4053 from mercurial import repoview
4054
4054
4055 opts = _byteskwargs(opts)
4055 opts = _byteskwargs(opts)
4056 timer, fm = gettimer(ui, opts)
4056 timer, fm = gettimer(ui, opts)
4057 clearcaches = opts[b'clear_caches']
4057 clearcaches = opts[b'clear_caches']
4058 unfi = repo.unfiltered()
4058 unfi = repo.unfiltered()
4059 x = [None] # used to pass data between closure
4059 x = [None] # used to pass data between closure
4060
4060
4061 # we use a `list` here to avoid possible side effect from smartset
4061 # we use a `list` here to avoid possible side effect from smartset
4062 baserevs = list(scmutil.revrange(repo, base))
4062 baserevs = list(scmutil.revrange(repo, base))
4063 targetrevs = list(scmutil.revrange(repo, target))
4063 targetrevs = list(scmutil.revrange(repo, target))
4064 if not baserevs:
4064 if not baserevs:
4065 raise error.Abort(b'no revisions selected for --base')
4065 raise error.Abort(b'no revisions selected for --base')
4066 if not targetrevs:
4066 if not targetrevs:
4067 raise error.Abort(b'no revisions selected for --target')
4067 raise error.Abort(b'no revisions selected for --target')
4068
4068
4069 # make sure the target branchmap also contains the one in the base
4069 # make sure the target branchmap also contains the one in the base
4070 targetrevs = list(set(baserevs) | set(targetrevs))
4070 targetrevs = list(set(baserevs) | set(targetrevs))
4071 targetrevs.sort()
4071 targetrevs.sort()
4072
4072
4073 cl = repo.changelog
4073 cl = repo.changelog
4074 allbaserevs = list(cl.ancestors(baserevs, inclusive=True))
4074 allbaserevs = list(cl.ancestors(baserevs, inclusive=True))
4075 allbaserevs.sort()
4075 allbaserevs.sort()
4076 alltargetrevs = frozenset(cl.ancestors(targetrevs, inclusive=True))
4076 alltargetrevs = frozenset(cl.ancestors(targetrevs, inclusive=True))
4077
4077
4078 newrevs = list(alltargetrevs.difference(allbaserevs))
4078 newrevs = list(alltargetrevs.difference(allbaserevs))
4079 newrevs.sort()
4079 newrevs.sort()
4080
4080
4081 allrevs = frozenset(unfi.changelog.revs())
4081 allrevs = frozenset(unfi.changelog.revs())
4082 basefilterrevs = frozenset(allrevs.difference(allbaserevs))
4082 basefilterrevs = frozenset(allrevs.difference(allbaserevs))
4083 targetfilterrevs = frozenset(allrevs.difference(alltargetrevs))
4083 targetfilterrevs = frozenset(allrevs.difference(alltargetrevs))
4084
4084
4085 def basefilter(repo, visibilityexceptions=None):
4085 def basefilter(repo, visibilityexceptions=None):
4086 return basefilterrevs
4086 return basefilterrevs
4087
4087
4088 def targetfilter(repo, visibilityexceptions=None):
4088 def targetfilter(repo, visibilityexceptions=None):
4089 return targetfilterrevs
4089 return targetfilterrevs
4090
4090
4091 msg = b'benchmark of branchmap with %d revisions with %d new ones\n'
4091 msg = b'benchmark of branchmap with %d revisions with %d new ones\n'
4092 ui.status(msg % (len(allbaserevs), len(newrevs)))
4092 ui.status(msg % (len(allbaserevs), len(newrevs)))
4093 if targetfilterrevs:
4093 if targetfilterrevs:
4094 msg = b'(%d revisions still filtered)\n'
4094 msg = b'(%d revisions still filtered)\n'
4095 ui.status(msg % len(targetfilterrevs))
4095 ui.status(msg % len(targetfilterrevs))
4096
4096
4097 try:
4097 try:
4098 repoview.filtertable[b'__perf_branchmap_update_base'] = basefilter
4098 repoview.filtertable[b'__perf_branchmap_update_base'] = basefilter
4099 repoview.filtertable[b'__perf_branchmap_update_target'] = targetfilter
4099 repoview.filtertable[b'__perf_branchmap_update_target'] = targetfilter
4100
4100
4101 baserepo = repo.filtered(b'__perf_branchmap_update_base')
4101 baserepo = repo.filtered(b'__perf_branchmap_update_base')
4102 targetrepo = repo.filtered(b'__perf_branchmap_update_target')
4102 targetrepo = repo.filtered(b'__perf_branchmap_update_target')
4103
4103
4104 # try to find an existing branchmap to reuse
4104 # try to find an existing branchmap to reuse
4105 subsettable = getbranchmapsubsettable()
4105 subsettable = getbranchmapsubsettable()
4106 candidatefilter = subsettable.get(None)
4106 candidatefilter = subsettable.get(None)
4107 while candidatefilter is not None:
4107 while candidatefilter is not None:
4108 candidatebm = repo.filtered(candidatefilter).branchmap()
4108 candidatebm = repo.filtered(candidatefilter).branchmap()
4109 if candidatebm.validfor(baserepo):
4109 if candidatebm.validfor(baserepo):
4110 filtered = repoview.filterrevs(repo, candidatefilter)
4110 filtered = repoview.filterrevs(repo, candidatefilter)
4111 missing = [r for r in allbaserevs if r in filtered]
4111 missing = [r for r in allbaserevs if r in filtered]
4112 base = candidatebm.copy()
4112 base = candidatebm.copy()
4113 base.update(baserepo, missing)
4113 base.update(baserepo, missing)
4114 break
4114 break
4115 candidatefilter = subsettable.get(candidatefilter)
4115 candidatefilter = subsettable.get(candidatefilter)
4116 else:
4116 else:
4117 # no suitable subset where found
4117 # no suitable subset where found
4118 base = branchmap.branchcache()
4118 base = branchmap.branchcache()
4119 base.update(baserepo, allbaserevs)
4119 base.update(baserepo, allbaserevs)
4120
4120
4121 def setup():
4121 def setup():
4122 x[0] = base.copy()
4122 x[0] = base.copy()
4123 if clearcaches:
4123 if clearcaches:
4124 unfi._revbranchcache = None
4124 unfi._revbranchcache = None
4125 clearchangelog(repo)
4125 clearchangelog(repo)
4126
4126
4127 def bench():
4127 def bench():
4128 x[0].update(targetrepo, newrevs)
4128 x[0].update(targetrepo, newrevs)
4129
4129
4130 timer(bench, setup=setup)
4130 timer(bench, setup=setup)
4131 fm.end()
4131 fm.end()
4132 finally:
4132 finally:
4133 repoview.filtertable.pop(b'__perf_branchmap_update_base', None)
4133 repoview.filtertable.pop(b'__perf_branchmap_update_base', None)
4134 repoview.filtertable.pop(b'__perf_branchmap_update_target', None)
4134 repoview.filtertable.pop(b'__perf_branchmap_update_target', None)
4135
4135
4136
4136
4137 @command(
4137 @command(
4138 b'perf::branchmapload|perfbranchmapload',
4138 b'perf::branchmapload|perfbranchmapload',
4139 [
4139 [
4140 (b'f', b'filter', b'', b'Specify repoview filter'),
4140 (b'f', b'filter', b'', b'Specify repoview filter'),
4141 (b'', b'list', False, b'List brachmap filter caches'),
4141 (b'', b'list', False, b'List brachmap filter caches'),
4142 (b'', b'clear-revlogs', False, b'refresh changelog and manifest'),
4142 (b'', b'clear-revlogs', False, b'refresh changelog and manifest'),
4143 ]
4143 ]
4144 + formatteropts,
4144 + formatteropts,
4145 )
4145 )
4146 def perfbranchmapload(ui, repo, filter=b'', list=False, **opts):
4146 def perfbranchmapload(ui, repo, filter=b'', list=False, **opts):
4147 """benchmark reading the branchmap"""
4147 """benchmark reading the branchmap"""
4148 opts = _byteskwargs(opts)
4148 opts = _byteskwargs(opts)
4149 clearrevlogs = opts[b'clear_revlogs']
4149 clearrevlogs = opts[b'clear_revlogs']
4150
4150
4151 if list:
4151 if list:
4152 for name, kind, st in repo.cachevfs.readdir(stat=True):
4152 for name, kind, st in repo.cachevfs.readdir(stat=True):
4153 if name.startswith(b'branch2'):
4153 if name.startswith(b'branch2'):
4154 filtername = name.partition(b'-')[2] or b'unfiltered'
4154 filtername = name.partition(b'-')[2] or b'unfiltered'
4155 ui.status(
4155 ui.status(
4156 b'%s - %s\n' % (filtername, util.bytecount(st.st_size))
4156 b'%s - %s\n' % (filtername, util.bytecount(st.st_size))
4157 )
4157 )
4158 return
4158 return
4159 if not filter:
4159 if not filter:
4160 filter = None
4160 filter = None
4161 subsettable = getbranchmapsubsettable()
4161 subsettable = getbranchmapsubsettable()
4162 if filter is None:
4162 if filter is None:
4163 repo = repo.unfiltered()
4163 repo = repo.unfiltered()
4164 else:
4164 else:
4165 repo = repoview.repoview(repo, filter)
4165 repo = repoview.repoview(repo, filter)
4166
4166
4167 repo.branchmap() # make sure we have a relevant, up to date branchmap
4167 repo.branchmap() # make sure we have a relevant, up to date branchmap
4168
4168
4169 try:
4169 try:
4170 fromfile = branchmap.branchcache.fromfile
4170 fromfile = branchmap.branchcache.fromfile
4171 except AttributeError:
4171 except AttributeError:
4172 # older versions
4172 # older versions
4173 fromfile = branchmap.read
4173 fromfile = branchmap.read
4174
4174
4175 currentfilter = filter
4175 currentfilter = filter
4176 # try once without timer, the filter may not be cached
4176 # try once without timer, the filter may not be cached
4177 while fromfile(repo) is None:
4177 while fromfile(repo) is None:
4178 currentfilter = subsettable.get(currentfilter)
4178 currentfilter = subsettable.get(currentfilter)
4179 if currentfilter is None:
4179 if currentfilter is None:
4180 raise error.Abort(
4180 raise error.Abort(
4181 b'No branchmap cached for %s repo' % (filter or b'unfiltered')
4181 b'No branchmap cached for %s repo' % (filter or b'unfiltered')
4182 )
4182 )
4183 repo = repo.filtered(currentfilter)
4183 repo = repo.filtered(currentfilter)
4184 timer, fm = gettimer(ui, opts)
4184 timer, fm = gettimer(ui, opts)
4185
4185
4186 def setup():
4186 def setup():
4187 if clearrevlogs:
4187 if clearrevlogs:
4188 clearchangelog(repo)
4188 clearchangelog(repo)
4189
4189
4190 def bench():
4190 def bench():
4191 fromfile(repo)
4191 fromfile(repo)
4192
4192
4193 timer(bench, setup=setup)
4193 timer(bench, setup=setup)
4194 fm.end()
4194 fm.end()
4195
4195
4196
4196
4197 @command(b'perf::loadmarkers|perfloadmarkers')
4197 @command(b'perf::loadmarkers|perfloadmarkers')
4198 def perfloadmarkers(ui, repo):
4198 def perfloadmarkers(ui, repo):
4199 """benchmark the time to parse the on-disk markers for a repo
4199 """benchmark the time to parse the on-disk markers for a repo
4200
4200
4201 Result is the number of markers in the repo."""
4201 Result is the number of markers in the repo."""
4202 timer, fm = gettimer(ui)
4202 timer, fm = gettimer(ui)
4203 svfs = getsvfs(repo)
4203 svfs = getsvfs(repo)
4204 timer(lambda: len(obsolete.obsstore(repo, svfs)))
4204 timer(lambda: len(obsolete.obsstore(repo, svfs)))
4205 fm.end()
4205 fm.end()
4206
4206
4207
4207
4208 @command(
4208 @command(
4209 b'perf::lrucachedict|perflrucachedict',
4209 b'perf::lrucachedict|perflrucachedict',
4210 formatteropts
4210 formatteropts
4211 + [
4211 + [
4212 (b'', b'costlimit', 0, b'maximum total cost of items in cache'),
4212 (b'', b'costlimit', 0, b'maximum total cost of items in cache'),
4213 (b'', b'mincost', 0, b'smallest cost of items in cache'),
4213 (b'', b'mincost', 0, b'smallest cost of items in cache'),
4214 (b'', b'maxcost', 100, b'maximum cost of items in cache'),
4214 (b'', b'maxcost', 100, b'maximum cost of items in cache'),
4215 (b'', b'size', 4, b'size of cache'),
4215 (b'', b'size', 4, b'size of cache'),
4216 (b'', b'gets', 10000, b'number of key lookups'),
4216 (b'', b'gets', 10000, b'number of key lookups'),
4217 (b'', b'sets', 10000, b'number of key sets'),
4217 (b'', b'sets', 10000, b'number of key sets'),
4218 (b'', b'mixed', 10000, b'number of mixed mode operations'),
4218 (b'', b'mixed', 10000, b'number of mixed mode operations'),
4219 (
4219 (
4220 b'',
4220 b'',
4221 b'mixedgetfreq',
4221 b'mixedgetfreq',
4222 50,
4222 50,
4223 b'frequency of get vs set ops in mixed mode',
4223 b'frequency of get vs set ops in mixed mode',
4224 ),
4224 ),
4225 ],
4225 ],
4226 norepo=True,
4226 norepo=True,
4227 )
4227 )
4228 def perflrucache(
4228 def perflrucache(
4229 ui,
4229 ui,
4230 mincost=0,
4230 mincost=0,
4231 maxcost=100,
4231 maxcost=100,
4232 costlimit=0,
4232 costlimit=0,
4233 size=4,
4233 size=4,
4234 gets=10000,
4234 gets=10000,
4235 sets=10000,
4235 sets=10000,
4236 mixed=10000,
4236 mixed=10000,
4237 mixedgetfreq=50,
4237 mixedgetfreq=50,
4238 **opts
4238 **opts
4239 ):
4239 ):
4240 opts = _byteskwargs(opts)
4240 opts = _byteskwargs(opts)
4241
4241
4242 def doinit():
4242 def doinit():
4243 for i in _xrange(10000):
4243 for i in _xrange(10000):
4244 util.lrucachedict(size)
4244 util.lrucachedict(size)
4245
4245
4246 costrange = list(range(mincost, maxcost + 1))
4246 costrange = list(range(mincost, maxcost + 1))
4247
4247
4248 values = []
4248 values = []
4249 for i in _xrange(size):
4249 for i in _xrange(size):
4250 values.append(random.randint(0, _maxint))
4250 values.append(random.randint(0, _maxint))
4251
4251
4252 # Get mode fills the cache and tests raw lookup performance with no
4252 # Get mode fills the cache and tests raw lookup performance with no
4253 # eviction.
4253 # eviction.
4254 getseq = []
4254 getseq = []
4255 for i in _xrange(gets):
4255 for i in _xrange(gets):
4256 getseq.append(random.choice(values))
4256 getseq.append(random.choice(values))
4257
4257
4258 def dogets():
4258 def dogets():
4259 d = util.lrucachedict(size)
4259 d = util.lrucachedict(size)
4260 for v in values:
4260 for v in values:
4261 d[v] = v
4261 d[v] = v
4262 for key in getseq:
4262 for key in getseq:
4263 value = d[key]
4263 value = d[key]
4264 value # silence pyflakes warning
4264 value # silence pyflakes warning
4265
4265
4266 def dogetscost():
4266 def dogetscost():
4267 d = util.lrucachedict(size, maxcost=costlimit)
4267 d = util.lrucachedict(size, maxcost=costlimit)
4268 for i, v in enumerate(values):
4268 for i, v in enumerate(values):
4269 d.insert(v, v, cost=costs[i])
4269 d.insert(v, v, cost=costs[i])
4270 for key in getseq:
4270 for key in getseq:
4271 try:
4271 try:
4272 value = d[key]
4272 value = d[key]
4273 value # silence pyflakes warning
4273 value # silence pyflakes warning
4274 except KeyError:
4274 except KeyError:
4275 pass
4275 pass
4276
4276
4277 # Set mode tests insertion speed with cache eviction.
4277 # Set mode tests insertion speed with cache eviction.
4278 setseq = []
4278 setseq = []
4279 costs = []
4279 costs = []
4280 for i in _xrange(sets):
4280 for i in _xrange(sets):
4281 setseq.append(random.randint(0, _maxint))
4281 setseq.append(random.randint(0, _maxint))
4282 costs.append(random.choice(costrange))
4282 costs.append(random.choice(costrange))
4283
4283
4284 def doinserts():
4284 def doinserts():
4285 d = util.lrucachedict(size)
4285 d = util.lrucachedict(size)
4286 for v in setseq:
4286 for v in setseq:
4287 d.insert(v, v)
4287 d.insert(v, v)
4288
4288
4289 def doinsertscost():
4289 def doinsertscost():
4290 d = util.lrucachedict(size, maxcost=costlimit)
4290 d = util.lrucachedict(size, maxcost=costlimit)
4291 for i, v in enumerate(setseq):
4291 for i, v in enumerate(setseq):
4292 d.insert(v, v, cost=costs[i])
4292 d.insert(v, v, cost=costs[i])
4293
4293
4294 def dosets():
4294 def dosets():
4295 d = util.lrucachedict(size)
4295 d = util.lrucachedict(size)
4296 for v in setseq:
4296 for v in setseq:
4297 d[v] = v
4297 d[v] = v
4298
4298
4299 # Mixed mode randomly performs gets and sets with eviction.
4299 # Mixed mode randomly performs gets and sets with eviction.
4300 mixedops = []
4300 mixedops = []
4301 for i in _xrange(mixed):
4301 for i in _xrange(mixed):
4302 r = random.randint(0, 100)
4302 r = random.randint(0, 100)
4303 if r < mixedgetfreq:
4303 if r < mixedgetfreq:
4304 op = 0
4304 op = 0
4305 else:
4305 else:
4306 op = 1
4306 op = 1
4307
4307
4308 mixedops.append(
4308 mixedops.append(
4309 (op, random.randint(0, size * 2), random.choice(costrange))
4309 (op, random.randint(0, size * 2), random.choice(costrange))
4310 )
4310 )
4311
4311
4312 def domixed():
4312 def domixed():
4313 d = util.lrucachedict(size)
4313 d = util.lrucachedict(size)
4314
4314
4315 for op, v, cost in mixedops:
4315 for op, v, cost in mixedops:
4316 if op == 0:
4316 if op == 0:
4317 try:
4317 try:
4318 d[v]
4318 d[v]
4319 except KeyError:
4319 except KeyError:
4320 pass
4320 pass
4321 else:
4321 else:
4322 d[v] = v
4322 d[v] = v
4323
4323
4324 def domixedcost():
4324 def domixedcost():
4325 d = util.lrucachedict(size, maxcost=costlimit)
4325 d = util.lrucachedict(size, maxcost=costlimit)
4326
4326
4327 for op, v, cost in mixedops:
4327 for op, v, cost in mixedops:
4328 if op == 0:
4328 if op == 0:
4329 try:
4329 try:
4330 d[v]
4330 d[v]
4331 except KeyError:
4331 except KeyError:
4332 pass
4332 pass
4333 else:
4333 else:
4334 d.insert(v, v, cost=cost)
4334 d.insert(v, v, cost=cost)
4335
4335
4336 benches = [
4336 benches = [
4337 (doinit, b'init'),
4337 (doinit, b'init'),
4338 ]
4338 ]
4339
4339
4340 if costlimit:
4340 if costlimit:
4341 benches.extend(
4341 benches.extend(
4342 [
4342 [
4343 (dogetscost, b'gets w/ cost limit'),
4343 (dogetscost, b'gets w/ cost limit'),
4344 (doinsertscost, b'inserts w/ cost limit'),
4344 (doinsertscost, b'inserts w/ cost limit'),
4345 (domixedcost, b'mixed w/ cost limit'),
4345 (domixedcost, b'mixed w/ cost limit'),
4346 ]
4346 ]
4347 )
4347 )
4348 else:
4348 else:
4349 benches.extend(
4349 benches.extend(
4350 [
4350 [
4351 (dogets, b'gets'),
4351 (dogets, b'gets'),
4352 (doinserts, b'inserts'),
4352 (doinserts, b'inserts'),
4353 (dosets, b'sets'),
4353 (dosets, b'sets'),
4354 (domixed, b'mixed'),
4354 (domixed, b'mixed'),
4355 ]
4355 ]
4356 )
4356 )
4357
4357
4358 for fn, title in benches:
4358 for fn, title in benches:
4359 timer, fm = gettimer(ui, opts)
4359 timer, fm = gettimer(ui, opts)
4360 timer(fn, title=title)
4360 timer(fn, title=title)
4361 fm.end()
4361 fm.end()
4362
4362
4363
4363
4364 @command(
4364 @command(
4365 b'perf::write|perfwrite',
4365 b'perf::write|perfwrite',
4366 formatteropts
4366 formatteropts
4367 + [
4367 + [
4368 (b'', b'write-method', b'write', b'ui write method'),
4368 (b'', b'write-method', b'write', b'ui write method'),
4369 (b'', b'nlines', 100, b'number of lines'),
4369 (b'', b'nlines', 100, b'number of lines'),
4370 (b'', b'nitems', 100, b'number of items (per line)'),
4370 (b'', b'nitems', 100, b'number of items (per line)'),
4371 (b'', b'item', b'x', b'item that is written'),
4371 (b'', b'item', b'x', b'item that is written'),
4372 (b'', b'batch-line', None, b'pass whole line to write method at once'),
4372 (b'', b'batch-line', None, b'pass whole line to write method at once'),
4373 (b'', b'flush-line', None, b'flush after each line'),
4373 (b'', b'flush-line', None, b'flush after each line'),
4374 ],
4374 ],
4375 )
4375 )
4376 def perfwrite(ui, repo, **opts):
4376 def perfwrite(ui, repo, **opts):
4377 """microbenchmark ui.write (and others)"""
4377 """microbenchmark ui.write (and others)"""
4378 opts = _byteskwargs(opts)
4378 opts = _byteskwargs(opts)
4379
4379
4380 write = getattr(ui, _sysstr(opts[b'write_method']))
4380 write = getattr(ui, _sysstr(opts[b'write_method']))
4381 nlines = int(opts[b'nlines'])
4381 nlines = int(opts[b'nlines'])
4382 nitems = int(opts[b'nitems'])
4382 nitems = int(opts[b'nitems'])
4383 item = opts[b'item']
4383 item = opts[b'item']
4384 batch_line = opts.get(b'batch_line')
4384 batch_line = opts.get(b'batch_line')
4385 flush_line = opts.get(b'flush_line')
4385 flush_line = opts.get(b'flush_line')
4386
4386
4387 if batch_line:
4387 if batch_line:
4388 line = item * nitems + b'\n'
4388 line = item * nitems + b'\n'
4389
4389
4390 def benchmark():
4390 def benchmark():
4391 for i in pycompat.xrange(nlines):
4391 for i in pycompat.xrange(nlines):
4392 if batch_line:
4392 if batch_line:
4393 write(line)
4393 write(line)
4394 else:
4394 else:
4395 for i in pycompat.xrange(nitems):
4395 for i in pycompat.xrange(nitems):
4396 write(item)
4396 write(item)
4397 write(b'\n')
4397 write(b'\n')
4398 if flush_line:
4398 if flush_line:
4399 ui.flush()
4399 ui.flush()
4400 ui.flush()
4400 ui.flush()
4401
4401
4402 timer, fm = gettimer(ui, opts)
4402 timer, fm = gettimer(ui, opts)
4403 timer(benchmark)
4403 timer(benchmark)
4404 fm.end()
4404 fm.end()
4405
4405
4406
4406
4407 def uisetup(ui):
4407 def uisetup(ui):
4408 if util.safehasattr(cmdutil, b'openrevlog') and not util.safehasattr(
4408 if util.safehasattr(cmdutil, b'openrevlog') and not util.safehasattr(
4409 commands, b'debugrevlogopts'
4409 commands, b'debugrevlogopts'
4410 ):
4410 ):
4411 # for "historical portability":
4411 # for "historical portability":
4412 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
4412 # In this case, Mercurial should be 1.9 (or a79fea6b3e77) -
4413 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
4413 # 3.7 (or 5606f7d0d063). Therefore, '--dir' option for
4414 # openrevlog() should cause failure, because it has been
4414 # openrevlog() should cause failure, because it has been
4415 # available since 3.5 (or 49c583ca48c4).
4415 # available since 3.5 (or 49c583ca48c4).
4416 def openrevlog(orig, repo, cmd, file_, opts):
4416 def openrevlog(orig, repo, cmd, file_, opts):
4417 if opts.get(b'dir') and not util.safehasattr(repo, b'dirlog'):
4417 if opts.get(b'dir') and not util.safehasattr(repo, b'dirlog'):
4418 raise error.Abort(
4418 raise error.Abort(
4419 b"This version doesn't support --dir option",
4419 b"This version doesn't support --dir option",
4420 hint=b"use 3.5 or later",
4420 hint=b"use 3.5 or later",
4421 )
4421 )
4422 return orig(repo, cmd, file_, opts)
4422 return orig(repo, cmd, file_, opts)
4423
4423
4424 name = _sysstr(b'openrevlog')
4424 name = _sysstr(b'openrevlog')
4425 extensions.wrapfunction(cmdutil, name, openrevlog)
4425 extensions.wrapfunction(cmdutil, name, openrevlog)
4426
4426
4427
4427
4428 @command(
4428 @command(
4429 b'perf::progress|perfprogress',
4429 b'perf::progress|perfprogress',
4430 formatteropts
4430 formatteropts
4431 + [
4431 + [
4432 (b'', b'topic', b'topic', b'topic for progress messages'),
4432 (b'', b'topic', b'topic', b'topic for progress messages'),
4433 (b'c', b'total', 1000000, b'total value we are progressing to'),
4433 (b'c', b'total', 1000000, b'total value we are progressing to'),
4434 ],
4434 ],
4435 norepo=True,
4435 norepo=True,
4436 )
4436 )
4437 def perfprogress(ui, topic=None, total=None, **opts):
4437 def perfprogress(ui, topic=None, total=None, **opts):
4438 """printing of progress bars"""
4438 """printing of progress bars"""
4439 opts = _byteskwargs(opts)
4439 opts = _byteskwargs(opts)
4440
4440
4441 timer, fm = gettimer(ui, opts)
4441 timer, fm = gettimer(ui, opts)
4442
4442
4443 def doprogress():
4443 def doprogress():
4444 with ui.makeprogress(topic, total=total) as progress:
4444 with ui.makeprogress(topic, total=total) as progress:
4445 for i in _xrange(total):
4445 for i in _xrange(total):
4446 progress.increment()
4446 progress.increment()
4447
4447
4448 timer(doprogress)
4448 timer(doprogress)
4449 fm.end()
4449 fm.end()
@@ -1,574 +1,576 b''
1 # common.py - common code for the convert extension
1 # common.py - common code for the convert extension
2 #
2 #
3 # Copyright 2005-2009 Olivia Mackall <olivia@selenic.com> and others
3 # Copyright 2005-2009 Olivia Mackall <olivia@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import base64
8 import base64
9 import datetime
9 import datetime
10 import os
10 import os
11 import pickle
11 import pickle
12 import re
12 import re
13 import shlex
13 import shlex
14 import subprocess
14 import subprocess
15
15
16 from mercurial.i18n import _
16 from mercurial.i18n import _
17 from mercurial.pycompat import open
17 from mercurial.pycompat import open
18 from mercurial import (
18 from mercurial import (
19 encoding,
19 encoding,
20 error,
20 error,
21 phases,
21 phases,
22 pycompat,
22 pycompat,
23 util,
23 util,
24 )
24 )
25 from mercurial.utils import procutil
25 from mercurial.utils import procutil
26
26
27 propertycache = util.propertycache
27 propertycache = util.propertycache
28
28
29
29
30 def _encodeornone(d):
30 def _encodeornone(d):
31 if d is None:
31 if d is None:
32 return
32 return
33 return d.encode('latin1')
33 return d.encode('latin1')
34
34
35
35
36 class _shlexpy3proxy:
36 class _shlexpy3proxy:
37 def __init__(self, l):
37 def __init__(self, l):
38 self._l = l
38 self._l = l
39
39
40 def __iter__(self):
40 def __iter__(self):
41 return (_encodeornone(v) for v in self._l)
41 return (_encodeornone(v) for v in self._l)
42
42
43 def get_token(self):
43 def get_token(self):
44 return _encodeornone(self._l.get_token())
44 return _encodeornone(self._l.get_token())
45
45
46 @property
46 @property
47 def infile(self):
47 def infile(self):
48 return self._l.infile or b'<unknown>'
48 return self._l.infile or b'<unknown>'
49
49
50 @property
50 @property
51 def lineno(self):
51 def lineno(self):
52 return self._l.lineno
52 return self._l.lineno
53
53
54
54
55 def shlexer(data=None, filepath=None, wordchars=None, whitespace=None):
55 def shlexer(data=None, filepath=None, wordchars=None, whitespace=None):
56 if data is None:
56 if data is None:
57 data = open(filepath, b'r', encoding='latin1')
57 data = open(filepath, b'r', encoding='latin1')
58 else:
58 else:
59 if filepath is not None:
59 if filepath is not None:
60 raise error.ProgrammingError(
60 raise error.ProgrammingError(
61 b'shlexer only accepts data or filepath, not both'
61 b'shlexer only accepts data or filepath, not both'
62 )
62 )
63 data = data.decode('latin1')
63 data = data.decode('latin1')
64 l = shlex.shlex(data, infile=filepath, posix=True)
64 l = shlex.shlex(data, infile=filepath, posix=True)
65 if whitespace is not None:
65 if whitespace is not None:
66 l.whitespace_split = True
66 l.whitespace_split = True
67 l.whitespace += whitespace.decode('latin1')
67 l.whitespace += whitespace.decode('latin1')
68 if wordchars is not None:
68 if wordchars is not None:
69 l.wordchars += wordchars.decode('latin1')
69 l.wordchars += wordchars.decode('latin1')
70 return _shlexpy3proxy(l)
70 return _shlexpy3proxy(l)
71
71
72
72
73 def encodeargs(args):
73 def encodeargs(args):
74 def encodearg(s):
74 def encodearg(s):
75 lines = base64.encodebytes(s)
75 lines = base64.encodebytes(s)
76 lines = [l.splitlines()[0] for l in pycompat.iterbytestr(lines)]
76 lines = [l.splitlines()[0] for l in pycompat.iterbytestr(lines)]
77 return b''.join(lines)
77 return b''.join(lines)
78
78
79 s = pickle.dumps(args)
79 s = pickle.dumps(args)
80 return encodearg(s)
80 return encodearg(s)
81
81
82
82
83 def decodeargs(s):
83 def decodeargs(s):
84 s = base64.decodebytes(s)
84 s = base64.decodebytes(s)
85 return pickle.loads(s)
85 return pickle.loads(s)
86
86
87
87
88 class MissingTool(Exception):
88 class MissingTool(Exception):
89 pass
89 pass
90
90
91
91
92 def checktool(exe, name=None, abort=True):
92 def checktool(exe, name=None, abort=True):
93 name = name or exe
93 name = name or exe
94 if not procutil.findexe(exe):
94 if not procutil.findexe(exe):
95 if abort:
95 if abort:
96 exc = error.Abort
96 exc = error.Abort
97 else:
97 else:
98 exc = MissingTool
98 exc = MissingTool
99 raise exc(_(b'cannot find required "%s" tool') % name)
99 raise exc(_(b'cannot find required "%s" tool') % name)
100
100
101
101
102 class NoRepo(Exception):
102 class NoRepo(Exception):
103 pass
103 pass
104
104
105
105
106 SKIPREV = b'SKIP'
106 SKIPREV = b'SKIP'
107
107
108
108
109 class commit:
109 class commit:
110 def __init__(
110 def __init__(
111 self,
111 self,
112 author,
112 author,
113 date,
113 date,
114 desc,
114 desc,
115 parents,
115 parents,
116 branch=None,
116 branch=None,
117 rev=None,
117 rev=None,
118 extra=None,
118 extra=None,
119 sortkey=None,
119 sortkey=None,
120 saverev=True,
120 saverev=True,
121 phase=phases.draft,
121 phase=phases.draft,
122 optparents=None,
122 optparents=None,
123 ctx=None,
123 ctx=None,
124 ):
124 ):
125 self.author = author or b'unknown'
125 self.author = author or b'unknown'
126 self.date = date or b'0 0'
126 self.date = date or b'0 0'
127 self.desc = desc
127 self.desc = desc
128 self.parents = parents # will be converted and used as parents
128 self.parents = parents # will be converted and used as parents
129 self.optparents = optparents or [] # will be used if already converted
129 self.optparents = optparents or [] # will be used if already converted
130 self.branch = branch
130 self.branch = branch
131 self.rev = rev
131 self.rev = rev
132 self.extra = extra or {}
132 self.extra = extra or {}
133 self.sortkey = sortkey
133 self.sortkey = sortkey
134 self.saverev = saverev
134 self.saverev = saverev
135 self.phase = phase
135 self.phase = phase
136 self.ctx = ctx # for hg to hg conversions
136 self.ctx = ctx # for hg to hg conversions
137
137
138
138
139 class converter_source:
139 class converter_source:
140 """Conversion source interface"""
140 """Conversion source interface"""
141
141
142 def __init__(self, ui, repotype, path=None, revs=None):
142 def __init__(self, ui, repotype, path=None, revs=None):
143 """Initialize conversion source (or raise NoRepo("message")
143 """Initialize conversion source (or raise NoRepo("message")
144 exception if path is not a valid repository)"""
144 exception if path is not a valid repository)"""
145 self.ui = ui
145 self.ui = ui
146 self.path = path
146 self.path = path
147 self.revs = revs
147 self.revs = revs
148 self.repotype = repotype
148 self.repotype = repotype
149
149
150 self.encoding = b'utf-8'
150 self.encoding = b'utf-8'
151
151
152 def checkhexformat(self, revstr, mapname=b'splicemap'):
152 def checkhexformat(self, revstr, mapname=b'splicemap'):
153 """fails if revstr is not a 40 byte hex. mercurial and git both uses
153 """fails if revstr is not a 40 byte hex. mercurial and git both uses
154 such format for their revision numbering
154 such format for their revision numbering
155 """
155 """
156 if not re.match(br'[0-9a-fA-F]{40,40}$', revstr):
156 if not re.match(br'[0-9a-fA-F]{40,40}$', revstr):
157 raise error.Abort(
157 raise error.Abort(
158 _(b'%s entry %s is not a valid revision identifier')
158 _(b'%s entry %s is not a valid revision identifier')
159 % (mapname, revstr)
159 % (mapname, revstr)
160 )
160 )
161
161
162 def before(self):
162 def before(self):
163 pass
163 pass
164
164
165 def after(self):
165 def after(self):
166 pass
166 pass
167
167
168 def targetfilebelongstosource(self, targetfilename):
168 def targetfilebelongstosource(self, targetfilename):
169 """Returns true if the given targetfile belongs to the source repo. This
169 """Returns true if the given targetfile belongs to the source repo. This
170 is useful when only a subdirectory of the target belongs to the source
170 is useful when only a subdirectory of the target belongs to the source
171 repo."""
171 repo."""
172 # For normal full repo converts, this is always True.
172 # For normal full repo converts, this is always True.
173 return True
173 return True
174
174
175 def setrevmap(self, revmap):
175 def setrevmap(self, revmap):
176 """set the map of already-converted revisions"""
176 """set the map of already-converted revisions"""
177
177
178 def getheads(self):
178 def getheads(self):
179 """Return a list of this repository's heads"""
179 """Return a list of this repository's heads"""
180 raise NotImplementedError
180 raise NotImplementedError
181
181
182 def getfile(self, name, rev):
182 def getfile(self, name, rev):
183 """Return a pair (data, mode) where data is the file content
183 """Return a pair (data, mode) where data is the file content
184 as a string and mode one of '', 'x' or 'l'. rev is the
184 as a string and mode one of '', 'x' or 'l'. rev is the
185 identifier returned by a previous call to getchanges().
185 identifier returned by a previous call to getchanges().
186 Data is None if file is missing/deleted in rev.
186 Data is None if file is missing/deleted in rev.
187 """
187 """
188 raise NotImplementedError
188 raise NotImplementedError
189
189
190 def getchanges(self, version, full):
190 def getchanges(self, version, full):
191 """Returns a tuple of (files, copies, cleanp2).
191 """Returns a tuple of (files, copies, cleanp2).
192
192
193 files is a sorted list of (filename, id) tuples for all files
193 files is a sorted list of (filename, id) tuples for all files
194 changed between version and its first parent returned by
194 changed between version and its first parent returned by
195 getcommit(). If full, all files in that revision is returned.
195 getcommit(). If full, all files in that revision is returned.
196 id is the source revision id of the file.
196 id is the source revision id of the file.
197
197
198 copies is a dictionary of dest: source
198 copies is a dictionary of dest: source
199
199
200 cleanp2 is the set of files filenames that are clean against p2.
200 cleanp2 is the set of files filenames that are clean against p2.
201 (Files that are clean against p1 are already not in files (unless
201 (Files that are clean against p1 are already not in files (unless
202 full). This makes it possible to handle p2 clean files similarly.)
202 full). This makes it possible to handle p2 clean files similarly.)
203 """
203 """
204 raise NotImplementedError
204 raise NotImplementedError
205
205
206 def getcommit(self, version):
206 def getcommit(self, version):
207 """Return the commit object for version"""
207 """Return the commit object for version"""
208 raise NotImplementedError
208 raise NotImplementedError
209
209
210 def numcommits(self):
210 def numcommits(self):
211 """Return the number of commits in this source.
211 """Return the number of commits in this source.
212
212
213 If unknown, return None.
213 If unknown, return None.
214 """
214 """
215 return None
215 return None
216
216
217 def gettags(self):
217 def gettags(self):
218 """Return the tags as a dictionary of name: revision
218 """Return the tags as a dictionary of name: revision
219
219
220 Tag names must be UTF-8 strings.
220 Tag names must be UTF-8 strings.
221 """
221 """
222 raise NotImplementedError
222 raise NotImplementedError
223
223
224 def recode(self, s, encoding=None):
224 def recode(self, s, encoding=None):
225 if not encoding:
225 if not encoding:
226 encoding = self.encoding or b'utf-8'
226 encoding = self.encoding or b'utf-8'
227
227
228 if isinstance(s, str):
228 if isinstance(s, str):
229 return s.encode("utf-8")
229 return s.encode("utf-8")
230 try:
230 try:
231 return s.decode(pycompat.sysstr(encoding)).encode("utf-8")
231 return s.decode(pycompat.sysstr(encoding)).encode("utf-8")
232 except UnicodeError:
232 except UnicodeError:
233 try:
233 try:
234 return s.decode("latin-1").encode("utf-8")
234 return s.decode("latin-1").encode("utf-8")
235 except UnicodeError:
235 except UnicodeError:
236 return s.decode(pycompat.sysstr(encoding), "replace").encode(
236 return s.decode(pycompat.sysstr(encoding), "replace").encode(
237 "utf-8"
237 "utf-8"
238 )
238 )
239
239
240 def getchangedfiles(self, rev, i):
240 def getchangedfiles(self, rev, i):
241 """Return the files changed by rev compared to parent[i].
241 """Return the files changed by rev compared to parent[i].
242
242
243 i is an index selecting one of the parents of rev. The return
243 i is an index selecting one of the parents of rev. The return
244 value should be the list of files that are different in rev and
244 value should be the list of files that are different in rev and
245 this parent.
245 this parent.
246
246
247 If rev has no parents, i is None.
247 If rev has no parents, i is None.
248
248
249 This function is only needed to support --filemap
249 This function is only needed to support --filemap
250 """
250 """
251 raise NotImplementedError
251 raise NotImplementedError
252
252
253 def converted(self, rev, sinkrev):
253 def converted(self, rev, sinkrev):
254 '''Notify the source that a revision has been converted.'''
254 '''Notify the source that a revision has been converted.'''
255
255
256 def hasnativeorder(self):
256 def hasnativeorder(self):
257 """Return true if this source has a meaningful, native revision
257 """Return true if this source has a meaningful, native revision
258 order. For instance, Mercurial revisions are store sequentially
258 order. For instance, Mercurial revisions are store sequentially
259 while there is no such global ordering with Darcs.
259 while there is no such global ordering with Darcs.
260 """
260 """
261 return False
261 return False
262
262
263 def hasnativeclose(self):
263 def hasnativeclose(self):
264 """Return true if this source has ability to close branch."""
264 """Return true if this source has ability to close branch."""
265 return False
265 return False
266
266
267 def lookuprev(self, rev):
267 def lookuprev(self, rev):
268 """If rev is a meaningful revision reference in source, return
268 """If rev is a meaningful revision reference in source, return
269 the referenced identifier in the same format used by getcommit().
269 the referenced identifier in the same format used by getcommit().
270 return None otherwise.
270 return None otherwise.
271 """
271 """
272 return None
272 return None
273
273
274 def getbookmarks(self):
274 def getbookmarks(self):
275 """Return the bookmarks as a dictionary of name: revision
275 """Return the bookmarks as a dictionary of name: revision
276
276
277 Bookmark names are to be UTF-8 strings.
277 Bookmark names are to be UTF-8 strings.
278 """
278 """
279 return {}
279 return {}
280
280
281 def checkrevformat(self, revstr, mapname=b'splicemap'):
281 def checkrevformat(self, revstr, mapname=b'splicemap'):
282 """revstr is a string that describes a revision in the given
282 """revstr is a string that describes a revision in the given
283 source control system. Return true if revstr has correct
283 source control system. Return true if revstr has correct
284 format.
284 format.
285 """
285 """
286 return True
286 return True
287
287
288
288
289 class converter_sink:
289 class converter_sink:
290 """Conversion sink (target) interface"""
290 """Conversion sink (target) interface"""
291
291
292 def __init__(self, ui, repotype, path):
292 def __init__(self, ui, repotype, path):
293 """Initialize conversion sink (or raise NoRepo("message")
293 """Initialize conversion sink (or raise NoRepo("message")
294 exception if path is not a valid repository)
294 exception if path is not a valid repository)
295
295
296 created is a list of paths to remove if a fatal error occurs
296 created is a list of paths to remove if a fatal error occurs
297 later"""
297 later"""
298 self.ui = ui
298 self.ui = ui
299 self.path = path
299 self.path = path
300 self.created = []
300 self.created = []
301 self.repotype = repotype
301 self.repotype = repotype
302
302
303 def revmapfile(self):
303 def revmapfile(self):
304 """Path to a file that will contain lines
304 """Path to a file that will contain lines
305 source_rev_id sink_rev_id
305 source_rev_id sink_rev_id
306 mapping equivalent revision identifiers for each system."""
306 mapping equivalent revision identifiers for each system."""
307 raise NotImplementedError
307 raise NotImplementedError
308
308
309 def authorfile(self):
309 def authorfile(self):
310 """Path to a file that will contain lines
310 """Path to a file that will contain lines
311 srcauthor=dstauthor
311 srcauthor=dstauthor
312 mapping equivalent authors identifiers for each system."""
312 mapping equivalent authors identifiers for each system."""
313 return None
313 return None
314
314
315 def putcommit(
315 def putcommit(
316 self, files, copies, parents, commit, source, revmap, full, cleanp2
316 self, files, copies, parents, commit, source, revmap, full, cleanp2
317 ):
317 ):
318 """Create a revision with all changed files listed in 'files'
318 """Create a revision with all changed files listed in 'files'
319 and having listed parents. 'commit' is a commit object
319 and having listed parents. 'commit' is a commit object
320 containing at a minimum the author, date, and message for this
320 containing at a minimum the author, date, and message for this
321 changeset. 'files' is a list of (path, version) tuples,
321 changeset. 'files' is a list of (path, version) tuples,
322 'copies' is a dictionary mapping destinations to sources,
322 'copies' is a dictionary mapping destinations to sources,
323 'source' is the source repository, and 'revmap' is a mapfile
323 'source' is the source repository, and 'revmap' is a mapfile
324 of source revisions to converted revisions. Only getfile() and
324 of source revisions to converted revisions. Only getfile() and
325 lookuprev() should be called on 'source'. 'full' means that 'files'
325 lookuprev() should be called on 'source'. 'full' means that 'files'
326 is complete and all other files should be removed.
326 is complete and all other files should be removed.
327 'cleanp2' is a set of the filenames that are unchanged from p2
327 'cleanp2' is a set of the filenames that are unchanged from p2
328 (only in the common merge case where there two parents).
328 (only in the common merge case where there two parents).
329
329
330 Note that the sink repository is not told to update itself to
330 Note that the sink repository is not told to update itself to
331 a particular revision (or even what that revision would be)
331 a particular revision (or even what that revision would be)
332 before it receives the file data.
332 before it receives the file data.
333 """
333 """
334 raise NotImplementedError
334 raise NotImplementedError
335
335
336 def puttags(self, tags):
336 def puttags(self, tags):
337 """Put tags into sink.
337 """Put tags into sink.
338
338
339 tags: {tagname: sink_rev_id, ...} where tagname is an UTF-8 string.
339 tags: {tagname: sink_rev_id, ...} where tagname is an UTF-8 string.
340 Return a pair (tag_revision, tag_parent_revision), or (None, None)
340 Return a pair (tag_revision, tag_parent_revision), or (None, None)
341 if nothing was changed.
341 if nothing was changed.
342 """
342 """
343 raise NotImplementedError
343 raise NotImplementedError
344
344
345 def setbranch(self, branch, pbranches):
345 def setbranch(self, branch, pbranches):
346 """Set the current branch name. Called before the first putcommit
346 """Set the current branch name. Called before the first putcommit
347 on the branch.
347 on the branch.
348 branch: branch name for subsequent commits
348 branch: branch name for subsequent commits
349 pbranches: (converted parent revision, parent branch) tuples"""
349 pbranches: (converted parent revision, parent branch) tuples"""
350
350
351 def setfilemapmode(self, active):
351 def setfilemapmode(self, active):
352 """Tell the destination that we're using a filemap
352 """Tell the destination that we're using a filemap
353
353
354 Some converter_sources (svn in particular) can claim that a file
354 Some converter_sources (svn in particular) can claim that a file
355 was changed in a revision, even if there was no change. This method
355 was changed in a revision, even if there was no change. This method
356 tells the destination that we're using a filemap and that it should
356 tells the destination that we're using a filemap and that it should
357 filter empty revisions.
357 filter empty revisions.
358 """
358 """
359
359
360 def before(self):
360 def before(self):
361 pass
361 pass
362
362
363 def after(self):
363 def after(self):
364 pass
364 pass
365
365
366 def putbookmarks(self, bookmarks):
366 def putbookmarks(self, bookmarks):
367 """Put bookmarks into sink.
367 """Put bookmarks into sink.
368
368
369 bookmarks: {bookmarkname: sink_rev_id, ...}
369 bookmarks: {bookmarkname: sink_rev_id, ...}
370 where bookmarkname is an UTF-8 string.
370 where bookmarkname is an UTF-8 string.
371 """
371 """
372
372
373 def hascommitfrommap(self, rev):
373 def hascommitfrommap(self, rev):
374 """Return False if a rev mentioned in a filemap is known to not be
374 """Return False if a rev mentioned in a filemap is known to not be
375 present."""
375 present."""
376 raise NotImplementedError
376 raise NotImplementedError
377
377
378 def hascommitforsplicemap(self, rev):
378 def hascommitforsplicemap(self, rev):
379 """This method is for the special needs for splicemap handling and not
379 """This method is for the special needs for splicemap handling and not
380 for general use. Returns True if the sink contains rev, aborts on some
380 for general use. Returns True if the sink contains rev, aborts on some
381 special cases."""
381 special cases."""
382 raise NotImplementedError
382 raise NotImplementedError
383
383
384
384
385 class commandline:
385 class commandline:
386 def __init__(self, ui, command):
386 def __init__(self, ui, command):
387 self.ui = ui
387 self.ui = ui
388 self.command = command
388 self.command = command
389
389
390 def prerun(self):
390 def prerun(self):
391 pass
391 pass
392
392
393 def postrun(self):
393 def postrun(self):
394 pass
394 pass
395
395
396 def _cmdline(self, cmd, *args, **kwargs):
396 def _cmdline(self, cmd, *args, **kwargs):
397 kwargs = pycompat.byteskwargs(kwargs)
397 kwargs = pycompat.byteskwargs(kwargs)
398 cmdline = [self.command, cmd] + list(args)
398 cmdline = [self.command, cmd] + list(args)
399 for k, v in kwargs.items():
399 for k, v in kwargs.items():
400 if len(k) == 1:
400 if len(k) == 1:
401 cmdline.append(b'-' + k)
401 cmdline.append(b'-' + k)
402 else:
402 else:
403 cmdline.append(b'--' + k.replace(b'_', b'-'))
403 cmdline.append(b'--' + k.replace(b'_', b'-'))
404 try:
404 try:
405 if len(k) == 1:
405 if len(k) == 1:
406 cmdline.append(b'' + v)
406 cmdline.append(b'' + v)
407 else:
407 else:
408 cmdline[-1] += b'=' + v
408 cmdline[-1] += b'=' + v
409 except TypeError:
409 except TypeError:
410 pass
410 pass
411 cmdline = [procutil.shellquote(arg) for arg in cmdline]
411 cmdline = [procutil.shellquote(arg) for arg in cmdline]
412 if not self.ui.debugflag:
412 if not self.ui.debugflag:
413 cmdline += [b'2>', pycompat.bytestr(os.devnull)]
413 cmdline += [b'2>', pycompat.bytestr(os.devnull)]
414 cmdline = b' '.join(cmdline)
414 cmdline = b' '.join(cmdline)
415 return cmdline
415 return cmdline
416
416
417 def _run(self, cmd, *args, **kwargs):
417 def _run(self, cmd, *args, **kwargs):
418 def popen(cmdline):
418 def popen(cmdline):
419 p = subprocess.Popen(
419 p = subprocess.Popen(
420 procutil.tonativestr(cmdline),
420 procutil.tonativestr(cmdline),
421 shell=True,
421 shell=True,
422 bufsize=-1,
422 bufsize=-1,
423 close_fds=procutil.closefds,
423 close_fds=procutil.closefds,
424 stdout=subprocess.PIPE,
424 stdout=subprocess.PIPE,
425 )
425 )
426 return p
426 return p
427
427
428 return self._dorun(popen, cmd, *args, **kwargs)
428 return self._dorun(popen, cmd, *args, **kwargs)
429
429
430 def _run2(self, cmd, *args, **kwargs):
430 def _run2(self, cmd, *args, **kwargs):
431 return self._dorun(procutil.popen2, cmd, *args, **kwargs)
431 return self._dorun(procutil.popen2, cmd, *args, **kwargs)
432
432
433 def _run3(self, cmd, *args, **kwargs):
433 def _run3(self, cmd, *args, **kwargs):
434 return self._dorun(procutil.popen3, cmd, *args, **kwargs)
434 return self._dorun(procutil.popen3, cmd, *args, **kwargs)
435
435
436 def _dorun(self, openfunc, cmd, *args, **kwargs):
436 def _dorun(self, openfunc, cmd, *args, **kwargs):
437 cmdline = self._cmdline(cmd, *args, **kwargs)
437 cmdline = self._cmdline(cmd, *args, **kwargs)
438 self.ui.debug(b'running: %s\n' % (cmdline,))
438 self.ui.debug(b'running: %s\n' % (cmdline,))
439 self.prerun()
439 self.prerun()
440 try:
440 try:
441 return openfunc(cmdline)
441 return openfunc(cmdline)
442 finally:
442 finally:
443 self.postrun()
443 self.postrun()
444
444
445 def run(self, cmd, *args, **kwargs):
445 def run(self, cmd, *args, **kwargs):
446 p = self._run(cmd, *args, **kwargs)
446 p = self._run(cmd, *args, **kwargs)
447 output = p.communicate()[0]
447 output = p.communicate()[0]
448 self.ui.debug(output)
448 self.ui.debug(output)
449 return output, p.returncode
449 return output, p.returncode
450
450
451 def runlines(self, cmd, *args, **kwargs):
451 def runlines(self, cmd, *args, **kwargs):
452 p = self._run(cmd, *args, **kwargs)
452 p = self._run(cmd, *args, **kwargs)
453 output = p.stdout.readlines()
453 output = p.stdout.readlines()
454 p.wait()
454 p.wait()
455 self.ui.debug(b''.join(output))
455 self.ui.debug(b''.join(output))
456 return output, p.returncode
456 return output, p.returncode
457
457
458 def checkexit(self, status, output=b''):
458 def checkexit(self, status, output=b''):
459 if status:
459 if status:
460 if output:
460 if output:
461 self.ui.warn(_(b'%s error:\n') % self.command)
461 self.ui.warn(_(b'%s error:\n') % self.command)
462 self.ui.warn(output)
462 self.ui.warn(output)
463 msg = procutil.explainexit(status)
463 msg = procutil.explainexit(status)
464 raise error.Abort(b'%s %s' % (self.command, msg))
464 raise error.Abort(b'%s %s' % (self.command, msg))
465
465
466 def run0(self, cmd, *args, **kwargs):
466 def run0(self, cmd, *args, **kwargs):
467 output, status = self.run(cmd, *args, **kwargs)
467 output, status = self.run(cmd, *args, **kwargs)
468 self.checkexit(status, output)
468 self.checkexit(status, output)
469 return output
469 return output
470
470
471 def runlines0(self, cmd, *args, **kwargs):
471 def runlines0(self, cmd, *args, **kwargs):
472 output, status = self.runlines(cmd, *args, **kwargs)
472 output, status = self.runlines(cmd, *args, **kwargs)
473 self.checkexit(status, b''.join(output))
473 self.checkexit(status, b''.join(output))
474 return output
474 return output
475
475
476 @propertycache
476 @propertycache
477 def argmax(self):
477 def argmax(self):
478 # POSIX requires at least 4096 bytes for ARG_MAX
478 # POSIX requires at least 4096 bytes for ARG_MAX
479 argmax = 4096
479 argmax = 4096
480 try:
480 try:
481 argmax = os.sysconf("SC_ARG_MAX")
481 argmax = os.sysconf("SC_ARG_MAX")
482 except (AttributeError, ValueError):
482 except (AttributeError, ValueError):
483 pass
483 pass
484
484
485 # Windows shells impose their own limits on command line length,
485 # Windows shells impose their own limits on command line length,
486 # down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes
486 # down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes
487 # for older 4nt.exe. See http://support.microsoft.com/kb/830473 for
487 # for older 4nt.exe. See http://support.microsoft.com/kb/830473 for
488 # details about cmd.exe limitations.
488 # details about cmd.exe limitations.
489
489
490 # Since ARG_MAX is for command line _and_ environment, lower our limit
490 # Since ARG_MAX is for command line _and_ environment, lower our limit
491 # (and make happy Windows shells while doing this).
491 # (and make happy Windows shells while doing this).
492 return argmax // 2 - 1
492 return argmax // 2 - 1
493
493
494 def _limit_arglist(self, arglist, cmd, *args, **kwargs):
494 def _limit_arglist(self, arglist, cmd, *args, **kwargs):
495 cmdlen = len(self._cmdline(cmd, *args, **kwargs))
495 cmdlen = len(self._cmdline(cmd, *args, **kwargs))
496 limit = self.argmax - cmdlen
496 limit = self.argmax - cmdlen
497 numbytes = 0
497 numbytes = 0
498 fl = []
498 fl = []
499 for fn in arglist:
499 for fn in arglist:
500 b = len(fn) + 3
500 b = len(fn) + 3
501 if numbytes + b < limit or len(fl) == 0:
501 if numbytes + b < limit or len(fl) == 0:
502 fl.append(fn)
502 fl.append(fn)
503 numbytes += b
503 numbytes += b
504 else:
504 else:
505 yield fl
505 yield fl
506 fl = [fn]
506 fl = [fn]
507 numbytes = b
507 numbytes = b
508 if fl:
508 if fl:
509 yield fl
509 yield fl
510
510
511 def xargs(self, arglist, cmd, *args, **kwargs):
511 def xargs(self, arglist, cmd, *args, **kwargs):
512 for l in self._limit_arglist(arglist, cmd, *args, **kwargs):
512 for l in self._limit_arglist(arglist, cmd, *args, **kwargs):
513 self.run0(cmd, *(list(args) + l), **kwargs)
513 self.run0(cmd, *(list(args) + l), **kwargs)
514
514
515
515
516 class mapfile(dict):
516 class mapfile(dict):
517 def __init__(self, ui, path):
517 def __init__(self, ui, path):
518 super(mapfile, self).__init__()
518 super(mapfile, self).__init__()
519 self.ui = ui
519 self.ui = ui
520 self.path = path
520 self.path = path
521 self.fp = None
521 self.fp = None
522 self.order = []
522 self.order = []
523 self._read()
523 self._read()
524
524
525 def _read(self):
525 def _read(self):
526 if not self.path:
526 if not self.path:
527 return
527 return
528 try:
528 try:
529 fp = open(self.path, b'rb')
529 fp = open(self.path, b'rb')
530 except FileNotFoundError:
530 except FileNotFoundError:
531 return
531 return
532 for i, line in enumerate(fp):
532 for i, line in enumerate(fp):
533 line = line.splitlines()[0].rstrip()
533 line = line.splitlines()[0].rstrip()
534 if not line:
534 if not line:
535 # Ignore blank lines
535 # Ignore blank lines
536 continue
536 continue
537 try:
537 try:
538 key, value = line.rsplit(b' ', 1)
538 key, value = line.rsplit(b' ', 1)
539 except ValueError:
539 except ValueError:
540 raise error.Abort(
540 raise error.Abort(
541 _(b'syntax error in %s(%d): key/value pair expected')
541 _(b'syntax error in %s(%d): key/value pair expected')
542 % (self.path, i + 1)
542 % (self.path, i + 1)
543 )
543 )
544 if key not in self:
544 if key not in self:
545 self.order.append(key)
545 self.order.append(key)
546 super(mapfile, self).__setitem__(key, value)
546 super(mapfile, self).__setitem__(key, value)
547 fp.close()
547 fp.close()
548
548
549 def __setitem__(self, key, value):
549 def __setitem__(self, key, value):
550 if self.fp is None:
550 if self.fp is None:
551 try:
551 try:
552 self.fp = open(self.path, b'ab')
552 self.fp = open(self.path, b'ab')
553 except IOError as err:
553 except IOError as err:
554 raise error.Abort(
554 raise error.Abort(
555 _(b'could not open map file %r: %s')
555 _(b'could not open map file %r: %s')
556 % (self.path, encoding.strtolocal(err.strerror))
556 % (self.path, encoding.strtolocal(err.strerror))
557 )
557 )
558 self.fp.write(util.tonativeeol(b'%s %s\n' % (key, value)))
558 self.fp.write(util.tonativeeol(b'%s %s\n' % (key, value)))
559 self.fp.flush()
559 self.fp.flush()
560 super(mapfile, self).__setitem__(key, value)
560 super(mapfile, self).__setitem__(key, value)
561
561
562 def close(self):
562 def close(self):
563 if self.fp:
563 if self.fp:
564 self.fp.close()
564 self.fp.close()
565 self.fp = None
565 self.fp = None
566
566
567
567
568 def makedatetimestamp(t):
568 def makedatetimestamp(t):
569 """Like dateutil.makedate() but for time t instead of current time"""
569 """Like dateutil.makedate() but for time t instead of current time"""
570 delta = datetime.datetime.utcfromtimestamp(
570 tz = round(
571 t
571 t
572 ) - datetime.datetime.fromtimestamp(t)
572 - datetime.datetime.fromtimestamp(t)
573 tz = delta.days * 86400 + delta.seconds
573 .replace(tzinfo=datetime.timezone.utc)
574 .timestamp()
575 )
574 return t, tz
576 return t, tz
@@ -1,996 +1,1010 b''
1 # extensions.py - extension handling for mercurial
1 # extensions.py - extension handling for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8
8
9 import ast
9 import ast
10 import collections
10 import collections
11 import functools
11 import functools
12 import imp
12 import importlib
13 import inspect
13 import inspect
14 import os
14 import os
15 import sys
15
16
16 from .i18n import (
17 from .i18n import (
17 _,
18 _,
18 gettext,
19 gettext,
19 )
20 )
20 from .pycompat import (
21 from .pycompat import (
21 getattr,
22 getattr,
22 open,
23 open,
23 setattr,
24 setattr,
24 )
25 )
25
26
26 from . import (
27 from . import (
27 cmdutil,
28 cmdutil,
28 configitems,
29 configitems,
29 error,
30 error,
30 pycompat,
31 pycompat,
31 util,
32 util,
32 )
33 )
33
34
34 from .utils import stringutil
35 from .utils import stringutil
35
36
36 _extensions = {}
37 _extensions = {}
37 _disabledextensions = {}
38 _disabledextensions = {}
38 _aftercallbacks = {}
39 _aftercallbacks = {}
39 _order = []
40 _order = []
40 _builtin = {
41 _builtin = {
41 b'hbisect',
42 b'hbisect',
42 b'bookmarks',
43 b'bookmarks',
43 b'color',
44 b'color',
44 b'parentrevspec',
45 b'parentrevspec',
45 b'progress',
46 b'progress',
46 b'interhg',
47 b'interhg',
47 b'inotify',
48 b'inotify',
48 b'hgcia',
49 b'hgcia',
49 b'shelve',
50 b'shelve',
50 }
51 }
51
52
52
53
53 def extensions(ui=None):
54 def extensions(ui=None):
54 if ui:
55 if ui:
55
56
56 def enabled(name):
57 def enabled(name):
57 for format in [b'%s', b'hgext.%s']:
58 for format in [b'%s', b'hgext.%s']:
58 conf = ui.config(b'extensions', format % name)
59 conf = ui.config(b'extensions', format % name)
59 if conf is not None and not conf.startswith(b'!'):
60 if conf is not None and not conf.startswith(b'!'):
60 return True
61 return True
61
62
62 else:
63 else:
63 enabled = lambda name: True
64 enabled = lambda name: True
64 for name in _order:
65 for name in _order:
65 module = _extensions[name]
66 module = _extensions[name]
66 if module and enabled(name):
67 if module and enabled(name):
67 yield name, module
68 yield name, module
68
69
69
70
70 def find(name):
71 def find(name):
71 '''return module with given extension name'''
72 '''return module with given extension name'''
72 mod = None
73 mod = None
73 try:
74 try:
74 mod = _extensions[name]
75 mod = _extensions[name]
75 except KeyError:
76 except KeyError:
76 for k, v in _extensions.items():
77 for k, v in _extensions.items():
77 if k.endswith(b'.' + name) or k.endswith(b'/' + name):
78 if k.endswith(b'.' + name) or k.endswith(b'/' + name):
78 mod = v
79 mod = v
79 break
80 break
80 if not mod:
81 if not mod:
81 raise KeyError(name)
82 raise KeyError(name)
82 return mod
83 return mod
83
84
84
85
85 def loadpath(path, module_name):
86 def loadpath(path, module_name):
86 module_name = module_name.replace(b'.', b'_')
87 module_name = module_name.replace(b'.', b'_')
87 path = util.normpath(util.expandpath(path))
88 path = util.normpath(util.expandpath(path))
88 module_name = pycompat.fsdecode(module_name)
89 module_name = pycompat.fsdecode(module_name)
89 path = pycompat.fsdecode(path)
90 path = pycompat.fsdecode(path)
90 if os.path.isdir(path):
91 if os.path.isdir(path):
91 # module/__init__.py style
92 # module/__init__.py style
92 d, f = os.path.split(path)
93 init_py_path = os.path.join(path, '__init__.py')
93 fd, fpath, desc = imp.find_module(f, [d])
94 if not os.path.exists(init_py_path):
94 # When https://github.com/python/typeshed/issues/3466 is fixed
95 raise ImportError("No module named '%s'" % os.path.basename(path))
95 # and in a pytype release we can drop this disable.
96 path = init_py_path
96 return imp.load_module(
97
97 module_name, fd, fpath, desc # pytype: disable=wrong-arg-types
98 loader = importlib.machinery.SourceFileLoader(module_name, path)
98 )
99 spec = importlib.util.spec_from_file_location(module_name, loader=loader)
99 else:
100 assert spec is not None # help Pytype
100 try:
101 module = importlib.util.module_from_spec(spec)
101 return imp.load_source(module_name, path)
102 sys.modules[module_name] = module
102 except IOError as exc:
103 spec.loader.exec_module(module)
103 if not exc.filename:
104 return module
104 exc.filename = path # python does not fill this
105 raise
106
105
107
106
108 def _importh(name):
107 def _importh(name):
109 """import and return the <name> module"""
108 """import and return the <name> module"""
110 mod = __import__(pycompat.sysstr(name))
109 mod = __import__(pycompat.sysstr(name))
111 components = name.split(b'.')
110 components = name.split(b'.')
112 for comp in components[1:]:
111 for comp in components[1:]:
113 mod = getattr(mod, comp)
112 mod = getattr(mod, comp)
114 return mod
113 return mod
115
114
116
115
117 def _importext(name, path=None, reportfunc=None):
116 def _importext(name, path=None, reportfunc=None):
118 if path:
117 if path:
119 # the module will be loaded in sys.modules
118 # the module will be loaded in sys.modules
120 # choose an unique name so that it doesn't
119 # choose an unique name so that it doesn't
121 # conflicts with other modules
120 # conflicts with other modules
122 mod = loadpath(path, b'hgext.%s' % name)
121 mod = loadpath(path, b'hgext.%s' % name)
123 else:
122 else:
124 try:
123 try:
125 mod = _importh(b"hgext.%s" % name)
124 mod = _importh(b"hgext.%s" % name)
126 except ImportError as err:
125 except ImportError as err:
127 if reportfunc:
126 if reportfunc:
128 reportfunc(err, b"hgext.%s" % name, b"hgext3rd.%s" % name)
127 reportfunc(err, b"hgext.%s" % name, b"hgext3rd.%s" % name)
129 try:
128 try:
130 mod = _importh(b"hgext3rd.%s" % name)
129 mod = _importh(b"hgext3rd.%s" % name)
131 except ImportError as err:
130 except ImportError as err:
132 if reportfunc:
131 if reportfunc:
133 reportfunc(err, b"hgext3rd.%s" % name, name)
132 reportfunc(err, b"hgext3rd.%s" % name, name)
134 mod = _importh(name)
133 mod = _importh(name)
135 return mod
134 return mod
136
135
137
136
138 def _reportimporterror(ui, err, failed, next):
137 def _reportimporterror(ui, err, failed, next):
139 # note: this ui.log happens before --debug is processed,
138 # note: this ui.log happens before --debug is processed,
140 # Use --config ui.debug=1 to see them.
139 # Use --config ui.debug=1 to see them.
141 ui.log(
140 ui.log(
142 b'extension',
141 b'extension',
143 b' - could not import %s (%s): trying %s\n',
142 b' - could not import %s (%s): trying %s\n',
144 failed,
143 failed,
145 stringutil.forcebytestr(err),
144 stringutil.forcebytestr(err),
146 next,
145 next,
147 )
146 )
148 if ui.debugflag and ui.configbool(b'devel', b'debug.extensions'):
147 if ui.debugflag and ui.configbool(b'devel', b'debug.extensions'):
149 ui.traceback()
148 ui.traceback()
150
149
151
150
152 def _rejectunicode(name, xs):
151 def _rejectunicode(name, xs):
153 if isinstance(xs, (list, set, tuple)):
152 if isinstance(xs, (list, set, tuple)):
154 for x in xs:
153 for x in xs:
155 _rejectunicode(name, x)
154 _rejectunicode(name, x)
156 elif isinstance(xs, dict):
155 elif isinstance(xs, dict):
157 for k, v in xs.items():
156 for k, v in xs.items():
158 _rejectunicode(name, k)
157 _rejectunicode(name, k)
159 _rejectunicode(b'%s.%s' % (name, stringutil.forcebytestr(k)), v)
158 _rejectunicode(b'%s.%s' % (name, stringutil.forcebytestr(k)), v)
160 elif isinstance(xs, type(u'')):
159 elif isinstance(xs, type(u'')):
161 raise error.ProgrammingError(
160 raise error.ProgrammingError(
162 b"unicode %r found in %s" % (xs, name),
161 b"unicode %r found in %s" % (xs, name),
163 hint=b"use b'' to make it byte string",
162 hint=b"use b'' to make it byte string",
164 )
163 )
165
164
166
165
167 # attributes set by registrar.command
166 # attributes set by registrar.command
168 _cmdfuncattrs = (b'norepo', b'optionalrepo', b'inferrepo')
167 _cmdfuncattrs = (b'norepo', b'optionalrepo', b'inferrepo')
169
168
170
169
171 def _validatecmdtable(ui, cmdtable):
170 def _validatecmdtable(ui, cmdtable):
172 """Check if extension commands have required attributes"""
171 """Check if extension commands have required attributes"""
173 for c, e in cmdtable.items():
172 for c, e in cmdtable.items():
174 f = e[0]
173 f = e[0]
175 missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)]
174 missing = [a for a in _cmdfuncattrs if not util.safehasattr(f, a)]
176 if not missing:
175 if not missing:
177 continue
176 continue
178 raise error.ProgrammingError(
177 raise error.ProgrammingError(
179 b'missing attributes: %s' % b', '.join(missing),
178 b'missing attributes: %s' % b', '.join(missing),
180 hint=b"use @command decorator to register '%s'" % c,
179 hint=b"use @command decorator to register '%s'" % c,
181 )
180 )
182
181
183
182
184 def _validatetables(ui, mod):
183 def _validatetables(ui, mod):
185 """Sanity check for loadable tables provided by extension module"""
184 """Sanity check for loadable tables provided by extension module"""
186 for t in [b'cmdtable', b'colortable', b'configtable']:
185 for t in [b'cmdtable', b'colortable', b'configtable']:
187 _rejectunicode(t, getattr(mod, t, {}))
186 _rejectunicode(t, getattr(mod, t, {}))
188 for t in [
187 for t in [
189 b'filesetpredicate',
188 b'filesetpredicate',
190 b'internalmerge',
189 b'internalmerge',
191 b'revsetpredicate',
190 b'revsetpredicate',
192 b'templatefilter',
191 b'templatefilter',
193 b'templatefunc',
192 b'templatefunc',
194 b'templatekeyword',
193 b'templatekeyword',
195 ]:
194 ]:
196 o = getattr(mod, t, None)
195 o = getattr(mod, t, None)
197 if o:
196 if o:
198 _rejectunicode(t, o._table)
197 _rejectunicode(t, o._table)
199 _validatecmdtable(ui, getattr(mod, 'cmdtable', {}))
198 _validatecmdtable(ui, getattr(mod, 'cmdtable', {}))
200
199
201
200
202 def load(ui, name, path, loadingtime=None):
201 def load(ui, name, path, loadingtime=None):
203 if name.startswith(b'hgext.') or name.startswith(b'hgext/'):
202 if name.startswith(b'hgext.') or name.startswith(b'hgext/'):
204 shortname = name[6:]
203 shortname = name[6:]
205 else:
204 else:
206 shortname = name
205 shortname = name
207 if shortname in _builtin:
206 if shortname in _builtin:
208 return None
207 return None
209 if shortname in _extensions:
208 if shortname in _extensions:
210 return _extensions[shortname]
209 return _extensions[shortname]
211 ui.log(b'extension', b' - loading extension: %s\n', shortname)
210 ui.log(b'extension', b' - loading extension: %s\n', shortname)
212 _extensions[shortname] = None
211 _extensions[shortname] = None
213 with util.timedcm('load extension %s', shortname) as stats:
212 with util.timedcm('load extension %s', shortname) as stats:
214 mod = _importext(name, path, bind(_reportimporterror, ui))
213 mod = _importext(name, path, bind(_reportimporterror, ui))
215 ui.log(b'extension', b' > %s extension loaded in %s\n', shortname, stats)
214 ui.log(b'extension', b' > %s extension loaded in %s\n', shortname, stats)
216 if loadingtime is not None:
215 if loadingtime is not None:
217 loadingtime[shortname] += stats.elapsed
216 loadingtime[shortname] += stats.elapsed
218
217
219 # Before we do anything with the extension, check against minimum stated
218 # Before we do anything with the extension, check against minimum stated
220 # compatibility. This gives extension authors a mechanism to have their
219 # compatibility. This gives extension authors a mechanism to have their
221 # extensions short circuit when loaded with a known incompatible version
220 # extensions short circuit when loaded with a known incompatible version
222 # of Mercurial.
221 # of Mercurial.
223 minver = getattr(mod, 'minimumhgversion', None)
222 minver = getattr(mod, 'minimumhgversion', None)
224 if minver:
223 if minver:
225 curver = util.versiontuple(n=2)
224 curver = util.versiontuple(n=2)
226 extmin = util.versiontuple(stringutil.forcebytestr(minver), 2)
225 extmin = util.versiontuple(stringutil.forcebytestr(minver), 2)
227
226
228 if None in extmin:
227 if None in extmin:
229 extmin = (extmin[0] or 0, extmin[1] or 0)
228 extmin = (extmin[0] or 0, extmin[1] or 0)
230
229
231 if None in curver or extmin > curver:
230 if None in curver or extmin > curver:
232 msg = _(
231 msg = _(
233 b'(third party extension %s requires version %s or newer '
232 b'(third party extension %s requires version %s or newer '
234 b'of Mercurial (current: %s); disabling)\n'
233 b'of Mercurial (current: %s); disabling)\n'
235 )
234 )
236 ui.warn(msg % (shortname, minver, util.version()))
235 ui.warn(msg % (shortname, minver, util.version()))
237 return
236 return
238 ui.log(b'extension', b' - validating extension tables: %s\n', shortname)
237 ui.log(b'extension', b' - validating extension tables: %s\n', shortname)
239 _validatetables(ui, mod)
238 _validatetables(ui, mod)
240
239
241 _extensions[shortname] = mod
240 _extensions[shortname] = mod
242 _order.append(shortname)
241 _order.append(shortname)
243 ui.log(
242 ui.log(
244 b'extension', b' - invoking registered callbacks: %s\n', shortname
243 b'extension', b' - invoking registered callbacks: %s\n', shortname
245 )
244 )
246 with util.timedcm('callbacks extension %s', shortname) as stats:
245 with util.timedcm('callbacks extension %s', shortname) as stats:
247 for fn in _aftercallbacks.get(shortname, []):
246 for fn in _aftercallbacks.get(shortname, []):
248 fn(loaded=True)
247 fn(loaded=True)
249 ui.log(b'extension', b' > callbacks completed in %s\n', stats)
248 ui.log(b'extension', b' > callbacks completed in %s\n', stats)
250 return mod
249 return mod
251
250
252
251
253 def _runuisetup(name, ui):
252 def _runuisetup(name, ui):
254 uisetup = getattr(_extensions[name], 'uisetup', None)
253 uisetup = getattr(_extensions[name], 'uisetup', None)
255 if uisetup:
254 if uisetup:
256 try:
255 try:
257 uisetup(ui)
256 uisetup(ui)
258 except Exception as inst:
257 except Exception as inst:
259 ui.traceback(force=True)
258 ui.traceback(force=True)
260 msg = stringutil.forcebytestr(inst)
259 msg = stringutil.forcebytestr(inst)
261 ui.warn(_(b"*** failed to set up extension %s: %s\n") % (name, msg))
260 ui.warn(_(b"*** failed to set up extension %s: %s\n") % (name, msg))
262 return False
261 return False
263 return True
262 return True
264
263
265
264
266 def _runextsetup(name, ui):
265 def _runextsetup(name, ui):
267 extsetup = getattr(_extensions[name], 'extsetup', None)
266 extsetup = getattr(_extensions[name], 'extsetup', None)
268 if extsetup:
267 if extsetup:
269 try:
268 try:
270 extsetup(ui)
269 extsetup(ui)
271 except Exception as inst:
270 except Exception as inst:
272 ui.traceback(force=True)
271 ui.traceback(force=True)
273 msg = stringutil.forcebytestr(inst)
272 msg = stringutil.forcebytestr(inst)
274 ui.warn(_(b"*** failed to set up extension %s: %s\n") % (name, msg))
273 ui.warn(_(b"*** failed to set up extension %s: %s\n") % (name, msg))
275 return False
274 return False
276 return True
275 return True
277
276
278
277
279 def loadall(ui, whitelist=None):
278 def loadall(ui, whitelist=None):
280 loadingtime = collections.defaultdict(int)
279 loadingtime = collections.defaultdict(int)
281 result = ui.configitems(b"extensions")
280 result = ui.configitems(b"extensions")
282 if whitelist is not None:
281 if whitelist is not None:
283 result = [(k, v) for (k, v) in result if k in whitelist]
282 result = [(k, v) for (k, v) in result if k in whitelist]
284 result = [(k, v) for (k, v) in result if b':' not in k]
283 result = [(k, v) for (k, v) in result if b':' not in k]
285 newindex = len(_order)
284 newindex = len(_order)
286 ui.log(
285 ui.log(
287 b'extension',
286 b'extension',
288 b'loading %sextensions\n',
287 b'loading %sextensions\n',
289 b'additional ' if newindex else b'',
288 b'additional ' if newindex else b'',
290 )
289 )
291 ui.log(b'extension', b'- processing %d entries\n', len(result))
290 ui.log(b'extension', b'- processing %d entries\n', len(result))
292 with util.timedcm('load all extensions') as stats:
291 with util.timedcm('load all extensions') as stats:
293 default_sub_options = ui.configsuboptions(b"extensions", b"*")[1]
292 default_sub_options = ui.configsuboptions(b"extensions", b"*")[1]
294
293
295 for (name, path) in result:
294 for (name, path) in result:
296 if path:
295 if path:
297 if path[0:1] == b'!':
296 if path[0:1] == b'!':
298 if name not in _disabledextensions:
297 if name not in _disabledextensions:
299 ui.log(
298 ui.log(
300 b'extension',
299 b'extension',
301 b' - skipping disabled extension: %s\n',
300 b' - skipping disabled extension: %s\n',
302 name,
301 name,
303 )
302 )
304 _disabledextensions[name] = path[1:]
303 _disabledextensions[name] = path[1:]
305 continue
304 continue
306 try:
305 try:
307 load(ui, name, path, loadingtime)
306 load(ui, name, path, loadingtime)
308 except Exception as inst:
307 except Exception as inst:
309 msg = stringutil.forcebytestr(inst)
308 msg = stringutil.forcebytestr(inst)
310 if path:
309 if path:
311 error_msg = _(
310 error_msg = _(
312 b'failed to import extension "%s" from %s: %s'
311 b'failed to import extension "%s" from %s: %s'
313 )
312 )
314 error_msg %= (name, path, msg)
313 error_msg %= (name, path, msg)
315 else:
314 else:
316 error_msg = _(b'failed to import extension "%s": %s')
315 error_msg = _(b'failed to import extension "%s": %s')
317 error_msg %= (name, msg)
316 error_msg %= (name, msg)
318
317
319 options = default_sub_options.copy()
318 options = default_sub_options.copy()
320 ext_options = ui.configsuboptions(b"extensions", name)[1]
319 ext_options = ui.configsuboptions(b"extensions", name)[1]
321 options.update(ext_options)
320 options.update(ext_options)
322 if stringutil.parsebool(options.get(b"required", b'no')):
321 if stringutil.parsebool(options.get(b"required", b'no')):
323 hint = None
322 hint = None
324 if isinstance(inst, error.Hint) and inst.hint:
323 if isinstance(inst, error.Hint) and inst.hint:
325 hint = inst.hint
324 hint = inst.hint
326 if hint is None:
325 if hint is None:
327 hint = _(
326 hint = _(
328 b"loading of this extension was required, "
327 b"loading of this extension was required, "
329 b"see `hg help config.extensions` for details"
328 b"see `hg help config.extensions` for details"
330 )
329 )
331 raise error.Abort(error_msg, hint=hint)
330 raise error.Abort(error_msg, hint=hint)
332 else:
331 else:
333 ui.warn((b"*** %s\n") % error_msg)
332 ui.warn((b"*** %s\n") % error_msg)
334 if isinstance(inst, error.Hint) and inst.hint:
333 if isinstance(inst, error.Hint) and inst.hint:
335 ui.warn(_(b"*** (%s)\n") % inst.hint)
334 ui.warn(_(b"*** (%s)\n") % inst.hint)
336 ui.traceback()
335 ui.traceback()
337
336
338 ui.log(
337 ui.log(
339 b'extension',
338 b'extension',
340 b'> loaded %d extensions, total time %s\n',
339 b'> loaded %d extensions, total time %s\n',
341 len(_order) - newindex,
340 len(_order) - newindex,
342 stats,
341 stats,
343 )
342 )
344 # list of (objname, loadermod, loadername) tuple:
343 # list of (objname, loadermod, loadername) tuple:
345 # - objname is the name of an object in extension module,
344 # - objname is the name of an object in extension module,
346 # from which extra information is loaded
345 # from which extra information is loaded
347 # - loadermod is the module where loader is placed
346 # - loadermod is the module where loader is placed
348 # - loadername is the name of the function,
347 # - loadername is the name of the function,
349 # which takes (ui, extensionname, extraobj) arguments
348 # which takes (ui, extensionname, extraobj) arguments
350 #
349 #
351 # This one is for the list of item that must be run before running any setup
350 # This one is for the list of item that must be run before running any setup
352 earlyextraloaders = [
351 earlyextraloaders = [
353 (b'configtable', configitems, b'loadconfigtable'),
352 (b'configtable', configitems, b'loadconfigtable'),
354 ]
353 ]
355
354
356 ui.log(b'extension', b'- loading configtable attributes\n')
355 ui.log(b'extension', b'- loading configtable attributes\n')
357 _loadextra(ui, newindex, earlyextraloaders)
356 _loadextra(ui, newindex, earlyextraloaders)
358
357
359 broken = set()
358 broken = set()
360 ui.log(b'extension', b'- executing uisetup hooks\n')
359 ui.log(b'extension', b'- executing uisetup hooks\n')
361 with util.timedcm('all uisetup') as alluisetupstats:
360 with util.timedcm('all uisetup') as alluisetupstats:
362 for name in _order[newindex:]:
361 for name in _order[newindex:]:
363 ui.log(b'extension', b' - running uisetup for %s\n', name)
362 ui.log(b'extension', b' - running uisetup for %s\n', name)
364 with util.timedcm('uisetup %s', name) as stats:
363 with util.timedcm('uisetup %s', name) as stats:
365 if not _runuisetup(name, ui):
364 if not _runuisetup(name, ui):
366 ui.log(
365 ui.log(
367 b'extension',
366 b'extension',
368 b' - the %s extension uisetup failed\n',
367 b' - the %s extension uisetup failed\n',
369 name,
368 name,
370 )
369 )
371 broken.add(name)
370 broken.add(name)
372 ui.log(b'extension', b' > uisetup for %s took %s\n', name, stats)
371 ui.log(b'extension', b' > uisetup for %s took %s\n', name, stats)
373 loadingtime[name] += stats.elapsed
372 loadingtime[name] += stats.elapsed
374 ui.log(b'extension', b'> all uisetup took %s\n', alluisetupstats)
373 ui.log(b'extension', b'> all uisetup took %s\n', alluisetupstats)
375
374
376 ui.log(b'extension', b'- executing extsetup hooks\n')
375 ui.log(b'extension', b'- executing extsetup hooks\n')
377 with util.timedcm('all extsetup') as allextetupstats:
376 with util.timedcm('all extsetup') as allextetupstats:
378 for name in _order[newindex:]:
377 for name in _order[newindex:]:
379 if name in broken:
378 if name in broken:
380 continue
379 continue
381 ui.log(b'extension', b' - running extsetup for %s\n', name)
380 ui.log(b'extension', b' - running extsetup for %s\n', name)
382 with util.timedcm('extsetup %s', name) as stats:
381 with util.timedcm('extsetup %s', name) as stats:
383 if not _runextsetup(name, ui):
382 if not _runextsetup(name, ui):
384 ui.log(
383 ui.log(
385 b'extension',
384 b'extension',
386 b' - the %s extension extsetup failed\n',
385 b' - the %s extension extsetup failed\n',
387 name,
386 name,
388 )
387 )
389 broken.add(name)
388 broken.add(name)
390 ui.log(b'extension', b' > extsetup for %s took %s\n', name, stats)
389 ui.log(b'extension', b' > extsetup for %s took %s\n', name, stats)
391 loadingtime[name] += stats.elapsed
390 loadingtime[name] += stats.elapsed
392 ui.log(b'extension', b'> all extsetup took %s\n', allextetupstats)
391 ui.log(b'extension', b'> all extsetup took %s\n', allextetupstats)
393
392
394 for name in broken:
393 for name in broken:
395 ui.log(b'extension', b' - disabling broken %s extension\n', name)
394 ui.log(b'extension', b' - disabling broken %s extension\n', name)
396 _extensions[name] = None
395 _extensions[name] = None
397
396
398 # Call aftercallbacks that were never met.
397 # Call aftercallbacks that were never met.
399 ui.log(b'extension', b'- executing remaining aftercallbacks\n')
398 ui.log(b'extension', b'- executing remaining aftercallbacks\n')
400 with util.timedcm('aftercallbacks') as stats:
399 with util.timedcm('aftercallbacks') as stats:
401 for shortname in _aftercallbacks:
400 for shortname in _aftercallbacks:
402 if shortname in _extensions:
401 if shortname in _extensions:
403 continue
402 continue
404
403
405 for fn in _aftercallbacks[shortname]:
404 for fn in _aftercallbacks[shortname]:
406 ui.log(
405 ui.log(
407 b'extension',
406 b'extension',
408 b' - extension %s not loaded, notify callbacks\n',
407 b' - extension %s not loaded, notify callbacks\n',
409 shortname,
408 shortname,
410 )
409 )
411 fn(loaded=False)
410 fn(loaded=False)
412 ui.log(b'extension', b'> remaining aftercallbacks completed in %s\n', stats)
411 ui.log(b'extension', b'> remaining aftercallbacks completed in %s\n', stats)
413
412
414 # loadall() is called multiple times and lingering _aftercallbacks
413 # loadall() is called multiple times and lingering _aftercallbacks
415 # entries could result in double execution. See issue4646.
414 # entries could result in double execution. See issue4646.
416 _aftercallbacks.clear()
415 _aftercallbacks.clear()
417
416
418 # delay importing avoids cyclic dependency (especially commands)
417 # delay importing avoids cyclic dependency (especially commands)
419 from . import (
418 from . import (
420 color,
419 color,
421 commands,
420 commands,
422 filemerge,
421 filemerge,
423 fileset,
422 fileset,
424 revset,
423 revset,
425 templatefilters,
424 templatefilters,
426 templatefuncs,
425 templatefuncs,
427 templatekw,
426 templatekw,
428 )
427 )
429
428
430 # list of (objname, loadermod, loadername) tuple:
429 # list of (objname, loadermod, loadername) tuple:
431 # - objname is the name of an object in extension module,
430 # - objname is the name of an object in extension module,
432 # from which extra information is loaded
431 # from which extra information is loaded
433 # - loadermod is the module where loader is placed
432 # - loadermod is the module where loader is placed
434 # - loadername is the name of the function,
433 # - loadername is the name of the function,
435 # which takes (ui, extensionname, extraobj) arguments
434 # which takes (ui, extensionname, extraobj) arguments
436 ui.log(b'extension', b'- loading extension registration objects\n')
435 ui.log(b'extension', b'- loading extension registration objects\n')
437 extraloaders = [
436 extraloaders = [
438 (b'cmdtable', commands, b'loadcmdtable'),
437 (b'cmdtable', commands, b'loadcmdtable'),
439 (b'colortable', color, b'loadcolortable'),
438 (b'colortable', color, b'loadcolortable'),
440 (b'filesetpredicate', fileset, b'loadpredicate'),
439 (b'filesetpredicate', fileset, b'loadpredicate'),
441 (b'internalmerge', filemerge, b'loadinternalmerge'),
440 (b'internalmerge', filemerge, b'loadinternalmerge'),
442 (b'revsetpredicate', revset, b'loadpredicate'),
441 (b'revsetpredicate', revset, b'loadpredicate'),
443 (b'templatefilter', templatefilters, b'loadfilter'),
442 (b'templatefilter', templatefilters, b'loadfilter'),
444 (b'templatefunc', templatefuncs, b'loadfunction'),
443 (b'templatefunc', templatefuncs, b'loadfunction'),
445 (b'templatekeyword', templatekw, b'loadkeyword'),
444 (b'templatekeyword', templatekw, b'loadkeyword'),
446 ]
445 ]
447 with util.timedcm('load registration objects') as stats:
446 with util.timedcm('load registration objects') as stats:
448 _loadextra(ui, newindex, extraloaders)
447 _loadextra(ui, newindex, extraloaders)
449 ui.log(
448 ui.log(
450 b'extension',
449 b'extension',
451 b'> extension registration object loading took %s\n',
450 b'> extension registration object loading took %s\n',
452 stats,
451 stats,
453 )
452 )
454
453
455 # Report per extension loading time (except reposetup)
454 # Report per extension loading time (except reposetup)
456 for name in sorted(loadingtime):
455 for name in sorted(loadingtime):
457 ui.log(
456 ui.log(
458 b'extension',
457 b'extension',
459 b'> extension %s take a total of %s to load\n',
458 b'> extension %s take a total of %s to load\n',
460 name,
459 name,
461 util.timecount(loadingtime[name]),
460 util.timecount(loadingtime[name]),
462 )
461 )
463
462
464 ui.log(b'extension', b'extension loading complete\n')
463 ui.log(b'extension', b'extension loading complete\n')
465
464
466
465
467 def _loadextra(ui, newindex, extraloaders):
466 def _loadextra(ui, newindex, extraloaders):
468 for name in _order[newindex:]:
467 for name in _order[newindex:]:
469 module = _extensions[name]
468 module = _extensions[name]
470 if not module:
469 if not module:
471 continue # loading this module failed
470 continue # loading this module failed
472
471
473 for objname, loadermod, loadername in extraloaders:
472 for objname, loadermod, loadername in extraloaders:
474 extraobj = getattr(module, objname, None)
473 extraobj = getattr(module, objname, None)
475 if extraobj is not None:
474 if extraobj is not None:
476 getattr(loadermod, loadername)(ui, name, extraobj)
475 getattr(loadermod, loadername)(ui, name, extraobj)
477
476
478
477
479 def afterloaded(extension, callback):
478 def afterloaded(extension, callback):
480 """Run the specified function after a named extension is loaded.
479 """Run the specified function after a named extension is loaded.
481
480
482 If the named extension is already loaded, the callback will be called
481 If the named extension is already loaded, the callback will be called
483 immediately.
482 immediately.
484
483
485 If the named extension never loads, the callback will be called after
484 If the named extension never loads, the callback will be called after
486 all extensions have been loaded.
485 all extensions have been loaded.
487
486
488 The callback receives the named argument ``loaded``, which is a boolean
487 The callback receives the named argument ``loaded``, which is a boolean
489 indicating whether the dependent extension actually loaded.
488 indicating whether the dependent extension actually loaded.
490 """
489 """
491
490
492 if extension in _extensions:
491 if extension in _extensions:
493 # Report loaded as False if the extension is disabled
492 # Report loaded as False if the extension is disabled
494 loaded = _extensions[extension] is not None
493 loaded = _extensions[extension] is not None
495 callback(loaded=loaded)
494 callback(loaded=loaded)
496 else:
495 else:
497 _aftercallbacks.setdefault(extension, []).append(callback)
496 _aftercallbacks.setdefault(extension, []).append(callback)
498
497
499
498
500 def populateui(ui):
499 def populateui(ui):
501 """Run extension hooks on the given ui to populate additional members,
500 """Run extension hooks on the given ui to populate additional members,
502 extend the class dynamically, etc.
501 extend the class dynamically, etc.
503
502
504 This will be called after the configuration is loaded, and/or extensions
503 This will be called after the configuration is loaded, and/or extensions
505 are loaded. In general, it's once per ui instance, but in command-server
504 are loaded. In general, it's once per ui instance, but in command-server
506 and hgweb, this may be called more than once with the same ui.
505 and hgweb, this may be called more than once with the same ui.
507 """
506 """
508 for name, mod in extensions(ui):
507 for name, mod in extensions(ui):
509 hook = getattr(mod, 'uipopulate', None)
508 hook = getattr(mod, 'uipopulate', None)
510 if not hook:
509 if not hook:
511 continue
510 continue
512 try:
511 try:
513 hook(ui)
512 hook(ui)
514 except Exception as inst:
513 except Exception as inst:
515 ui.traceback(force=True)
514 ui.traceback(force=True)
516 ui.warn(
515 ui.warn(
517 _(b'*** failed to populate ui by extension %s: %s\n')
516 _(b'*** failed to populate ui by extension %s: %s\n')
518 % (name, stringutil.forcebytestr(inst))
517 % (name, stringutil.forcebytestr(inst))
519 )
518 )
520
519
521
520
522 def bind(func, *args):
521 def bind(func, *args):
523 """Partial function application
522 """Partial function application
524
523
525 Returns a new function that is the partial application of args and kwargs
524 Returns a new function that is the partial application of args and kwargs
526 to func. For example,
525 to func. For example,
527
526
528 f(1, 2, bar=3) === bind(f, 1)(2, bar=3)"""
527 f(1, 2, bar=3) === bind(f, 1)(2, bar=3)"""
529 assert callable(func)
528 assert callable(func)
530
529
531 def closure(*a, **kw):
530 def closure(*a, **kw):
532 return func(*(args + a), **kw)
531 return func(*(args + a), **kw)
533
532
534 return closure
533 return closure
535
534
536
535
537 def _updatewrapper(wrap, origfn, unboundwrapper):
536 def _updatewrapper(wrap, origfn, unboundwrapper):
538 '''Copy and add some useful attributes to wrapper'''
537 '''Copy and add some useful attributes to wrapper'''
539 try:
538 try:
540 wrap.__name__ = origfn.__name__
539 wrap.__name__ = origfn.__name__
541 except AttributeError:
540 except AttributeError:
542 pass
541 pass
543 wrap.__module__ = getattr(origfn, '__module__')
542 wrap.__module__ = getattr(origfn, '__module__')
544 wrap.__doc__ = getattr(origfn, '__doc__')
543 wrap.__doc__ = getattr(origfn, '__doc__')
545 wrap.__dict__.update(getattr(origfn, '__dict__', {}))
544 wrap.__dict__.update(getattr(origfn, '__dict__', {}))
546 wrap._origfunc = origfn
545 wrap._origfunc = origfn
547 wrap._unboundwrapper = unboundwrapper
546 wrap._unboundwrapper = unboundwrapper
548
547
549
548
550 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
549 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
551 '''Wrap the command named `command' in table
550 '''Wrap the command named `command' in table
552
551
553 Replace command in the command table with wrapper. The wrapped command will
552 Replace command in the command table with wrapper. The wrapped command will
554 be inserted into the command table specified by the table argument.
553 be inserted into the command table specified by the table argument.
555
554
556 The wrapper will be called like
555 The wrapper will be called like
557
556
558 wrapper(orig, *args, **kwargs)
557 wrapper(orig, *args, **kwargs)
559
558
560 where orig is the original (wrapped) function, and *args, **kwargs
559 where orig is the original (wrapped) function, and *args, **kwargs
561 are the arguments passed to it.
560 are the arguments passed to it.
562
561
563 Optionally append to the command synopsis and docstring, used for help.
562 Optionally append to the command synopsis and docstring, used for help.
564 For example, if your extension wraps the ``bookmarks`` command to add the
563 For example, if your extension wraps the ``bookmarks`` command to add the
565 flags ``--remote`` and ``--all`` you might call this function like so:
564 flags ``--remote`` and ``--all`` you might call this function like so:
566
565
567 synopsis = ' [-a] [--remote]'
566 synopsis = ' [-a] [--remote]'
568 docstring = """
567 docstring = """
569
568
570 The ``remotenames`` extension adds the ``--remote`` and ``--all`` (``-a``)
569 The ``remotenames`` extension adds the ``--remote`` and ``--all`` (``-a``)
571 flags to the bookmarks command. Either flag will show the remote bookmarks
570 flags to the bookmarks command. Either flag will show the remote bookmarks
572 known to the repository; ``--remote`` will also suppress the output of the
571 known to the repository; ``--remote`` will also suppress the output of the
573 local bookmarks.
572 local bookmarks.
574 """
573 """
575
574
576 extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
575 extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
577 synopsis, docstring)
576 synopsis, docstring)
578 '''
577 '''
579 assert callable(wrapper)
578 assert callable(wrapper)
580 aliases, entry = cmdutil.findcmd(command, table)
579 aliases, entry = cmdutil.findcmd(command, table)
581 for alias, e in table.items():
580 for alias, e in table.items():
582 if e is entry:
581 if e is entry:
583 key = alias
582 key = alias
584 break
583 break
585
584
586 origfn = entry[0]
585 origfn = entry[0]
587 wrap = functools.partial(
586 wrap = functools.partial(
588 util.checksignature(wrapper), util.checksignature(origfn)
587 util.checksignature(wrapper), util.checksignature(origfn)
589 )
588 )
590 _updatewrapper(wrap, origfn, wrapper)
589 _updatewrapper(wrap, origfn, wrapper)
591 if docstring is not None:
590 if docstring is not None:
592 wrap.__doc__ += docstring
591 wrap.__doc__ += docstring
593
592
594 newentry = list(entry)
593 newentry = list(entry)
595 newentry[0] = wrap
594 newentry[0] = wrap
596 if synopsis is not None:
595 if synopsis is not None:
597 newentry[2] += synopsis
596 newentry[2] += synopsis
598 table[key] = tuple(newentry)
597 table[key] = tuple(newentry)
599 return entry
598 return entry
600
599
601
600
602 def wrapfilecache(cls, propname, wrapper):
601 def wrapfilecache(cls, propname, wrapper):
603 """Wraps a filecache property.
602 """Wraps a filecache property.
604
603
605 These can't be wrapped using the normal wrapfunction.
604 These can't be wrapped using the normal wrapfunction.
606 """
605 """
607 propname = pycompat.sysstr(propname)
606 propname = pycompat.sysstr(propname)
608 assert callable(wrapper)
607 assert callable(wrapper)
609 for currcls in cls.__mro__:
608 for currcls in cls.__mro__:
610 if propname in currcls.__dict__:
609 if propname in currcls.__dict__:
611 origfn = currcls.__dict__[propname].func
610 origfn = currcls.__dict__[propname].func
612 assert callable(origfn)
611 assert callable(origfn)
613
612
614 def wrap(*args, **kwargs):
613 def wrap(*args, **kwargs):
615 return wrapper(origfn, *args, **kwargs)
614 return wrapper(origfn, *args, **kwargs)
616
615
617 currcls.__dict__[propname].func = wrap
616 currcls.__dict__[propname].func = wrap
618 break
617 break
619
618
620 if currcls is object:
619 if currcls is object:
621 raise AttributeError("type '%s' has no property '%s'" % (cls, propname))
620 raise AttributeError("type '%s' has no property '%s'" % (cls, propname))
622
621
623
622
624 class wrappedfunction:
623 class wrappedfunction:
625 '''context manager for temporarily wrapping a function'''
624 '''context manager for temporarily wrapping a function'''
626
625
627 def __init__(self, container, funcname, wrapper):
626 def __init__(self, container, funcname, wrapper):
628 assert callable(wrapper)
627 assert callable(wrapper)
629 if not isinstance(funcname, str):
628 if not isinstance(funcname, str):
630 msg = b"pass wrappedfunction target name as `str`, not `bytes`"
629 msg = b"pass wrappedfunction target name as `str`, not `bytes`"
631 util.nouideprecwarn(msg, b"6.6", stacklevel=2)
630 util.nouideprecwarn(msg, b"6.6", stacklevel=2)
632 funcname = pycompat.sysstr(funcname)
631 funcname = pycompat.sysstr(funcname)
633 self._container = container
632 self._container = container
634 self._funcname = funcname
633 self._funcname = funcname
635 self._wrapper = wrapper
634 self._wrapper = wrapper
636
635
637 def __enter__(self):
636 def __enter__(self):
638 wrapfunction(self._container, self._funcname, self._wrapper)
637 wrapfunction(self._container, self._funcname, self._wrapper)
639
638
640 def __exit__(self, exctype, excvalue, traceback):
639 def __exit__(self, exctype, excvalue, traceback):
641 unwrapfunction(self._container, self._funcname, self._wrapper)
640 unwrapfunction(self._container, self._funcname, self._wrapper)
642
641
643
642
644 def wrapfunction(container, funcname, wrapper):
643 def wrapfunction(container, funcname, wrapper):
645 """Wrap the function named funcname in container
644 """Wrap the function named funcname in container
646
645
647 Replace the funcname member in the given container with the specified
646 Replace the funcname member in the given container with the specified
648 wrapper. The container is typically a module, class, or instance.
647 wrapper. The container is typically a module, class, or instance.
649
648
650 The wrapper will be called like
649 The wrapper will be called like
651
650
652 wrapper(orig, *args, **kwargs)
651 wrapper(orig, *args, **kwargs)
653
652
654 where orig is the original (wrapped) function, and *args, **kwargs
653 where orig is the original (wrapped) function, and *args, **kwargs
655 are the arguments passed to it.
654 are the arguments passed to it.
656
655
657 Wrapping methods of the repository object is not recommended since
656 Wrapping methods of the repository object is not recommended since
658 it conflicts with extensions that extend the repository by
657 it conflicts with extensions that extend the repository by
659 subclassing. All extensions that need to extend methods of
658 subclassing. All extensions that need to extend methods of
660 localrepository should use this subclassing trick: namely,
659 localrepository should use this subclassing trick: namely,
661 reposetup() should look like
660 reposetup() should look like
662
661
663 def reposetup(ui, repo):
662 def reposetup(ui, repo):
664 class myrepo(repo.__class__):
663 class myrepo(repo.__class__):
665 def whatever(self, *args, **kwargs):
664 def whatever(self, *args, **kwargs):
666 [...extension stuff...]
665 [...extension stuff...]
667 super(myrepo, self).whatever(*args, **kwargs)
666 super(myrepo, self).whatever(*args, **kwargs)
668 [...extension stuff...]
667 [...extension stuff...]
669
668
670 repo.__class__ = myrepo
669 repo.__class__ = myrepo
671
670
672 In general, combining wrapfunction() with subclassing does not
671 In general, combining wrapfunction() with subclassing does not
673 work. Since you cannot control what other extensions are loaded by
672 work. Since you cannot control what other extensions are loaded by
674 your end users, you should play nicely with others by using the
673 your end users, you should play nicely with others by using the
675 subclass trick.
674 subclass trick.
676 """
675 """
677 assert callable(wrapper)
676 assert callable(wrapper)
678
677
679 if not isinstance(funcname, str):
678 if not isinstance(funcname, str):
680 msg = b"pass wrapfunction target name as `str`, not `bytes`"
679 msg = b"pass wrapfunction target name as `str`, not `bytes`"
681 util.nouideprecwarn(msg, b"6.6", stacklevel=2)
680 util.nouideprecwarn(msg, b"6.6", stacklevel=2)
682 funcname = pycompat.sysstr(funcname)
681 funcname = pycompat.sysstr(funcname)
683
682
684 origfn = getattr(container, funcname)
683 origfn = getattr(container, funcname)
685 assert callable(origfn)
684 assert callable(origfn)
686 if inspect.ismodule(container):
685 if inspect.ismodule(container):
687 # origfn is not an instance or class method. "partial" can be used.
686 # origfn is not an instance or class method. "partial" can be used.
688 # "partial" won't insert a frame in traceback.
687 # "partial" won't insert a frame in traceback.
689 wrap = functools.partial(wrapper, origfn)
688 wrap = functools.partial(wrapper, origfn)
690 else:
689 else:
691 # "partial" cannot be safely used. Emulate its effect by using "bind".
690 # "partial" cannot be safely used. Emulate its effect by using "bind".
692 # The downside is one more frame in traceback.
691 # The downside is one more frame in traceback.
693 wrap = bind(wrapper, origfn)
692 wrap = bind(wrapper, origfn)
694 _updatewrapper(wrap, origfn, wrapper)
693 _updatewrapper(wrap, origfn, wrapper)
695 setattr(container, funcname, wrap)
694 setattr(container, funcname, wrap)
696 return origfn
695 return origfn
697
696
698
697
699 def unwrapfunction(container, funcname, wrapper=None):
698 def unwrapfunction(container, funcname, wrapper=None):
700 """undo wrapfunction
699 """undo wrapfunction
701
700
702 If wrappers is None, undo the last wrap. Otherwise removes the wrapper
701 If wrappers is None, undo the last wrap. Otherwise removes the wrapper
703 from the chain of wrappers.
702 from the chain of wrappers.
704
703
705 Return the removed wrapper.
704 Return the removed wrapper.
706 Raise IndexError if wrapper is None and nothing to unwrap; ValueError if
705 Raise IndexError if wrapper is None and nothing to unwrap; ValueError if
707 wrapper is not None but is not found in the wrapper chain.
706 wrapper is not None but is not found in the wrapper chain.
708 """
707 """
709 chain = getwrapperchain(container, funcname)
708 chain = getwrapperchain(container, funcname)
710 origfn = chain.pop()
709 origfn = chain.pop()
711 if wrapper is None:
710 if wrapper is None:
712 wrapper = chain[0]
711 wrapper = chain[0]
713 chain.remove(wrapper)
712 chain.remove(wrapper)
714 setattr(container, funcname, origfn)
713 setattr(container, funcname, origfn)
715 for w in reversed(chain):
714 for w in reversed(chain):
716 wrapfunction(container, funcname, w)
715 wrapfunction(container, funcname, w)
717 return wrapper
716 return wrapper
718
717
719
718
720 def getwrapperchain(container, funcname):
719 def getwrapperchain(container, funcname):
721 """get a chain of wrappers of a function
720 """get a chain of wrappers of a function
722
721
723 Return a list of functions: [newest wrapper, ..., oldest wrapper, origfunc]
722 Return a list of functions: [newest wrapper, ..., oldest wrapper, origfunc]
724
723
725 The wrapper functions are the ones passed to wrapfunction, whose first
724 The wrapper functions are the ones passed to wrapfunction, whose first
726 argument is origfunc.
725 argument is origfunc.
727 """
726 """
728 result = []
727 result = []
729 fn = getattr(container, funcname)
728 fn = getattr(container, funcname)
730 while fn:
729 while fn:
731 assert callable(fn)
730 assert callable(fn)
732 result.append(getattr(fn, '_unboundwrapper', fn))
731 result.append(getattr(fn, '_unboundwrapper', fn))
733 fn = getattr(fn, '_origfunc', None)
732 fn = getattr(fn, '_origfunc', None)
734 return result
733 return result
735
734
736
735
737 def _disabledpaths():
736 def _disabledpaths():
738 '''find paths of disabled extensions. returns a dict of {name: path}'''
737 '''find paths of disabled extensions. returns a dict of {name: path}'''
739 import hgext
738 import hgext
740
739
741 exts = {}
740 exts = {}
742
741
743 # The hgext might not have a __file__ attribute (e.g. in PyOxidizer) and
742 # The hgext might not have a __file__ attribute (e.g. in PyOxidizer) and
744 # it might not be on a filesystem even if it does.
743 # it might not be on a filesystem even if it does.
745 if util.safehasattr(hgext, '__file__'):
744 if util.safehasattr(hgext, '__file__'):
746 extpath = os.path.dirname(
745 extpath = os.path.dirname(
747 util.abspath(pycompat.fsencode(hgext.__file__))
746 util.abspath(pycompat.fsencode(hgext.__file__))
748 )
747 )
749 try:
748 try:
750 files = os.listdir(extpath)
749 files = os.listdir(extpath)
751 except OSError:
750 except OSError:
752 pass
751 pass
753 else:
752 else:
754 for e in files:
753 for e in files:
755 if e.endswith(b'.py'):
754 if e.endswith(b'.py'):
756 name = e.rsplit(b'.', 1)[0]
755 name = e.rsplit(b'.', 1)[0]
757 path = os.path.join(extpath, e)
756 path = os.path.join(extpath, e)
758 else:
757 else:
759 name = e
758 name = e
760 path = os.path.join(extpath, e, b'__init__.py')
759 path = os.path.join(extpath, e, b'__init__.py')
761 if not os.path.exists(path):
760 if not os.path.exists(path):
762 continue
761 continue
763 if name in exts or name in _order or name == b'__init__':
762 if name in exts or name in _order or name == b'__init__':
764 continue
763 continue
765 exts[name] = path
764 exts[name] = path
766
765
767 for name, path in _disabledextensions.items():
766 for name, path in _disabledextensions.items():
768 # If no path was provided for a disabled extension (e.g. "color=!"),
767 # If no path was provided for a disabled extension (e.g. "color=!"),
769 # don't replace the path we already found by the scan above.
768 # don't replace the path we already found by the scan above.
770 if path:
769 if path:
771 exts[name] = path
770 exts[name] = path
772 return exts
771 return exts
773
772
774
773
775 def _moduledoc(file):
774 def _moduledoc(file):
776 """return the top-level python documentation for the given file
775 """return the top-level python documentation for the given file
777
776
778 Loosely inspired by pydoc.source_synopsis(), but rewritten to
777 Loosely inspired by pydoc.source_synopsis(), but rewritten to
779 handle triple quotes and to return the whole text instead of just
778 handle triple quotes and to return the whole text instead of just
780 the synopsis"""
779 the synopsis"""
781 result = []
780 result = []
782
781
783 line = file.readline()
782 line = file.readline()
784 while line[:1] == b'#' or not line.strip():
783 while line[:1] == b'#' or not line.strip():
785 line = file.readline()
784 line = file.readline()
786 if not line:
785 if not line:
787 break
786 break
788
787
789 start = line[:3]
788 start = line[:3]
790 if start == b'"""' or start == b"'''":
789 if start == b'"""' or start == b"'''":
791 line = line[3:]
790 line = line[3:]
792 while line:
791 while line:
793 if line.rstrip().endswith(start):
792 if line.rstrip().endswith(start):
794 line = line.split(start)[0]
793 line = line.split(start)[0]
795 if line:
794 if line:
796 result.append(line)
795 result.append(line)
797 break
796 break
798 elif not line:
797 elif not line:
799 return None # unmatched delimiter
798 return None # unmatched delimiter
800 result.append(line)
799 result.append(line)
801 line = file.readline()
800 line = file.readline()
802 else:
801 else:
803 return None
802 return None
804
803
805 return b''.join(result)
804 return b''.join(result)
806
805
807
806
808 def _disabledhelp(path):
807 def _disabledhelp(path):
809 '''retrieve help synopsis of a disabled extension (without importing)'''
808 '''retrieve help synopsis of a disabled extension (without importing)'''
810 try:
809 try:
811 with open(path, b'rb') as src:
810 with open(path, b'rb') as src:
812 doc = _moduledoc(src)
811 doc = _moduledoc(src)
813 except IOError:
812 except IOError:
814 return
813 return
815
814
816 if doc: # extracting localized synopsis
815 if doc: # extracting localized synopsis
817 return gettext(doc)
816 return gettext(doc)
818 else:
817 else:
819 return _(b'(no help text available)')
818 return _(b'(no help text available)')
820
819
821
820
822 def disabled():
821 def disabled():
823 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
822 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
824 try:
823 try:
825 from hgext import __index__ # pytype: disable=import-error
824 from hgext import __index__ # pytype: disable=import-error
826
825
827 return {
826 return {
828 name: gettext(desc)
827 name: gettext(desc)
829 for name, desc in __index__.docs.items()
828 for name, desc in __index__.docs.items()
830 if name not in _order
829 if name not in _order
831 }
830 }
832 except (ImportError, AttributeError):
831 except (ImportError, AttributeError):
833 pass
832 pass
834
833
835 paths = _disabledpaths()
834 paths = _disabledpaths()
836 if not paths:
835 if not paths:
837 return {}
836 return {}
838
837
839 exts = {}
838 exts = {}
840 for name, path in paths.items():
839 for name, path in paths.items():
841 doc = _disabledhelp(path)
840 doc = _disabledhelp(path)
842 if doc and name != b'__index__':
841 if doc and name != b'__index__':
843 exts[name] = stringutil.firstline(doc)
842 exts[name] = stringutil.firstline(doc)
844
843
845 return exts
844 return exts
846
845
847
846
848 def disabled_help(name):
847 def disabled_help(name):
849 """Obtain the full help text for a disabled extension, or None."""
848 """Obtain the full help text for a disabled extension, or None."""
850 paths = _disabledpaths()
849 paths = _disabledpaths()
851 if name in paths:
850 if name in paths:
852 return _disabledhelp(paths[name])
851 return _disabledhelp(paths[name])
853 else:
852 else:
854 try:
853 try:
855 import hgext
854 import hgext
856 from hgext import __index__ # pytype: disable=import-error
855 from hgext import __index__ # pytype: disable=import-error
857
856
858 # The extensions are filesystem based, so either an error occurred
857 # The extensions are filesystem based, so either an error occurred
859 # or all are enabled.
858 # or all are enabled.
860 if util.safehasattr(hgext, '__file__'):
859 if util.safehasattr(hgext, '__file__'):
861 return
860 return
862
861
863 if name in _order: # enabled
862 if name in _order: # enabled
864 return
863 return
865 else:
864 else:
866 return gettext(__index__.docs.get(name))
865 return gettext(__index__.docs.get(name))
867 except (ImportError, AttributeError):
866 except (ImportError, AttributeError):
868 pass
867 pass
869
868
870
869
871 def _walkcommand(node):
870 def _walkcommand(node):
872 """Scan @command() decorators in the tree starting at node"""
871 """Scan @command() decorators in the tree starting at node"""
873 todo = collections.deque([node])
872 todo = collections.deque([node])
874 while todo:
873 while todo:
875 node = todo.popleft()
874 node = todo.popleft()
876 if not isinstance(node, ast.FunctionDef):
875 if not isinstance(node, ast.FunctionDef):
877 todo.extend(ast.iter_child_nodes(node))
876 todo.extend(ast.iter_child_nodes(node))
878 continue
877 continue
879 for d in node.decorator_list:
878 for d in node.decorator_list:
880 if not isinstance(d, ast.Call):
879 if not isinstance(d, ast.Call):
881 continue
880 continue
882 if not isinstance(d.func, ast.Name):
881 if not isinstance(d.func, ast.Name):
883 continue
882 continue
884 if d.func.id != 'command':
883 if d.func.id != 'command':
885 continue
884 continue
886 yield d
885 yield d
887
886
888
887
889 def _disabledcmdtable(path):
888 def _disabledcmdtable(path):
890 """Construct a dummy command table without loading the extension module
889 """Construct a dummy command table without loading the extension module
891
890
892 This may raise IOError or SyntaxError.
891 This may raise IOError or SyntaxError.
893 """
892 """
894 with open(path, b'rb') as src:
893 with open(path, b'rb') as src:
895 root = ast.parse(src.read(), path)
894 root = ast.parse(src.read(), path)
896 cmdtable = {}
895 cmdtable = {}
896
897 # Python 3.12 started removing Bytes and Str and deprecate harder
898 use_constant = 'Bytes' not in vars(ast)
899
897 for node in _walkcommand(root):
900 for node in _walkcommand(root):
898 if not node.args:
901 if not node.args:
899 continue
902 continue
900 a = node.args[0]
903 a = node.args[0]
901 if isinstance(a, ast.Str):
904 if use_constant: # Valid since Python 3.8
902 name = pycompat.sysbytes(a.s)
905 if isinstance(a, ast.Constant):
903 elif isinstance(a, ast.Bytes):
906 if isinstance(a.value, str):
904 name = a.s
907 name = pycompat.sysbytes(a.value)
905 else:
908 elif isinstance(a.value, bytes):
906 continue
909 name = a.value
910 else:
911 continue
912 else:
913 continue
914 else: # Valid until 3.11
915 if isinstance(a, ast.Str):
916 name = pycompat.sysbytes(a.s)
917 elif isinstance(a, ast.Bytes):
918 name = a.s
919 else:
920 continue
907 cmdtable[name] = (None, [], b'')
921 cmdtable[name] = (None, [], b'')
908 return cmdtable
922 return cmdtable
909
923
910
924
911 def _finddisabledcmd(ui, cmd, name, path, strict):
925 def _finddisabledcmd(ui, cmd, name, path, strict):
912 try:
926 try:
913 cmdtable = _disabledcmdtable(path)
927 cmdtable = _disabledcmdtable(path)
914 except (IOError, SyntaxError):
928 except (IOError, SyntaxError):
915 return
929 return
916 try:
930 try:
917 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
931 aliases, entry = cmdutil.findcmd(cmd, cmdtable, strict)
918 except (error.AmbiguousCommand, error.UnknownCommand):
932 except (error.AmbiguousCommand, error.UnknownCommand):
919 return
933 return
920 for c in aliases:
934 for c in aliases:
921 if c.startswith(cmd):
935 if c.startswith(cmd):
922 cmd = c
936 cmd = c
923 break
937 break
924 else:
938 else:
925 cmd = aliases[0]
939 cmd = aliases[0]
926 doc = _disabledhelp(path)
940 doc = _disabledhelp(path)
927 return (cmd, name, doc)
941 return (cmd, name, doc)
928
942
929
943
930 def disabledcmd(ui, cmd, strict=False):
944 def disabledcmd(ui, cmd, strict=False):
931 """find cmd from disabled extensions without importing.
945 """find cmd from disabled extensions without importing.
932 returns (cmdname, extname, doc)"""
946 returns (cmdname, extname, doc)"""
933
947
934 paths = _disabledpaths()
948 paths = _disabledpaths()
935 if not paths:
949 if not paths:
936 raise error.UnknownCommand(cmd)
950 raise error.UnknownCommand(cmd)
937
951
938 ext = None
952 ext = None
939 # first, search for an extension with the same name as the command
953 # first, search for an extension with the same name as the command
940 path = paths.pop(cmd, None)
954 path = paths.pop(cmd, None)
941 if path:
955 if path:
942 ext = _finddisabledcmd(ui, cmd, cmd, path, strict=strict)
956 ext = _finddisabledcmd(ui, cmd, cmd, path, strict=strict)
943 if not ext:
957 if not ext:
944 # otherwise, interrogate each extension until there's a match
958 # otherwise, interrogate each extension until there's a match
945 for name, path in paths.items():
959 for name, path in paths.items():
946 ext = _finddisabledcmd(ui, cmd, name, path, strict=strict)
960 ext = _finddisabledcmd(ui, cmd, name, path, strict=strict)
947 if ext:
961 if ext:
948 break
962 break
949 if ext:
963 if ext:
950 return ext
964 return ext
951
965
952 raise error.UnknownCommand(cmd)
966 raise error.UnknownCommand(cmd)
953
967
954
968
955 def enabled(shortname=True):
969 def enabled(shortname=True):
956 '''return a dict of {name: desc} of extensions'''
970 '''return a dict of {name: desc} of extensions'''
957 exts = {}
971 exts = {}
958 for ename, ext in extensions():
972 for ename, ext in extensions():
959 doc = gettext(ext.__doc__) or _(b'(no help text available)')
973 doc = gettext(ext.__doc__) or _(b'(no help text available)')
960 assert doc is not None # help pytype
974 assert doc is not None # help pytype
961 if shortname:
975 if shortname:
962 ename = ename.split(b'.')[-1]
976 ename = ename.split(b'.')[-1]
963 exts[ename] = stringutil.firstline(doc).strip()
977 exts[ename] = stringutil.firstline(doc).strip()
964
978
965 return exts
979 return exts
966
980
967
981
968 def notloaded():
982 def notloaded():
969 '''return short names of extensions that failed to load'''
983 '''return short names of extensions that failed to load'''
970 return [name for name, mod in _extensions.items() if mod is None]
984 return [name for name, mod in _extensions.items() if mod is None]
971
985
972
986
973 def moduleversion(module):
987 def moduleversion(module):
974 '''return version information from given module as a string'''
988 '''return version information from given module as a string'''
975 if util.safehasattr(module, b'getversion') and callable(module.getversion):
989 if util.safehasattr(module, b'getversion') and callable(module.getversion):
976 try:
990 try:
977 version = module.getversion()
991 version = module.getversion()
978 except Exception:
992 except Exception:
979 version = b'unknown'
993 version = b'unknown'
980
994
981 elif util.safehasattr(module, b'__version__'):
995 elif util.safehasattr(module, b'__version__'):
982 version = module.__version__
996 version = module.__version__
983 else:
997 else:
984 version = b''
998 version = b''
985 if isinstance(version, (list, tuple)):
999 if isinstance(version, (list, tuple)):
986 version = b'.'.join(pycompat.bytestr(o) for o in version)
1000 version = b'.'.join(pycompat.bytestr(o) for o in version)
987 else:
1001 else:
988 # version data should be bytes, but not all extensions are ported
1002 # version data should be bytes, but not all extensions are ported
989 # to py3.
1003 # to py3.
990 version = stringutil.forcebytestr(version)
1004 version = stringutil.forcebytestr(version)
991 return version
1005 return version
992
1006
993
1007
994 def ismoduleinternal(module):
1008 def ismoduleinternal(module):
995 exttestedwith = getattr(module, 'testedwith', None)
1009 exttestedwith = getattr(module, 'testedwith', None)
996 return exttestedwith == b"ships-with-hg-core"
1010 return exttestedwith == b"ships-with-hg-core"
@@ -1,486 +1,488 b''
1 # repoview.py - Filtered view of a localrepo object
1 # repoview.py - Filtered view of a localrepo object
2 #
2 #
3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
4 # Logilab SA <contact@logilab.fr>
4 # Logilab SA <contact@logilab.fr>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9
9
10 import copy
10 import copy
11 import weakref
11 import weakref
12
12
13 from .i18n import _
13 from .i18n import _
14 from .node import (
14 from .node import (
15 hex,
15 hex,
16 nullrev,
16 nullrev,
17 )
17 )
18 from .pycompat import (
18 from .pycompat import (
19 delattr,
19 delattr,
20 getattr,
20 getattr,
21 setattr,
21 setattr,
22 )
22 )
23 from . import (
23 from . import (
24 error,
24 error,
25 obsolete,
25 obsolete,
26 phases,
26 phases,
27 pycompat,
27 pycompat,
28 tags as tagsmod,
28 tags as tagsmod,
29 util,
29 util,
30 )
30 )
31 from .utils import repoviewutil
31 from .utils import repoviewutil
32
32
33
33
34 def hideablerevs(repo):
34 def hideablerevs(repo):
35 """Revision candidates to be hidden
35 """Revision candidates to be hidden
36
36
37 This is a standalone function to allow extensions to wrap it.
37 This is a standalone function to allow extensions to wrap it.
38
38
39 Because we use the set of immutable changesets as a fallback subset in
39 Because we use the set of immutable changesets as a fallback subset in
40 branchmap (see mercurial.utils.repoviewutils.subsettable), you cannot set
40 branchmap (see mercurial.utils.repoviewutils.subsettable), you cannot set
41 "public" changesets as "hideable". Doing so would break multiple code
41 "public" changesets as "hideable". Doing so would break multiple code
42 assertions and lead to crashes."""
42 assertions and lead to crashes."""
43 obsoletes = obsolete.getrevs(repo, b'obsolete')
43 obsoletes = obsolete.getrevs(repo, b'obsolete')
44 internals = repo._phasecache.getrevset(repo, phases.localhiddenphases)
44 internals = repo._phasecache.getrevset(repo, phases.localhiddenphases)
45 internals = frozenset(internals)
45 internals = frozenset(internals)
46 return obsoletes | internals
46 return obsoletes | internals
47
47
48
48
49 def pinnedrevs(repo):
49 def pinnedrevs(repo):
50 """revisions blocking hidden changesets from being filtered"""
50 """revisions blocking hidden changesets from being filtered"""
51
51
52 cl = repo.changelog
52 cl = repo.changelog
53 pinned = set()
53 pinned = set()
54 pinned.update([par.rev() for par in repo[None].parents()])
54 pinned.update([par.rev() for par in repo[None].parents()])
55 pinned.update([cl.rev(bm) for bm in repo._bookmarks.values()])
55 pinned.update([cl.rev(bm) for bm in repo._bookmarks.values()])
56
56
57 tags = {}
57 tags = {}
58 tagsmod.readlocaltags(repo.ui, repo, tags, {})
58 tagsmod.readlocaltags(repo.ui, repo, tags, {})
59 if tags:
59 if tags:
60 rev = cl.index.get_rev
60 rev = cl.index.get_rev
61 pinned.update(rev(t[0]) for t in tags.values())
61 pinned.update(rev(t[0]) for t in tags.values())
62 pinned.discard(None)
62 pinned.discard(None)
63
63
64 # Avoid cycle: mercurial.filemerge -> mercurial.templater ->
64 # Avoid cycle: mercurial.filemerge -> mercurial.templater ->
65 # mercurial.templatefuncs -> mercurial.revset -> mercurial.repoview ->
65 # mercurial.templatefuncs -> mercurial.revset -> mercurial.repoview ->
66 # mercurial.mergestate -> mercurial.filemerge
66 # mercurial.mergestate -> mercurial.filemerge
67 from . import mergestate
67 from . import mergestate
68
68
69 ms = mergestate.mergestate.read(repo)
69 ms = mergestate.mergestate.read(repo)
70 if ms.active() and ms.unresolvedcount():
70 if ms.active() and ms.unresolvedcount():
71 for node in (ms.local, ms.other):
71 for node in (ms.local, ms.other):
72 rev = cl.index.get_rev(node)
72 rev = cl.index.get_rev(node)
73 if rev is not None:
73 if rev is not None:
74 pinned.add(rev)
74 pinned.add(rev)
75
75
76 return pinned
76 return pinned
77
77
78
78
79 def _revealancestors(pfunc, hidden, revs):
79 def _revealancestors(pfunc, hidden, revs):
80 """reveals contiguous chains of hidden ancestors of 'revs' by removing them
80 """reveals contiguous chains of hidden ancestors of 'revs' by removing them
81 from 'hidden'
81 from 'hidden'
82
82
83 - pfunc(r): a funtion returning parent of 'r',
83 - pfunc(r): a funtion returning parent of 'r',
84 - hidden: the (preliminary) hidden revisions, to be updated
84 - hidden: the (preliminary) hidden revisions, to be updated
85 - revs: iterable of revnum,
85 - revs: iterable of revnum,
86
86
87 (Ancestors are revealed exclusively, i.e. the elements in 'revs' are
87 (Ancestors are revealed exclusively, i.e. the elements in 'revs' are
88 *not* revealed)
88 *not* revealed)
89 """
89 """
90 stack = list(revs)
90 stack = list(revs)
91 while stack:
91 while stack:
92 for p in pfunc(stack.pop()):
92 for p in pfunc(stack.pop()):
93 if p != nullrev and p in hidden:
93 if p != nullrev and p in hidden:
94 hidden.remove(p)
94 hidden.remove(p)
95 stack.append(p)
95 stack.append(p)
96
96
97
97
98 def computehidden(repo, visibilityexceptions=None):
98 def computehidden(repo, visibilityexceptions=None):
99 """compute the set of hidden revision to filter
99 """compute the set of hidden revision to filter
100
100
101 During most operation hidden should be filtered."""
101 During most operation hidden should be filtered."""
102 assert not repo.changelog.filteredrevs
102 assert not repo.changelog.filteredrevs
103
103
104 hidden = hideablerevs(repo)
104 hidden = hideablerevs(repo)
105 if hidden:
105 if hidden:
106 hidden = set(hidden - pinnedrevs(repo))
106 hidden = set(hidden - pinnedrevs(repo))
107 if visibilityexceptions:
107 if visibilityexceptions:
108 hidden -= visibilityexceptions
108 hidden -= visibilityexceptions
109 pfunc = repo.changelog.parentrevs
109 pfunc = repo.changelog.parentrevs
110 mutable = repo._phasecache.getrevset(repo, phases.mutablephases)
110 mutable = repo._phasecache.getrevset(repo, phases.mutablephases)
111
111
112 visible = mutable - hidden
112 visible = mutable - hidden
113 _revealancestors(pfunc, hidden, visible)
113 _revealancestors(pfunc, hidden, visible)
114 return frozenset(hidden)
114 return frozenset(hidden)
115
115
116
116
117 def computesecret(repo, visibilityexceptions=None):
117 def computesecret(repo, visibilityexceptions=None):
118 """compute the set of revision that can never be exposed through hgweb
118 """compute the set of revision that can never be exposed through hgweb
119
119
120 Changeset in the secret phase (or above) should stay unaccessible."""
120 Changeset in the secret phase (or above) should stay unaccessible."""
121 assert not repo.changelog.filteredrevs
121 assert not repo.changelog.filteredrevs
122 secrets = repo._phasecache.getrevset(repo, phases.remotehiddenphases)
122 secrets = repo._phasecache.getrevset(repo, phases.remotehiddenphases)
123 return frozenset(secrets)
123 return frozenset(secrets)
124
124
125
125
126 def computeunserved(repo, visibilityexceptions=None):
126 def computeunserved(repo, visibilityexceptions=None):
127 """compute the set of revision that should be filtered when used a server
127 """compute the set of revision that should be filtered when used a server
128
128
129 Secret and hidden changeset should not pretend to be here."""
129 Secret and hidden changeset should not pretend to be here."""
130 assert not repo.changelog.filteredrevs
130 assert not repo.changelog.filteredrevs
131 # fast path in simple case to avoid impact of non optimised code
131 # fast path in simple case to avoid impact of non optimised code
132 hiddens = filterrevs(repo, b'visible')
132 hiddens = filterrevs(repo, b'visible')
133 secrets = filterrevs(repo, b'served.hidden')
133 secrets = filterrevs(repo, b'served.hidden')
134 if secrets:
134 if secrets:
135 return frozenset(hiddens | secrets)
135 return frozenset(hiddens | secrets)
136 else:
136 else:
137 return hiddens
137 return hiddens
138
138
139
139
140 def computemutable(repo, visibilityexceptions=None):
140 def computemutable(repo, visibilityexceptions=None):
141 assert not repo.changelog.filteredrevs
141 assert not repo.changelog.filteredrevs
142 # fast check to avoid revset call on huge repo
142 # fast check to avoid revset call on huge repo
143 if repo._phasecache.hasnonpublicphases(repo):
143 if repo._phasecache.hasnonpublicphases(repo):
144 return frozenset(repo._phasecache.getrevset(repo, phases.mutablephases))
144 return frozenset(repo._phasecache.getrevset(repo, phases.mutablephases))
145 return frozenset()
145 return frozenset()
146
146
147
147
148 def computeimpactable(repo, visibilityexceptions=None):
148 def computeimpactable(repo, visibilityexceptions=None):
149 """Everything impactable by mutable revision
149 """Everything impactable by mutable revision
150
150
151 The immutable filter still have some chance to get invalidated. This will
151 The immutable filter still have some chance to get invalidated. This will
152 happen when:
152 happen when:
153
153
154 - you garbage collect hidden changeset,
154 - you garbage collect hidden changeset,
155 - public phase is moved backward,
155 - public phase is moved backward,
156 - something is changed in the filtering (this could be fixed)
156 - something is changed in the filtering (this could be fixed)
157
157
158 This filter out any mutable changeset and any public changeset that may be
158 This filter out any mutable changeset and any public changeset that may be
159 impacted by something happening to a mutable revision.
159 impacted by something happening to a mutable revision.
160
160
161 This is achieved by filtered everything with a revision number equal or
161 This is achieved by filtered everything with a revision number equal or
162 higher than the first mutable changeset is filtered."""
162 higher than the first mutable changeset is filtered."""
163 assert not repo.changelog.filteredrevs
163 assert not repo.changelog.filteredrevs
164 cl = repo.changelog
164 cl = repo.changelog
165 firstmutable = len(cl)
165 firstmutable = len(cl)
166 roots = repo._phasecache.nonpublicphaseroots(repo)
166 roots = repo._phasecache.nonpublicphaseroots(repo)
167 if roots:
167 if roots:
168 firstmutable = min(firstmutable, min(cl.rev(r) for r in roots))
168 firstmutable = min(firstmutable, min(cl.rev(r) for r in roots))
169 # protect from nullrev root
169 # protect from nullrev root
170 firstmutable = max(0, firstmutable)
170 firstmutable = max(0, firstmutable)
171 return frozenset(range(firstmutable, len(cl)))
171 return frozenset(range(firstmutable, len(cl)))
172
172
173
173
174 # function to compute filtered set
174 # function to compute filtered set
175 #
175 #
176 # When adding a new filter you MUST update the table at:
176 # When adding a new filter you MUST update the table at:
177 # mercurial.utils.repoviewutil.subsettable
177 # mercurial.utils.repoviewutil.subsettable
178 # Otherwise your filter will have to recompute all its branches cache
178 # Otherwise your filter will have to recompute all its branches cache
179 # from scratch (very slow).
179 # from scratch (very slow).
180 filtertable = {
180 filtertable = {
181 b'visible': computehidden,
181 b'visible': computehidden,
182 b'visible-hidden': computehidden,
182 b'visible-hidden': computehidden,
183 b'served.hidden': computesecret,
183 b'served.hidden': computesecret,
184 b'served': computeunserved,
184 b'served': computeunserved,
185 b'immutable': computemutable,
185 b'immutable': computemutable,
186 b'base': computeimpactable,
186 b'base': computeimpactable,
187 }
187 }
188
188
189 # set of filter level that will include the working copy parent no matter what.
189 # set of filter level that will include the working copy parent no matter what.
190 filter_has_wc = {b'visible', b'visible-hidden'}
190 filter_has_wc = {b'visible', b'visible-hidden'}
191
191
192 _basefiltername = list(filtertable)
192 _basefiltername = list(filtertable)
193
193
194
194
195 def extrafilter(ui):
195 def extrafilter(ui):
196 """initialize extra filter and return its id
196 """initialize extra filter and return its id
197
197
198 If extra filtering is configured, we make sure the associated filtered view
198 If extra filtering is configured, we make sure the associated filtered view
199 are declared and return the associated id.
199 are declared and return the associated id.
200 """
200 """
201 frevs = ui.config(b'experimental', b'extra-filter-revs')
201 frevs = ui.config(b'experimental', b'extra-filter-revs')
202 if frevs is None:
202 if frevs is None:
203 return None
203 return None
204
204
205 fid = pycompat.sysbytes(util.DIGESTS[b'sha1'](frevs).hexdigest())[:12]
205 fid = pycompat.sysbytes(util.DIGESTS[b'sha1'](frevs).hexdigest())[:12]
206
206
207 combine = lambda fname: fname + b'%' + fid
207 combine = lambda fname: fname + b'%' + fid
208
208
209 subsettable = repoviewutil.subsettable
209 subsettable = repoviewutil.subsettable
210
210
211 if combine(b'base') not in filtertable:
211 if combine(b'base') not in filtertable:
212 for name in _basefiltername:
212 for base_name in _basefiltername:
213
213
214 def extrafilteredrevs(repo, *args, **kwargs):
214 def extrafilteredrevs(repo, *args, name=base_name, **kwargs):
215 baserevs = filtertable[name](repo, *args, **kwargs)
215 baserevs = filtertable[name](repo, *args, **kwargs)
216 extrarevs = frozenset(repo.revs(frevs))
216 extrarevs = frozenset(repo.revs(frevs))
217 return baserevs | extrarevs
217 return baserevs | extrarevs
218
218
219 filtertable[combine(name)] = extrafilteredrevs
219 filtertable[combine(base_name)] = extrafilteredrevs
220 if name in subsettable:
220 if base_name in subsettable:
221 subsettable[combine(name)] = combine(subsettable[name])
221 subsettable[combine(base_name)] = combine(
222 subsettable[base_name]
223 )
222 return fid
224 return fid
223
225
224
226
225 def filterrevs(repo, filtername, visibilityexceptions=None):
227 def filterrevs(repo, filtername, visibilityexceptions=None):
226 """returns set of filtered revision for this filter name
228 """returns set of filtered revision for this filter name
227
229
228 visibilityexceptions is a set of revs which must are exceptions for
230 visibilityexceptions is a set of revs which must are exceptions for
229 hidden-state and must be visible. They are dynamic and hence we should not
231 hidden-state and must be visible. They are dynamic and hence we should not
230 cache it's result"""
232 cache it's result"""
231 if filtername not in repo.filteredrevcache:
233 if filtername not in repo.filteredrevcache:
232 if repo.ui.configbool(b'devel', b'debug.repo-filters'):
234 if repo.ui.configbool(b'devel', b'debug.repo-filters'):
233 msg = b'computing revision filter for "%s"'
235 msg = b'computing revision filter for "%s"'
234 msg %= filtername
236 msg %= filtername
235 if repo.ui.tracebackflag and repo.ui.debugflag:
237 if repo.ui.tracebackflag and repo.ui.debugflag:
236 # XXX use ui.write_err
238 # XXX use ui.write_err
237 util.debugstacktrace(
239 util.debugstacktrace(
238 msg,
240 msg,
239 f=repo.ui._fout,
241 f=repo.ui._fout,
240 otherf=repo.ui._ferr,
242 otherf=repo.ui._ferr,
241 prefix=b'debug.filters: ',
243 prefix=b'debug.filters: ',
242 )
244 )
243 else:
245 else:
244 repo.ui.debug(b'debug.filters: %s\n' % msg)
246 repo.ui.debug(b'debug.filters: %s\n' % msg)
245 func = filtertable[filtername]
247 func = filtertable[filtername]
246 if visibilityexceptions:
248 if visibilityexceptions:
247 return func(repo.unfiltered, visibilityexceptions)
249 return func(repo.unfiltered, visibilityexceptions)
248 repo.filteredrevcache[filtername] = func(repo.unfiltered())
250 repo.filteredrevcache[filtername] = func(repo.unfiltered())
249 return repo.filteredrevcache[filtername]
251 return repo.filteredrevcache[filtername]
250
252
251
253
252 def wrapchangelog(unfichangelog, filteredrevs):
254 def wrapchangelog(unfichangelog, filteredrevs):
253 cl = copy.copy(unfichangelog)
255 cl = copy.copy(unfichangelog)
254 cl.filteredrevs = filteredrevs
256 cl.filteredrevs = filteredrevs
255
257
256 class filteredchangelog(filteredchangelogmixin, cl.__class__):
258 class filteredchangelog(filteredchangelogmixin, cl.__class__):
257 pass
259 pass
258
260
259 cl.__class__ = filteredchangelog
261 cl.__class__ = filteredchangelog
260
262
261 return cl
263 return cl
262
264
263
265
264 class filteredchangelogmixin:
266 class filteredchangelogmixin:
265 def tiprev(self):
267 def tiprev(self):
266 """filtered version of revlog.tiprev"""
268 """filtered version of revlog.tiprev"""
267 for i in range(len(self) - 1, -2, -1):
269 for i in range(len(self) - 1, -2, -1):
268 if i not in self.filteredrevs:
270 if i not in self.filteredrevs:
269 return i
271 return i
270
272
271 def __contains__(self, rev):
273 def __contains__(self, rev):
272 """filtered version of revlog.__contains__"""
274 """filtered version of revlog.__contains__"""
273 return 0 <= rev < len(self) and rev not in self.filteredrevs
275 return 0 <= rev < len(self) and rev not in self.filteredrevs
274
276
275 def __iter__(self):
277 def __iter__(self):
276 """filtered version of revlog.__iter__"""
278 """filtered version of revlog.__iter__"""
277
279
278 def filterediter():
280 def filterediter():
279 for i in range(len(self)):
281 for i in range(len(self)):
280 if i not in self.filteredrevs:
282 if i not in self.filteredrevs:
281 yield i
283 yield i
282
284
283 return filterediter()
285 return filterediter()
284
286
285 def revs(self, start=0, stop=None):
287 def revs(self, start=0, stop=None):
286 """filtered version of revlog.revs"""
288 """filtered version of revlog.revs"""
287 for i in super(filteredchangelogmixin, self).revs(start, stop):
289 for i in super(filteredchangelogmixin, self).revs(start, stop):
288 if i not in self.filteredrevs:
290 if i not in self.filteredrevs:
289 yield i
291 yield i
290
292
291 def _checknofilteredinrevs(self, revs):
293 def _checknofilteredinrevs(self, revs):
292 """raise the appropriate error if 'revs' contains a filtered revision
294 """raise the appropriate error if 'revs' contains a filtered revision
293
295
294 This returns a version of 'revs' to be used thereafter by the caller.
296 This returns a version of 'revs' to be used thereafter by the caller.
295 In particular, if revs is an iterator, it is converted into a set.
297 In particular, if revs is an iterator, it is converted into a set.
296 """
298 """
297 safehasattr = util.safehasattr
299 safehasattr = util.safehasattr
298 if safehasattr(revs, '__next__'):
300 if safehasattr(revs, '__next__'):
299 # Note that inspect.isgenerator() is not true for iterators,
301 # Note that inspect.isgenerator() is not true for iterators,
300 revs = set(revs)
302 revs = set(revs)
301
303
302 filteredrevs = self.filteredrevs
304 filteredrevs = self.filteredrevs
303 if safehasattr(revs, 'first'): # smartset
305 if safehasattr(revs, 'first'): # smartset
304 offenders = revs & filteredrevs
306 offenders = revs & filteredrevs
305 else:
307 else:
306 offenders = filteredrevs.intersection(revs)
308 offenders = filteredrevs.intersection(revs)
307
309
308 for rev in offenders:
310 for rev in offenders:
309 raise error.FilteredIndexError(rev)
311 raise error.FilteredIndexError(rev)
310 return revs
312 return revs
311
313
312 def headrevs(self, revs=None):
314 def headrevs(self, revs=None):
313 if revs is None:
315 if revs is None:
314 try:
316 try:
315 return self.index.headrevsfiltered(self.filteredrevs)
317 return self.index.headrevsfiltered(self.filteredrevs)
316 # AttributeError covers non-c-extension environments and
318 # AttributeError covers non-c-extension environments and
317 # old c extensions without filter handling.
319 # old c extensions without filter handling.
318 except AttributeError:
320 except AttributeError:
319 return self._headrevs()
321 return self._headrevs()
320
322
321 revs = self._checknofilteredinrevs(revs)
323 revs = self._checknofilteredinrevs(revs)
322 return super(filteredchangelogmixin, self).headrevs(revs)
324 return super(filteredchangelogmixin, self).headrevs(revs)
323
325
324 def strip(self, *args, **kwargs):
326 def strip(self, *args, **kwargs):
325 # XXX make something better than assert
327 # XXX make something better than assert
326 # We can't expect proper strip behavior if we are filtered.
328 # We can't expect proper strip behavior if we are filtered.
327 assert not self.filteredrevs
329 assert not self.filteredrevs
328 super(filteredchangelogmixin, self).strip(*args, **kwargs)
330 super(filteredchangelogmixin, self).strip(*args, **kwargs)
329
331
330 def rev(self, node):
332 def rev(self, node):
331 """filtered version of revlog.rev"""
333 """filtered version of revlog.rev"""
332 r = super(filteredchangelogmixin, self).rev(node)
334 r = super(filteredchangelogmixin, self).rev(node)
333 if r in self.filteredrevs:
335 if r in self.filteredrevs:
334 raise error.FilteredLookupError(
336 raise error.FilteredLookupError(
335 hex(node), self.display_id, _(b'filtered node')
337 hex(node), self.display_id, _(b'filtered node')
336 )
338 )
337 return r
339 return r
338
340
339 def node(self, rev):
341 def node(self, rev):
340 """filtered version of revlog.node"""
342 """filtered version of revlog.node"""
341 if rev in self.filteredrevs:
343 if rev in self.filteredrevs:
342 raise error.FilteredIndexError(rev)
344 raise error.FilteredIndexError(rev)
343 return super(filteredchangelogmixin, self).node(rev)
345 return super(filteredchangelogmixin, self).node(rev)
344
346
345 def linkrev(self, rev):
347 def linkrev(self, rev):
346 """filtered version of revlog.linkrev"""
348 """filtered version of revlog.linkrev"""
347 if rev in self.filteredrevs:
349 if rev in self.filteredrevs:
348 raise error.FilteredIndexError(rev)
350 raise error.FilteredIndexError(rev)
349 return super(filteredchangelogmixin, self).linkrev(rev)
351 return super(filteredchangelogmixin, self).linkrev(rev)
350
352
351 def parentrevs(self, rev):
353 def parentrevs(self, rev):
352 """filtered version of revlog.parentrevs"""
354 """filtered version of revlog.parentrevs"""
353 if rev in self.filteredrevs:
355 if rev in self.filteredrevs:
354 raise error.FilteredIndexError(rev)
356 raise error.FilteredIndexError(rev)
355 return super(filteredchangelogmixin, self).parentrevs(rev)
357 return super(filteredchangelogmixin, self).parentrevs(rev)
356
358
357 def flags(self, rev):
359 def flags(self, rev):
358 """filtered version of revlog.flags"""
360 """filtered version of revlog.flags"""
359 if rev in self.filteredrevs:
361 if rev in self.filteredrevs:
360 raise error.FilteredIndexError(rev)
362 raise error.FilteredIndexError(rev)
361 return super(filteredchangelogmixin, self).flags(rev)
363 return super(filteredchangelogmixin, self).flags(rev)
362
364
363
365
364 class repoview:
366 class repoview:
365 """Provide a read/write view of a repo through a filtered changelog
367 """Provide a read/write view of a repo through a filtered changelog
366
368
367 This object is used to access a filtered version of a repository without
369 This object is used to access a filtered version of a repository without
368 altering the original repository object itself. We can not alter the
370 altering the original repository object itself. We can not alter the
369 original object for two main reasons:
371 original object for two main reasons:
370 - It prevents the use of a repo with multiple filters at the same time. In
372 - It prevents the use of a repo with multiple filters at the same time. In
371 particular when multiple threads are involved.
373 particular when multiple threads are involved.
372 - It makes scope of the filtering harder to control.
374 - It makes scope of the filtering harder to control.
373
375
374 This object behaves very closely to the original repository. All attribute
376 This object behaves very closely to the original repository. All attribute
375 operations are done on the original repository:
377 operations are done on the original repository:
376 - An access to `repoview.someattr` actually returns `repo.someattr`,
378 - An access to `repoview.someattr` actually returns `repo.someattr`,
377 - A write to `repoview.someattr` actually sets value of `repo.someattr`,
379 - A write to `repoview.someattr` actually sets value of `repo.someattr`,
378 - A deletion of `repoview.someattr` actually drops `someattr`
380 - A deletion of `repoview.someattr` actually drops `someattr`
379 from `repo.__dict__`.
381 from `repo.__dict__`.
380
382
381 The only exception is the `changelog` property. It is overridden to return
383 The only exception is the `changelog` property. It is overridden to return
382 a (surface) copy of `repo.changelog` with some revisions filtered. The
384 a (surface) copy of `repo.changelog` with some revisions filtered. The
383 `filtername` attribute of the view control the revisions that need to be
385 `filtername` attribute of the view control the revisions that need to be
384 filtered. (the fact the changelog is copied is an implementation detail).
386 filtered. (the fact the changelog is copied is an implementation detail).
385
387
386 Unlike attributes, this object intercepts all method calls. This means that
388 Unlike attributes, this object intercepts all method calls. This means that
387 all methods are run on the `repoview` object with the filtered `changelog`
389 all methods are run on the `repoview` object with the filtered `changelog`
388 property. For this purpose the simple `repoview` class must be mixed with
390 property. For this purpose the simple `repoview` class must be mixed with
389 the actual class of the repository. This ensures that the resulting
391 the actual class of the repository. This ensures that the resulting
390 `repoview` object have the very same methods than the repo object. This
392 `repoview` object have the very same methods than the repo object. This
391 leads to the property below.
393 leads to the property below.
392
394
393 repoview.method() --> repo.__class__.method(repoview)
395 repoview.method() --> repo.__class__.method(repoview)
394
396
395 The inheritance has to be done dynamically because `repo` can be of any
397 The inheritance has to be done dynamically because `repo` can be of any
396 subclasses of `localrepo`. Eg: `bundlerepo` or `statichttprepo`.
398 subclasses of `localrepo`. Eg: `bundlerepo` or `statichttprepo`.
397 """
399 """
398
400
399 def __init__(self, repo, filtername, visibilityexceptions=None):
401 def __init__(self, repo, filtername, visibilityexceptions=None):
400 object.__setattr__(self, '_unfilteredrepo', repo)
402 object.__setattr__(self, '_unfilteredrepo', repo)
401 object.__setattr__(self, 'filtername', filtername)
403 object.__setattr__(self, 'filtername', filtername)
402 object.__setattr__(self, '_clcachekey', None)
404 object.__setattr__(self, '_clcachekey', None)
403 object.__setattr__(self, '_clcache', None)
405 object.__setattr__(self, '_clcache', None)
404 # revs which are exceptions and must not be hidden
406 # revs which are exceptions and must not be hidden
405 object.__setattr__(self, '_visibilityexceptions', visibilityexceptions)
407 object.__setattr__(self, '_visibilityexceptions', visibilityexceptions)
406
408
407 # not a propertycache on purpose we shall implement a proper cache later
409 # not a propertycache on purpose we shall implement a proper cache later
408 @property
410 @property
409 def changelog(self):
411 def changelog(self):
410 """return a filtered version of the changeset
412 """return a filtered version of the changeset
411
413
412 this changelog must not be used for writing"""
414 this changelog must not be used for writing"""
413 # some cache may be implemented later
415 # some cache may be implemented later
414 unfi = self._unfilteredrepo
416 unfi = self._unfilteredrepo
415 unfichangelog = unfi.changelog
417 unfichangelog = unfi.changelog
416 # bypass call to changelog.method
418 # bypass call to changelog.method
417 unfiindex = unfichangelog.index
419 unfiindex = unfichangelog.index
418 unfilen = len(unfiindex)
420 unfilen = len(unfiindex)
419 unfinode = unfiindex[unfilen - 1][7]
421 unfinode = unfiindex[unfilen - 1][7]
420 with util.timedcm('repo filter for %s', self.filtername):
422 with util.timedcm('repo filter for %s', self.filtername):
421 revs = filterrevs(unfi, self.filtername, self._visibilityexceptions)
423 revs = filterrevs(unfi, self.filtername, self._visibilityexceptions)
422 cl = self._clcache
424 cl = self._clcache
423 newkey = (unfilen, unfinode, hash(revs), unfichangelog._delayed)
425 newkey = (unfilen, unfinode, hash(revs), unfichangelog._delayed)
424 # if cl.index is not unfiindex, unfi.changelog would be
426 # if cl.index is not unfiindex, unfi.changelog would be
425 # recreated, and our clcache refers to garbage object
427 # recreated, and our clcache refers to garbage object
426 if cl is not None and (
428 if cl is not None and (
427 cl.index is not unfiindex or newkey != self._clcachekey
429 cl.index is not unfiindex or newkey != self._clcachekey
428 ):
430 ):
429 cl = None
431 cl = None
430 # could have been made None by the previous if
432 # could have been made None by the previous if
431 if cl is None:
433 if cl is None:
432 # Only filter if there's something to filter
434 # Only filter if there's something to filter
433 cl = wrapchangelog(unfichangelog, revs) if revs else unfichangelog
435 cl = wrapchangelog(unfichangelog, revs) if revs else unfichangelog
434 object.__setattr__(self, '_clcache', cl)
436 object.__setattr__(self, '_clcache', cl)
435 object.__setattr__(self, '_clcachekey', newkey)
437 object.__setattr__(self, '_clcachekey', newkey)
436 return cl
438 return cl
437
439
438 def unfiltered(self):
440 def unfiltered(self):
439 """Return an unfiltered version of a repo"""
441 """Return an unfiltered version of a repo"""
440 return self._unfilteredrepo
442 return self._unfilteredrepo
441
443
442 def filtered(self, name, visibilityexceptions=None):
444 def filtered(self, name, visibilityexceptions=None):
443 """Return a filtered version of a repository"""
445 """Return a filtered version of a repository"""
444 if name == self.filtername and not visibilityexceptions:
446 if name == self.filtername and not visibilityexceptions:
445 return self
447 return self
446 return self.unfiltered().filtered(name, visibilityexceptions)
448 return self.unfiltered().filtered(name, visibilityexceptions)
447
449
448 def __repr__(self):
450 def __repr__(self):
449 return '<%s:%s %r>' % (
451 return '<%s:%s %r>' % (
450 self.__class__.__name__,
452 self.__class__.__name__,
451 pycompat.sysstr(self.filtername),
453 pycompat.sysstr(self.filtername),
452 self.unfiltered(),
454 self.unfiltered(),
453 )
455 )
454
456
455 # everything access are forwarded to the proxied repo
457 # everything access are forwarded to the proxied repo
456 def __getattr__(self, attr):
458 def __getattr__(self, attr):
457 return getattr(self._unfilteredrepo, attr)
459 return getattr(self._unfilteredrepo, attr)
458
460
459 def __setattr__(self, attr, value):
461 def __setattr__(self, attr, value):
460 return setattr(self._unfilteredrepo, attr, value)
462 return setattr(self._unfilteredrepo, attr, value)
461
463
462 def __delattr__(self, attr):
464 def __delattr__(self, attr):
463 return delattr(self._unfilteredrepo, attr)
465 return delattr(self._unfilteredrepo, attr)
464
466
465
467
466 # Dynamically created classes introduce memory cycles via __mro__. See
468 # Dynamically created classes introduce memory cycles via __mro__. See
467 # https://bugs.python.org/issue17950.
469 # https://bugs.python.org/issue17950.
468 # This need of the garbage collector can turn into memory leak in
470 # This need of the garbage collector can turn into memory leak in
469 # Python <3.4, which is the first version released with PEP 442.
471 # Python <3.4, which is the first version released with PEP 442.
470 _filteredrepotypes = weakref.WeakKeyDictionary()
472 _filteredrepotypes = weakref.WeakKeyDictionary()
471
473
472
474
473 def newtype(base):
475 def newtype(base):
474 """Create a new type with the repoview mixin and the given base class"""
476 """Create a new type with the repoview mixin and the given base class"""
475 ref = _filteredrepotypes.get(base)
477 ref = _filteredrepotypes.get(base)
476 if ref is not None:
478 if ref is not None:
477 cls = ref()
479 cls = ref()
478 if cls is not None:
480 if cls is not None:
479 return cls
481 return cls
480
482
481 class filteredrepo(repoview, base):
483 class filteredrepo(repoview, base):
482 pass
484 pass
483
485
484 _filteredrepotypes[base] = weakref.ref(filteredrepo)
486 _filteredrepotypes[base] = weakref.ref(filteredrepo)
485 # do not reread from weakref to be 100% sure not to return None
487 # do not reread from weakref to be 100% sure not to return None
486 return filteredrepo
488 return filteredrepo
@@ -1,3527 +1,3530 b''
1 # revlog.py - storage back-end for mercurial
1 # revlog.py - storage back-end for mercurial
2 # coding: utf8
2 # coding: utf8
3 #
3 #
4 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 """Storage back-end for Mercurial.
9 """Storage back-end for Mercurial.
10
10
11 This provides efficient delta storage with O(1) retrieve and append
11 This provides efficient delta storage with O(1) retrieve and append
12 and O(changes) merge between branches.
12 and O(changes) merge between branches.
13 """
13 """
14
14
15
15
16 import binascii
16 import binascii
17 import collections
17 import collections
18 import contextlib
18 import contextlib
19 import io
19 import io
20 import os
20 import os
21 import struct
21 import struct
22 import weakref
22 import weakref
23 import zlib
23 import zlib
24
24
25 # import stuff from node for others to import from revlog
25 # import stuff from node for others to import from revlog
26 from .node import (
26 from .node import (
27 bin,
27 bin,
28 hex,
28 hex,
29 nullrev,
29 nullrev,
30 sha1nodeconstants,
30 sha1nodeconstants,
31 short,
31 short,
32 wdirrev,
32 wdirrev,
33 )
33 )
34 from .i18n import _
34 from .i18n import _
35 from .pycompat import getattr
35 from .pycompat import getattr
36 from .revlogutils.constants import (
36 from .revlogutils.constants import (
37 ALL_KINDS,
37 ALL_KINDS,
38 CHANGELOGV2,
38 CHANGELOGV2,
39 COMP_MODE_DEFAULT,
39 COMP_MODE_DEFAULT,
40 COMP_MODE_INLINE,
40 COMP_MODE_INLINE,
41 COMP_MODE_PLAIN,
41 COMP_MODE_PLAIN,
42 DELTA_BASE_REUSE_NO,
42 DELTA_BASE_REUSE_NO,
43 DELTA_BASE_REUSE_TRY,
43 DELTA_BASE_REUSE_TRY,
44 ENTRY_RANK,
44 ENTRY_RANK,
45 FEATURES_BY_VERSION,
45 FEATURES_BY_VERSION,
46 FLAG_GENERALDELTA,
46 FLAG_GENERALDELTA,
47 FLAG_INLINE_DATA,
47 FLAG_INLINE_DATA,
48 INDEX_HEADER,
48 INDEX_HEADER,
49 KIND_CHANGELOG,
49 KIND_CHANGELOG,
50 KIND_FILELOG,
50 KIND_FILELOG,
51 RANK_UNKNOWN,
51 RANK_UNKNOWN,
52 REVLOGV0,
52 REVLOGV0,
53 REVLOGV1,
53 REVLOGV1,
54 REVLOGV1_FLAGS,
54 REVLOGV1_FLAGS,
55 REVLOGV2,
55 REVLOGV2,
56 REVLOGV2_FLAGS,
56 REVLOGV2_FLAGS,
57 REVLOG_DEFAULT_FLAGS,
57 REVLOG_DEFAULT_FLAGS,
58 REVLOG_DEFAULT_FORMAT,
58 REVLOG_DEFAULT_FORMAT,
59 REVLOG_DEFAULT_VERSION,
59 REVLOG_DEFAULT_VERSION,
60 SUPPORTED_FLAGS,
60 SUPPORTED_FLAGS,
61 )
61 )
62 from .revlogutils.flagutil import (
62 from .revlogutils.flagutil import (
63 REVIDX_DEFAULT_FLAGS,
63 REVIDX_DEFAULT_FLAGS,
64 REVIDX_ELLIPSIS,
64 REVIDX_ELLIPSIS,
65 REVIDX_EXTSTORED,
65 REVIDX_EXTSTORED,
66 REVIDX_FLAGS_ORDER,
66 REVIDX_FLAGS_ORDER,
67 REVIDX_HASCOPIESINFO,
67 REVIDX_HASCOPIESINFO,
68 REVIDX_ISCENSORED,
68 REVIDX_ISCENSORED,
69 REVIDX_RAWTEXT_CHANGING_FLAGS,
69 REVIDX_RAWTEXT_CHANGING_FLAGS,
70 )
70 )
71 from .thirdparty import attr
71 from .thirdparty import attr
72 from . import (
72 from . import (
73 ancestor,
73 ancestor,
74 dagop,
74 dagop,
75 error,
75 error,
76 mdiff,
76 mdiff,
77 policy,
77 policy,
78 pycompat,
78 pycompat,
79 revlogutils,
79 revlogutils,
80 templatefilters,
80 templatefilters,
81 util,
81 util,
82 )
82 )
83 from .interfaces import (
83 from .interfaces import (
84 repository,
84 repository,
85 util as interfaceutil,
85 util as interfaceutil,
86 )
86 )
87 from .revlogutils import (
87 from .revlogutils import (
88 deltas as deltautil,
88 deltas as deltautil,
89 docket as docketutil,
89 docket as docketutil,
90 flagutil,
90 flagutil,
91 nodemap as nodemaputil,
91 nodemap as nodemaputil,
92 randomaccessfile,
92 randomaccessfile,
93 revlogv0,
93 revlogv0,
94 rewrite,
94 rewrite,
95 sidedata as sidedatautil,
95 sidedata as sidedatautil,
96 )
96 )
97 from .utils import (
97 from .utils import (
98 storageutil,
98 storageutil,
99 stringutil,
99 stringutil,
100 )
100 )
101
101
102 # blanked usage of all the name to prevent pyflakes constraints
102 # blanked usage of all the name to prevent pyflakes constraints
103 # We need these name available in the module for extensions.
103 # We need these name available in the module for extensions.
104
104
105 REVLOGV0
105 REVLOGV0
106 REVLOGV1
106 REVLOGV1
107 REVLOGV2
107 REVLOGV2
108 CHANGELOGV2
108 CHANGELOGV2
109 FLAG_INLINE_DATA
109 FLAG_INLINE_DATA
110 FLAG_GENERALDELTA
110 FLAG_GENERALDELTA
111 REVLOG_DEFAULT_FLAGS
111 REVLOG_DEFAULT_FLAGS
112 REVLOG_DEFAULT_FORMAT
112 REVLOG_DEFAULT_FORMAT
113 REVLOG_DEFAULT_VERSION
113 REVLOG_DEFAULT_VERSION
114 REVLOGV1_FLAGS
114 REVLOGV1_FLAGS
115 REVLOGV2_FLAGS
115 REVLOGV2_FLAGS
116 REVIDX_ISCENSORED
116 REVIDX_ISCENSORED
117 REVIDX_ELLIPSIS
117 REVIDX_ELLIPSIS
118 REVIDX_HASCOPIESINFO
118 REVIDX_HASCOPIESINFO
119 REVIDX_EXTSTORED
119 REVIDX_EXTSTORED
120 REVIDX_DEFAULT_FLAGS
120 REVIDX_DEFAULT_FLAGS
121 REVIDX_FLAGS_ORDER
121 REVIDX_FLAGS_ORDER
122 REVIDX_RAWTEXT_CHANGING_FLAGS
122 REVIDX_RAWTEXT_CHANGING_FLAGS
123
123
124 parsers = policy.importmod('parsers')
124 parsers = policy.importmod('parsers')
125 rustancestor = policy.importrust('ancestor')
125 rustancestor = policy.importrust('ancestor')
126 rustdagop = policy.importrust('dagop')
126 rustdagop = policy.importrust('dagop')
127 rustrevlog = policy.importrust('revlog')
127 rustrevlog = policy.importrust('revlog')
128
128
129 # Aliased for performance.
129 # Aliased for performance.
130 _zlibdecompress = zlib.decompress
130 _zlibdecompress = zlib.decompress
131
131
132 # max size of inline data embedded into a revlog
132 # max size of inline data embedded into a revlog
133 _maxinline = 131072
133 _maxinline = 131072
134
134
135 # Flag processors for REVIDX_ELLIPSIS.
135 # Flag processors for REVIDX_ELLIPSIS.
136 def ellipsisreadprocessor(rl, text):
136 def ellipsisreadprocessor(rl, text):
137 return text, False
137 return text, False
138
138
139
139
140 def ellipsiswriteprocessor(rl, text):
140 def ellipsiswriteprocessor(rl, text):
141 return text, False
141 return text, False
142
142
143
143
144 def ellipsisrawprocessor(rl, text):
144 def ellipsisrawprocessor(rl, text):
145 return False
145 return False
146
146
147
147
148 ellipsisprocessor = (
148 ellipsisprocessor = (
149 ellipsisreadprocessor,
149 ellipsisreadprocessor,
150 ellipsiswriteprocessor,
150 ellipsiswriteprocessor,
151 ellipsisrawprocessor,
151 ellipsisrawprocessor,
152 )
152 )
153
153
154
154
155 def _verify_revision(rl, skipflags, state, node):
155 def _verify_revision(rl, skipflags, state, node):
156 """Verify the integrity of the given revlog ``node`` while providing a hook
156 """Verify the integrity of the given revlog ``node`` while providing a hook
157 point for extensions to influence the operation."""
157 point for extensions to influence the operation."""
158 if skipflags:
158 if skipflags:
159 state[b'skipread'].add(node)
159 state[b'skipread'].add(node)
160 else:
160 else:
161 # Side-effect: read content and verify hash.
161 # Side-effect: read content and verify hash.
162 rl.revision(node)
162 rl.revision(node)
163
163
164
164
165 # True if a fast implementation for persistent-nodemap is available
165 # True if a fast implementation for persistent-nodemap is available
166 #
166 #
167 # We also consider we have a "fast" implementation in "pure" python because
167 # We also consider we have a "fast" implementation in "pure" python because
168 # people using pure don't really have performance consideration (and a
168 # people using pure don't really have performance consideration (and a
169 # wheelbarrow of other slowness source)
169 # wheelbarrow of other slowness source)
170 HAS_FAST_PERSISTENT_NODEMAP = rustrevlog is not None or util.safehasattr(
170 HAS_FAST_PERSISTENT_NODEMAP = rustrevlog is not None or util.safehasattr(
171 parsers, 'BaseIndexObject'
171 parsers, 'BaseIndexObject'
172 )
172 )
173
173
174
174
175 @interfaceutil.implementer(repository.irevisiondelta)
175 @interfaceutil.implementer(repository.irevisiondelta)
176 @attr.s(slots=True)
176 @attr.s(slots=True)
177 class revlogrevisiondelta:
177 class revlogrevisiondelta:
178 node = attr.ib()
178 node = attr.ib()
179 p1node = attr.ib()
179 p1node = attr.ib()
180 p2node = attr.ib()
180 p2node = attr.ib()
181 basenode = attr.ib()
181 basenode = attr.ib()
182 flags = attr.ib()
182 flags = attr.ib()
183 baserevisionsize = attr.ib()
183 baserevisionsize = attr.ib()
184 revision = attr.ib()
184 revision = attr.ib()
185 delta = attr.ib()
185 delta = attr.ib()
186 sidedata = attr.ib()
186 sidedata = attr.ib()
187 protocol_flags = attr.ib()
187 protocol_flags = attr.ib()
188 linknode = attr.ib(default=None)
188 linknode = attr.ib(default=None)
189
189
190
190
191 @interfaceutil.implementer(repository.iverifyproblem)
191 @interfaceutil.implementer(repository.iverifyproblem)
192 @attr.s(frozen=True)
192 @attr.s(frozen=True)
193 class revlogproblem:
193 class revlogproblem:
194 warning = attr.ib(default=None)
194 warning = attr.ib(default=None)
195 error = attr.ib(default=None)
195 error = attr.ib(default=None)
196 node = attr.ib(default=None)
196 node = attr.ib(default=None)
197
197
198
198
199 def parse_index_v1(data, inline):
199 def parse_index_v1(data, inline):
200 # call the C implementation to parse the index data
200 # call the C implementation to parse the index data
201 index, cache = parsers.parse_index2(data, inline)
201 index, cache = parsers.parse_index2(data, inline)
202 return index, cache
202 return index, cache
203
203
204
204
205 def parse_index_v2(data, inline):
205 def parse_index_v2(data, inline):
206 # call the C implementation to parse the index data
206 # call the C implementation to parse the index data
207 index, cache = parsers.parse_index2(data, inline, format=REVLOGV2)
207 index, cache = parsers.parse_index2(data, inline, format=REVLOGV2)
208 return index, cache
208 return index, cache
209
209
210
210
211 def parse_index_cl_v2(data, inline):
211 def parse_index_cl_v2(data, inline):
212 # call the C implementation to parse the index data
212 # call the C implementation to parse the index data
213 index, cache = parsers.parse_index2(data, inline, format=CHANGELOGV2)
213 index, cache = parsers.parse_index2(data, inline, format=CHANGELOGV2)
214 return index, cache
214 return index, cache
215
215
216
216
217 if util.safehasattr(parsers, 'parse_index_devel_nodemap'):
217 if util.safehasattr(parsers, 'parse_index_devel_nodemap'):
218
218
219 def parse_index_v1_nodemap(data, inline):
219 def parse_index_v1_nodemap(data, inline):
220 index, cache = parsers.parse_index_devel_nodemap(data, inline)
220 index, cache = parsers.parse_index_devel_nodemap(data, inline)
221 return index, cache
221 return index, cache
222
222
223
223
224 else:
224 else:
225 parse_index_v1_nodemap = None
225 parse_index_v1_nodemap = None
226
226
227
227
228 def parse_index_v1_mixed(data, inline):
228 def parse_index_v1_mixed(data, inline):
229 index, cache = parse_index_v1(data, inline)
229 index, cache = parse_index_v1(data, inline)
230 return rustrevlog.MixedIndex(index), cache
230 return rustrevlog.MixedIndex(index), cache
231
231
232
232
233 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
233 # corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
234 # signed integer)
234 # signed integer)
235 _maxentrysize = 0x7FFFFFFF
235 _maxentrysize = 0x7FFFFFFF
236
236
237 FILE_TOO_SHORT_MSG = _(
237 FILE_TOO_SHORT_MSG = _(
238 b'cannot read from revlog %s;'
238 b'cannot read from revlog %s;'
239 b' expected %d bytes from offset %d, data size is %d'
239 b' expected %d bytes from offset %d, data size is %d'
240 )
240 )
241
241
242 hexdigits = b'0123456789abcdefABCDEF'
242 hexdigits = b'0123456789abcdefABCDEF'
243
243
244
244
245 class revlog:
245 class revlog:
246 """
246 """
247 the underlying revision storage object
247 the underlying revision storage object
248
248
249 A revlog consists of two parts, an index and the revision data.
249 A revlog consists of two parts, an index and the revision data.
250
250
251 The index is a file with a fixed record size containing
251 The index is a file with a fixed record size containing
252 information on each revision, including its nodeid (hash), the
252 information on each revision, including its nodeid (hash), the
253 nodeids of its parents, the position and offset of its data within
253 nodeids of its parents, the position and offset of its data within
254 the data file, and the revision it's based on. Finally, each entry
254 the data file, and the revision it's based on. Finally, each entry
255 contains a linkrev entry that can serve as a pointer to external
255 contains a linkrev entry that can serve as a pointer to external
256 data.
256 data.
257
257
258 The revision data itself is a linear collection of data chunks.
258 The revision data itself is a linear collection of data chunks.
259 Each chunk represents a revision and is usually represented as a
259 Each chunk represents a revision and is usually represented as a
260 delta against the previous chunk. To bound lookup time, runs of
260 delta against the previous chunk. To bound lookup time, runs of
261 deltas are limited to about 2 times the length of the original
261 deltas are limited to about 2 times the length of the original
262 version data. This makes retrieval of a version proportional to
262 version data. This makes retrieval of a version proportional to
263 its size, or O(1) relative to the number of revisions.
263 its size, or O(1) relative to the number of revisions.
264
264
265 Both pieces of the revlog are written to in an append-only
265 Both pieces of the revlog are written to in an append-only
266 fashion, which means we never need to rewrite a file to insert or
266 fashion, which means we never need to rewrite a file to insert or
267 remove data, and can use some simple techniques to avoid the need
267 remove data, and can use some simple techniques to avoid the need
268 for locking while reading.
268 for locking while reading.
269
269
270 If checkambig, indexfile is opened with checkambig=True at
270 If checkambig, indexfile is opened with checkambig=True at
271 writing, to avoid file stat ambiguity.
271 writing, to avoid file stat ambiguity.
272
272
273 If mmaplargeindex is True, and an mmapindexthreshold is set, the
273 If mmaplargeindex is True, and an mmapindexthreshold is set, the
274 index will be mmapped rather than read if it is larger than the
274 index will be mmapped rather than read if it is larger than the
275 configured threshold.
275 configured threshold.
276
276
277 If censorable is True, the revlog can have censored revisions.
277 If censorable is True, the revlog can have censored revisions.
278
278
279 If `upperboundcomp` is not None, this is the expected maximal gain from
279 If `upperboundcomp` is not None, this is the expected maximal gain from
280 compression for the data content.
280 compression for the data content.
281
281
282 `concurrencychecker` is an optional function that receives 3 arguments: a
282 `concurrencychecker` is an optional function that receives 3 arguments: a
283 file handle, a filename, and an expected position. It should check whether
283 file handle, a filename, and an expected position. It should check whether
284 the current position in the file handle is valid, and log/warn/fail (by
284 the current position in the file handle is valid, and log/warn/fail (by
285 raising).
285 raising).
286
286
287 See mercurial/revlogutils/contants.py for details about the content of an
287 See mercurial/revlogutils/contants.py for details about the content of an
288 index entry.
288 index entry.
289 """
289 """
290
290
291 _flagserrorclass = error.RevlogError
291 _flagserrorclass = error.RevlogError
292
292
293 @staticmethod
293 @staticmethod
294 def is_inline_index(header_bytes):
294 def is_inline_index(header_bytes):
295 header = INDEX_HEADER.unpack(header_bytes)[0]
295 header = INDEX_HEADER.unpack(header_bytes)[0]
296
296
297 _format_flags = header & ~0xFFFF
297 _format_flags = header & ~0xFFFF
298 _format_version = header & 0xFFFF
298 _format_version = header & 0xFFFF
299
299
300 features = FEATURES_BY_VERSION[_format_version]
300 features = FEATURES_BY_VERSION[_format_version]
301 return features[b'inline'](_format_flags)
301 return features[b'inline'](_format_flags)
302
302
303 def __init__(
303 def __init__(
304 self,
304 self,
305 opener,
305 opener,
306 target,
306 target,
307 radix,
307 radix,
308 postfix=None, # only exist for `tmpcensored` now
308 postfix=None, # only exist for `tmpcensored` now
309 checkambig=False,
309 checkambig=False,
310 mmaplargeindex=False,
310 mmaplargeindex=False,
311 censorable=False,
311 censorable=False,
312 upperboundcomp=None,
312 upperboundcomp=None,
313 persistentnodemap=False,
313 persistentnodemap=False,
314 concurrencychecker=None,
314 concurrencychecker=None,
315 trypending=False,
315 trypending=False,
316 try_split=False,
316 try_split=False,
317 canonical_parent_order=True,
317 canonical_parent_order=True,
318 ):
318 ):
319 """
319 """
320 create a revlog object
320 create a revlog object
321
321
322 opener is a function that abstracts the file opening operation
322 opener is a function that abstracts the file opening operation
323 and can be used to implement COW semantics or the like.
323 and can be used to implement COW semantics or the like.
324
324
325 `target`: a (KIND, ID) tuple that identify the content stored in
325 `target`: a (KIND, ID) tuple that identify the content stored in
326 this revlog. It help the rest of the code to understand what the revlog
326 this revlog. It help the rest of the code to understand what the revlog
327 is about without having to resort to heuristic and index filename
327 is about without having to resort to heuristic and index filename
328 analysis. Note: that this must be reliably be set by normal code, but
328 analysis. Note: that this must be reliably be set by normal code, but
329 that test, debug, or performance measurement code might not set this to
329 that test, debug, or performance measurement code might not set this to
330 accurate value.
330 accurate value.
331 """
331 """
332 self.upperboundcomp = upperboundcomp
332 self.upperboundcomp = upperboundcomp
333
333
334 self.radix = radix
334 self.radix = radix
335
335
336 self._docket_file = None
336 self._docket_file = None
337 self._indexfile = None
337 self._indexfile = None
338 self._datafile = None
338 self._datafile = None
339 self._sidedatafile = None
339 self._sidedatafile = None
340 self._nodemap_file = None
340 self._nodemap_file = None
341 self.postfix = postfix
341 self.postfix = postfix
342 self._trypending = trypending
342 self._trypending = trypending
343 self._try_split = try_split
343 self._try_split = try_split
344 self.opener = opener
344 self.opener = opener
345 if persistentnodemap:
345 if persistentnodemap:
346 self._nodemap_file = nodemaputil.get_nodemap_file(self)
346 self._nodemap_file = nodemaputil.get_nodemap_file(self)
347
347
348 assert target[0] in ALL_KINDS
348 assert target[0] in ALL_KINDS
349 assert len(target) == 2
349 assert len(target) == 2
350 self.target = target
350 self.target = target
351 # When True, indexfile is opened with checkambig=True at writing, to
351 # When True, indexfile is opened with checkambig=True at writing, to
352 # avoid file stat ambiguity.
352 # avoid file stat ambiguity.
353 self._checkambig = checkambig
353 self._checkambig = checkambig
354 self._mmaplargeindex = mmaplargeindex
354 self._mmaplargeindex = mmaplargeindex
355 self._censorable = censorable
355 self._censorable = censorable
356 # 3-tuple of (node, rev, text) for a raw revision.
356 # 3-tuple of (node, rev, text) for a raw revision.
357 self._revisioncache = None
357 self._revisioncache = None
358 # Maps rev to chain base rev.
358 # Maps rev to chain base rev.
359 self._chainbasecache = util.lrucachedict(100)
359 self._chainbasecache = util.lrucachedict(100)
360 # 2-tuple of (offset, data) of raw data from the revlog at an offset.
360 # 2-tuple of (offset, data) of raw data from the revlog at an offset.
361 self._chunkcache = (0, b'')
361 self._chunkcache = (0, b'')
362 # How much data to read and cache into the raw revlog data cache.
362 # How much data to read and cache into the raw revlog data cache.
363 self._chunkcachesize = 65536
363 self._chunkcachesize = 65536
364 self._maxchainlen = None
364 self._maxchainlen = None
365 self._deltabothparents = True
365 self._deltabothparents = True
366 self._candidate_group_chunk_size = 0
366 self._candidate_group_chunk_size = 0
367 self._debug_delta = False
367 self._debug_delta = False
368 self.index = None
368 self.index = None
369 self._docket = None
369 self._docket = None
370 self._nodemap_docket = None
370 self._nodemap_docket = None
371 # Mapping of partial identifiers to full nodes.
371 # Mapping of partial identifiers to full nodes.
372 self._pcache = {}
372 self._pcache = {}
373 # Mapping of revision integer to full node.
373 # Mapping of revision integer to full node.
374 self._compengine = b'zlib'
374 self._compengine = b'zlib'
375 self._compengineopts = {}
375 self._compengineopts = {}
376 self._maxdeltachainspan = -1
376 self._maxdeltachainspan = -1
377 self._withsparseread = False
377 self._withsparseread = False
378 self._sparserevlog = False
378 self._sparserevlog = False
379 self.hassidedata = False
379 self.hassidedata = False
380 self._srdensitythreshold = 0.50
380 self._srdensitythreshold = 0.50
381 self._srmingapsize = 262144
381 self._srmingapsize = 262144
382
382
383 # other optionnals features
383 # other optionnals features
384
384
385 # might remove rank configuration once the computation has no impact
385 # might remove rank configuration once the computation has no impact
386 self._compute_rank = False
386 self._compute_rank = False
387
387
388 # Make copy of flag processors so each revlog instance can support
388 # Make copy of flag processors so each revlog instance can support
389 # custom flags.
389 # custom flags.
390 self._flagprocessors = dict(flagutil.flagprocessors)
390 self._flagprocessors = dict(flagutil.flagprocessors)
391
391
392 # 3-tuple of file handles being used for active writing.
392 # 3-tuple of file handles being used for active writing.
393 self._writinghandles = None
393 self._writinghandles = None
394 # prevent nesting of addgroup
394 # prevent nesting of addgroup
395 self._adding_group = None
395 self._adding_group = None
396
396
397 self._loadindex()
397 self._loadindex()
398
398
399 self._concurrencychecker = concurrencychecker
399 self._concurrencychecker = concurrencychecker
400
400
401 # parent order is supposed to be semantically irrelevant, so we
401 # parent order is supposed to be semantically irrelevant, so we
402 # normally resort parents to ensure that the first parent is non-null,
402 # normally resort parents to ensure that the first parent is non-null,
403 # if there is a non-null parent at all.
403 # if there is a non-null parent at all.
404 # filelog abuses the parent order as flag to mark some instances of
404 # filelog abuses the parent order as flag to mark some instances of
405 # meta-encoded files, so allow it to disable this behavior.
405 # meta-encoded files, so allow it to disable this behavior.
406 self.canonical_parent_order = canonical_parent_order
406 self.canonical_parent_order = canonical_parent_order
407
407
408 def _init_opts(self):
408 def _init_opts(self):
409 """process options (from above/config) to setup associated default revlog mode
409 """process options (from above/config) to setup associated default revlog mode
410
410
411 These values might be affected when actually reading on disk information.
411 These values might be affected when actually reading on disk information.
412
412
413 The relevant values are returned for use in _loadindex().
413 The relevant values are returned for use in _loadindex().
414
414
415 * newversionflags:
415 * newversionflags:
416 version header to use if we need to create a new revlog
416 version header to use if we need to create a new revlog
417
417
418 * mmapindexthreshold:
418 * mmapindexthreshold:
419 minimal index size for start to use mmap
419 minimal index size for start to use mmap
420
420
421 * force_nodemap:
421 * force_nodemap:
422 force the usage of a "development" version of the nodemap code
422 force the usage of a "development" version of the nodemap code
423 """
423 """
424 mmapindexthreshold = None
424 mmapindexthreshold = None
425 opts = self.opener.options
425 opts = self.opener.options
426
426
427 if b'changelogv2' in opts and self.revlog_kind == KIND_CHANGELOG:
427 if b'changelogv2' in opts and self.revlog_kind == KIND_CHANGELOG:
428 new_header = CHANGELOGV2
428 new_header = CHANGELOGV2
429 self._compute_rank = opts.get(b'changelogv2.compute-rank', True)
429 self._compute_rank = opts.get(b'changelogv2.compute-rank', True)
430 elif b'revlogv2' in opts:
430 elif b'revlogv2' in opts:
431 new_header = REVLOGV2
431 new_header = REVLOGV2
432 elif b'revlogv1' in opts:
432 elif b'revlogv1' in opts:
433 new_header = REVLOGV1 | FLAG_INLINE_DATA
433 new_header = REVLOGV1 | FLAG_INLINE_DATA
434 if b'generaldelta' in opts:
434 if b'generaldelta' in opts:
435 new_header |= FLAG_GENERALDELTA
435 new_header |= FLAG_GENERALDELTA
436 elif b'revlogv0' in self.opener.options:
436 elif b'revlogv0' in self.opener.options:
437 new_header = REVLOGV0
437 new_header = REVLOGV0
438 else:
438 else:
439 new_header = REVLOG_DEFAULT_VERSION
439 new_header = REVLOG_DEFAULT_VERSION
440
440
441 if b'chunkcachesize' in opts:
441 if b'chunkcachesize' in opts:
442 self._chunkcachesize = opts[b'chunkcachesize']
442 self._chunkcachesize = opts[b'chunkcachesize']
443 if b'maxchainlen' in opts:
443 if b'maxchainlen' in opts:
444 self._maxchainlen = opts[b'maxchainlen']
444 self._maxchainlen = opts[b'maxchainlen']
445 if b'deltabothparents' in opts:
445 if b'deltabothparents' in opts:
446 self._deltabothparents = opts[b'deltabothparents']
446 self._deltabothparents = opts[b'deltabothparents']
447 dps_cgds = opts.get(b'delta-parent-search.candidate-group-chunk-size')
447 dps_cgds = opts.get(b'delta-parent-search.candidate-group-chunk-size')
448 if dps_cgds:
448 if dps_cgds:
449 self._candidate_group_chunk_size = dps_cgds
449 self._candidate_group_chunk_size = dps_cgds
450 self._lazydelta = bool(opts.get(b'lazydelta', True))
450 self._lazydelta = bool(opts.get(b'lazydelta', True))
451 self._lazydeltabase = False
451 self._lazydeltabase = False
452 if self._lazydelta:
452 if self._lazydelta:
453 self._lazydeltabase = bool(opts.get(b'lazydeltabase', False))
453 self._lazydeltabase = bool(opts.get(b'lazydeltabase', False))
454 if b'debug-delta' in opts:
454 if b'debug-delta' in opts:
455 self._debug_delta = opts[b'debug-delta']
455 self._debug_delta = opts[b'debug-delta']
456 if b'compengine' in opts:
456 if b'compengine' in opts:
457 self._compengine = opts[b'compengine']
457 self._compengine = opts[b'compengine']
458 if b'zlib.level' in opts:
458 if b'zlib.level' in opts:
459 self._compengineopts[b'zlib.level'] = opts[b'zlib.level']
459 self._compengineopts[b'zlib.level'] = opts[b'zlib.level']
460 if b'zstd.level' in opts:
460 if b'zstd.level' in opts:
461 self._compengineopts[b'zstd.level'] = opts[b'zstd.level']
461 self._compengineopts[b'zstd.level'] = opts[b'zstd.level']
462 if b'maxdeltachainspan' in opts:
462 if b'maxdeltachainspan' in opts:
463 self._maxdeltachainspan = opts[b'maxdeltachainspan']
463 self._maxdeltachainspan = opts[b'maxdeltachainspan']
464 if self._mmaplargeindex and b'mmapindexthreshold' in opts:
464 if self._mmaplargeindex and b'mmapindexthreshold' in opts:
465 mmapindexthreshold = opts[b'mmapindexthreshold']
465 mmapindexthreshold = opts[b'mmapindexthreshold']
466 self._sparserevlog = bool(opts.get(b'sparse-revlog', False))
466 self._sparserevlog = bool(opts.get(b'sparse-revlog', False))
467 withsparseread = bool(opts.get(b'with-sparse-read', False))
467 withsparseread = bool(opts.get(b'with-sparse-read', False))
468 # sparse-revlog forces sparse-read
468 # sparse-revlog forces sparse-read
469 self._withsparseread = self._sparserevlog or withsparseread
469 self._withsparseread = self._sparserevlog or withsparseread
470 if b'sparse-read-density-threshold' in opts:
470 if b'sparse-read-density-threshold' in opts:
471 self._srdensitythreshold = opts[b'sparse-read-density-threshold']
471 self._srdensitythreshold = opts[b'sparse-read-density-threshold']
472 if b'sparse-read-min-gap-size' in opts:
472 if b'sparse-read-min-gap-size' in opts:
473 self._srmingapsize = opts[b'sparse-read-min-gap-size']
473 self._srmingapsize = opts[b'sparse-read-min-gap-size']
474 if opts.get(b'enableellipsis'):
474 if opts.get(b'enableellipsis'):
475 self._flagprocessors[REVIDX_ELLIPSIS] = ellipsisprocessor
475 self._flagprocessors[REVIDX_ELLIPSIS] = ellipsisprocessor
476
476
477 # revlog v0 doesn't have flag processors
477 # revlog v0 doesn't have flag processors
478 for flag, processor in opts.get(b'flagprocessors', {}).items():
478 for flag, processor in opts.get(b'flagprocessors', {}).items():
479 flagutil.insertflagprocessor(flag, processor, self._flagprocessors)
479 flagutil.insertflagprocessor(flag, processor, self._flagprocessors)
480
480
481 if self._chunkcachesize <= 0:
481 if self._chunkcachesize <= 0:
482 raise error.RevlogError(
482 raise error.RevlogError(
483 _(b'revlog chunk cache size %r is not greater than 0')
483 _(b'revlog chunk cache size %r is not greater than 0')
484 % self._chunkcachesize
484 % self._chunkcachesize
485 )
485 )
486 elif self._chunkcachesize & (self._chunkcachesize - 1):
486 elif self._chunkcachesize & (self._chunkcachesize - 1):
487 raise error.RevlogError(
487 raise error.RevlogError(
488 _(b'revlog chunk cache size %r is not a power of 2')
488 _(b'revlog chunk cache size %r is not a power of 2')
489 % self._chunkcachesize
489 % self._chunkcachesize
490 )
490 )
491 force_nodemap = opts.get(b'devel-force-nodemap', False)
491 force_nodemap = opts.get(b'devel-force-nodemap', False)
492 return new_header, mmapindexthreshold, force_nodemap
492 return new_header, mmapindexthreshold, force_nodemap
493
493
494 def _get_data(self, filepath, mmap_threshold, size=None):
494 def _get_data(self, filepath, mmap_threshold, size=None):
495 """return a file content with or without mmap
495 """return a file content with or without mmap
496
496
497 If the file is missing return the empty string"""
497 If the file is missing return the empty string"""
498 try:
498 try:
499 with self.opener(filepath) as fp:
499 with self.opener(filepath) as fp:
500 if mmap_threshold is not None:
500 if mmap_threshold is not None:
501 file_size = self.opener.fstat(fp).st_size
501 file_size = self.opener.fstat(fp).st_size
502 if file_size >= mmap_threshold:
502 if file_size >= mmap_threshold:
503 if size is not None:
503 if size is not None:
504 # avoid potentiel mmap crash
504 # avoid potentiel mmap crash
505 size = min(file_size, size)
505 size = min(file_size, size)
506 # TODO: should .close() to release resources without
506 # TODO: should .close() to release resources without
507 # relying on Python GC
507 # relying on Python GC
508 if size is None:
508 if size is None:
509 return util.buffer(util.mmapread(fp))
509 return util.buffer(util.mmapread(fp))
510 else:
510 else:
511 return util.buffer(util.mmapread(fp, size))
511 return util.buffer(util.mmapread(fp, size))
512 if size is None:
512 if size is None:
513 return fp.read()
513 return fp.read()
514 else:
514 else:
515 return fp.read(size)
515 return fp.read(size)
516 except FileNotFoundError:
516 except FileNotFoundError:
517 return b''
517 return b''
518
518
519 def get_streams(self, max_linkrev, force_inline=False):
519 def get_streams(self, max_linkrev, force_inline=False):
520 n = len(self)
520 n = len(self)
521 index = self.index
521 index = self.index
522 while n > 0:
522 while n > 0:
523 linkrev = index[n - 1][4]
523 linkrev = index[n - 1][4]
524 if linkrev < max_linkrev:
524 if linkrev < max_linkrev:
525 break
525 break
526 # note: this loop will rarely go through multiple iterations, since
526 # note: this loop will rarely go through multiple iterations, since
527 # it only traverses commits created during the current streaming
527 # it only traverses commits created during the current streaming
528 # pull operation.
528 # pull operation.
529 #
529 #
530 # If this become a problem, using a binary search should cap the
530 # If this become a problem, using a binary search should cap the
531 # runtime of this.
531 # runtime of this.
532 n = n - 1
532 n = n - 1
533 if n == 0:
533 if n == 0:
534 # no data to send
534 # no data to send
535 return []
535 return []
536 index_size = n * index.entry_size
536 index_size = n * index.entry_size
537 data_size = self.end(n - 1)
537 data_size = self.end(n - 1)
538
538
539 # XXX we might have been split (or stripped) since the object
539 # XXX we might have been split (or stripped) since the object
540 # initialization, We need to close this race too, but having a way to
540 # initialization, We need to close this race too, but having a way to
541 # pre-open the file we feed to the revlog and never closing them before
541 # pre-open the file we feed to the revlog and never closing them before
542 # we are done streaming.
542 # we are done streaming.
543
543
544 if self._inline:
544 if self._inline:
545
545
546 def get_stream():
546 def get_stream():
547 with self._indexfp() as fp:
547 with self._indexfp() as fp:
548 yield None
548 yield None
549 size = index_size + data_size
549 size = index_size + data_size
550 if size <= 65536:
550 if size <= 65536:
551 yield fp.read(size)
551 yield fp.read(size)
552 else:
552 else:
553 yield from util.filechunkiter(fp, limit=size)
553 yield from util.filechunkiter(fp, limit=size)
554
554
555 inline_stream = get_stream()
555 inline_stream = get_stream()
556 next(inline_stream)
556 next(inline_stream)
557 return [
557 return [
558 (self._indexfile, inline_stream, index_size + data_size),
558 (self._indexfile, inline_stream, index_size + data_size),
559 ]
559 ]
560 elif force_inline:
560 elif force_inline:
561
561
562 def get_stream():
562 def get_stream():
563 with self._datafp() as fp_d:
563 with self._datafp() as fp_d:
564 yield None
564 yield None
565
565
566 for rev in range(n):
566 for rev in range(n):
567 idx = self.index.entry_binary(rev)
567 idx = self.index.entry_binary(rev)
568 if rev == 0 and self._docket is None:
568 if rev == 0 and self._docket is None:
569 # re-inject the inline flag
569 # re-inject the inline flag
570 header = self._format_flags
570 header = self._format_flags
571 header |= self._format_version
571 header |= self._format_version
572 header |= FLAG_INLINE_DATA
572 header |= FLAG_INLINE_DATA
573 header = self.index.pack_header(header)
573 header = self.index.pack_header(header)
574 idx = header + idx
574 idx = header + idx
575 yield idx
575 yield idx
576 yield self._getsegmentforrevs(rev, rev, df=fp_d)[1]
576 yield self._getsegmentforrevs(rev, rev, df=fp_d)[1]
577
577
578 inline_stream = get_stream()
578 inline_stream = get_stream()
579 next(inline_stream)
579 next(inline_stream)
580 return [
580 return [
581 (self._indexfile, inline_stream, index_size + data_size),
581 (self._indexfile, inline_stream, index_size + data_size),
582 ]
582 ]
583 else:
583 else:
584
584
585 def get_index_stream():
585 def get_index_stream():
586 with self._indexfp() as fp:
586 with self._indexfp() as fp:
587 yield None
587 yield None
588 if index_size <= 65536:
588 if index_size <= 65536:
589 yield fp.read(index_size)
589 yield fp.read(index_size)
590 else:
590 else:
591 yield from util.filechunkiter(fp, limit=index_size)
591 yield from util.filechunkiter(fp, limit=index_size)
592
592
593 def get_data_stream():
593 def get_data_stream():
594 with self._datafp() as fp:
594 with self._datafp() as fp:
595 yield None
595 yield None
596 if data_size <= 65536:
596 if data_size <= 65536:
597 yield fp.read(data_size)
597 yield fp.read(data_size)
598 else:
598 else:
599 yield from util.filechunkiter(fp, limit=data_size)
599 yield from util.filechunkiter(fp, limit=data_size)
600
600
601 index_stream = get_index_stream()
601 index_stream = get_index_stream()
602 next(index_stream)
602 next(index_stream)
603 data_stream = get_data_stream()
603 data_stream = get_data_stream()
604 next(data_stream)
604 next(data_stream)
605 return [
605 return [
606 (self._datafile, data_stream, data_size),
606 (self._datafile, data_stream, data_size),
607 (self._indexfile, index_stream, index_size),
607 (self._indexfile, index_stream, index_size),
608 ]
608 ]
609
609
610 def _loadindex(self, docket=None):
610 def _loadindex(self, docket=None):
611
611
612 new_header, mmapindexthreshold, force_nodemap = self._init_opts()
612 new_header, mmapindexthreshold, force_nodemap = self._init_opts()
613
613
614 if self.postfix is not None:
614 if self.postfix is not None:
615 entry_point = b'%s.i.%s' % (self.radix, self.postfix)
615 entry_point = b'%s.i.%s' % (self.radix, self.postfix)
616 elif self._trypending and self.opener.exists(b'%s.i.a' % self.radix):
616 elif self._trypending and self.opener.exists(b'%s.i.a' % self.radix):
617 entry_point = b'%s.i.a' % self.radix
617 entry_point = b'%s.i.a' % self.radix
618 elif self._try_split and self.opener.exists(self._split_index_file):
618 elif self._try_split and self.opener.exists(self._split_index_file):
619 entry_point = self._split_index_file
619 entry_point = self._split_index_file
620 else:
620 else:
621 entry_point = b'%s.i' % self.radix
621 entry_point = b'%s.i' % self.radix
622
622
623 if docket is not None:
623 if docket is not None:
624 self._docket = docket
624 self._docket = docket
625 self._docket_file = entry_point
625 self._docket_file = entry_point
626 else:
626 else:
627 self._initempty = True
627 self._initempty = True
628 entry_data = self._get_data(entry_point, mmapindexthreshold)
628 entry_data = self._get_data(entry_point, mmapindexthreshold)
629 if len(entry_data) > 0:
629 if len(entry_data) > 0:
630 header = INDEX_HEADER.unpack(entry_data[:4])[0]
630 header = INDEX_HEADER.unpack(entry_data[:4])[0]
631 self._initempty = False
631 self._initempty = False
632 else:
632 else:
633 header = new_header
633 header = new_header
634
634
635 self._format_flags = header & ~0xFFFF
635 self._format_flags = header & ~0xFFFF
636 self._format_version = header & 0xFFFF
636 self._format_version = header & 0xFFFF
637
637
638 supported_flags = SUPPORTED_FLAGS.get(self._format_version)
638 supported_flags = SUPPORTED_FLAGS.get(self._format_version)
639 if supported_flags is None:
639 if supported_flags is None:
640 msg = _(b'unknown version (%d) in revlog %s')
640 msg = _(b'unknown version (%d) in revlog %s')
641 msg %= (self._format_version, self.display_id)
641 msg %= (self._format_version, self.display_id)
642 raise error.RevlogError(msg)
642 raise error.RevlogError(msg)
643 elif self._format_flags & ~supported_flags:
643 elif self._format_flags & ~supported_flags:
644 msg = _(b'unknown flags (%#04x) in version %d revlog %s')
644 msg = _(b'unknown flags (%#04x) in version %d revlog %s')
645 display_flag = self._format_flags >> 16
645 display_flag = self._format_flags >> 16
646 msg %= (display_flag, self._format_version, self.display_id)
646 msg %= (display_flag, self._format_version, self.display_id)
647 raise error.RevlogError(msg)
647 raise error.RevlogError(msg)
648
648
649 features = FEATURES_BY_VERSION[self._format_version]
649 features = FEATURES_BY_VERSION[self._format_version]
650 self._inline = features[b'inline'](self._format_flags)
650 self._inline = features[b'inline'](self._format_flags)
651 self._generaldelta = features[b'generaldelta'](self._format_flags)
651 self._generaldelta = features[b'generaldelta'](self._format_flags)
652 self.hassidedata = features[b'sidedata']
652 self.hassidedata = features[b'sidedata']
653
653
654 if not features[b'docket']:
654 if not features[b'docket']:
655 self._indexfile = entry_point
655 self._indexfile = entry_point
656 index_data = entry_data
656 index_data = entry_data
657 else:
657 else:
658 self._docket_file = entry_point
658 self._docket_file = entry_point
659 if self._initempty:
659 if self._initempty:
660 self._docket = docketutil.default_docket(self, header)
660 self._docket = docketutil.default_docket(self, header)
661 else:
661 else:
662 self._docket = docketutil.parse_docket(
662 self._docket = docketutil.parse_docket(
663 self, entry_data, use_pending=self._trypending
663 self, entry_data, use_pending=self._trypending
664 )
664 )
665
665
666 if self._docket is not None:
666 if self._docket is not None:
667 self._indexfile = self._docket.index_filepath()
667 self._indexfile = self._docket.index_filepath()
668 index_data = b''
668 index_data = b''
669 index_size = self._docket.index_end
669 index_size = self._docket.index_end
670 if index_size > 0:
670 if index_size > 0:
671 index_data = self._get_data(
671 index_data = self._get_data(
672 self._indexfile, mmapindexthreshold, size=index_size
672 self._indexfile, mmapindexthreshold, size=index_size
673 )
673 )
674 if len(index_data) < index_size:
674 if len(index_data) < index_size:
675 msg = _(b'too few index data for %s: got %d, expected %d')
675 msg = _(b'too few index data for %s: got %d, expected %d')
676 msg %= (self.display_id, len(index_data), index_size)
676 msg %= (self.display_id, len(index_data), index_size)
677 raise error.RevlogError(msg)
677 raise error.RevlogError(msg)
678
678
679 self._inline = False
679 self._inline = False
680 # generaldelta implied by version 2 revlogs.
680 # generaldelta implied by version 2 revlogs.
681 self._generaldelta = True
681 self._generaldelta = True
682 # the logic for persistent nodemap will be dealt with within the
682 # the logic for persistent nodemap will be dealt with within the
683 # main docket, so disable it for now.
683 # main docket, so disable it for now.
684 self._nodemap_file = None
684 self._nodemap_file = None
685
685
686 if self._docket is not None:
686 if self._docket is not None:
687 self._datafile = self._docket.data_filepath()
687 self._datafile = self._docket.data_filepath()
688 self._sidedatafile = self._docket.sidedata_filepath()
688 self._sidedatafile = self._docket.sidedata_filepath()
689 elif self.postfix is None:
689 elif self.postfix is None:
690 self._datafile = b'%s.d' % self.radix
690 self._datafile = b'%s.d' % self.radix
691 else:
691 else:
692 self._datafile = b'%s.d.%s' % (self.radix, self.postfix)
692 self._datafile = b'%s.d.%s' % (self.radix, self.postfix)
693
693
694 self.nodeconstants = sha1nodeconstants
694 self.nodeconstants = sha1nodeconstants
695 self.nullid = self.nodeconstants.nullid
695 self.nullid = self.nodeconstants.nullid
696
696
697 # sparse-revlog can't be on without general-delta (issue6056)
697 # sparse-revlog can't be on without general-delta (issue6056)
698 if not self._generaldelta:
698 if not self._generaldelta:
699 self._sparserevlog = False
699 self._sparserevlog = False
700
700
701 self._storedeltachains = True
701 self._storedeltachains = True
702
702
703 devel_nodemap = (
703 devel_nodemap = (
704 self._nodemap_file
704 self._nodemap_file
705 and force_nodemap
705 and force_nodemap
706 and parse_index_v1_nodemap is not None
706 and parse_index_v1_nodemap is not None
707 )
707 )
708
708
709 use_rust_index = False
709 use_rust_index = False
710 if rustrevlog is not None:
710 if rustrevlog is not None:
711 if self._nodemap_file is not None:
711 if self._nodemap_file is not None:
712 use_rust_index = True
712 use_rust_index = True
713 else:
713 else:
714 use_rust_index = self.opener.options.get(b'rust.index')
714 use_rust_index = self.opener.options.get(b'rust.index')
715
715
716 self._parse_index = parse_index_v1
716 self._parse_index = parse_index_v1
717 if self._format_version == REVLOGV0:
717 if self._format_version == REVLOGV0:
718 self._parse_index = revlogv0.parse_index_v0
718 self._parse_index = revlogv0.parse_index_v0
719 elif self._format_version == REVLOGV2:
719 elif self._format_version == REVLOGV2:
720 self._parse_index = parse_index_v2
720 self._parse_index = parse_index_v2
721 elif self._format_version == CHANGELOGV2:
721 elif self._format_version == CHANGELOGV2:
722 self._parse_index = parse_index_cl_v2
722 self._parse_index = parse_index_cl_v2
723 elif devel_nodemap:
723 elif devel_nodemap:
724 self._parse_index = parse_index_v1_nodemap
724 self._parse_index = parse_index_v1_nodemap
725 elif use_rust_index:
725 elif use_rust_index:
726 self._parse_index = parse_index_v1_mixed
726 self._parse_index = parse_index_v1_mixed
727 try:
727 try:
728 d = self._parse_index(index_data, self._inline)
728 d = self._parse_index(index_data, self._inline)
729 index, chunkcache = d
729 index, chunkcache = d
730 use_nodemap = (
730 use_nodemap = (
731 not self._inline
731 not self._inline
732 and self._nodemap_file is not None
732 and self._nodemap_file is not None
733 and util.safehasattr(index, 'update_nodemap_data')
733 and util.safehasattr(index, 'update_nodemap_data')
734 )
734 )
735 if use_nodemap:
735 if use_nodemap:
736 nodemap_data = nodemaputil.persisted_data(self)
736 nodemap_data = nodemaputil.persisted_data(self)
737 if nodemap_data is not None:
737 if nodemap_data is not None:
738 docket = nodemap_data[0]
738 docket = nodemap_data[0]
739 if (
739 if (
740 len(d[0]) > docket.tip_rev
740 len(d[0]) > docket.tip_rev
741 and d[0][docket.tip_rev][7] == docket.tip_node
741 and d[0][docket.tip_rev][7] == docket.tip_node
742 ):
742 ):
743 # no changelog tampering
743 # no changelog tampering
744 self._nodemap_docket = docket
744 self._nodemap_docket = docket
745 index.update_nodemap_data(*nodemap_data)
745 index.update_nodemap_data(*nodemap_data)
746 except (ValueError, IndexError):
746 except (ValueError, IndexError):
747 raise error.RevlogError(
747 raise error.RevlogError(
748 _(b"index %s is corrupted") % self.display_id
748 _(b"index %s is corrupted") % self.display_id
749 )
749 )
750 self.index = index
750 self.index = index
751 self._segmentfile = randomaccessfile.randomaccessfile(
751 self._segmentfile = randomaccessfile.randomaccessfile(
752 self.opener,
752 self.opener,
753 (self._indexfile if self._inline else self._datafile),
753 (self._indexfile if self._inline else self._datafile),
754 self._chunkcachesize,
754 self._chunkcachesize,
755 chunkcache,
755 chunkcache,
756 )
756 )
757 self._segmentfile_sidedata = randomaccessfile.randomaccessfile(
757 self._segmentfile_sidedata = randomaccessfile.randomaccessfile(
758 self.opener,
758 self.opener,
759 self._sidedatafile,
759 self._sidedatafile,
760 self._chunkcachesize,
760 self._chunkcachesize,
761 )
761 )
762 # revnum -> (chain-length, sum-delta-length)
762 # revnum -> (chain-length, sum-delta-length)
763 self._chaininfocache = util.lrucachedict(500)
763 self._chaininfocache = util.lrucachedict(500)
764 # revlog header -> revlog compressor
764 # revlog header -> revlog compressor
765 self._decompressors = {}
765 self._decompressors = {}
766
766
767 def get_revlog(self):
767 def get_revlog(self):
768 """simple function to mirror API of other not-really-revlog API"""
768 """simple function to mirror API of other not-really-revlog API"""
769 return self
769 return self
770
770
771 @util.propertycache
771 @util.propertycache
772 def revlog_kind(self):
772 def revlog_kind(self):
773 return self.target[0]
773 return self.target[0]
774
774
775 @util.propertycache
775 @util.propertycache
776 def display_id(self):
776 def display_id(self):
777 """The public facing "ID" of the revlog that we use in message"""
777 """The public facing "ID" of the revlog that we use in message"""
778 if self.revlog_kind == KIND_FILELOG:
778 if self.revlog_kind == KIND_FILELOG:
779 # Reference the file without the "data/" prefix, so it is familiar
779 # Reference the file without the "data/" prefix, so it is familiar
780 # to the user.
780 # to the user.
781 return self.target[1]
781 return self.target[1]
782 else:
782 else:
783 return self.radix
783 return self.radix
784
784
785 def _get_decompressor(self, t):
785 def _get_decompressor(self, t):
786 try:
786 try:
787 compressor = self._decompressors[t]
787 compressor = self._decompressors[t]
788 except KeyError:
788 except KeyError:
789 try:
789 try:
790 engine = util.compengines.forrevlogheader(t)
790 engine = util.compengines.forrevlogheader(t)
791 compressor = engine.revlogcompressor(self._compengineopts)
791 compressor = engine.revlogcompressor(self._compengineopts)
792 self._decompressors[t] = compressor
792 self._decompressors[t] = compressor
793 except KeyError:
793 except KeyError:
794 raise error.RevlogError(
794 raise error.RevlogError(
795 _(b'unknown compression type %s') % binascii.hexlify(t)
795 _(b'unknown compression type %s') % binascii.hexlify(t)
796 )
796 )
797 return compressor
797 return compressor
798
798
799 @util.propertycache
799 @util.propertycache
800 def _compressor(self):
800 def _compressor(self):
801 engine = util.compengines[self._compengine]
801 engine = util.compengines[self._compengine]
802 return engine.revlogcompressor(self._compengineopts)
802 return engine.revlogcompressor(self._compengineopts)
803
803
804 @util.propertycache
804 @util.propertycache
805 def _decompressor(self):
805 def _decompressor(self):
806 """the default decompressor"""
806 """the default decompressor"""
807 if self._docket is None:
807 if self._docket is None:
808 return None
808 return None
809 t = self._docket.default_compression_header
809 t = self._docket.default_compression_header
810 c = self._get_decompressor(t)
810 c = self._get_decompressor(t)
811 return c.decompress
811 return c.decompress
812
812
813 def _indexfp(self):
813 def _indexfp(self):
814 """file object for the revlog's index file"""
814 """file object for the revlog's index file"""
815 return self.opener(self._indexfile, mode=b"r")
815 return self.opener(self._indexfile, mode=b"r")
816
816
817 def __index_write_fp(self):
817 def __index_write_fp(self):
818 # You should not use this directly and use `_writing` instead
818 # You should not use this directly and use `_writing` instead
819 try:
819 try:
820 f = self.opener(
820 f = self.opener(
821 self._indexfile, mode=b"r+", checkambig=self._checkambig
821 self._indexfile, mode=b"r+", checkambig=self._checkambig
822 )
822 )
823 if self._docket is None:
823 if self._docket is None:
824 f.seek(0, os.SEEK_END)
824 f.seek(0, os.SEEK_END)
825 else:
825 else:
826 f.seek(self._docket.index_end, os.SEEK_SET)
826 f.seek(self._docket.index_end, os.SEEK_SET)
827 return f
827 return f
828 except FileNotFoundError:
828 except FileNotFoundError:
829 return self.opener(
829 return self.opener(
830 self._indexfile, mode=b"w+", checkambig=self._checkambig
830 self._indexfile, mode=b"w+", checkambig=self._checkambig
831 )
831 )
832
832
833 def __index_new_fp(self):
833 def __index_new_fp(self):
834 # You should not use this unless you are upgrading from inline revlog
834 # You should not use this unless you are upgrading from inline revlog
835 return self.opener(
835 return self.opener(
836 self._indexfile,
836 self._indexfile,
837 mode=b"w",
837 mode=b"w",
838 checkambig=self._checkambig,
838 checkambig=self._checkambig,
839 atomictemp=True,
839 atomictemp=True,
840 )
840 )
841
841
842 def _datafp(self, mode=b'r'):
842 def _datafp(self, mode=b'r'):
843 """file object for the revlog's data file"""
843 """file object for the revlog's data file"""
844 return self.opener(self._datafile, mode=mode)
844 return self.opener(self._datafile, mode=mode)
845
845
846 @contextlib.contextmanager
846 @contextlib.contextmanager
847 def _sidedatareadfp(self):
847 def _sidedatareadfp(self):
848 """file object suitable to read sidedata"""
848 """file object suitable to read sidedata"""
849 if self._writinghandles:
849 if self._writinghandles:
850 yield self._writinghandles[2]
850 yield self._writinghandles[2]
851 else:
851 else:
852 with self.opener(self._sidedatafile) as fp:
852 with self.opener(self._sidedatafile) as fp:
853 yield fp
853 yield fp
854
854
855 def tiprev(self):
855 def tiprev(self):
856 return len(self.index) - 1
856 return len(self.index) - 1
857
857
858 def tip(self):
858 def tip(self):
859 return self.node(self.tiprev())
859 return self.node(self.tiprev())
860
860
861 def __contains__(self, rev):
861 def __contains__(self, rev):
862 return 0 <= rev < len(self)
862 return 0 <= rev < len(self)
863
863
864 def __len__(self):
864 def __len__(self):
865 return len(self.index)
865 return len(self.index)
866
866
867 def __iter__(self):
867 def __iter__(self):
868 return iter(range(len(self)))
868 return iter(range(len(self)))
869
869
870 def revs(self, start=0, stop=None):
870 def revs(self, start=0, stop=None):
871 """iterate over all rev in this revlog (from start to stop)"""
871 """iterate over all rev in this revlog (from start to stop)"""
872 return storageutil.iterrevs(len(self), start=start, stop=stop)
872 return storageutil.iterrevs(len(self), start=start, stop=stop)
873
873
874 def hasnode(self, node):
874 def hasnode(self, node):
875 try:
875 try:
876 self.rev(node)
876 self.rev(node)
877 return True
877 return True
878 except KeyError:
878 except KeyError:
879 return False
879 return False
880
880
881 def candelta(self, baserev, rev):
881 def candelta(self, baserev, rev):
882 """whether two revisions (baserev, rev) can be delta-ed or not"""
882 """whether two revisions (baserev, rev) can be delta-ed or not"""
883 # Disable delta if either rev requires a content-changing flag
883 # Disable delta if either rev requires a content-changing flag
884 # processor (ex. LFS). This is because such flag processor can alter
884 # processor (ex. LFS). This is because such flag processor can alter
885 # the rawtext content that the delta will be based on, and two clients
885 # the rawtext content that the delta will be based on, and two clients
886 # could have a same revlog node with different flags (i.e. different
886 # could have a same revlog node with different flags (i.e. different
887 # rawtext contents) and the delta could be incompatible.
887 # rawtext contents) and the delta could be incompatible.
888 if (self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS) or (
888 if (self.flags(baserev) & REVIDX_RAWTEXT_CHANGING_FLAGS) or (
889 self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS
889 self.flags(rev) & REVIDX_RAWTEXT_CHANGING_FLAGS
890 ):
890 ):
891 return False
891 return False
892 return True
892 return True
893
893
894 def update_caches(self, transaction):
894 def update_caches(self, transaction):
895 if self._nodemap_file is not None:
895 if self._nodemap_file is not None:
896 if transaction is None:
896 if transaction is None:
897 nodemaputil.update_persistent_nodemap(self)
897 nodemaputil.update_persistent_nodemap(self)
898 else:
898 else:
899 nodemaputil.setup_persistent_nodemap(transaction, self)
899 nodemaputil.setup_persistent_nodemap(transaction, self)
900
900
901 def clearcaches(self):
901 def clearcaches(self):
902 self._revisioncache = None
902 self._revisioncache = None
903 self._chainbasecache.clear()
903 self._chainbasecache.clear()
904 self._segmentfile.clear_cache()
904 self._segmentfile.clear_cache()
905 self._segmentfile_sidedata.clear_cache()
905 self._segmentfile_sidedata.clear_cache()
906 self._pcache = {}
906 self._pcache = {}
907 self._nodemap_docket = None
907 self._nodemap_docket = None
908 self.index.clearcaches()
908 self.index.clearcaches()
909 # The python code is the one responsible for validating the docket, we
909 # The python code is the one responsible for validating the docket, we
910 # end up having to refresh it here.
910 # end up having to refresh it here.
911 use_nodemap = (
911 use_nodemap = (
912 not self._inline
912 not self._inline
913 and self._nodemap_file is not None
913 and self._nodemap_file is not None
914 and util.safehasattr(self.index, 'update_nodemap_data')
914 and util.safehasattr(self.index, 'update_nodemap_data')
915 )
915 )
916 if use_nodemap:
916 if use_nodemap:
917 nodemap_data = nodemaputil.persisted_data(self)
917 nodemap_data = nodemaputil.persisted_data(self)
918 if nodemap_data is not None:
918 if nodemap_data is not None:
919 self._nodemap_docket = nodemap_data[0]
919 self._nodemap_docket = nodemap_data[0]
920 self.index.update_nodemap_data(*nodemap_data)
920 self.index.update_nodemap_data(*nodemap_data)
921
921
922 def rev(self, node):
922 def rev(self, node):
923 try:
923 try:
924 return self.index.rev(node)
924 return self.index.rev(node)
925 except TypeError:
925 except TypeError:
926 raise
926 raise
927 except error.RevlogError:
927 except error.RevlogError:
928 # parsers.c radix tree lookup failed
928 # parsers.c radix tree lookup failed
929 if (
929 if (
930 node == self.nodeconstants.wdirid
930 node == self.nodeconstants.wdirid
931 or node in self.nodeconstants.wdirfilenodeids
931 or node in self.nodeconstants.wdirfilenodeids
932 ):
932 ):
933 raise error.WdirUnsupported
933 raise error.WdirUnsupported
934 raise error.LookupError(node, self.display_id, _(b'no node'))
934 raise error.LookupError(node, self.display_id, _(b'no node'))
935
935
936 # Accessors for index entries.
936 # Accessors for index entries.
937
937
938 # First tuple entry is 8 bytes. First 6 bytes are offset. Last 2 bytes
938 # First tuple entry is 8 bytes. First 6 bytes are offset. Last 2 bytes
939 # are flags.
939 # are flags.
940 def start(self, rev):
940 def start(self, rev):
941 return int(self.index[rev][0] >> 16)
941 return int(self.index[rev][0] >> 16)
942
942
943 def sidedata_cut_off(self, rev):
943 def sidedata_cut_off(self, rev):
944 sd_cut_off = self.index[rev][8]
944 sd_cut_off = self.index[rev][8]
945 if sd_cut_off != 0:
945 if sd_cut_off != 0:
946 return sd_cut_off
946 return sd_cut_off
947 # This is some annoying dance, because entries without sidedata
947 # This is some annoying dance, because entries without sidedata
948 # currently use 0 as their ofsset. (instead of previous-offset +
948 # currently use 0 as their ofsset. (instead of previous-offset +
949 # previous-size)
949 # previous-size)
950 #
950 #
951 # We should reconsider this sidedata → 0 sidata_offset policy.
951 # We should reconsider this sidedata → 0 sidata_offset policy.
952 # In the meantime, we need this.
952 # In the meantime, we need this.
953 while 0 <= rev:
953 while 0 <= rev:
954 e = self.index[rev]
954 e = self.index[rev]
955 if e[9] != 0:
955 if e[9] != 0:
956 return e[8] + e[9]
956 return e[8] + e[9]
957 rev -= 1
957 rev -= 1
958 return 0
958 return 0
959
959
960 def flags(self, rev):
960 def flags(self, rev):
961 return self.index[rev][0] & 0xFFFF
961 return self.index[rev][0] & 0xFFFF
962
962
963 def length(self, rev):
963 def length(self, rev):
964 return self.index[rev][1]
964 return self.index[rev][1]
965
965
966 def sidedata_length(self, rev):
966 def sidedata_length(self, rev):
967 if not self.hassidedata:
967 if not self.hassidedata:
968 return 0
968 return 0
969 return self.index[rev][9]
969 return self.index[rev][9]
970
970
971 def rawsize(self, rev):
971 def rawsize(self, rev):
972 """return the length of the uncompressed text for a given revision"""
972 """return the length of the uncompressed text for a given revision"""
973 l = self.index[rev][2]
973 l = self.index[rev][2]
974 if l >= 0:
974 if l >= 0:
975 return l
975 return l
976
976
977 t = self.rawdata(rev)
977 t = self.rawdata(rev)
978 return len(t)
978 return len(t)
979
979
980 def size(self, rev):
980 def size(self, rev):
981 """length of non-raw text (processed by a "read" flag processor)"""
981 """length of non-raw text (processed by a "read" flag processor)"""
982 # fast path: if no "read" flag processor could change the content,
982 # fast path: if no "read" flag processor could change the content,
983 # size is rawsize. note: ELLIPSIS is known to not change the content.
983 # size is rawsize. note: ELLIPSIS is known to not change the content.
984 flags = self.flags(rev)
984 flags = self.flags(rev)
985 if flags & (flagutil.REVIDX_KNOWN_FLAGS ^ REVIDX_ELLIPSIS) == 0:
985 if flags & (flagutil.REVIDX_KNOWN_FLAGS ^ REVIDX_ELLIPSIS) == 0:
986 return self.rawsize(rev)
986 return self.rawsize(rev)
987
987
988 return len(self.revision(rev))
988 return len(self.revision(rev))
989
989
990 def fast_rank(self, rev):
990 def fast_rank(self, rev):
991 """Return the rank of a revision if already known, or None otherwise.
991 """Return the rank of a revision if already known, or None otherwise.
992
992
993 The rank of a revision is the size of the sub-graph it defines as a
993 The rank of a revision is the size of the sub-graph it defines as a
994 head. Equivalently, the rank of a revision `r` is the size of the set
994 head. Equivalently, the rank of a revision `r` is the size of the set
995 `ancestors(r)`, `r` included.
995 `ancestors(r)`, `r` included.
996
996
997 This method returns the rank retrieved from the revlog in constant
997 This method returns the rank retrieved from the revlog in constant
998 time. It makes no attempt at computing unknown values for versions of
998 time. It makes no attempt at computing unknown values for versions of
999 the revlog which do not persist the rank.
999 the revlog which do not persist the rank.
1000 """
1000 """
1001 rank = self.index[rev][ENTRY_RANK]
1001 rank = self.index[rev][ENTRY_RANK]
1002 if self._format_version != CHANGELOGV2 or rank == RANK_UNKNOWN:
1002 if self._format_version != CHANGELOGV2 or rank == RANK_UNKNOWN:
1003 return None
1003 return None
1004 if rev == nullrev:
1004 if rev == nullrev:
1005 return 0 # convention
1005 return 0 # convention
1006 return rank
1006 return rank
1007
1007
1008 def chainbase(self, rev):
1008 def chainbase(self, rev):
1009 base = self._chainbasecache.get(rev)
1009 base = self._chainbasecache.get(rev)
1010 if base is not None:
1010 if base is not None:
1011 return base
1011 return base
1012
1012
1013 index = self.index
1013 index = self.index
1014 iterrev = rev
1014 iterrev = rev
1015 base = index[iterrev][3]
1015 base = index[iterrev][3]
1016 while base != iterrev:
1016 while base != iterrev:
1017 iterrev = base
1017 iterrev = base
1018 base = index[iterrev][3]
1018 base = index[iterrev][3]
1019
1019
1020 self._chainbasecache[rev] = base
1020 self._chainbasecache[rev] = base
1021 return base
1021 return base
1022
1022
1023 def linkrev(self, rev):
1023 def linkrev(self, rev):
1024 return self.index[rev][4]
1024 return self.index[rev][4]
1025
1025
1026 def parentrevs(self, rev):
1026 def parentrevs(self, rev):
1027 try:
1027 try:
1028 entry = self.index[rev]
1028 entry = self.index[rev]
1029 except IndexError:
1029 except IndexError:
1030 if rev == wdirrev:
1030 if rev == wdirrev:
1031 raise error.WdirUnsupported
1031 raise error.WdirUnsupported
1032 raise
1032 raise
1033
1033
1034 if self.canonical_parent_order and entry[5] == nullrev:
1034 if self.canonical_parent_order and entry[5] == nullrev:
1035 return entry[6], entry[5]
1035 return entry[6], entry[5]
1036 else:
1036 else:
1037 return entry[5], entry[6]
1037 return entry[5], entry[6]
1038
1038
1039 # fast parentrevs(rev) where rev isn't filtered
1039 # fast parentrevs(rev) where rev isn't filtered
1040 _uncheckedparentrevs = parentrevs
1040 _uncheckedparentrevs = parentrevs
1041
1041
1042 def node(self, rev):
1042 def node(self, rev):
1043 try:
1043 try:
1044 return self.index[rev][7]
1044 return self.index[rev][7]
1045 except IndexError:
1045 except IndexError:
1046 if rev == wdirrev:
1046 if rev == wdirrev:
1047 raise error.WdirUnsupported
1047 raise error.WdirUnsupported
1048 raise
1048 raise
1049
1049
1050 # Derived from index values.
1050 # Derived from index values.
1051
1051
1052 def end(self, rev):
1052 def end(self, rev):
1053 return self.start(rev) + self.length(rev)
1053 return self.start(rev) + self.length(rev)
1054
1054
1055 def parents(self, node):
1055 def parents(self, node):
1056 i = self.index
1056 i = self.index
1057 d = i[self.rev(node)]
1057 d = i[self.rev(node)]
1058 # inline node() to avoid function call overhead
1058 # inline node() to avoid function call overhead
1059 if self.canonical_parent_order and d[5] == self.nullid:
1059 if self.canonical_parent_order and d[5] == self.nullid:
1060 return i[d[6]][7], i[d[5]][7]
1060 return i[d[6]][7], i[d[5]][7]
1061 else:
1061 else:
1062 return i[d[5]][7], i[d[6]][7]
1062 return i[d[5]][7], i[d[6]][7]
1063
1063
1064 def chainlen(self, rev):
1064 def chainlen(self, rev):
1065 return self._chaininfo(rev)[0]
1065 return self._chaininfo(rev)[0]
1066
1066
1067 def _chaininfo(self, rev):
1067 def _chaininfo(self, rev):
1068 chaininfocache = self._chaininfocache
1068 chaininfocache = self._chaininfocache
1069 if rev in chaininfocache:
1069 if rev in chaininfocache:
1070 return chaininfocache[rev]
1070 return chaininfocache[rev]
1071 index = self.index
1071 index = self.index
1072 generaldelta = self._generaldelta
1072 generaldelta = self._generaldelta
1073 iterrev = rev
1073 iterrev = rev
1074 e = index[iterrev]
1074 e = index[iterrev]
1075 clen = 0
1075 clen = 0
1076 compresseddeltalen = 0
1076 compresseddeltalen = 0
1077 while iterrev != e[3]:
1077 while iterrev != e[3]:
1078 clen += 1
1078 clen += 1
1079 compresseddeltalen += e[1]
1079 compresseddeltalen += e[1]
1080 if generaldelta:
1080 if generaldelta:
1081 iterrev = e[3]
1081 iterrev = e[3]
1082 else:
1082 else:
1083 iterrev -= 1
1083 iterrev -= 1
1084 if iterrev in chaininfocache:
1084 if iterrev in chaininfocache:
1085 t = chaininfocache[iterrev]
1085 t = chaininfocache[iterrev]
1086 clen += t[0]
1086 clen += t[0]
1087 compresseddeltalen += t[1]
1087 compresseddeltalen += t[1]
1088 break
1088 break
1089 e = index[iterrev]
1089 e = index[iterrev]
1090 else:
1090 else:
1091 # Add text length of base since decompressing that also takes
1091 # Add text length of base since decompressing that also takes
1092 # work. For cache hits the length is already included.
1092 # work. For cache hits the length is already included.
1093 compresseddeltalen += e[1]
1093 compresseddeltalen += e[1]
1094 r = (clen, compresseddeltalen)
1094 r = (clen, compresseddeltalen)
1095 chaininfocache[rev] = r
1095 chaininfocache[rev] = r
1096 return r
1096 return r
1097
1097
1098 def _deltachain(self, rev, stoprev=None):
1098 def _deltachain(self, rev, stoprev=None):
1099 """Obtain the delta chain for a revision.
1099 """Obtain the delta chain for a revision.
1100
1100
1101 ``stoprev`` specifies a revision to stop at. If not specified, we
1101 ``stoprev`` specifies a revision to stop at. If not specified, we
1102 stop at the base of the chain.
1102 stop at the base of the chain.
1103
1103
1104 Returns a 2-tuple of (chain, stopped) where ``chain`` is a list of
1104 Returns a 2-tuple of (chain, stopped) where ``chain`` is a list of
1105 revs in ascending order and ``stopped`` is a bool indicating whether
1105 revs in ascending order and ``stopped`` is a bool indicating whether
1106 ``stoprev`` was hit.
1106 ``stoprev`` was hit.
1107 """
1107 """
1108 # Try C implementation.
1108 # Try C implementation.
1109 try:
1109 try:
1110 return self.index.deltachain(rev, stoprev, self._generaldelta)
1110 return self.index.deltachain(rev, stoprev, self._generaldelta)
1111 except AttributeError:
1111 except AttributeError:
1112 pass
1112 pass
1113
1113
1114 chain = []
1114 chain = []
1115
1115
1116 # Alias to prevent attribute lookup in tight loop.
1116 # Alias to prevent attribute lookup in tight loop.
1117 index = self.index
1117 index = self.index
1118 generaldelta = self._generaldelta
1118 generaldelta = self._generaldelta
1119
1119
1120 iterrev = rev
1120 iterrev = rev
1121 e = index[iterrev]
1121 e = index[iterrev]
1122 while iterrev != e[3] and iterrev != stoprev:
1122 while iterrev != e[3] and iterrev != stoprev:
1123 chain.append(iterrev)
1123 chain.append(iterrev)
1124 if generaldelta:
1124 if generaldelta:
1125 iterrev = e[3]
1125 iterrev = e[3]
1126 else:
1126 else:
1127 iterrev -= 1
1127 iterrev -= 1
1128 e = index[iterrev]
1128 e = index[iterrev]
1129
1129
1130 if iterrev == stoprev:
1130 if iterrev == stoprev:
1131 stopped = True
1131 stopped = True
1132 else:
1132 else:
1133 chain.append(iterrev)
1133 chain.append(iterrev)
1134 stopped = False
1134 stopped = False
1135
1135
1136 chain.reverse()
1136 chain.reverse()
1137 return chain, stopped
1137 return chain, stopped
1138
1138
1139 def ancestors(self, revs, stoprev=0, inclusive=False):
1139 def ancestors(self, revs, stoprev=0, inclusive=False):
1140 """Generate the ancestors of 'revs' in reverse revision order.
1140 """Generate the ancestors of 'revs' in reverse revision order.
1141 Does not generate revs lower than stoprev.
1141 Does not generate revs lower than stoprev.
1142
1142
1143 See the documentation for ancestor.lazyancestors for more details."""
1143 See the documentation for ancestor.lazyancestors for more details."""
1144
1144
1145 # first, make sure start revisions aren't filtered
1145 # first, make sure start revisions aren't filtered
1146 revs = list(revs)
1146 revs = list(revs)
1147 checkrev = self.node
1147 checkrev = self.node
1148 for r in revs:
1148 for r in revs:
1149 checkrev(r)
1149 checkrev(r)
1150 # and we're sure ancestors aren't filtered as well
1150 # and we're sure ancestors aren't filtered as well
1151
1151
1152 if rustancestor is not None and self.index.rust_ext_compat:
1152 if rustancestor is not None and self.index.rust_ext_compat:
1153 lazyancestors = rustancestor.LazyAncestors
1153 lazyancestors = rustancestor.LazyAncestors
1154 arg = self.index
1154 arg = self.index
1155 else:
1155 else:
1156 lazyancestors = ancestor.lazyancestors
1156 lazyancestors = ancestor.lazyancestors
1157 arg = self._uncheckedparentrevs
1157 arg = self._uncheckedparentrevs
1158 return lazyancestors(arg, revs, stoprev=stoprev, inclusive=inclusive)
1158 return lazyancestors(arg, revs, stoprev=stoprev, inclusive=inclusive)
1159
1159
1160 def descendants(self, revs):
1160 def descendants(self, revs):
1161 return dagop.descendantrevs(revs, self.revs, self.parentrevs)
1161 return dagop.descendantrevs(revs, self.revs, self.parentrevs)
1162
1162
1163 def findcommonmissing(self, common=None, heads=None):
1163 def findcommonmissing(self, common=None, heads=None):
1164 """Return a tuple of the ancestors of common and the ancestors of heads
1164 """Return a tuple of the ancestors of common and the ancestors of heads
1165 that are not ancestors of common. In revset terminology, we return the
1165 that are not ancestors of common. In revset terminology, we return the
1166 tuple:
1166 tuple:
1167
1167
1168 ::common, (::heads) - (::common)
1168 ::common, (::heads) - (::common)
1169
1169
1170 The list is sorted by revision number, meaning it is
1170 The list is sorted by revision number, meaning it is
1171 topologically sorted.
1171 topologically sorted.
1172
1172
1173 'heads' and 'common' are both lists of node IDs. If heads is
1173 'heads' and 'common' are both lists of node IDs. If heads is
1174 not supplied, uses all of the revlog's heads. If common is not
1174 not supplied, uses all of the revlog's heads. If common is not
1175 supplied, uses nullid."""
1175 supplied, uses nullid."""
1176 if common is None:
1176 if common is None:
1177 common = [self.nullid]
1177 common = [self.nullid]
1178 if heads is None:
1178 if heads is None:
1179 heads = self.heads()
1179 heads = self.heads()
1180
1180
1181 common = [self.rev(n) for n in common]
1181 common = [self.rev(n) for n in common]
1182 heads = [self.rev(n) for n in heads]
1182 heads = [self.rev(n) for n in heads]
1183
1183
1184 # we want the ancestors, but inclusive
1184 # we want the ancestors, but inclusive
1185 class lazyset:
1185 class lazyset:
1186 def __init__(self, lazyvalues):
1186 def __init__(self, lazyvalues):
1187 self.addedvalues = set()
1187 self.addedvalues = set()
1188 self.lazyvalues = lazyvalues
1188 self.lazyvalues = lazyvalues
1189
1189
1190 def __contains__(self, value):
1190 def __contains__(self, value):
1191 return value in self.addedvalues or value in self.lazyvalues
1191 return value in self.addedvalues or value in self.lazyvalues
1192
1192
1193 def __iter__(self):
1193 def __iter__(self):
1194 added = self.addedvalues
1194 added = self.addedvalues
1195 for r in added:
1195 for r in added:
1196 yield r
1196 yield r
1197 for r in self.lazyvalues:
1197 for r in self.lazyvalues:
1198 if not r in added:
1198 if not r in added:
1199 yield r
1199 yield r
1200
1200
1201 def add(self, value):
1201 def add(self, value):
1202 self.addedvalues.add(value)
1202 self.addedvalues.add(value)
1203
1203
1204 def update(self, values):
1204 def update(self, values):
1205 self.addedvalues.update(values)
1205 self.addedvalues.update(values)
1206
1206
1207 has = lazyset(self.ancestors(common))
1207 has = lazyset(self.ancestors(common))
1208 has.add(nullrev)
1208 has.add(nullrev)
1209 has.update(common)
1209 has.update(common)
1210
1210
1211 # take all ancestors from heads that aren't in has
1211 # take all ancestors from heads that aren't in has
1212 missing = set()
1212 missing = set()
1213 visit = collections.deque(r for r in heads if r not in has)
1213 visit = collections.deque(r for r in heads if r not in has)
1214 while visit:
1214 while visit:
1215 r = visit.popleft()
1215 r = visit.popleft()
1216 if r in missing:
1216 if r in missing:
1217 continue
1217 continue
1218 else:
1218 else:
1219 missing.add(r)
1219 missing.add(r)
1220 for p in self.parentrevs(r):
1220 for p in self.parentrevs(r):
1221 if p not in has:
1221 if p not in has:
1222 visit.append(p)
1222 visit.append(p)
1223 missing = list(missing)
1223 missing = list(missing)
1224 missing.sort()
1224 missing.sort()
1225 return has, [self.node(miss) for miss in missing]
1225 return has, [self.node(miss) for miss in missing]
1226
1226
1227 def incrementalmissingrevs(self, common=None):
1227 def incrementalmissingrevs(self, common=None):
1228 """Return an object that can be used to incrementally compute the
1228 """Return an object that can be used to incrementally compute the
1229 revision numbers of the ancestors of arbitrary sets that are not
1229 revision numbers of the ancestors of arbitrary sets that are not
1230 ancestors of common. This is an ancestor.incrementalmissingancestors
1230 ancestors of common. This is an ancestor.incrementalmissingancestors
1231 object.
1231 object.
1232
1232
1233 'common' is a list of revision numbers. If common is not supplied, uses
1233 'common' is a list of revision numbers. If common is not supplied, uses
1234 nullrev.
1234 nullrev.
1235 """
1235 """
1236 if common is None:
1236 if common is None:
1237 common = [nullrev]
1237 common = [nullrev]
1238
1238
1239 if rustancestor is not None and self.index.rust_ext_compat:
1239 if rustancestor is not None and self.index.rust_ext_compat:
1240 return rustancestor.MissingAncestors(self.index, common)
1240 return rustancestor.MissingAncestors(self.index, common)
1241 return ancestor.incrementalmissingancestors(self.parentrevs, common)
1241 return ancestor.incrementalmissingancestors(self.parentrevs, common)
1242
1242
1243 def findmissingrevs(self, common=None, heads=None):
1243 def findmissingrevs(self, common=None, heads=None):
1244 """Return the revision numbers of the ancestors of heads that
1244 """Return the revision numbers of the ancestors of heads that
1245 are not ancestors of common.
1245 are not ancestors of common.
1246
1246
1247 More specifically, return a list of revision numbers corresponding to
1247 More specifically, return a list of revision numbers corresponding to
1248 nodes N such that every N satisfies the following constraints:
1248 nodes N such that every N satisfies the following constraints:
1249
1249
1250 1. N is an ancestor of some node in 'heads'
1250 1. N is an ancestor of some node in 'heads'
1251 2. N is not an ancestor of any node in 'common'
1251 2. N is not an ancestor of any node in 'common'
1252
1252
1253 The list is sorted by revision number, meaning it is
1253 The list is sorted by revision number, meaning it is
1254 topologically sorted.
1254 topologically sorted.
1255
1255
1256 'heads' and 'common' are both lists of revision numbers. If heads is
1256 'heads' and 'common' are both lists of revision numbers. If heads is
1257 not supplied, uses all of the revlog's heads. If common is not
1257 not supplied, uses all of the revlog's heads. If common is not
1258 supplied, uses nullid."""
1258 supplied, uses nullid."""
1259 if common is None:
1259 if common is None:
1260 common = [nullrev]
1260 common = [nullrev]
1261 if heads is None:
1261 if heads is None:
1262 heads = self.headrevs()
1262 heads = self.headrevs()
1263
1263
1264 inc = self.incrementalmissingrevs(common=common)
1264 inc = self.incrementalmissingrevs(common=common)
1265 return inc.missingancestors(heads)
1265 return inc.missingancestors(heads)
1266
1266
1267 def findmissing(self, common=None, heads=None):
1267 def findmissing(self, common=None, heads=None):
1268 """Return the ancestors of heads that are not ancestors of common.
1268 """Return the ancestors of heads that are not ancestors of common.
1269
1269
1270 More specifically, return a list of nodes N such that every N
1270 More specifically, return a list of nodes N such that every N
1271 satisfies the following constraints:
1271 satisfies the following constraints:
1272
1272
1273 1. N is an ancestor of some node in 'heads'
1273 1. N is an ancestor of some node in 'heads'
1274 2. N is not an ancestor of any node in 'common'
1274 2. N is not an ancestor of any node in 'common'
1275
1275
1276 The list is sorted by revision number, meaning it is
1276 The list is sorted by revision number, meaning it is
1277 topologically sorted.
1277 topologically sorted.
1278
1278
1279 'heads' and 'common' are both lists of node IDs. If heads is
1279 'heads' and 'common' are both lists of node IDs. If heads is
1280 not supplied, uses all of the revlog's heads. If common is not
1280 not supplied, uses all of the revlog's heads. If common is not
1281 supplied, uses nullid."""
1281 supplied, uses nullid."""
1282 if common is None:
1282 if common is None:
1283 common = [self.nullid]
1283 common = [self.nullid]
1284 if heads is None:
1284 if heads is None:
1285 heads = self.heads()
1285 heads = self.heads()
1286
1286
1287 common = [self.rev(n) for n in common]
1287 common = [self.rev(n) for n in common]
1288 heads = [self.rev(n) for n in heads]
1288 heads = [self.rev(n) for n in heads]
1289
1289
1290 inc = self.incrementalmissingrevs(common=common)
1290 inc = self.incrementalmissingrevs(common=common)
1291 return [self.node(r) for r in inc.missingancestors(heads)]
1291 return [self.node(r) for r in inc.missingancestors(heads)]
1292
1292
1293 def nodesbetween(self, roots=None, heads=None):
1293 def nodesbetween(self, roots=None, heads=None):
1294 """Return a topological path from 'roots' to 'heads'.
1294 """Return a topological path from 'roots' to 'heads'.
1295
1295
1296 Return a tuple (nodes, outroots, outheads) where 'nodes' is a
1296 Return a tuple (nodes, outroots, outheads) where 'nodes' is a
1297 topologically sorted list of all nodes N that satisfy both of
1297 topologically sorted list of all nodes N that satisfy both of
1298 these constraints:
1298 these constraints:
1299
1299
1300 1. N is a descendant of some node in 'roots'
1300 1. N is a descendant of some node in 'roots'
1301 2. N is an ancestor of some node in 'heads'
1301 2. N is an ancestor of some node in 'heads'
1302
1302
1303 Every node is considered to be both a descendant and an ancestor
1303 Every node is considered to be both a descendant and an ancestor
1304 of itself, so every reachable node in 'roots' and 'heads' will be
1304 of itself, so every reachable node in 'roots' and 'heads' will be
1305 included in 'nodes'.
1305 included in 'nodes'.
1306
1306
1307 'outroots' is the list of reachable nodes in 'roots', i.e., the
1307 'outroots' is the list of reachable nodes in 'roots', i.e., the
1308 subset of 'roots' that is returned in 'nodes'. Likewise,
1308 subset of 'roots' that is returned in 'nodes'. Likewise,
1309 'outheads' is the subset of 'heads' that is also in 'nodes'.
1309 'outheads' is the subset of 'heads' that is also in 'nodes'.
1310
1310
1311 'roots' and 'heads' are both lists of node IDs. If 'roots' is
1311 'roots' and 'heads' are both lists of node IDs. If 'roots' is
1312 unspecified, uses nullid as the only root. If 'heads' is
1312 unspecified, uses nullid as the only root. If 'heads' is
1313 unspecified, uses list of all of the revlog's heads."""
1313 unspecified, uses list of all of the revlog's heads."""
1314 nonodes = ([], [], [])
1314 nonodes = ([], [], [])
1315 if roots is not None:
1315 if roots is not None:
1316 roots = list(roots)
1316 roots = list(roots)
1317 if not roots:
1317 if not roots:
1318 return nonodes
1318 return nonodes
1319 lowestrev = min([self.rev(n) for n in roots])
1319 lowestrev = min([self.rev(n) for n in roots])
1320 else:
1320 else:
1321 roots = [self.nullid] # Everybody's a descendant of nullid
1321 roots = [self.nullid] # Everybody's a descendant of nullid
1322 lowestrev = nullrev
1322 lowestrev = nullrev
1323 if (lowestrev == nullrev) and (heads is None):
1323 if (lowestrev == nullrev) and (heads is None):
1324 # We want _all_ the nodes!
1324 # We want _all_ the nodes!
1325 return (
1325 return (
1326 [self.node(r) for r in self],
1326 [self.node(r) for r in self],
1327 [self.nullid],
1327 [self.nullid],
1328 list(self.heads()),
1328 list(self.heads()),
1329 )
1329 )
1330 if heads is None:
1330 if heads is None:
1331 # All nodes are ancestors, so the latest ancestor is the last
1331 # All nodes are ancestors, so the latest ancestor is the last
1332 # node.
1332 # node.
1333 highestrev = len(self) - 1
1333 highestrev = len(self) - 1
1334 # Set ancestors to None to signal that every node is an ancestor.
1334 # Set ancestors to None to signal that every node is an ancestor.
1335 ancestors = None
1335 ancestors = None
1336 # Set heads to an empty dictionary for later discovery of heads
1336 # Set heads to an empty dictionary for later discovery of heads
1337 heads = {}
1337 heads = {}
1338 else:
1338 else:
1339 heads = list(heads)
1339 heads = list(heads)
1340 if not heads:
1340 if not heads:
1341 return nonodes
1341 return nonodes
1342 ancestors = set()
1342 ancestors = set()
1343 # Turn heads into a dictionary so we can remove 'fake' heads.
1343 # Turn heads into a dictionary so we can remove 'fake' heads.
1344 # Also, later we will be using it to filter out the heads we can't
1344 # Also, later we will be using it to filter out the heads we can't
1345 # find from roots.
1345 # find from roots.
1346 heads = dict.fromkeys(heads, False)
1346 heads = dict.fromkeys(heads, False)
1347 # Start at the top and keep marking parents until we're done.
1347 # Start at the top and keep marking parents until we're done.
1348 nodestotag = set(heads)
1348 nodestotag = set(heads)
1349 # Remember where the top was so we can use it as a limit later.
1349 # Remember where the top was so we can use it as a limit later.
1350 highestrev = max([self.rev(n) for n in nodestotag])
1350 highestrev = max([self.rev(n) for n in nodestotag])
1351 while nodestotag:
1351 while nodestotag:
1352 # grab a node to tag
1352 # grab a node to tag
1353 n = nodestotag.pop()
1353 n = nodestotag.pop()
1354 # Never tag nullid
1354 # Never tag nullid
1355 if n == self.nullid:
1355 if n == self.nullid:
1356 continue
1356 continue
1357 # A node's revision number represents its place in a
1357 # A node's revision number represents its place in a
1358 # topologically sorted list of nodes.
1358 # topologically sorted list of nodes.
1359 r = self.rev(n)
1359 r = self.rev(n)
1360 if r >= lowestrev:
1360 if r >= lowestrev:
1361 if n not in ancestors:
1361 if n not in ancestors:
1362 # If we are possibly a descendant of one of the roots
1362 # If we are possibly a descendant of one of the roots
1363 # and we haven't already been marked as an ancestor
1363 # and we haven't already been marked as an ancestor
1364 ancestors.add(n) # Mark as ancestor
1364 ancestors.add(n) # Mark as ancestor
1365 # Add non-nullid parents to list of nodes to tag.
1365 # Add non-nullid parents to list of nodes to tag.
1366 nodestotag.update(
1366 nodestotag.update(
1367 [p for p in self.parents(n) if p != self.nullid]
1367 [p for p in self.parents(n) if p != self.nullid]
1368 )
1368 )
1369 elif n in heads: # We've seen it before, is it a fake head?
1369 elif n in heads: # We've seen it before, is it a fake head?
1370 # So it is, real heads should not be the ancestors of
1370 # So it is, real heads should not be the ancestors of
1371 # any other heads.
1371 # any other heads.
1372 heads.pop(n)
1372 heads.pop(n)
1373 if not ancestors:
1373 if not ancestors:
1374 return nonodes
1374 return nonodes
1375 # Now that we have our set of ancestors, we want to remove any
1375 # Now that we have our set of ancestors, we want to remove any
1376 # roots that are not ancestors.
1376 # roots that are not ancestors.
1377
1377
1378 # If one of the roots was nullid, everything is included anyway.
1378 # If one of the roots was nullid, everything is included anyway.
1379 if lowestrev > nullrev:
1379 if lowestrev > nullrev:
1380 # But, since we weren't, let's recompute the lowest rev to not
1380 # But, since we weren't, let's recompute the lowest rev to not
1381 # include roots that aren't ancestors.
1381 # include roots that aren't ancestors.
1382
1382
1383 # Filter out roots that aren't ancestors of heads
1383 # Filter out roots that aren't ancestors of heads
1384 roots = [root for root in roots if root in ancestors]
1384 roots = [root for root in roots if root in ancestors]
1385 # Recompute the lowest revision
1385 # Recompute the lowest revision
1386 if roots:
1386 if roots:
1387 lowestrev = min([self.rev(root) for root in roots])
1387 lowestrev = min([self.rev(root) for root in roots])
1388 else:
1388 else:
1389 # No more roots? Return empty list
1389 # No more roots? Return empty list
1390 return nonodes
1390 return nonodes
1391 else:
1391 else:
1392 # We are descending from nullid, and don't need to care about
1392 # We are descending from nullid, and don't need to care about
1393 # any other roots.
1393 # any other roots.
1394 lowestrev = nullrev
1394 lowestrev = nullrev
1395 roots = [self.nullid]
1395 roots = [self.nullid]
1396 # Transform our roots list into a set.
1396 # Transform our roots list into a set.
1397 descendants = set(roots)
1397 descendants = set(roots)
1398 # Also, keep the original roots so we can filter out roots that aren't
1398 # Also, keep the original roots so we can filter out roots that aren't
1399 # 'real' roots (i.e. are descended from other roots).
1399 # 'real' roots (i.e. are descended from other roots).
1400 roots = descendants.copy()
1400 roots = descendants.copy()
1401 # Our topologically sorted list of output nodes.
1401 # Our topologically sorted list of output nodes.
1402 orderedout = []
1402 orderedout = []
1403 # Don't start at nullid since we don't want nullid in our output list,
1403 # Don't start at nullid since we don't want nullid in our output list,
1404 # and if nullid shows up in descendants, empty parents will look like
1404 # and if nullid shows up in descendants, empty parents will look like
1405 # they're descendants.
1405 # they're descendants.
1406 for r in self.revs(start=max(lowestrev, 0), stop=highestrev + 1):
1406 for r in self.revs(start=max(lowestrev, 0), stop=highestrev + 1):
1407 n = self.node(r)
1407 n = self.node(r)
1408 isdescendant = False
1408 isdescendant = False
1409 if lowestrev == nullrev: # Everybody is a descendant of nullid
1409 if lowestrev == nullrev: # Everybody is a descendant of nullid
1410 isdescendant = True
1410 isdescendant = True
1411 elif n in descendants:
1411 elif n in descendants:
1412 # n is already a descendant
1412 # n is already a descendant
1413 isdescendant = True
1413 isdescendant = True
1414 # This check only needs to be done here because all the roots
1414 # This check only needs to be done here because all the roots
1415 # will start being marked is descendants before the loop.
1415 # will start being marked is descendants before the loop.
1416 if n in roots:
1416 if n in roots:
1417 # If n was a root, check if it's a 'real' root.
1417 # If n was a root, check if it's a 'real' root.
1418 p = tuple(self.parents(n))
1418 p = tuple(self.parents(n))
1419 # If any of its parents are descendants, it's not a root.
1419 # If any of its parents are descendants, it's not a root.
1420 if (p[0] in descendants) or (p[1] in descendants):
1420 if (p[0] in descendants) or (p[1] in descendants):
1421 roots.remove(n)
1421 roots.remove(n)
1422 else:
1422 else:
1423 p = tuple(self.parents(n))
1423 p = tuple(self.parents(n))
1424 # A node is a descendant if either of its parents are
1424 # A node is a descendant if either of its parents are
1425 # descendants. (We seeded the dependents list with the roots
1425 # descendants. (We seeded the dependents list with the roots
1426 # up there, remember?)
1426 # up there, remember?)
1427 if (p[0] in descendants) or (p[1] in descendants):
1427 if (p[0] in descendants) or (p[1] in descendants):
1428 descendants.add(n)
1428 descendants.add(n)
1429 isdescendant = True
1429 isdescendant = True
1430 if isdescendant and ((ancestors is None) or (n in ancestors)):
1430 if isdescendant and ((ancestors is None) or (n in ancestors)):
1431 # Only include nodes that are both descendants and ancestors.
1431 # Only include nodes that are both descendants and ancestors.
1432 orderedout.append(n)
1432 orderedout.append(n)
1433 if (ancestors is not None) and (n in heads):
1433 if (ancestors is not None) and (n in heads):
1434 # We're trying to figure out which heads are reachable
1434 # We're trying to figure out which heads are reachable
1435 # from roots.
1435 # from roots.
1436 # Mark this head as having been reached
1436 # Mark this head as having been reached
1437 heads[n] = True
1437 heads[n] = True
1438 elif ancestors is None:
1438 elif ancestors is None:
1439 # Otherwise, we're trying to discover the heads.
1439 # Otherwise, we're trying to discover the heads.
1440 # Assume this is a head because if it isn't, the next step
1440 # Assume this is a head because if it isn't, the next step
1441 # will eventually remove it.
1441 # will eventually remove it.
1442 heads[n] = True
1442 heads[n] = True
1443 # But, obviously its parents aren't.
1443 # But, obviously its parents aren't.
1444 for p in self.parents(n):
1444 for p in self.parents(n):
1445 heads.pop(p, None)
1445 heads.pop(p, None)
1446 heads = [head for head, flag in heads.items() if flag]
1446 heads = [head for head, flag in heads.items() if flag]
1447 roots = list(roots)
1447 roots = list(roots)
1448 assert orderedout
1448 assert orderedout
1449 assert roots
1449 assert roots
1450 assert heads
1450 assert heads
1451 return (orderedout, roots, heads)
1451 return (orderedout, roots, heads)
1452
1452
1453 def headrevs(self, revs=None):
1453 def headrevs(self, revs=None):
1454 if revs is None:
1454 if revs is None:
1455 try:
1455 try:
1456 return self.index.headrevs()
1456 return self.index.headrevs()
1457 except AttributeError:
1457 except AttributeError:
1458 return self._headrevs()
1458 return self._headrevs()
1459 if rustdagop is not None and self.index.rust_ext_compat:
1459 if rustdagop is not None and self.index.rust_ext_compat:
1460 return rustdagop.headrevs(self.index, revs)
1460 return rustdagop.headrevs(self.index, revs)
1461 return dagop.headrevs(revs, self._uncheckedparentrevs)
1461 return dagop.headrevs(revs, self._uncheckedparentrevs)
1462
1462
1463 def computephases(self, roots):
1463 def computephases(self, roots):
1464 return self.index.computephasesmapsets(roots)
1464 return self.index.computephasesmapsets(roots)
1465
1465
1466 def _headrevs(self):
1466 def _headrevs(self):
1467 count = len(self)
1467 count = len(self)
1468 if not count:
1468 if not count:
1469 return [nullrev]
1469 return [nullrev]
1470 # we won't iter over filtered rev so nobody is a head at start
1470 # we won't iter over filtered rev so nobody is a head at start
1471 ishead = [0] * (count + 1)
1471 ishead = [0] * (count + 1)
1472 index = self.index
1472 index = self.index
1473 for r in self:
1473 for r in self:
1474 ishead[r] = 1 # I may be an head
1474 ishead[r] = 1 # I may be an head
1475 e = index[r]
1475 e = index[r]
1476 ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
1476 ishead[e[5]] = ishead[e[6]] = 0 # my parent are not
1477 return [r for r, val in enumerate(ishead) if val]
1477 return [r for r, val in enumerate(ishead) if val]
1478
1478
1479 def heads(self, start=None, stop=None):
1479 def heads(self, start=None, stop=None):
1480 """return the list of all nodes that have no children
1480 """return the list of all nodes that have no children
1481
1481
1482 if start is specified, only heads that are descendants of
1482 if start is specified, only heads that are descendants of
1483 start will be returned
1483 start will be returned
1484 if stop is specified, it will consider all the revs from stop
1484 if stop is specified, it will consider all the revs from stop
1485 as if they had no children
1485 as if they had no children
1486 """
1486 """
1487 if start is None and stop is None:
1487 if start is None and stop is None:
1488 if not len(self):
1488 if not len(self):
1489 return [self.nullid]
1489 return [self.nullid]
1490 return [self.node(r) for r in self.headrevs()]
1490 return [self.node(r) for r in self.headrevs()]
1491
1491
1492 if start is None:
1492 if start is None:
1493 start = nullrev
1493 start = nullrev
1494 else:
1494 else:
1495 start = self.rev(start)
1495 start = self.rev(start)
1496
1496
1497 stoprevs = {self.rev(n) for n in stop or []}
1497 stoprevs = {self.rev(n) for n in stop or []}
1498
1498
1499 revs = dagop.headrevssubset(
1499 revs = dagop.headrevssubset(
1500 self.revs, self.parentrevs, startrev=start, stoprevs=stoprevs
1500 self.revs, self.parentrevs, startrev=start, stoprevs=stoprevs
1501 )
1501 )
1502
1502
1503 return [self.node(rev) for rev in revs]
1503 return [self.node(rev) for rev in revs]
1504
1504
1505 def children(self, node):
1505 def children(self, node):
1506 """find the children of a given node"""
1506 """find the children of a given node"""
1507 c = []
1507 c = []
1508 p = self.rev(node)
1508 p = self.rev(node)
1509 for r in self.revs(start=p + 1):
1509 for r in self.revs(start=p + 1):
1510 prevs = [pr for pr in self.parentrevs(r) if pr != nullrev]
1510 prevs = [pr for pr in self.parentrevs(r) if pr != nullrev]
1511 if prevs:
1511 if prevs:
1512 for pr in prevs:
1512 for pr in prevs:
1513 if pr == p:
1513 if pr == p:
1514 c.append(self.node(r))
1514 c.append(self.node(r))
1515 elif p == nullrev:
1515 elif p == nullrev:
1516 c.append(self.node(r))
1516 c.append(self.node(r))
1517 return c
1517 return c
1518
1518
1519 def commonancestorsheads(self, a, b):
1519 def commonancestorsheads(self, a, b):
1520 """calculate all the heads of the common ancestors of nodes a and b"""
1520 """calculate all the heads of the common ancestors of nodes a and b"""
1521 a, b = self.rev(a), self.rev(b)
1521 a, b = self.rev(a), self.rev(b)
1522 ancs = self._commonancestorsheads(a, b)
1522 ancs = self._commonancestorsheads(a, b)
1523 return pycompat.maplist(self.node, ancs)
1523 return pycompat.maplist(self.node, ancs)
1524
1524
1525 def _commonancestorsheads(self, *revs):
1525 def _commonancestorsheads(self, *revs):
1526 """calculate all the heads of the common ancestors of revs"""
1526 """calculate all the heads of the common ancestors of revs"""
1527 try:
1527 try:
1528 ancs = self.index.commonancestorsheads(*revs)
1528 ancs = self.index.commonancestorsheads(*revs)
1529 except (AttributeError, OverflowError): # C implementation failed
1529 except (AttributeError, OverflowError): # C implementation failed
1530 ancs = ancestor.commonancestorsheads(self.parentrevs, *revs)
1530 ancs = ancestor.commonancestorsheads(self.parentrevs, *revs)
1531 return ancs
1531 return ancs
1532
1532
1533 def isancestor(self, a, b):
1533 def isancestor(self, a, b):
1534 """return True if node a is an ancestor of node b
1534 """return True if node a is an ancestor of node b
1535
1535
1536 A revision is considered an ancestor of itself."""
1536 A revision is considered an ancestor of itself."""
1537 a, b = self.rev(a), self.rev(b)
1537 a, b = self.rev(a), self.rev(b)
1538 return self.isancestorrev(a, b)
1538 return self.isancestorrev(a, b)
1539
1539
1540 def isancestorrev(self, a, b):
1540 def isancestorrev(self, a, b):
1541 """return True if revision a is an ancestor of revision b
1541 """return True if revision a is an ancestor of revision b
1542
1542
1543 A revision is considered an ancestor of itself.
1543 A revision is considered an ancestor of itself.
1544
1544
1545 The implementation of this is trivial but the use of
1545 The implementation of this is trivial but the use of
1546 reachableroots is not."""
1546 reachableroots is not."""
1547 if a == nullrev:
1547 if a == nullrev:
1548 return True
1548 return True
1549 elif a == b:
1549 elif a == b:
1550 return True
1550 return True
1551 elif a > b:
1551 elif a > b:
1552 return False
1552 return False
1553 return bool(self.reachableroots(a, [b], [a], includepath=False))
1553 return bool(self.reachableroots(a, [b], [a], includepath=False))
1554
1554
1555 def reachableroots(self, minroot, heads, roots, includepath=False):
1555 def reachableroots(self, minroot, heads, roots, includepath=False):
1556 """return (heads(::(<roots> and <roots>::<heads>)))
1556 """return (heads(::(<roots> and <roots>::<heads>)))
1557
1557
1558 If includepath is True, return (<roots>::<heads>)."""
1558 If includepath is True, return (<roots>::<heads>)."""
1559 try:
1559 try:
1560 return self.index.reachableroots2(
1560 return self.index.reachableroots2(
1561 minroot, heads, roots, includepath
1561 minroot, heads, roots, includepath
1562 )
1562 )
1563 except AttributeError:
1563 except AttributeError:
1564 return dagop._reachablerootspure(
1564 return dagop._reachablerootspure(
1565 self.parentrevs, minroot, roots, heads, includepath
1565 self.parentrevs, minroot, roots, heads, includepath
1566 )
1566 )
1567
1567
1568 def ancestor(self, a, b):
1568 def ancestor(self, a, b):
1569 """calculate the "best" common ancestor of nodes a and b"""
1569 """calculate the "best" common ancestor of nodes a and b"""
1570
1570
1571 a, b = self.rev(a), self.rev(b)
1571 a, b = self.rev(a), self.rev(b)
1572 try:
1572 try:
1573 ancs = self.index.ancestors(a, b)
1573 ancs = self.index.ancestors(a, b)
1574 except (AttributeError, OverflowError):
1574 except (AttributeError, OverflowError):
1575 ancs = ancestor.ancestors(self.parentrevs, a, b)
1575 ancs = ancestor.ancestors(self.parentrevs, a, b)
1576 if ancs:
1576 if ancs:
1577 # choose a consistent winner when there's a tie
1577 # choose a consistent winner when there's a tie
1578 return min(map(self.node, ancs))
1578 return min(map(self.node, ancs))
1579 return self.nullid
1579 return self.nullid
1580
1580
1581 def _match(self, id):
1581 def _match(self, id):
1582 if isinstance(id, int):
1582 if isinstance(id, int):
1583 # rev
1583 # rev
1584 return self.node(id)
1584 return self.node(id)
1585 if len(id) == self.nodeconstants.nodelen:
1585 if len(id) == self.nodeconstants.nodelen:
1586 # possibly a binary node
1586 # possibly a binary node
1587 # odds of a binary node being all hex in ASCII are 1 in 10**25
1587 # odds of a binary node being all hex in ASCII are 1 in 10**25
1588 try:
1588 try:
1589 node = id
1589 node = id
1590 self.rev(node) # quick search the index
1590 self.rev(node) # quick search the index
1591 return node
1591 return node
1592 except error.LookupError:
1592 except error.LookupError:
1593 pass # may be partial hex id
1593 pass # may be partial hex id
1594 try:
1594 try:
1595 # str(rev)
1595 # str(rev)
1596 rev = int(id)
1596 rev = int(id)
1597 if b"%d" % rev != id:
1597 if b"%d" % rev != id:
1598 raise ValueError
1598 raise ValueError
1599 if rev < 0:
1599 if rev < 0:
1600 rev = len(self) + rev
1600 rev = len(self) + rev
1601 if rev < 0 or rev >= len(self):
1601 if rev < 0 or rev >= len(self):
1602 raise ValueError
1602 raise ValueError
1603 return self.node(rev)
1603 return self.node(rev)
1604 except (ValueError, OverflowError):
1604 except (ValueError, OverflowError):
1605 pass
1605 pass
1606 if len(id) == 2 * self.nodeconstants.nodelen:
1606 if len(id) == 2 * self.nodeconstants.nodelen:
1607 try:
1607 try:
1608 # a full hex nodeid?
1608 # a full hex nodeid?
1609 node = bin(id)
1609 node = bin(id)
1610 self.rev(node)
1610 self.rev(node)
1611 return node
1611 return node
1612 except (binascii.Error, error.LookupError):
1612 except (binascii.Error, error.LookupError):
1613 pass
1613 pass
1614
1614
1615 def _partialmatch(self, id):
1615 def _partialmatch(self, id):
1616 # we don't care wdirfilenodeids as they should be always full hash
1616 # we don't care wdirfilenodeids as they should be always full hash
1617 maybewdir = self.nodeconstants.wdirhex.startswith(id)
1617 maybewdir = self.nodeconstants.wdirhex.startswith(id)
1618 ambiguous = False
1618 ambiguous = False
1619 try:
1619 try:
1620 partial = self.index.partialmatch(id)
1620 partial = self.index.partialmatch(id)
1621 if partial and self.hasnode(partial):
1621 if partial and self.hasnode(partial):
1622 if maybewdir:
1622 if maybewdir:
1623 # single 'ff...' match in radix tree, ambiguous with wdir
1623 # single 'ff...' match in radix tree, ambiguous with wdir
1624 ambiguous = True
1624 ambiguous = True
1625 else:
1625 else:
1626 return partial
1626 return partial
1627 elif maybewdir:
1627 elif maybewdir:
1628 # no 'ff...' match in radix tree, wdir identified
1628 # no 'ff...' match in radix tree, wdir identified
1629 raise error.WdirUnsupported
1629 raise error.WdirUnsupported
1630 else:
1630 else:
1631 return None
1631 return None
1632 except error.RevlogError:
1632 except error.RevlogError:
1633 # parsers.c radix tree lookup gave multiple matches
1633 # parsers.c radix tree lookup gave multiple matches
1634 # fast path: for unfiltered changelog, radix tree is accurate
1634 # fast path: for unfiltered changelog, radix tree is accurate
1635 if not getattr(self, 'filteredrevs', None):
1635 if not getattr(self, 'filteredrevs', None):
1636 ambiguous = True
1636 ambiguous = True
1637 # fall through to slow path that filters hidden revisions
1637 # fall through to slow path that filters hidden revisions
1638 except (AttributeError, ValueError):
1638 except (AttributeError, ValueError):
1639 # we are pure python, or key is not hex
1639 # we are pure python, or key is not hex
1640 pass
1640 pass
1641 if ambiguous:
1641 if ambiguous:
1642 raise error.AmbiguousPrefixLookupError(
1642 raise error.AmbiguousPrefixLookupError(
1643 id, self.display_id, _(b'ambiguous identifier')
1643 id, self.display_id, _(b'ambiguous identifier')
1644 )
1644 )
1645
1645
1646 if id in self._pcache:
1646 if id in self._pcache:
1647 return self._pcache[id]
1647 return self._pcache[id]
1648
1648
1649 if len(id) <= 40:
1649 if len(id) <= 40:
1650 # hex(node)[:...]
1650 # hex(node)[:...]
1651 l = len(id) // 2 * 2 # grab an even number of digits
1651 l = len(id) // 2 * 2 # grab an even number of digits
1652 try:
1652 try:
1653 # we're dropping the last digit, so let's check that it's hex,
1653 # we're dropping the last digit, so let's check that it's hex,
1654 # to avoid the expensive computation below if it's not
1654 # to avoid the expensive computation below if it's not
1655 if len(id) % 2 > 0:
1655 if len(id) % 2 > 0:
1656 if not (id[-1] in hexdigits):
1656 if not (id[-1] in hexdigits):
1657 return None
1657 return None
1658 prefix = bin(id[:l])
1658 prefix = bin(id[:l])
1659 except binascii.Error:
1659 except binascii.Error:
1660 pass
1660 pass
1661 else:
1661 else:
1662 nl = [e[7] for e in self.index if e[7].startswith(prefix)]
1662 nl = [e[7] for e in self.index if e[7].startswith(prefix)]
1663 nl = [
1663 nl = [
1664 n for n in nl if hex(n).startswith(id) and self.hasnode(n)
1664 n for n in nl if hex(n).startswith(id) and self.hasnode(n)
1665 ]
1665 ]
1666 if self.nodeconstants.nullhex.startswith(id):
1666 if self.nodeconstants.nullhex.startswith(id):
1667 nl.append(self.nullid)
1667 nl.append(self.nullid)
1668 if len(nl) > 0:
1668 if len(nl) > 0:
1669 if len(nl) == 1 and not maybewdir:
1669 if len(nl) == 1 and not maybewdir:
1670 self._pcache[id] = nl[0]
1670 self._pcache[id] = nl[0]
1671 return nl[0]
1671 return nl[0]
1672 raise error.AmbiguousPrefixLookupError(
1672 raise error.AmbiguousPrefixLookupError(
1673 id, self.display_id, _(b'ambiguous identifier')
1673 id, self.display_id, _(b'ambiguous identifier')
1674 )
1674 )
1675 if maybewdir:
1675 if maybewdir:
1676 raise error.WdirUnsupported
1676 raise error.WdirUnsupported
1677 return None
1677 return None
1678
1678
1679 def lookup(self, id):
1679 def lookup(self, id):
1680 """locate a node based on:
1680 """locate a node based on:
1681 - revision number or str(revision number)
1681 - revision number or str(revision number)
1682 - nodeid or subset of hex nodeid
1682 - nodeid or subset of hex nodeid
1683 """
1683 """
1684 n = self._match(id)
1684 n = self._match(id)
1685 if n is not None:
1685 if n is not None:
1686 return n
1686 return n
1687 n = self._partialmatch(id)
1687 n = self._partialmatch(id)
1688 if n:
1688 if n:
1689 return n
1689 return n
1690
1690
1691 raise error.LookupError(id, self.display_id, _(b'no match found'))
1691 raise error.LookupError(id, self.display_id, _(b'no match found'))
1692
1692
1693 def shortest(self, node, minlength=1):
1693 def shortest(self, node, minlength=1):
1694 """Find the shortest unambiguous prefix that matches node."""
1694 """Find the shortest unambiguous prefix that matches node."""
1695
1695
1696 def isvalid(prefix):
1696 def isvalid(prefix):
1697 try:
1697 try:
1698 matchednode = self._partialmatch(prefix)
1698 matchednode = self._partialmatch(prefix)
1699 except error.AmbiguousPrefixLookupError:
1699 except error.AmbiguousPrefixLookupError:
1700 return False
1700 return False
1701 except error.WdirUnsupported:
1701 except error.WdirUnsupported:
1702 # single 'ff...' match
1702 # single 'ff...' match
1703 return True
1703 return True
1704 if matchednode is None:
1704 if matchednode is None:
1705 raise error.LookupError(node, self.display_id, _(b'no node'))
1705 raise error.LookupError(node, self.display_id, _(b'no node'))
1706 return True
1706 return True
1707
1707
1708 def maybewdir(prefix):
1708 def maybewdir(prefix):
1709 return all(c == b'f' for c in pycompat.iterbytestr(prefix))
1709 return all(c == b'f' for c in pycompat.iterbytestr(prefix))
1710
1710
1711 hexnode = hex(node)
1711 hexnode = hex(node)
1712
1712
1713 def disambiguate(hexnode, minlength):
1713 def disambiguate(hexnode, minlength):
1714 """Disambiguate against wdirid."""
1714 """Disambiguate against wdirid."""
1715 for length in range(minlength, len(hexnode) + 1):
1715 for length in range(minlength, len(hexnode) + 1):
1716 prefix = hexnode[:length]
1716 prefix = hexnode[:length]
1717 if not maybewdir(prefix):
1717 if not maybewdir(prefix):
1718 return prefix
1718 return prefix
1719
1719
1720 if not getattr(self, 'filteredrevs', None):
1720 if not getattr(self, 'filteredrevs', None):
1721 try:
1721 try:
1722 length = max(self.index.shortest(node), minlength)
1722 length = max(self.index.shortest(node), minlength)
1723 return disambiguate(hexnode, length)
1723 return disambiguate(hexnode, length)
1724 except error.RevlogError:
1724 except error.RevlogError:
1725 if node != self.nodeconstants.wdirid:
1725 if node != self.nodeconstants.wdirid:
1726 raise error.LookupError(
1726 raise error.LookupError(
1727 node, self.display_id, _(b'no node')
1727 node, self.display_id, _(b'no node')
1728 )
1728 )
1729 except AttributeError:
1729 except AttributeError:
1730 # Fall through to pure code
1730 # Fall through to pure code
1731 pass
1731 pass
1732
1732
1733 if node == self.nodeconstants.wdirid:
1733 if node == self.nodeconstants.wdirid:
1734 for length in range(minlength, len(hexnode) + 1):
1734 for length in range(minlength, len(hexnode) + 1):
1735 prefix = hexnode[:length]
1735 prefix = hexnode[:length]
1736 if isvalid(prefix):
1736 if isvalid(prefix):
1737 return prefix
1737 return prefix
1738
1738
1739 for length in range(minlength, len(hexnode) + 1):
1739 for length in range(minlength, len(hexnode) + 1):
1740 prefix = hexnode[:length]
1740 prefix = hexnode[:length]
1741 if isvalid(prefix):
1741 if isvalid(prefix):
1742 return disambiguate(hexnode, length)
1742 return disambiguate(hexnode, length)
1743
1743
1744 def cmp(self, node, text):
1744 def cmp(self, node, text):
1745 """compare text with a given file revision
1745 """compare text with a given file revision
1746
1746
1747 returns True if text is different than what is stored.
1747 returns True if text is different than what is stored.
1748 """
1748 """
1749 p1, p2 = self.parents(node)
1749 p1, p2 = self.parents(node)
1750 return storageutil.hashrevisionsha1(text, p1, p2) != node
1750 return storageutil.hashrevisionsha1(text, p1, p2) != node
1751
1751
1752 def _getsegmentforrevs(self, startrev, endrev, df=None):
1752 def _getsegmentforrevs(self, startrev, endrev, df=None):
1753 """Obtain a segment of raw data corresponding to a range of revisions.
1753 """Obtain a segment of raw data corresponding to a range of revisions.
1754
1754
1755 Accepts the start and end revisions and an optional already-open
1755 Accepts the start and end revisions and an optional already-open
1756 file handle to be used for reading. If the file handle is read, its
1756 file handle to be used for reading. If the file handle is read, its
1757 seek position will not be preserved.
1757 seek position will not be preserved.
1758
1758
1759 Requests for data may be satisfied by a cache.
1759 Requests for data may be satisfied by a cache.
1760
1760
1761 Returns a 2-tuple of (offset, data) for the requested range of
1761 Returns a 2-tuple of (offset, data) for the requested range of
1762 revisions. Offset is the integer offset from the beginning of the
1762 revisions. Offset is the integer offset from the beginning of the
1763 revlog and data is a str or buffer of the raw byte data.
1763 revlog and data is a str or buffer of the raw byte data.
1764
1764
1765 Callers will need to call ``self.start(rev)`` and ``self.length(rev)``
1765 Callers will need to call ``self.start(rev)`` and ``self.length(rev)``
1766 to determine where each revision's data begins and ends.
1766 to determine where each revision's data begins and ends.
1767 """
1767 """
1768 # Inlined self.start(startrev) & self.end(endrev) for perf reasons
1768 # Inlined self.start(startrev) & self.end(endrev) for perf reasons
1769 # (functions are expensive).
1769 # (functions are expensive).
1770 index = self.index
1770 index = self.index
1771 istart = index[startrev]
1771 istart = index[startrev]
1772 start = int(istart[0] >> 16)
1772 start = int(istart[0] >> 16)
1773 if startrev == endrev:
1773 if startrev == endrev:
1774 end = start + istart[1]
1774 end = start + istart[1]
1775 else:
1775 else:
1776 iend = index[endrev]
1776 iend = index[endrev]
1777 end = int(iend[0] >> 16) + iend[1]
1777 end = int(iend[0] >> 16) + iend[1]
1778
1778
1779 if self._inline:
1779 if self._inline:
1780 start += (startrev + 1) * self.index.entry_size
1780 start += (startrev + 1) * self.index.entry_size
1781 end += (endrev + 1) * self.index.entry_size
1781 end += (endrev + 1) * self.index.entry_size
1782 length = end - start
1782 length = end - start
1783
1783
1784 return start, self._segmentfile.read_chunk(start, length, df)
1784 return start, self._segmentfile.read_chunk(start, length, df)
1785
1785
1786 def _chunk(self, rev, df=None):
1786 def _chunk(self, rev, df=None):
1787 """Obtain a single decompressed chunk for a revision.
1787 """Obtain a single decompressed chunk for a revision.
1788
1788
1789 Accepts an integer revision and an optional already-open file handle
1789 Accepts an integer revision and an optional already-open file handle
1790 to be used for reading. If used, the seek position of the file will not
1790 to be used for reading. If used, the seek position of the file will not
1791 be preserved.
1791 be preserved.
1792
1792
1793 Returns a str holding uncompressed data for the requested revision.
1793 Returns a str holding uncompressed data for the requested revision.
1794 """
1794 """
1795 compression_mode = self.index[rev][10]
1795 compression_mode = self.index[rev][10]
1796 data = self._getsegmentforrevs(rev, rev, df=df)[1]
1796 data = self._getsegmentforrevs(rev, rev, df=df)[1]
1797 if compression_mode == COMP_MODE_PLAIN:
1797 if compression_mode == COMP_MODE_PLAIN:
1798 return data
1798 return data
1799 elif compression_mode == COMP_MODE_DEFAULT:
1799 elif compression_mode == COMP_MODE_DEFAULT:
1800 return self._decompressor(data)
1800 return self._decompressor(data)
1801 elif compression_mode == COMP_MODE_INLINE:
1801 elif compression_mode == COMP_MODE_INLINE:
1802 return self.decompress(data)
1802 return self.decompress(data)
1803 else:
1803 else:
1804 msg = b'unknown compression mode %d'
1804 msg = b'unknown compression mode %d'
1805 msg %= compression_mode
1805 msg %= compression_mode
1806 raise error.RevlogError(msg)
1806 raise error.RevlogError(msg)
1807
1807
1808 def _chunks(self, revs, df=None, targetsize=None):
1808 def _chunks(self, revs, df=None, targetsize=None):
1809 """Obtain decompressed chunks for the specified revisions.
1809 """Obtain decompressed chunks for the specified revisions.
1810
1810
1811 Accepts an iterable of numeric revisions that are assumed to be in
1811 Accepts an iterable of numeric revisions that are assumed to be in
1812 ascending order. Also accepts an optional already-open file handle
1812 ascending order. Also accepts an optional already-open file handle
1813 to be used for reading. If used, the seek position of the file will
1813 to be used for reading. If used, the seek position of the file will
1814 not be preserved.
1814 not be preserved.
1815
1815
1816 This function is similar to calling ``self._chunk()`` multiple times,
1816 This function is similar to calling ``self._chunk()`` multiple times,
1817 but is faster.
1817 but is faster.
1818
1818
1819 Returns a list with decompressed data for each requested revision.
1819 Returns a list with decompressed data for each requested revision.
1820 """
1820 """
1821 if not revs:
1821 if not revs:
1822 return []
1822 return []
1823 start = self.start
1823 start = self.start
1824 length = self.length
1824 length = self.length
1825 inline = self._inline
1825 inline = self._inline
1826 iosize = self.index.entry_size
1826 iosize = self.index.entry_size
1827 buffer = util.buffer
1827 buffer = util.buffer
1828
1828
1829 l = []
1829 l = []
1830 ladd = l.append
1830 ladd = l.append
1831
1831
1832 if not self._withsparseread:
1832 if not self._withsparseread:
1833 slicedchunks = (revs,)
1833 slicedchunks = (revs,)
1834 else:
1834 else:
1835 slicedchunks = deltautil.slicechunk(
1835 slicedchunks = deltautil.slicechunk(
1836 self, revs, targetsize=targetsize
1836 self, revs, targetsize=targetsize
1837 )
1837 )
1838
1838
1839 for revschunk in slicedchunks:
1839 for revschunk in slicedchunks:
1840 firstrev = revschunk[0]
1840 firstrev = revschunk[0]
1841 # Skip trailing revisions with empty diff
1841 # Skip trailing revisions with empty diff
1842 for lastrev in revschunk[::-1]:
1842 for lastrev in revschunk[::-1]:
1843 if length(lastrev) != 0:
1843 if length(lastrev) != 0:
1844 break
1844 break
1845
1845
1846 try:
1846 try:
1847 offset, data = self._getsegmentforrevs(firstrev, lastrev, df=df)
1847 offset, data = self._getsegmentforrevs(firstrev, lastrev, df=df)
1848 except OverflowError:
1848 except OverflowError:
1849 # issue4215 - we can't cache a run of chunks greater than
1849 # issue4215 - we can't cache a run of chunks greater than
1850 # 2G on Windows
1850 # 2G on Windows
1851 return [self._chunk(rev, df=df) for rev in revschunk]
1851 return [self._chunk(rev, df=df) for rev in revschunk]
1852
1852
1853 decomp = self.decompress
1853 decomp = self.decompress
1854 # self._decompressor might be None, but will not be used in that case
1854 # self._decompressor might be None, but will not be used in that case
1855 def_decomp = self._decompressor
1855 def_decomp = self._decompressor
1856 for rev in revschunk:
1856 for rev in revschunk:
1857 chunkstart = start(rev)
1857 chunkstart = start(rev)
1858 if inline:
1858 if inline:
1859 chunkstart += (rev + 1) * iosize
1859 chunkstart += (rev + 1) * iosize
1860 chunklength = length(rev)
1860 chunklength = length(rev)
1861 comp_mode = self.index[rev][10]
1861 comp_mode = self.index[rev][10]
1862 c = buffer(data, chunkstart - offset, chunklength)
1862 c = buffer(data, chunkstart - offset, chunklength)
1863 if comp_mode == COMP_MODE_PLAIN:
1863 if comp_mode == COMP_MODE_PLAIN:
1864 ladd(c)
1864 ladd(c)
1865 elif comp_mode == COMP_MODE_INLINE:
1865 elif comp_mode == COMP_MODE_INLINE:
1866 ladd(decomp(c))
1866 ladd(decomp(c))
1867 elif comp_mode == COMP_MODE_DEFAULT:
1867 elif comp_mode == COMP_MODE_DEFAULT:
1868 ladd(def_decomp(c))
1868 ladd(def_decomp(c))
1869 else:
1869 else:
1870 msg = b'unknown compression mode %d'
1870 msg = b'unknown compression mode %d'
1871 msg %= comp_mode
1871 msg %= comp_mode
1872 raise error.RevlogError(msg)
1872 raise error.RevlogError(msg)
1873
1873
1874 return l
1874 return l
1875
1875
1876 def deltaparent(self, rev):
1876 def deltaparent(self, rev):
1877 """return deltaparent of the given revision"""
1877 """return deltaparent of the given revision"""
1878 base = self.index[rev][3]
1878 base = self.index[rev][3]
1879 if base == rev:
1879 if base == rev:
1880 return nullrev
1880 return nullrev
1881 elif self._generaldelta:
1881 elif self._generaldelta:
1882 return base
1882 return base
1883 else:
1883 else:
1884 return rev - 1
1884 return rev - 1
1885
1885
1886 def issnapshot(self, rev):
1886 def issnapshot(self, rev):
1887 """tells whether rev is a snapshot"""
1887 """tells whether rev is a snapshot"""
1888 if not self._sparserevlog:
1888 if not self._sparserevlog:
1889 return self.deltaparent(rev) == nullrev
1889 return self.deltaparent(rev) == nullrev
1890 elif util.safehasattr(self.index, 'issnapshot'):
1890 elif util.safehasattr(self.index, 'issnapshot'):
1891 # directly assign the method to cache the testing and access
1891 # directly assign the method to cache the testing and access
1892 self.issnapshot = self.index.issnapshot
1892 self.issnapshot = self.index.issnapshot
1893 return self.issnapshot(rev)
1893 return self.issnapshot(rev)
1894 if rev == nullrev:
1894 if rev == nullrev:
1895 return True
1895 return True
1896 entry = self.index[rev]
1896 entry = self.index[rev]
1897 base = entry[3]
1897 base = entry[3]
1898 if base == rev:
1898 if base == rev:
1899 return True
1899 return True
1900 if base == nullrev:
1900 if base == nullrev:
1901 return True
1901 return True
1902 p1 = entry[5]
1902 p1 = entry[5]
1903 while self.length(p1) == 0:
1903 while self.length(p1) == 0:
1904 b = self.deltaparent(p1)
1904 b = self.deltaparent(p1)
1905 if b == p1:
1905 if b == p1:
1906 break
1906 break
1907 p1 = b
1907 p1 = b
1908 p2 = entry[6]
1908 p2 = entry[6]
1909 while self.length(p2) == 0:
1909 while self.length(p2) == 0:
1910 b = self.deltaparent(p2)
1910 b = self.deltaparent(p2)
1911 if b == p2:
1911 if b == p2:
1912 break
1912 break
1913 p2 = b
1913 p2 = b
1914 if base == p1 or base == p2:
1914 if base == p1 or base == p2:
1915 return False
1915 return False
1916 return self.issnapshot(base)
1916 return self.issnapshot(base)
1917
1917
1918 def snapshotdepth(self, rev):
1918 def snapshotdepth(self, rev):
1919 """number of snapshot in the chain before this one"""
1919 """number of snapshot in the chain before this one"""
1920 if not self.issnapshot(rev):
1920 if not self.issnapshot(rev):
1921 raise error.ProgrammingError(b'revision %d not a snapshot')
1921 raise error.ProgrammingError(b'revision %d not a snapshot')
1922 return len(self._deltachain(rev)[0]) - 1
1922 return len(self._deltachain(rev)[0]) - 1
1923
1923
1924 def revdiff(self, rev1, rev2):
1924 def revdiff(self, rev1, rev2):
1925 """return or calculate a delta between two revisions
1925 """return or calculate a delta between two revisions
1926
1926
1927 The delta calculated is in binary form and is intended to be written to
1927 The delta calculated is in binary form and is intended to be written to
1928 revlog data directly. So this function needs raw revision data.
1928 revlog data directly. So this function needs raw revision data.
1929 """
1929 """
1930 if rev1 != nullrev and self.deltaparent(rev2) == rev1:
1930 if rev1 != nullrev and self.deltaparent(rev2) == rev1:
1931 return bytes(self._chunk(rev2))
1931 return bytes(self._chunk(rev2))
1932
1932
1933 return mdiff.textdiff(self.rawdata(rev1), self.rawdata(rev2))
1933 return mdiff.textdiff(self.rawdata(rev1), self.rawdata(rev2))
1934
1934
1935 def revision(self, nodeorrev, _df=None):
1935 def revision(self, nodeorrev, _df=None):
1936 """return an uncompressed revision of a given node or revision
1936 """return an uncompressed revision of a given node or revision
1937 number.
1937 number.
1938
1938
1939 _df - an existing file handle to read from. (internal-only)
1939 _df - an existing file handle to read from. (internal-only)
1940 """
1940 """
1941 return self._revisiondata(nodeorrev, _df)
1941 return self._revisiondata(nodeorrev, _df)
1942
1942
1943 def sidedata(self, nodeorrev, _df=None):
1943 def sidedata(self, nodeorrev, _df=None):
1944 """a map of extra data related to the changeset but not part of the hash
1944 """a map of extra data related to the changeset but not part of the hash
1945
1945
1946 This function currently return a dictionary. However, more advanced
1946 This function currently return a dictionary. However, more advanced
1947 mapping object will likely be used in the future for a more
1947 mapping object will likely be used in the future for a more
1948 efficient/lazy code.
1948 efficient/lazy code.
1949 """
1949 """
1950 # deal with <nodeorrev> argument type
1950 # deal with <nodeorrev> argument type
1951 if isinstance(nodeorrev, int):
1951 if isinstance(nodeorrev, int):
1952 rev = nodeorrev
1952 rev = nodeorrev
1953 else:
1953 else:
1954 rev = self.rev(nodeorrev)
1954 rev = self.rev(nodeorrev)
1955 return self._sidedata(rev)
1955 return self._sidedata(rev)
1956
1956
1957 def _revisiondata(self, nodeorrev, _df=None, raw=False):
1957 def _revisiondata(self, nodeorrev, _df=None, raw=False):
1958 # deal with <nodeorrev> argument type
1958 # deal with <nodeorrev> argument type
1959 if isinstance(nodeorrev, int):
1959 if isinstance(nodeorrev, int):
1960 rev = nodeorrev
1960 rev = nodeorrev
1961 node = self.node(rev)
1961 node = self.node(rev)
1962 else:
1962 else:
1963 node = nodeorrev
1963 node = nodeorrev
1964 rev = None
1964 rev = None
1965
1965
1966 # fast path the special `nullid` rev
1966 # fast path the special `nullid` rev
1967 if node == self.nullid:
1967 if node == self.nullid:
1968 return b""
1968 return b""
1969
1969
1970 # ``rawtext`` is the text as stored inside the revlog. Might be the
1970 # ``rawtext`` is the text as stored inside the revlog. Might be the
1971 # revision or might need to be processed to retrieve the revision.
1971 # revision or might need to be processed to retrieve the revision.
1972 rev, rawtext, validated = self._rawtext(node, rev, _df=_df)
1972 rev, rawtext, validated = self._rawtext(node, rev, _df=_df)
1973
1973
1974 if raw and validated:
1974 if raw and validated:
1975 # if we don't want to process the raw text and that raw
1975 # if we don't want to process the raw text and that raw
1976 # text is cached, we can exit early.
1976 # text is cached, we can exit early.
1977 return rawtext
1977 return rawtext
1978 if rev is None:
1978 if rev is None:
1979 rev = self.rev(node)
1979 rev = self.rev(node)
1980 # the revlog's flag for this revision
1980 # the revlog's flag for this revision
1981 # (usually alter its state or content)
1981 # (usually alter its state or content)
1982 flags = self.flags(rev)
1982 flags = self.flags(rev)
1983
1983
1984 if validated and flags == REVIDX_DEFAULT_FLAGS:
1984 if validated and flags == REVIDX_DEFAULT_FLAGS:
1985 # no extra flags set, no flag processor runs, text = rawtext
1985 # no extra flags set, no flag processor runs, text = rawtext
1986 return rawtext
1986 return rawtext
1987
1987
1988 if raw:
1988 if raw:
1989 validatehash = flagutil.processflagsraw(self, rawtext, flags)
1989 validatehash = flagutil.processflagsraw(self, rawtext, flags)
1990 text = rawtext
1990 text = rawtext
1991 else:
1991 else:
1992 r = flagutil.processflagsread(self, rawtext, flags)
1992 r = flagutil.processflagsread(self, rawtext, flags)
1993 text, validatehash = r
1993 text, validatehash = r
1994 if validatehash:
1994 if validatehash:
1995 self.checkhash(text, node, rev=rev)
1995 self.checkhash(text, node, rev=rev)
1996 if not validated:
1996 if not validated:
1997 self._revisioncache = (node, rev, rawtext)
1997 self._revisioncache = (node, rev, rawtext)
1998
1998
1999 return text
1999 return text
2000
2000
2001 def _rawtext(self, node, rev, _df=None):
2001 def _rawtext(self, node, rev, _df=None):
2002 """return the possibly unvalidated rawtext for a revision
2002 """return the possibly unvalidated rawtext for a revision
2003
2003
2004 returns (rev, rawtext, validated)
2004 returns (rev, rawtext, validated)
2005 """
2005 """
2006
2006
2007 # revision in the cache (could be useful to apply delta)
2007 # revision in the cache (could be useful to apply delta)
2008 cachedrev = None
2008 cachedrev = None
2009 # An intermediate text to apply deltas to
2009 # An intermediate text to apply deltas to
2010 basetext = None
2010 basetext = None
2011
2011
2012 # Check if we have the entry in cache
2012 # Check if we have the entry in cache
2013 # The cache entry looks like (node, rev, rawtext)
2013 # The cache entry looks like (node, rev, rawtext)
2014 if self._revisioncache:
2014 if self._revisioncache:
2015 if self._revisioncache[0] == node:
2015 if self._revisioncache[0] == node:
2016 return (rev, self._revisioncache[2], True)
2016 return (rev, self._revisioncache[2], True)
2017 cachedrev = self._revisioncache[1]
2017 cachedrev = self._revisioncache[1]
2018
2018
2019 if rev is None:
2019 if rev is None:
2020 rev = self.rev(node)
2020 rev = self.rev(node)
2021
2021
2022 chain, stopped = self._deltachain(rev, stoprev=cachedrev)
2022 chain, stopped = self._deltachain(rev, stoprev=cachedrev)
2023 if stopped:
2023 if stopped:
2024 basetext = self._revisioncache[2]
2024 basetext = self._revisioncache[2]
2025
2025
2026 # drop cache to save memory, the caller is expected to
2026 # drop cache to save memory, the caller is expected to
2027 # update self._revisioncache after validating the text
2027 # update self._revisioncache after validating the text
2028 self._revisioncache = None
2028 self._revisioncache = None
2029
2029
2030 targetsize = None
2030 targetsize = None
2031 rawsize = self.index[rev][2]
2031 rawsize = self.index[rev][2]
2032 if 0 <= rawsize:
2032 if 0 <= rawsize:
2033 targetsize = 4 * rawsize
2033 targetsize = 4 * rawsize
2034
2034
2035 bins = self._chunks(chain, df=_df, targetsize=targetsize)
2035 bins = self._chunks(chain, df=_df, targetsize=targetsize)
2036 if basetext is None:
2036 if basetext is None:
2037 basetext = bytes(bins[0])
2037 basetext = bytes(bins[0])
2038 bins = bins[1:]
2038 bins = bins[1:]
2039
2039
2040 rawtext = mdiff.patches(basetext, bins)
2040 rawtext = mdiff.patches(basetext, bins)
2041 del basetext # let us have a chance to free memory early
2041 del basetext # let us have a chance to free memory early
2042 return (rev, rawtext, False)
2042 return (rev, rawtext, False)
2043
2043
2044 def _sidedata(self, rev):
2044 def _sidedata(self, rev):
2045 """Return the sidedata for a given revision number."""
2045 """Return the sidedata for a given revision number."""
2046 index_entry = self.index[rev]
2046 index_entry = self.index[rev]
2047 sidedata_offset = index_entry[8]
2047 sidedata_offset = index_entry[8]
2048 sidedata_size = index_entry[9]
2048 sidedata_size = index_entry[9]
2049
2049
2050 if self._inline:
2050 if self._inline:
2051 sidedata_offset += self.index.entry_size * (1 + rev)
2051 sidedata_offset += self.index.entry_size * (1 + rev)
2052 if sidedata_size == 0:
2052 if sidedata_size == 0:
2053 return {}
2053 return {}
2054
2054
2055 if self._docket.sidedata_end < sidedata_offset + sidedata_size:
2055 if self._docket.sidedata_end < sidedata_offset + sidedata_size:
2056 filename = self._sidedatafile
2056 filename = self._sidedatafile
2057 end = self._docket.sidedata_end
2057 end = self._docket.sidedata_end
2058 offset = sidedata_offset
2058 offset = sidedata_offset
2059 length = sidedata_size
2059 length = sidedata_size
2060 m = FILE_TOO_SHORT_MSG % (filename, length, offset, end)
2060 m = FILE_TOO_SHORT_MSG % (filename, length, offset, end)
2061 raise error.RevlogError(m)
2061 raise error.RevlogError(m)
2062
2062
2063 comp_segment = self._segmentfile_sidedata.read_chunk(
2063 comp_segment = self._segmentfile_sidedata.read_chunk(
2064 sidedata_offset, sidedata_size
2064 sidedata_offset, sidedata_size
2065 )
2065 )
2066
2066
2067 comp = self.index[rev][11]
2067 comp = self.index[rev][11]
2068 if comp == COMP_MODE_PLAIN:
2068 if comp == COMP_MODE_PLAIN:
2069 segment = comp_segment
2069 segment = comp_segment
2070 elif comp == COMP_MODE_DEFAULT:
2070 elif comp == COMP_MODE_DEFAULT:
2071 segment = self._decompressor(comp_segment)
2071 segment = self._decompressor(comp_segment)
2072 elif comp == COMP_MODE_INLINE:
2072 elif comp == COMP_MODE_INLINE:
2073 segment = self.decompress(comp_segment)
2073 segment = self.decompress(comp_segment)
2074 else:
2074 else:
2075 msg = b'unknown compression mode %d'
2075 msg = b'unknown compression mode %d'
2076 msg %= comp
2076 msg %= comp
2077 raise error.RevlogError(msg)
2077 raise error.RevlogError(msg)
2078
2078
2079 sidedata = sidedatautil.deserialize_sidedata(segment)
2079 sidedata = sidedatautil.deserialize_sidedata(segment)
2080 return sidedata
2080 return sidedata
2081
2081
2082 def rawdata(self, nodeorrev, _df=None):
2082 def rawdata(self, nodeorrev, _df=None):
2083 """return an uncompressed raw data of a given node or revision number.
2083 """return an uncompressed raw data of a given node or revision number.
2084
2084
2085 _df - an existing file handle to read from. (internal-only)
2085 _df - an existing file handle to read from. (internal-only)
2086 """
2086 """
2087 return self._revisiondata(nodeorrev, _df, raw=True)
2087 return self._revisiondata(nodeorrev, _df, raw=True)
2088
2088
2089 def hash(self, text, p1, p2):
2089 def hash(self, text, p1, p2):
2090 """Compute a node hash.
2090 """Compute a node hash.
2091
2091
2092 Available as a function so that subclasses can replace the hash
2092 Available as a function so that subclasses can replace the hash
2093 as needed.
2093 as needed.
2094 """
2094 """
2095 return storageutil.hashrevisionsha1(text, p1, p2)
2095 return storageutil.hashrevisionsha1(text, p1, p2)
2096
2096
2097 def checkhash(self, text, node, p1=None, p2=None, rev=None):
2097 def checkhash(self, text, node, p1=None, p2=None, rev=None):
2098 """Check node hash integrity.
2098 """Check node hash integrity.
2099
2099
2100 Available as a function so that subclasses can extend hash mismatch
2100 Available as a function so that subclasses can extend hash mismatch
2101 behaviors as needed.
2101 behaviors as needed.
2102 """
2102 """
2103 try:
2103 try:
2104 if p1 is None and p2 is None:
2104 if p1 is None and p2 is None:
2105 p1, p2 = self.parents(node)
2105 p1, p2 = self.parents(node)
2106 if node != self.hash(text, p1, p2):
2106 if node != self.hash(text, p1, p2):
2107 # Clear the revision cache on hash failure. The revision cache
2107 # Clear the revision cache on hash failure. The revision cache
2108 # only stores the raw revision and clearing the cache does have
2108 # only stores the raw revision and clearing the cache does have
2109 # the side-effect that we won't have a cache hit when the raw
2109 # the side-effect that we won't have a cache hit when the raw
2110 # revision data is accessed. But this case should be rare and
2110 # revision data is accessed. But this case should be rare and
2111 # it is extra work to teach the cache about the hash
2111 # it is extra work to teach the cache about the hash
2112 # verification state.
2112 # verification state.
2113 if self._revisioncache and self._revisioncache[0] == node:
2113 if self._revisioncache and self._revisioncache[0] == node:
2114 self._revisioncache = None
2114 self._revisioncache = None
2115
2115
2116 revornode = rev
2116 revornode = rev
2117 if revornode is None:
2117 if revornode is None:
2118 revornode = templatefilters.short(hex(node))
2118 revornode = templatefilters.short(hex(node))
2119 raise error.RevlogError(
2119 raise error.RevlogError(
2120 _(b"integrity check failed on %s:%s")
2120 _(b"integrity check failed on %s:%s")
2121 % (self.display_id, pycompat.bytestr(revornode))
2121 % (self.display_id, pycompat.bytestr(revornode))
2122 )
2122 )
2123 except error.RevlogError:
2123 except error.RevlogError:
2124 if self._censorable and storageutil.iscensoredtext(text):
2124 if self._censorable and storageutil.iscensoredtext(text):
2125 raise error.CensoredNodeError(self.display_id, node, text)
2125 raise error.CensoredNodeError(self.display_id, node, text)
2126 raise
2126 raise
2127
2127
2128 @property
2128 @property
2129 def _split_index_file(self):
2129 def _split_index_file(self):
2130 """the path where to expect the index of an ongoing splitting operation
2130 """the path where to expect the index of an ongoing splitting operation
2131
2131
2132 The file will only exist if a splitting operation is in progress, but
2132 The file will only exist if a splitting operation is in progress, but
2133 it is always expected at the same location."""
2133 it is always expected at the same location."""
2134 parts = os.path.split(self.radix)
2134 parts = self.radix.split(b'/')
2135 if len(parts) > 1:
2135 if len(parts) > 1:
2136 # adds a '-s' prefix to the ``data/` or `meta/` base
2136 # adds a '-s' prefix to the ``data/` or `meta/` base
2137 head = parts[0] + b'-s'
2137 head = parts[0] + b'-s'
2138 return os.path.join(head, *parts[1:])
2138 mids = parts[1:-1]
2139 tail = parts[-1] + b'.i'
2140 pieces = [head] + mids + [tail]
2141 return b'/'.join(pieces)
2139 else:
2142 else:
2140 # the revlog is stored at the root of the store (changelog or
2143 # the revlog is stored at the root of the store (changelog or
2141 # manifest), no risk of collision.
2144 # manifest), no risk of collision.
2142 return self.radix + b'.i.s'
2145 return self.radix + b'.i.s'
2143
2146
2144 def _enforceinlinesize(self, tr, side_write=True):
2147 def _enforceinlinesize(self, tr, side_write=True):
2145 """Check if the revlog is too big for inline and convert if so.
2148 """Check if the revlog is too big for inline and convert if so.
2146
2149
2147 This should be called after revisions are added to the revlog. If the
2150 This should be called after revisions are added to the revlog. If the
2148 revlog has grown too large to be an inline revlog, it will convert it
2151 revlog has grown too large to be an inline revlog, it will convert it
2149 to use multiple index and data files.
2152 to use multiple index and data files.
2150 """
2153 """
2151 tiprev = len(self) - 1
2154 tiprev = len(self) - 1
2152 total_size = self.start(tiprev) + self.length(tiprev)
2155 total_size = self.start(tiprev) + self.length(tiprev)
2153 if not self._inline or total_size < _maxinline:
2156 if not self._inline or total_size < _maxinline:
2154 return
2157 return
2155
2158
2156 troffset = tr.findoffset(self._indexfile)
2159 troffset = tr.findoffset(self._indexfile)
2157 if troffset is None:
2160 if troffset is None:
2158 raise error.RevlogError(
2161 raise error.RevlogError(
2159 _(b"%s not found in the transaction") % self._indexfile
2162 _(b"%s not found in the transaction") % self._indexfile
2160 )
2163 )
2161 if troffset:
2164 if troffset:
2162 tr.addbackup(self._indexfile, for_offset=True)
2165 tr.addbackup(self._indexfile, for_offset=True)
2163 tr.add(self._datafile, 0)
2166 tr.add(self._datafile, 0)
2164
2167
2165 existing_handles = False
2168 existing_handles = False
2166 if self._writinghandles is not None:
2169 if self._writinghandles is not None:
2167 existing_handles = True
2170 existing_handles = True
2168 fp = self._writinghandles[0]
2171 fp = self._writinghandles[0]
2169 fp.flush()
2172 fp.flush()
2170 fp.close()
2173 fp.close()
2171 # We can't use the cached file handle after close(). So prevent
2174 # We can't use the cached file handle after close(). So prevent
2172 # its usage.
2175 # its usage.
2173 self._writinghandles = None
2176 self._writinghandles = None
2174 self._segmentfile.writing_handle = None
2177 self._segmentfile.writing_handle = None
2175 # No need to deal with sidedata writing handle as it is only
2178 # No need to deal with sidedata writing handle as it is only
2176 # relevant with revlog-v2 which is never inline, not reaching
2179 # relevant with revlog-v2 which is never inline, not reaching
2177 # this code
2180 # this code
2178 if side_write:
2181 if side_write:
2179 old_index_file_path = self._indexfile
2182 old_index_file_path = self._indexfile
2180 new_index_file_path = self._split_index_file
2183 new_index_file_path = self._split_index_file
2181 opener = self.opener
2184 opener = self.opener
2182 weak_self = weakref.ref(self)
2185 weak_self = weakref.ref(self)
2183
2186
2184 # the "split" index replace the real index when the transaction is finalized
2187 # the "split" index replace the real index when the transaction is finalized
2185 def finalize_callback(tr):
2188 def finalize_callback(tr):
2186 opener.rename(
2189 opener.rename(
2187 new_index_file_path,
2190 new_index_file_path,
2188 old_index_file_path,
2191 old_index_file_path,
2189 checkambig=True,
2192 checkambig=True,
2190 )
2193 )
2191 maybe_self = weak_self()
2194 maybe_self = weak_self()
2192 if maybe_self is not None:
2195 if maybe_self is not None:
2193 maybe_self._indexfile = old_index_file_path
2196 maybe_self._indexfile = old_index_file_path
2194
2197
2195 def abort_callback(tr):
2198 def abort_callback(tr):
2196 maybe_self = weak_self()
2199 maybe_self = weak_self()
2197 if maybe_self is not None:
2200 if maybe_self is not None:
2198 maybe_self._indexfile = old_index_file_path
2201 maybe_self._indexfile = old_index_file_path
2199
2202
2200 tr.registertmp(new_index_file_path)
2203 tr.registertmp(new_index_file_path)
2201 if self.target[1] is not None:
2204 if self.target[1] is not None:
2202 callback_id = b'000-revlog-split-%d-%s' % self.target
2205 callback_id = b'000-revlog-split-%d-%s' % self.target
2203 else:
2206 else:
2204 callback_id = b'000-revlog-split-%d' % self.target[0]
2207 callback_id = b'000-revlog-split-%d' % self.target[0]
2205 tr.addfinalize(callback_id, finalize_callback)
2208 tr.addfinalize(callback_id, finalize_callback)
2206 tr.addabort(callback_id, abort_callback)
2209 tr.addabort(callback_id, abort_callback)
2207
2210
2208 new_dfh = self._datafp(b'w+')
2211 new_dfh = self._datafp(b'w+')
2209 new_dfh.truncate(0) # drop any potentially existing data
2212 new_dfh.truncate(0) # drop any potentially existing data
2210 try:
2213 try:
2211 with self._indexfp() as read_ifh:
2214 with self._indexfp() as read_ifh:
2212 for r in self:
2215 for r in self:
2213 new_dfh.write(self._getsegmentforrevs(r, r, df=read_ifh)[1])
2216 new_dfh.write(self._getsegmentforrevs(r, r, df=read_ifh)[1])
2214 new_dfh.flush()
2217 new_dfh.flush()
2215
2218
2216 if side_write:
2219 if side_write:
2217 self._indexfile = new_index_file_path
2220 self._indexfile = new_index_file_path
2218 with self.__index_new_fp() as fp:
2221 with self.__index_new_fp() as fp:
2219 self._format_flags &= ~FLAG_INLINE_DATA
2222 self._format_flags &= ~FLAG_INLINE_DATA
2220 self._inline = False
2223 self._inline = False
2221 for i in self:
2224 for i in self:
2222 e = self.index.entry_binary(i)
2225 e = self.index.entry_binary(i)
2223 if i == 0 and self._docket is None:
2226 if i == 0 and self._docket is None:
2224 header = self._format_flags | self._format_version
2227 header = self._format_flags | self._format_version
2225 header = self.index.pack_header(header)
2228 header = self.index.pack_header(header)
2226 e = header + e
2229 e = header + e
2227 fp.write(e)
2230 fp.write(e)
2228 if self._docket is not None:
2231 if self._docket is not None:
2229 self._docket.index_end = fp.tell()
2232 self._docket.index_end = fp.tell()
2230
2233
2231 # If we don't use side-write, the temp file replace the real
2234 # If we don't use side-write, the temp file replace the real
2232 # index when we exit the context manager
2235 # index when we exit the context manager
2233
2236
2234 nodemaputil.setup_persistent_nodemap(tr, self)
2237 nodemaputil.setup_persistent_nodemap(tr, self)
2235 self._segmentfile = randomaccessfile.randomaccessfile(
2238 self._segmentfile = randomaccessfile.randomaccessfile(
2236 self.opener,
2239 self.opener,
2237 self._datafile,
2240 self._datafile,
2238 self._chunkcachesize,
2241 self._chunkcachesize,
2239 )
2242 )
2240
2243
2241 if existing_handles:
2244 if existing_handles:
2242 # switched from inline to conventional reopen the index
2245 # switched from inline to conventional reopen the index
2243 ifh = self.__index_write_fp()
2246 ifh = self.__index_write_fp()
2244 self._writinghandles = (ifh, new_dfh, None)
2247 self._writinghandles = (ifh, new_dfh, None)
2245 self._segmentfile.writing_handle = new_dfh
2248 self._segmentfile.writing_handle = new_dfh
2246 new_dfh = None
2249 new_dfh = None
2247 # No need to deal with sidedata writing handle as it is only
2250 # No need to deal with sidedata writing handle as it is only
2248 # relevant with revlog-v2 which is never inline, not reaching
2251 # relevant with revlog-v2 which is never inline, not reaching
2249 # this code
2252 # this code
2250 finally:
2253 finally:
2251 if new_dfh is not None:
2254 if new_dfh is not None:
2252 new_dfh.close()
2255 new_dfh.close()
2253
2256
2254 def _nodeduplicatecallback(self, transaction, node):
2257 def _nodeduplicatecallback(self, transaction, node):
2255 """called when trying to add a node already stored."""
2258 """called when trying to add a node already stored."""
2256
2259
2257 @contextlib.contextmanager
2260 @contextlib.contextmanager
2258 def reading(self):
2261 def reading(self):
2259 """Context manager that keeps data and sidedata files open for reading"""
2262 """Context manager that keeps data and sidedata files open for reading"""
2260 with self._segmentfile.reading():
2263 with self._segmentfile.reading():
2261 with self._segmentfile_sidedata.reading():
2264 with self._segmentfile_sidedata.reading():
2262 yield
2265 yield
2263
2266
2264 @contextlib.contextmanager
2267 @contextlib.contextmanager
2265 def _writing(self, transaction):
2268 def _writing(self, transaction):
2266 if self._trypending:
2269 if self._trypending:
2267 msg = b'try to write in a `trypending` revlog: %s'
2270 msg = b'try to write in a `trypending` revlog: %s'
2268 msg %= self.display_id
2271 msg %= self.display_id
2269 raise error.ProgrammingError(msg)
2272 raise error.ProgrammingError(msg)
2270 if self._writinghandles is not None:
2273 if self._writinghandles is not None:
2271 yield
2274 yield
2272 else:
2275 else:
2273 ifh = dfh = sdfh = None
2276 ifh = dfh = sdfh = None
2274 try:
2277 try:
2275 r = len(self)
2278 r = len(self)
2276 # opening the data file.
2279 # opening the data file.
2277 dsize = 0
2280 dsize = 0
2278 if r:
2281 if r:
2279 dsize = self.end(r - 1)
2282 dsize = self.end(r - 1)
2280 dfh = None
2283 dfh = None
2281 if not self._inline:
2284 if not self._inline:
2282 try:
2285 try:
2283 dfh = self._datafp(b"r+")
2286 dfh = self._datafp(b"r+")
2284 if self._docket is None:
2287 if self._docket is None:
2285 dfh.seek(0, os.SEEK_END)
2288 dfh.seek(0, os.SEEK_END)
2286 else:
2289 else:
2287 dfh.seek(self._docket.data_end, os.SEEK_SET)
2290 dfh.seek(self._docket.data_end, os.SEEK_SET)
2288 except FileNotFoundError:
2291 except FileNotFoundError:
2289 dfh = self._datafp(b"w+")
2292 dfh = self._datafp(b"w+")
2290 transaction.add(self._datafile, dsize)
2293 transaction.add(self._datafile, dsize)
2291 if self._sidedatafile is not None:
2294 if self._sidedatafile is not None:
2292 # revlog-v2 does not inline, help Pytype
2295 # revlog-v2 does not inline, help Pytype
2293 assert dfh is not None
2296 assert dfh is not None
2294 try:
2297 try:
2295 sdfh = self.opener(self._sidedatafile, mode=b"r+")
2298 sdfh = self.opener(self._sidedatafile, mode=b"r+")
2296 dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
2299 dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
2297 except FileNotFoundError:
2300 except FileNotFoundError:
2298 sdfh = self.opener(self._sidedatafile, mode=b"w+")
2301 sdfh = self.opener(self._sidedatafile, mode=b"w+")
2299 transaction.add(
2302 transaction.add(
2300 self._sidedatafile, self._docket.sidedata_end
2303 self._sidedatafile, self._docket.sidedata_end
2301 )
2304 )
2302
2305
2303 # opening the index file.
2306 # opening the index file.
2304 isize = r * self.index.entry_size
2307 isize = r * self.index.entry_size
2305 ifh = self.__index_write_fp()
2308 ifh = self.__index_write_fp()
2306 if self._inline:
2309 if self._inline:
2307 transaction.add(self._indexfile, dsize + isize)
2310 transaction.add(self._indexfile, dsize + isize)
2308 else:
2311 else:
2309 transaction.add(self._indexfile, isize)
2312 transaction.add(self._indexfile, isize)
2310 # exposing all file handle for writing.
2313 # exposing all file handle for writing.
2311 self._writinghandles = (ifh, dfh, sdfh)
2314 self._writinghandles = (ifh, dfh, sdfh)
2312 self._segmentfile.writing_handle = ifh if self._inline else dfh
2315 self._segmentfile.writing_handle = ifh if self._inline else dfh
2313 self._segmentfile_sidedata.writing_handle = sdfh
2316 self._segmentfile_sidedata.writing_handle = sdfh
2314 yield
2317 yield
2315 if self._docket is not None:
2318 if self._docket is not None:
2316 self._write_docket(transaction)
2319 self._write_docket(transaction)
2317 finally:
2320 finally:
2318 self._writinghandles = None
2321 self._writinghandles = None
2319 self._segmentfile.writing_handle = None
2322 self._segmentfile.writing_handle = None
2320 self._segmentfile_sidedata.writing_handle = None
2323 self._segmentfile_sidedata.writing_handle = None
2321 if dfh is not None:
2324 if dfh is not None:
2322 dfh.close()
2325 dfh.close()
2323 if sdfh is not None:
2326 if sdfh is not None:
2324 sdfh.close()
2327 sdfh.close()
2325 # closing the index file last to avoid exposing referent to
2328 # closing the index file last to avoid exposing referent to
2326 # potential unflushed data content.
2329 # potential unflushed data content.
2327 if ifh is not None:
2330 if ifh is not None:
2328 ifh.close()
2331 ifh.close()
2329
2332
2330 def _write_docket(self, transaction):
2333 def _write_docket(self, transaction):
2331 """write the current docket on disk
2334 """write the current docket on disk
2332
2335
2333 Exist as a method to help changelog to implement transaction logic
2336 Exist as a method to help changelog to implement transaction logic
2334
2337
2335 We could also imagine using the same transaction logic for all revlog
2338 We could also imagine using the same transaction logic for all revlog
2336 since docket are cheap."""
2339 since docket are cheap."""
2337 self._docket.write(transaction)
2340 self._docket.write(transaction)
2338
2341
2339 def addrevision(
2342 def addrevision(
2340 self,
2343 self,
2341 text,
2344 text,
2342 transaction,
2345 transaction,
2343 link,
2346 link,
2344 p1,
2347 p1,
2345 p2,
2348 p2,
2346 cachedelta=None,
2349 cachedelta=None,
2347 node=None,
2350 node=None,
2348 flags=REVIDX_DEFAULT_FLAGS,
2351 flags=REVIDX_DEFAULT_FLAGS,
2349 deltacomputer=None,
2352 deltacomputer=None,
2350 sidedata=None,
2353 sidedata=None,
2351 ):
2354 ):
2352 """add a revision to the log
2355 """add a revision to the log
2353
2356
2354 text - the revision data to add
2357 text - the revision data to add
2355 transaction - the transaction object used for rollback
2358 transaction - the transaction object used for rollback
2356 link - the linkrev data to add
2359 link - the linkrev data to add
2357 p1, p2 - the parent nodeids of the revision
2360 p1, p2 - the parent nodeids of the revision
2358 cachedelta - an optional precomputed delta
2361 cachedelta - an optional precomputed delta
2359 node - nodeid of revision; typically node is not specified, and it is
2362 node - nodeid of revision; typically node is not specified, and it is
2360 computed by default as hash(text, p1, p2), however subclasses might
2363 computed by default as hash(text, p1, p2), however subclasses might
2361 use different hashing method (and override checkhash() in such case)
2364 use different hashing method (and override checkhash() in such case)
2362 flags - the known flags to set on the revision
2365 flags - the known flags to set on the revision
2363 deltacomputer - an optional deltacomputer instance shared between
2366 deltacomputer - an optional deltacomputer instance shared between
2364 multiple calls
2367 multiple calls
2365 """
2368 """
2366 if link == nullrev:
2369 if link == nullrev:
2367 raise error.RevlogError(
2370 raise error.RevlogError(
2368 _(b"attempted to add linkrev -1 to %s") % self.display_id
2371 _(b"attempted to add linkrev -1 to %s") % self.display_id
2369 )
2372 )
2370
2373
2371 if sidedata is None:
2374 if sidedata is None:
2372 sidedata = {}
2375 sidedata = {}
2373 elif sidedata and not self.hassidedata:
2376 elif sidedata and not self.hassidedata:
2374 raise error.ProgrammingError(
2377 raise error.ProgrammingError(
2375 _(b"trying to add sidedata to a revlog who don't support them")
2378 _(b"trying to add sidedata to a revlog who don't support them")
2376 )
2379 )
2377
2380
2378 if flags:
2381 if flags:
2379 node = node or self.hash(text, p1, p2)
2382 node = node or self.hash(text, p1, p2)
2380
2383
2381 rawtext, validatehash = flagutil.processflagswrite(self, text, flags)
2384 rawtext, validatehash = flagutil.processflagswrite(self, text, flags)
2382
2385
2383 # If the flag processor modifies the revision data, ignore any provided
2386 # If the flag processor modifies the revision data, ignore any provided
2384 # cachedelta.
2387 # cachedelta.
2385 if rawtext != text:
2388 if rawtext != text:
2386 cachedelta = None
2389 cachedelta = None
2387
2390
2388 if len(rawtext) > _maxentrysize:
2391 if len(rawtext) > _maxentrysize:
2389 raise error.RevlogError(
2392 raise error.RevlogError(
2390 _(
2393 _(
2391 b"%s: size of %d bytes exceeds maximum revlog storage of 2GiB"
2394 b"%s: size of %d bytes exceeds maximum revlog storage of 2GiB"
2392 )
2395 )
2393 % (self.display_id, len(rawtext))
2396 % (self.display_id, len(rawtext))
2394 )
2397 )
2395
2398
2396 node = node or self.hash(rawtext, p1, p2)
2399 node = node or self.hash(rawtext, p1, p2)
2397 rev = self.index.get_rev(node)
2400 rev = self.index.get_rev(node)
2398 if rev is not None:
2401 if rev is not None:
2399 return rev
2402 return rev
2400
2403
2401 if validatehash:
2404 if validatehash:
2402 self.checkhash(rawtext, node, p1=p1, p2=p2)
2405 self.checkhash(rawtext, node, p1=p1, p2=p2)
2403
2406
2404 return self.addrawrevision(
2407 return self.addrawrevision(
2405 rawtext,
2408 rawtext,
2406 transaction,
2409 transaction,
2407 link,
2410 link,
2408 p1,
2411 p1,
2409 p2,
2412 p2,
2410 node,
2413 node,
2411 flags,
2414 flags,
2412 cachedelta=cachedelta,
2415 cachedelta=cachedelta,
2413 deltacomputer=deltacomputer,
2416 deltacomputer=deltacomputer,
2414 sidedata=sidedata,
2417 sidedata=sidedata,
2415 )
2418 )
2416
2419
2417 def addrawrevision(
2420 def addrawrevision(
2418 self,
2421 self,
2419 rawtext,
2422 rawtext,
2420 transaction,
2423 transaction,
2421 link,
2424 link,
2422 p1,
2425 p1,
2423 p2,
2426 p2,
2424 node,
2427 node,
2425 flags,
2428 flags,
2426 cachedelta=None,
2429 cachedelta=None,
2427 deltacomputer=None,
2430 deltacomputer=None,
2428 sidedata=None,
2431 sidedata=None,
2429 ):
2432 ):
2430 """add a raw revision with known flags, node and parents
2433 """add a raw revision with known flags, node and parents
2431 useful when reusing a revision not stored in this revlog (ex: received
2434 useful when reusing a revision not stored in this revlog (ex: received
2432 over wire, or read from an external bundle).
2435 over wire, or read from an external bundle).
2433 """
2436 """
2434 with self._writing(transaction):
2437 with self._writing(transaction):
2435 return self._addrevision(
2438 return self._addrevision(
2436 node,
2439 node,
2437 rawtext,
2440 rawtext,
2438 transaction,
2441 transaction,
2439 link,
2442 link,
2440 p1,
2443 p1,
2441 p2,
2444 p2,
2442 flags,
2445 flags,
2443 cachedelta,
2446 cachedelta,
2444 deltacomputer=deltacomputer,
2447 deltacomputer=deltacomputer,
2445 sidedata=sidedata,
2448 sidedata=sidedata,
2446 )
2449 )
2447
2450
2448 def compress(self, data):
2451 def compress(self, data):
2449 """Generate a possibly-compressed representation of data."""
2452 """Generate a possibly-compressed representation of data."""
2450 if not data:
2453 if not data:
2451 return b'', data
2454 return b'', data
2452
2455
2453 compressed = self._compressor.compress(data)
2456 compressed = self._compressor.compress(data)
2454
2457
2455 if compressed:
2458 if compressed:
2456 # The revlog compressor added the header in the returned data.
2459 # The revlog compressor added the header in the returned data.
2457 return b'', compressed
2460 return b'', compressed
2458
2461
2459 if data[0:1] == b'\0':
2462 if data[0:1] == b'\0':
2460 return b'', data
2463 return b'', data
2461 return b'u', data
2464 return b'u', data
2462
2465
2463 def decompress(self, data):
2466 def decompress(self, data):
2464 """Decompress a revlog chunk.
2467 """Decompress a revlog chunk.
2465
2468
2466 The chunk is expected to begin with a header identifying the
2469 The chunk is expected to begin with a header identifying the
2467 format type so it can be routed to an appropriate decompressor.
2470 format type so it can be routed to an appropriate decompressor.
2468 """
2471 """
2469 if not data:
2472 if not data:
2470 return data
2473 return data
2471
2474
2472 # Revlogs are read much more frequently than they are written and many
2475 # Revlogs are read much more frequently than they are written and many
2473 # chunks only take microseconds to decompress, so performance is
2476 # chunks only take microseconds to decompress, so performance is
2474 # important here.
2477 # important here.
2475 #
2478 #
2476 # We can make a few assumptions about revlogs:
2479 # We can make a few assumptions about revlogs:
2477 #
2480 #
2478 # 1) the majority of chunks will be compressed (as opposed to inline
2481 # 1) the majority of chunks will be compressed (as opposed to inline
2479 # raw data).
2482 # raw data).
2480 # 2) decompressing *any* data will likely by at least 10x slower than
2483 # 2) decompressing *any* data will likely by at least 10x slower than
2481 # returning raw inline data.
2484 # returning raw inline data.
2482 # 3) we want to prioritize common and officially supported compression
2485 # 3) we want to prioritize common and officially supported compression
2483 # engines
2486 # engines
2484 #
2487 #
2485 # It follows that we want to optimize for "decompress compressed data
2488 # It follows that we want to optimize for "decompress compressed data
2486 # when encoded with common and officially supported compression engines"
2489 # when encoded with common and officially supported compression engines"
2487 # case over "raw data" and "data encoded by less common or non-official
2490 # case over "raw data" and "data encoded by less common or non-official
2488 # compression engines." That is why we have the inline lookup first
2491 # compression engines." That is why we have the inline lookup first
2489 # followed by the compengines lookup.
2492 # followed by the compengines lookup.
2490 #
2493 #
2491 # According to `hg perfrevlogchunks`, this is ~0.5% faster for zlib
2494 # According to `hg perfrevlogchunks`, this is ~0.5% faster for zlib
2492 # compressed chunks. And this matters for changelog and manifest reads.
2495 # compressed chunks. And this matters for changelog and manifest reads.
2493 t = data[0:1]
2496 t = data[0:1]
2494
2497
2495 if t == b'x':
2498 if t == b'x':
2496 try:
2499 try:
2497 return _zlibdecompress(data)
2500 return _zlibdecompress(data)
2498 except zlib.error as e:
2501 except zlib.error as e:
2499 raise error.RevlogError(
2502 raise error.RevlogError(
2500 _(b'revlog decompress error: %s')
2503 _(b'revlog decompress error: %s')
2501 % stringutil.forcebytestr(e)
2504 % stringutil.forcebytestr(e)
2502 )
2505 )
2503 # '\0' is more common than 'u' so it goes first.
2506 # '\0' is more common than 'u' so it goes first.
2504 elif t == b'\0':
2507 elif t == b'\0':
2505 return data
2508 return data
2506 elif t == b'u':
2509 elif t == b'u':
2507 return util.buffer(data, 1)
2510 return util.buffer(data, 1)
2508
2511
2509 compressor = self._get_decompressor(t)
2512 compressor = self._get_decompressor(t)
2510
2513
2511 return compressor.decompress(data)
2514 return compressor.decompress(data)
2512
2515
2513 def _addrevision(
2516 def _addrevision(
2514 self,
2517 self,
2515 node,
2518 node,
2516 rawtext,
2519 rawtext,
2517 transaction,
2520 transaction,
2518 link,
2521 link,
2519 p1,
2522 p1,
2520 p2,
2523 p2,
2521 flags,
2524 flags,
2522 cachedelta,
2525 cachedelta,
2523 alwayscache=False,
2526 alwayscache=False,
2524 deltacomputer=None,
2527 deltacomputer=None,
2525 sidedata=None,
2528 sidedata=None,
2526 ):
2529 ):
2527 """internal function to add revisions to the log
2530 """internal function to add revisions to the log
2528
2531
2529 see addrevision for argument descriptions.
2532 see addrevision for argument descriptions.
2530
2533
2531 note: "addrevision" takes non-raw text, "_addrevision" takes raw text.
2534 note: "addrevision" takes non-raw text, "_addrevision" takes raw text.
2532
2535
2533 if "deltacomputer" is not provided or None, a defaultdeltacomputer will
2536 if "deltacomputer" is not provided or None, a defaultdeltacomputer will
2534 be used.
2537 be used.
2535
2538
2536 invariants:
2539 invariants:
2537 - rawtext is optional (can be None); if not set, cachedelta must be set.
2540 - rawtext is optional (can be None); if not set, cachedelta must be set.
2538 if both are set, they must correspond to each other.
2541 if both are set, they must correspond to each other.
2539 """
2542 """
2540 if node == self.nullid:
2543 if node == self.nullid:
2541 raise error.RevlogError(
2544 raise error.RevlogError(
2542 _(b"%s: attempt to add null revision") % self.display_id
2545 _(b"%s: attempt to add null revision") % self.display_id
2543 )
2546 )
2544 if (
2547 if (
2545 node == self.nodeconstants.wdirid
2548 node == self.nodeconstants.wdirid
2546 or node in self.nodeconstants.wdirfilenodeids
2549 or node in self.nodeconstants.wdirfilenodeids
2547 ):
2550 ):
2548 raise error.RevlogError(
2551 raise error.RevlogError(
2549 _(b"%s: attempt to add wdir revision") % self.display_id
2552 _(b"%s: attempt to add wdir revision") % self.display_id
2550 )
2553 )
2551 if self._writinghandles is None:
2554 if self._writinghandles is None:
2552 msg = b'adding revision outside `revlog._writing` context'
2555 msg = b'adding revision outside `revlog._writing` context'
2553 raise error.ProgrammingError(msg)
2556 raise error.ProgrammingError(msg)
2554
2557
2555 if self._inline:
2558 if self._inline:
2556 fh = self._writinghandles[0]
2559 fh = self._writinghandles[0]
2557 else:
2560 else:
2558 fh = self._writinghandles[1]
2561 fh = self._writinghandles[1]
2559
2562
2560 btext = [rawtext]
2563 btext = [rawtext]
2561
2564
2562 curr = len(self)
2565 curr = len(self)
2563 prev = curr - 1
2566 prev = curr - 1
2564
2567
2565 offset = self._get_data_offset(prev)
2568 offset = self._get_data_offset(prev)
2566
2569
2567 if self._concurrencychecker:
2570 if self._concurrencychecker:
2568 ifh, dfh, sdfh = self._writinghandles
2571 ifh, dfh, sdfh = self._writinghandles
2569 # XXX no checking for the sidedata file
2572 # XXX no checking for the sidedata file
2570 if self._inline:
2573 if self._inline:
2571 # offset is "as if" it were in the .d file, so we need to add on
2574 # offset is "as if" it were in the .d file, so we need to add on
2572 # the size of the entry metadata.
2575 # the size of the entry metadata.
2573 self._concurrencychecker(
2576 self._concurrencychecker(
2574 ifh, self._indexfile, offset + curr * self.index.entry_size
2577 ifh, self._indexfile, offset + curr * self.index.entry_size
2575 )
2578 )
2576 else:
2579 else:
2577 # Entries in the .i are a consistent size.
2580 # Entries in the .i are a consistent size.
2578 self._concurrencychecker(
2581 self._concurrencychecker(
2579 ifh, self._indexfile, curr * self.index.entry_size
2582 ifh, self._indexfile, curr * self.index.entry_size
2580 )
2583 )
2581 self._concurrencychecker(dfh, self._datafile, offset)
2584 self._concurrencychecker(dfh, self._datafile, offset)
2582
2585
2583 p1r, p2r = self.rev(p1), self.rev(p2)
2586 p1r, p2r = self.rev(p1), self.rev(p2)
2584
2587
2585 # full versions are inserted when the needed deltas
2588 # full versions are inserted when the needed deltas
2586 # become comparable to the uncompressed text
2589 # become comparable to the uncompressed text
2587 if rawtext is None:
2590 if rawtext is None:
2588 # need rawtext size, before changed by flag processors, which is
2591 # need rawtext size, before changed by flag processors, which is
2589 # the non-raw size. use revlog explicitly to avoid filelog's extra
2592 # the non-raw size. use revlog explicitly to avoid filelog's extra
2590 # logic that might remove metadata size.
2593 # logic that might remove metadata size.
2591 textlen = mdiff.patchedsize(
2594 textlen = mdiff.patchedsize(
2592 revlog.size(self, cachedelta[0]), cachedelta[1]
2595 revlog.size(self, cachedelta[0]), cachedelta[1]
2593 )
2596 )
2594 else:
2597 else:
2595 textlen = len(rawtext)
2598 textlen = len(rawtext)
2596
2599
2597 if deltacomputer is None:
2600 if deltacomputer is None:
2598 write_debug = None
2601 write_debug = None
2599 if self._debug_delta:
2602 if self._debug_delta:
2600 write_debug = transaction._report
2603 write_debug = transaction._report
2601 deltacomputer = deltautil.deltacomputer(
2604 deltacomputer = deltautil.deltacomputer(
2602 self, write_debug=write_debug
2605 self, write_debug=write_debug
2603 )
2606 )
2604
2607
2605 if cachedelta is not None and len(cachedelta) == 2:
2608 if cachedelta is not None and len(cachedelta) == 2:
2606 # If the cached delta has no information about how it should be
2609 # If the cached delta has no information about how it should be
2607 # reused, add the default reuse instruction according to the
2610 # reused, add the default reuse instruction according to the
2608 # revlog's configuration.
2611 # revlog's configuration.
2609 if self._generaldelta and self._lazydeltabase:
2612 if self._generaldelta and self._lazydeltabase:
2610 delta_base_reuse = DELTA_BASE_REUSE_TRY
2613 delta_base_reuse = DELTA_BASE_REUSE_TRY
2611 else:
2614 else:
2612 delta_base_reuse = DELTA_BASE_REUSE_NO
2615 delta_base_reuse = DELTA_BASE_REUSE_NO
2613 cachedelta = (cachedelta[0], cachedelta[1], delta_base_reuse)
2616 cachedelta = (cachedelta[0], cachedelta[1], delta_base_reuse)
2614
2617
2615 revinfo = revlogutils.revisioninfo(
2618 revinfo = revlogutils.revisioninfo(
2616 node,
2619 node,
2617 p1,
2620 p1,
2618 p2,
2621 p2,
2619 btext,
2622 btext,
2620 textlen,
2623 textlen,
2621 cachedelta,
2624 cachedelta,
2622 flags,
2625 flags,
2623 )
2626 )
2624
2627
2625 deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
2628 deltainfo = deltacomputer.finddeltainfo(revinfo, fh)
2626
2629
2627 compression_mode = COMP_MODE_INLINE
2630 compression_mode = COMP_MODE_INLINE
2628 if self._docket is not None:
2631 if self._docket is not None:
2629 default_comp = self._docket.default_compression_header
2632 default_comp = self._docket.default_compression_header
2630 r = deltautil.delta_compression(default_comp, deltainfo)
2633 r = deltautil.delta_compression(default_comp, deltainfo)
2631 compression_mode, deltainfo = r
2634 compression_mode, deltainfo = r
2632
2635
2633 sidedata_compression_mode = COMP_MODE_INLINE
2636 sidedata_compression_mode = COMP_MODE_INLINE
2634 if sidedata and self.hassidedata:
2637 if sidedata and self.hassidedata:
2635 sidedata_compression_mode = COMP_MODE_PLAIN
2638 sidedata_compression_mode = COMP_MODE_PLAIN
2636 serialized_sidedata = sidedatautil.serialize_sidedata(sidedata)
2639 serialized_sidedata = sidedatautil.serialize_sidedata(sidedata)
2637 sidedata_offset = self._docket.sidedata_end
2640 sidedata_offset = self._docket.sidedata_end
2638 h, comp_sidedata = self.compress(serialized_sidedata)
2641 h, comp_sidedata = self.compress(serialized_sidedata)
2639 if (
2642 if (
2640 h != b'u'
2643 h != b'u'
2641 and comp_sidedata[0:1] != b'\0'
2644 and comp_sidedata[0:1] != b'\0'
2642 and len(comp_sidedata) < len(serialized_sidedata)
2645 and len(comp_sidedata) < len(serialized_sidedata)
2643 ):
2646 ):
2644 assert not h
2647 assert not h
2645 if (
2648 if (
2646 comp_sidedata[0:1]
2649 comp_sidedata[0:1]
2647 == self._docket.default_compression_header
2650 == self._docket.default_compression_header
2648 ):
2651 ):
2649 sidedata_compression_mode = COMP_MODE_DEFAULT
2652 sidedata_compression_mode = COMP_MODE_DEFAULT
2650 serialized_sidedata = comp_sidedata
2653 serialized_sidedata = comp_sidedata
2651 else:
2654 else:
2652 sidedata_compression_mode = COMP_MODE_INLINE
2655 sidedata_compression_mode = COMP_MODE_INLINE
2653 serialized_sidedata = comp_sidedata
2656 serialized_sidedata = comp_sidedata
2654 else:
2657 else:
2655 serialized_sidedata = b""
2658 serialized_sidedata = b""
2656 # Don't store the offset if the sidedata is empty, that way
2659 # Don't store the offset if the sidedata is empty, that way
2657 # we can easily detect empty sidedata and they will be no different
2660 # we can easily detect empty sidedata and they will be no different
2658 # than ones we manually add.
2661 # than ones we manually add.
2659 sidedata_offset = 0
2662 sidedata_offset = 0
2660
2663
2661 rank = RANK_UNKNOWN
2664 rank = RANK_UNKNOWN
2662 if self._compute_rank:
2665 if self._compute_rank:
2663 if (p1r, p2r) == (nullrev, nullrev):
2666 if (p1r, p2r) == (nullrev, nullrev):
2664 rank = 1
2667 rank = 1
2665 elif p1r != nullrev and p2r == nullrev:
2668 elif p1r != nullrev and p2r == nullrev:
2666 rank = 1 + self.fast_rank(p1r)
2669 rank = 1 + self.fast_rank(p1r)
2667 elif p1r == nullrev and p2r != nullrev:
2670 elif p1r == nullrev and p2r != nullrev:
2668 rank = 1 + self.fast_rank(p2r)
2671 rank = 1 + self.fast_rank(p2r)
2669 else: # merge node
2672 else: # merge node
2670 if rustdagop is not None and self.index.rust_ext_compat:
2673 if rustdagop is not None and self.index.rust_ext_compat:
2671 rank = rustdagop.rank(self.index, p1r, p2r)
2674 rank = rustdagop.rank(self.index, p1r, p2r)
2672 else:
2675 else:
2673 pmin, pmax = sorted((p1r, p2r))
2676 pmin, pmax = sorted((p1r, p2r))
2674 rank = 1 + self.fast_rank(pmax)
2677 rank = 1 + self.fast_rank(pmax)
2675 rank += sum(1 for _ in self.findmissingrevs([pmax], [pmin]))
2678 rank += sum(1 for _ in self.findmissingrevs([pmax], [pmin]))
2676
2679
2677 e = revlogutils.entry(
2680 e = revlogutils.entry(
2678 flags=flags,
2681 flags=flags,
2679 data_offset=offset,
2682 data_offset=offset,
2680 data_compressed_length=deltainfo.deltalen,
2683 data_compressed_length=deltainfo.deltalen,
2681 data_uncompressed_length=textlen,
2684 data_uncompressed_length=textlen,
2682 data_compression_mode=compression_mode,
2685 data_compression_mode=compression_mode,
2683 data_delta_base=deltainfo.base,
2686 data_delta_base=deltainfo.base,
2684 link_rev=link,
2687 link_rev=link,
2685 parent_rev_1=p1r,
2688 parent_rev_1=p1r,
2686 parent_rev_2=p2r,
2689 parent_rev_2=p2r,
2687 node_id=node,
2690 node_id=node,
2688 sidedata_offset=sidedata_offset,
2691 sidedata_offset=sidedata_offset,
2689 sidedata_compressed_length=len(serialized_sidedata),
2692 sidedata_compressed_length=len(serialized_sidedata),
2690 sidedata_compression_mode=sidedata_compression_mode,
2693 sidedata_compression_mode=sidedata_compression_mode,
2691 rank=rank,
2694 rank=rank,
2692 )
2695 )
2693
2696
2694 self.index.append(e)
2697 self.index.append(e)
2695 entry = self.index.entry_binary(curr)
2698 entry = self.index.entry_binary(curr)
2696 if curr == 0 and self._docket is None:
2699 if curr == 0 and self._docket is None:
2697 header = self._format_flags | self._format_version
2700 header = self._format_flags | self._format_version
2698 header = self.index.pack_header(header)
2701 header = self.index.pack_header(header)
2699 entry = header + entry
2702 entry = header + entry
2700 self._writeentry(
2703 self._writeentry(
2701 transaction,
2704 transaction,
2702 entry,
2705 entry,
2703 deltainfo.data,
2706 deltainfo.data,
2704 link,
2707 link,
2705 offset,
2708 offset,
2706 serialized_sidedata,
2709 serialized_sidedata,
2707 sidedata_offset,
2710 sidedata_offset,
2708 )
2711 )
2709
2712
2710 rawtext = btext[0]
2713 rawtext = btext[0]
2711
2714
2712 if alwayscache and rawtext is None:
2715 if alwayscache and rawtext is None:
2713 rawtext = deltacomputer.buildtext(revinfo, fh)
2716 rawtext = deltacomputer.buildtext(revinfo, fh)
2714
2717
2715 if type(rawtext) == bytes: # only accept immutable objects
2718 if type(rawtext) == bytes: # only accept immutable objects
2716 self._revisioncache = (node, curr, rawtext)
2719 self._revisioncache = (node, curr, rawtext)
2717 self._chainbasecache[curr] = deltainfo.chainbase
2720 self._chainbasecache[curr] = deltainfo.chainbase
2718 return curr
2721 return curr
2719
2722
2720 def _get_data_offset(self, prev):
2723 def _get_data_offset(self, prev):
2721 """Returns the current offset in the (in-transaction) data file.
2724 """Returns the current offset in the (in-transaction) data file.
2722 Versions < 2 of the revlog can get this 0(1), revlog v2 needs a docket
2725 Versions < 2 of the revlog can get this 0(1), revlog v2 needs a docket
2723 file to store that information: since sidedata can be rewritten to the
2726 file to store that information: since sidedata can be rewritten to the
2724 end of the data file within a transaction, you can have cases where, for
2727 end of the data file within a transaction, you can have cases where, for
2725 example, rev `n` does not have sidedata while rev `n - 1` does, leading
2728 example, rev `n` does not have sidedata while rev `n - 1` does, leading
2726 to `n - 1`'s sidedata being written after `n`'s data.
2729 to `n - 1`'s sidedata being written after `n`'s data.
2727
2730
2728 TODO cache this in a docket file before getting out of experimental."""
2731 TODO cache this in a docket file before getting out of experimental."""
2729 if self._docket is None:
2732 if self._docket is None:
2730 return self.end(prev)
2733 return self.end(prev)
2731 else:
2734 else:
2732 return self._docket.data_end
2735 return self._docket.data_end
2733
2736
2734 def _writeentry(
2737 def _writeentry(
2735 self, transaction, entry, data, link, offset, sidedata, sidedata_offset
2738 self, transaction, entry, data, link, offset, sidedata, sidedata_offset
2736 ):
2739 ):
2737 # Files opened in a+ mode have inconsistent behavior on various
2740 # Files opened in a+ mode have inconsistent behavior on various
2738 # platforms. Windows requires that a file positioning call be made
2741 # platforms. Windows requires that a file positioning call be made
2739 # when the file handle transitions between reads and writes. See
2742 # when the file handle transitions between reads and writes. See
2740 # 3686fa2b8eee and the mixedfilemodewrapper in windows.py. On other
2743 # 3686fa2b8eee and the mixedfilemodewrapper in windows.py. On other
2741 # platforms, Python or the platform itself can be buggy. Some versions
2744 # platforms, Python or the platform itself can be buggy. Some versions
2742 # of Solaris have been observed to not append at the end of the file
2745 # of Solaris have been observed to not append at the end of the file
2743 # if the file was seeked to before the end. See issue4943 for more.
2746 # if the file was seeked to before the end. See issue4943 for more.
2744 #
2747 #
2745 # We work around this issue by inserting a seek() before writing.
2748 # We work around this issue by inserting a seek() before writing.
2746 # Note: This is likely not necessary on Python 3. However, because
2749 # Note: This is likely not necessary on Python 3. However, because
2747 # the file handle is reused for reads and may be seeked there, we need
2750 # the file handle is reused for reads and may be seeked there, we need
2748 # to be careful before changing this.
2751 # to be careful before changing this.
2749 if self._writinghandles is None:
2752 if self._writinghandles is None:
2750 msg = b'adding revision outside `revlog._writing` context'
2753 msg = b'adding revision outside `revlog._writing` context'
2751 raise error.ProgrammingError(msg)
2754 raise error.ProgrammingError(msg)
2752 ifh, dfh, sdfh = self._writinghandles
2755 ifh, dfh, sdfh = self._writinghandles
2753 if self._docket is None:
2756 if self._docket is None:
2754 ifh.seek(0, os.SEEK_END)
2757 ifh.seek(0, os.SEEK_END)
2755 else:
2758 else:
2756 ifh.seek(self._docket.index_end, os.SEEK_SET)
2759 ifh.seek(self._docket.index_end, os.SEEK_SET)
2757 if dfh:
2760 if dfh:
2758 if self._docket is None:
2761 if self._docket is None:
2759 dfh.seek(0, os.SEEK_END)
2762 dfh.seek(0, os.SEEK_END)
2760 else:
2763 else:
2761 dfh.seek(self._docket.data_end, os.SEEK_SET)
2764 dfh.seek(self._docket.data_end, os.SEEK_SET)
2762 if sdfh:
2765 if sdfh:
2763 sdfh.seek(self._docket.sidedata_end, os.SEEK_SET)
2766 sdfh.seek(self._docket.sidedata_end, os.SEEK_SET)
2764
2767
2765 curr = len(self) - 1
2768 curr = len(self) - 1
2766 if not self._inline:
2769 if not self._inline:
2767 transaction.add(self._datafile, offset)
2770 transaction.add(self._datafile, offset)
2768 if self._sidedatafile:
2771 if self._sidedatafile:
2769 transaction.add(self._sidedatafile, sidedata_offset)
2772 transaction.add(self._sidedatafile, sidedata_offset)
2770 transaction.add(self._indexfile, curr * len(entry))
2773 transaction.add(self._indexfile, curr * len(entry))
2771 if data[0]:
2774 if data[0]:
2772 dfh.write(data[0])
2775 dfh.write(data[0])
2773 dfh.write(data[1])
2776 dfh.write(data[1])
2774 if sidedata:
2777 if sidedata:
2775 sdfh.write(sidedata)
2778 sdfh.write(sidedata)
2776 ifh.write(entry)
2779 ifh.write(entry)
2777 else:
2780 else:
2778 offset += curr * self.index.entry_size
2781 offset += curr * self.index.entry_size
2779 transaction.add(self._indexfile, offset)
2782 transaction.add(self._indexfile, offset)
2780 ifh.write(entry)
2783 ifh.write(entry)
2781 ifh.write(data[0])
2784 ifh.write(data[0])
2782 ifh.write(data[1])
2785 ifh.write(data[1])
2783 assert not sidedata
2786 assert not sidedata
2784 self._enforceinlinesize(transaction)
2787 self._enforceinlinesize(transaction)
2785 if self._docket is not None:
2788 if self._docket is not None:
2786 # revlog-v2 always has 3 writing handles, help Pytype
2789 # revlog-v2 always has 3 writing handles, help Pytype
2787 wh1 = self._writinghandles[0]
2790 wh1 = self._writinghandles[0]
2788 wh2 = self._writinghandles[1]
2791 wh2 = self._writinghandles[1]
2789 wh3 = self._writinghandles[2]
2792 wh3 = self._writinghandles[2]
2790 assert wh1 is not None
2793 assert wh1 is not None
2791 assert wh2 is not None
2794 assert wh2 is not None
2792 assert wh3 is not None
2795 assert wh3 is not None
2793 self._docket.index_end = wh1.tell()
2796 self._docket.index_end = wh1.tell()
2794 self._docket.data_end = wh2.tell()
2797 self._docket.data_end = wh2.tell()
2795 self._docket.sidedata_end = wh3.tell()
2798 self._docket.sidedata_end = wh3.tell()
2796
2799
2797 nodemaputil.setup_persistent_nodemap(transaction, self)
2800 nodemaputil.setup_persistent_nodemap(transaction, self)
2798
2801
2799 def addgroup(
2802 def addgroup(
2800 self,
2803 self,
2801 deltas,
2804 deltas,
2802 linkmapper,
2805 linkmapper,
2803 transaction,
2806 transaction,
2804 alwayscache=False,
2807 alwayscache=False,
2805 addrevisioncb=None,
2808 addrevisioncb=None,
2806 duplicaterevisioncb=None,
2809 duplicaterevisioncb=None,
2807 debug_info=None,
2810 debug_info=None,
2808 delta_base_reuse_policy=None,
2811 delta_base_reuse_policy=None,
2809 ):
2812 ):
2810 """
2813 """
2811 add a delta group
2814 add a delta group
2812
2815
2813 given a set of deltas, add them to the revision log. the
2816 given a set of deltas, add them to the revision log. the
2814 first delta is against its parent, which should be in our
2817 first delta is against its parent, which should be in our
2815 log, the rest are against the previous delta.
2818 log, the rest are against the previous delta.
2816
2819
2817 If ``addrevisioncb`` is defined, it will be called with arguments of
2820 If ``addrevisioncb`` is defined, it will be called with arguments of
2818 this revlog and the node that was added.
2821 this revlog and the node that was added.
2819 """
2822 """
2820
2823
2821 if self._adding_group:
2824 if self._adding_group:
2822 raise error.ProgrammingError(b'cannot nest addgroup() calls')
2825 raise error.ProgrammingError(b'cannot nest addgroup() calls')
2823
2826
2824 # read the default delta-base reuse policy from revlog config if the
2827 # read the default delta-base reuse policy from revlog config if the
2825 # group did not specify one.
2828 # group did not specify one.
2826 if delta_base_reuse_policy is None:
2829 if delta_base_reuse_policy is None:
2827 if self._generaldelta and self._lazydeltabase:
2830 if self._generaldelta and self._lazydeltabase:
2828 delta_base_reuse_policy = DELTA_BASE_REUSE_TRY
2831 delta_base_reuse_policy = DELTA_BASE_REUSE_TRY
2829 else:
2832 else:
2830 delta_base_reuse_policy = DELTA_BASE_REUSE_NO
2833 delta_base_reuse_policy = DELTA_BASE_REUSE_NO
2831
2834
2832 self._adding_group = True
2835 self._adding_group = True
2833 empty = True
2836 empty = True
2834 try:
2837 try:
2835 with self._writing(transaction):
2838 with self._writing(transaction):
2836 write_debug = None
2839 write_debug = None
2837 if self._debug_delta:
2840 if self._debug_delta:
2838 write_debug = transaction._report
2841 write_debug = transaction._report
2839 deltacomputer = deltautil.deltacomputer(
2842 deltacomputer = deltautil.deltacomputer(
2840 self,
2843 self,
2841 write_debug=write_debug,
2844 write_debug=write_debug,
2842 debug_info=debug_info,
2845 debug_info=debug_info,
2843 )
2846 )
2844 # loop through our set of deltas
2847 # loop through our set of deltas
2845 for data in deltas:
2848 for data in deltas:
2846 (
2849 (
2847 node,
2850 node,
2848 p1,
2851 p1,
2849 p2,
2852 p2,
2850 linknode,
2853 linknode,
2851 deltabase,
2854 deltabase,
2852 delta,
2855 delta,
2853 flags,
2856 flags,
2854 sidedata,
2857 sidedata,
2855 ) = data
2858 ) = data
2856 link = linkmapper(linknode)
2859 link = linkmapper(linknode)
2857 flags = flags or REVIDX_DEFAULT_FLAGS
2860 flags = flags or REVIDX_DEFAULT_FLAGS
2858
2861
2859 rev = self.index.get_rev(node)
2862 rev = self.index.get_rev(node)
2860 if rev is not None:
2863 if rev is not None:
2861 # this can happen if two branches make the same change
2864 # this can happen if two branches make the same change
2862 self._nodeduplicatecallback(transaction, rev)
2865 self._nodeduplicatecallback(transaction, rev)
2863 if duplicaterevisioncb:
2866 if duplicaterevisioncb:
2864 duplicaterevisioncb(self, rev)
2867 duplicaterevisioncb(self, rev)
2865 empty = False
2868 empty = False
2866 continue
2869 continue
2867
2870
2868 for p in (p1, p2):
2871 for p in (p1, p2):
2869 if not self.index.has_node(p):
2872 if not self.index.has_node(p):
2870 raise error.LookupError(
2873 raise error.LookupError(
2871 p, self.radix, _(b'unknown parent')
2874 p, self.radix, _(b'unknown parent')
2872 )
2875 )
2873
2876
2874 if not self.index.has_node(deltabase):
2877 if not self.index.has_node(deltabase):
2875 raise error.LookupError(
2878 raise error.LookupError(
2876 deltabase, self.display_id, _(b'unknown delta base')
2879 deltabase, self.display_id, _(b'unknown delta base')
2877 )
2880 )
2878
2881
2879 baserev = self.rev(deltabase)
2882 baserev = self.rev(deltabase)
2880
2883
2881 if baserev != nullrev and self.iscensored(baserev):
2884 if baserev != nullrev and self.iscensored(baserev):
2882 # if base is censored, delta must be full replacement in a
2885 # if base is censored, delta must be full replacement in a
2883 # single patch operation
2886 # single patch operation
2884 hlen = struct.calcsize(b">lll")
2887 hlen = struct.calcsize(b">lll")
2885 oldlen = self.rawsize(baserev)
2888 oldlen = self.rawsize(baserev)
2886 newlen = len(delta) - hlen
2889 newlen = len(delta) - hlen
2887 if delta[:hlen] != mdiff.replacediffheader(
2890 if delta[:hlen] != mdiff.replacediffheader(
2888 oldlen, newlen
2891 oldlen, newlen
2889 ):
2892 ):
2890 raise error.CensoredBaseError(
2893 raise error.CensoredBaseError(
2891 self.display_id, self.node(baserev)
2894 self.display_id, self.node(baserev)
2892 )
2895 )
2893
2896
2894 if not flags and self._peek_iscensored(baserev, delta):
2897 if not flags and self._peek_iscensored(baserev, delta):
2895 flags |= REVIDX_ISCENSORED
2898 flags |= REVIDX_ISCENSORED
2896
2899
2897 # We assume consumers of addrevisioncb will want to retrieve
2900 # We assume consumers of addrevisioncb will want to retrieve
2898 # the added revision, which will require a call to
2901 # the added revision, which will require a call to
2899 # revision(). revision() will fast path if there is a cache
2902 # revision(). revision() will fast path if there is a cache
2900 # hit. So, we tell _addrevision() to always cache in this case.
2903 # hit. So, we tell _addrevision() to always cache in this case.
2901 # We're only using addgroup() in the context of changegroup
2904 # We're only using addgroup() in the context of changegroup
2902 # generation so the revision data can always be handled as raw
2905 # generation so the revision data can always be handled as raw
2903 # by the flagprocessor.
2906 # by the flagprocessor.
2904 rev = self._addrevision(
2907 rev = self._addrevision(
2905 node,
2908 node,
2906 None,
2909 None,
2907 transaction,
2910 transaction,
2908 link,
2911 link,
2909 p1,
2912 p1,
2910 p2,
2913 p2,
2911 flags,
2914 flags,
2912 (baserev, delta, delta_base_reuse_policy),
2915 (baserev, delta, delta_base_reuse_policy),
2913 alwayscache=alwayscache,
2916 alwayscache=alwayscache,
2914 deltacomputer=deltacomputer,
2917 deltacomputer=deltacomputer,
2915 sidedata=sidedata,
2918 sidedata=sidedata,
2916 )
2919 )
2917
2920
2918 if addrevisioncb:
2921 if addrevisioncb:
2919 addrevisioncb(self, rev)
2922 addrevisioncb(self, rev)
2920 empty = False
2923 empty = False
2921 finally:
2924 finally:
2922 self._adding_group = False
2925 self._adding_group = False
2923 return not empty
2926 return not empty
2924
2927
2925 def iscensored(self, rev):
2928 def iscensored(self, rev):
2926 """Check if a file revision is censored."""
2929 """Check if a file revision is censored."""
2927 if not self._censorable:
2930 if not self._censorable:
2928 return False
2931 return False
2929
2932
2930 return self.flags(rev) & REVIDX_ISCENSORED
2933 return self.flags(rev) & REVIDX_ISCENSORED
2931
2934
2932 def _peek_iscensored(self, baserev, delta):
2935 def _peek_iscensored(self, baserev, delta):
2933 """Quickly check if a delta produces a censored revision."""
2936 """Quickly check if a delta produces a censored revision."""
2934 if not self._censorable:
2937 if not self._censorable:
2935 return False
2938 return False
2936
2939
2937 return storageutil.deltaiscensored(delta, baserev, self.rawsize)
2940 return storageutil.deltaiscensored(delta, baserev, self.rawsize)
2938
2941
2939 def getstrippoint(self, minlink):
2942 def getstrippoint(self, minlink):
2940 """find the minimum rev that must be stripped to strip the linkrev
2943 """find the minimum rev that must be stripped to strip the linkrev
2941
2944
2942 Returns a tuple containing the minimum rev and a set of all revs that
2945 Returns a tuple containing the minimum rev and a set of all revs that
2943 have linkrevs that will be broken by this strip.
2946 have linkrevs that will be broken by this strip.
2944 """
2947 """
2945 return storageutil.resolvestripinfo(
2948 return storageutil.resolvestripinfo(
2946 minlink,
2949 minlink,
2947 len(self) - 1,
2950 len(self) - 1,
2948 self.headrevs(),
2951 self.headrevs(),
2949 self.linkrev,
2952 self.linkrev,
2950 self.parentrevs,
2953 self.parentrevs,
2951 )
2954 )
2952
2955
2953 def strip(self, minlink, transaction):
2956 def strip(self, minlink, transaction):
2954 """truncate the revlog on the first revision with a linkrev >= minlink
2957 """truncate the revlog on the first revision with a linkrev >= minlink
2955
2958
2956 This function is called when we're stripping revision minlink and
2959 This function is called when we're stripping revision minlink and
2957 its descendants from the repository.
2960 its descendants from the repository.
2958
2961
2959 We have to remove all revisions with linkrev >= minlink, because
2962 We have to remove all revisions with linkrev >= minlink, because
2960 the equivalent changelog revisions will be renumbered after the
2963 the equivalent changelog revisions will be renumbered after the
2961 strip.
2964 strip.
2962
2965
2963 So we truncate the revlog on the first of these revisions, and
2966 So we truncate the revlog on the first of these revisions, and
2964 trust that the caller has saved the revisions that shouldn't be
2967 trust that the caller has saved the revisions that shouldn't be
2965 removed and that it'll re-add them after this truncation.
2968 removed and that it'll re-add them after this truncation.
2966 """
2969 """
2967 if len(self) == 0:
2970 if len(self) == 0:
2968 return
2971 return
2969
2972
2970 rev, _ = self.getstrippoint(minlink)
2973 rev, _ = self.getstrippoint(minlink)
2971 if rev == len(self):
2974 if rev == len(self):
2972 return
2975 return
2973
2976
2974 # first truncate the files on disk
2977 # first truncate the files on disk
2975 data_end = self.start(rev)
2978 data_end = self.start(rev)
2976 if not self._inline:
2979 if not self._inline:
2977 transaction.add(self._datafile, data_end)
2980 transaction.add(self._datafile, data_end)
2978 end = rev * self.index.entry_size
2981 end = rev * self.index.entry_size
2979 else:
2982 else:
2980 end = data_end + (rev * self.index.entry_size)
2983 end = data_end + (rev * self.index.entry_size)
2981
2984
2982 if self._sidedatafile:
2985 if self._sidedatafile:
2983 sidedata_end = self.sidedata_cut_off(rev)
2986 sidedata_end = self.sidedata_cut_off(rev)
2984 transaction.add(self._sidedatafile, sidedata_end)
2987 transaction.add(self._sidedatafile, sidedata_end)
2985
2988
2986 transaction.add(self._indexfile, end)
2989 transaction.add(self._indexfile, end)
2987 if self._docket is not None:
2990 if self._docket is not None:
2988 # XXX we could, leverage the docket while stripping. However it is
2991 # XXX we could, leverage the docket while stripping. However it is
2989 # not powerfull enough at the time of this comment
2992 # not powerfull enough at the time of this comment
2990 self._docket.index_end = end
2993 self._docket.index_end = end
2991 self._docket.data_end = data_end
2994 self._docket.data_end = data_end
2992 self._docket.sidedata_end = sidedata_end
2995 self._docket.sidedata_end = sidedata_end
2993 self._docket.write(transaction, stripping=True)
2996 self._docket.write(transaction, stripping=True)
2994
2997
2995 # then reset internal state in memory to forget those revisions
2998 # then reset internal state in memory to forget those revisions
2996 self._revisioncache = None
2999 self._revisioncache = None
2997 self._chaininfocache = util.lrucachedict(500)
3000 self._chaininfocache = util.lrucachedict(500)
2998 self._segmentfile.clear_cache()
3001 self._segmentfile.clear_cache()
2999 self._segmentfile_sidedata.clear_cache()
3002 self._segmentfile_sidedata.clear_cache()
3000
3003
3001 del self.index[rev:-1]
3004 del self.index[rev:-1]
3002
3005
3003 def checksize(self):
3006 def checksize(self):
3004 """Check size of index and data files
3007 """Check size of index and data files
3005
3008
3006 return a (dd, di) tuple.
3009 return a (dd, di) tuple.
3007 - dd: extra bytes for the "data" file
3010 - dd: extra bytes for the "data" file
3008 - di: extra bytes for the "index" file
3011 - di: extra bytes for the "index" file
3009
3012
3010 A healthy revlog will return (0, 0).
3013 A healthy revlog will return (0, 0).
3011 """
3014 """
3012 expected = 0
3015 expected = 0
3013 if len(self):
3016 if len(self):
3014 expected = max(0, self.end(len(self) - 1))
3017 expected = max(0, self.end(len(self) - 1))
3015
3018
3016 try:
3019 try:
3017 with self._datafp() as f:
3020 with self._datafp() as f:
3018 f.seek(0, io.SEEK_END)
3021 f.seek(0, io.SEEK_END)
3019 actual = f.tell()
3022 actual = f.tell()
3020 dd = actual - expected
3023 dd = actual - expected
3021 except FileNotFoundError:
3024 except FileNotFoundError:
3022 dd = 0
3025 dd = 0
3023
3026
3024 try:
3027 try:
3025 f = self.opener(self._indexfile)
3028 f = self.opener(self._indexfile)
3026 f.seek(0, io.SEEK_END)
3029 f.seek(0, io.SEEK_END)
3027 actual = f.tell()
3030 actual = f.tell()
3028 f.close()
3031 f.close()
3029 s = self.index.entry_size
3032 s = self.index.entry_size
3030 i = max(0, actual // s)
3033 i = max(0, actual // s)
3031 di = actual - (i * s)
3034 di = actual - (i * s)
3032 if self._inline:
3035 if self._inline:
3033 databytes = 0
3036 databytes = 0
3034 for r in self:
3037 for r in self:
3035 databytes += max(0, self.length(r))
3038 databytes += max(0, self.length(r))
3036 dd = 0
3039 dd = 0
3037 di = actual - len(self) * s - databytes
3040 di = actual - len(self) * s - databytes
3038 except FileNotFoundError:
3041 except FileNotFoundError:
3039 di = 0
3042 di = 0
3040
3043
3041 return (dd, di)
3044 return (dd, di)
3042
3045
3043 def files(self):
3046 def files(self):
3044 res = [self._indexfile]
3047 res = [self._indexfile]
3045 if self._docket_file is None:
3048 if self._docket_file is None:
3046 if not self._inline:
3049 if not self._inline:
3047 res.append(self._datafile)
3050 res.append(self._datafile)
3048 else:
3051 else:
3049 res.append(self._docket_file)
3052 res.append(self._docket_file)
3050 res.extend(self._docket.old_index_filepaths(include_empty=False))
3053 res.extend(self._docket.old_index_filepaths(include_empty=False))
3051 if self._docket.data_end:
3054 if self._docket.data_end:
3052 res.append(self._datafile)
3055 res.append(self._datafile)
3053 res.extend(self._docket.old_data_filepaths(include_empty=False))
3056 res.extend(self._docket.old_data_filepaths(include_empty=False))
3054 if self._docket.sidedata_end:
3057 if self._docket.sidedata_end:
3055 res.append(self._sidedatafile)
3058 res.append(self._sidedatafile)
3056 res.extend(self._docket.old_sidedata_filepaths(include_empty=False))
3059 res.extend(self._docket.old_sidedata_filepaths(include_empty=False))
3057 return res
3060 return res
3058
3061
3059 def emitrevisions(
3062 def emitrevisions(
3060 self,
3063 self,
3061 nodes,
3064 nodes,
3062 nodesorder=None,
3065 nodesorder=None,
3063 revisiondata=False,
3066 revisiondata=False,
3064 assumehaveparentrevisions=False,
3067 assumehaveparentrevisions=False,
3065 deltamode=repository.CG_DELTAMODE_STD,
3068 deltamode=repository.CG_DELTAMODE_STD,
3066 sidedata_helpers=None,
3069 sidedata_helpers=None,
3067 debug_info=None,
3070 debug_info=None,
3068 ):
3071 ):
3069 if nodesorder not in (b'nodes', b'storage', b'linear', None):
3072 if nodesorder not in (b'nodes', b'storage', b'linear', None):
3070 raise error.ProgrammingError(
3073 raise error.ProgrammingError(
3071 b'unhandled value for nodesorder: %s' % nodesorder
3074 b'unhandled value for nodesorder: %s' % nodesorder
3072 )
3075 )
3073
3076
3074 if nodesorder is None and not self._generaldelta:
3077 if nodesorder is None and not self._generaldelta:
3075 nodesorder = b'storage'
3078 nodesorder = b'storage'
3076
3079
3077 if (
3080 if (
3078 not self._storedeltachains
3081 not self._storedeltachains
3079 and deltamode != repository.CG_DELTAMODE_PREV
3082 and deltamode != repository.CG_DELTAMODE_PREV
3080 ):
3083 ):
3081 deltamode = repository.CG_DELTAMODE_FULL
3084 deltamode = repository.CG_DELTAMODE_FULL
3082
3085
3083 return storageutil.emitrevisions(
3086 return storageutil.emitrevisions(
3084 self,
3087 self,
3085 nodes,
3088 nodes,
3086 nodesorder,
3089 nodesorder,
3087 revlogrevisiondelta,
3090 revlogrevisiondelta,
3088 deltaparentfn=self.deltaparent,
3091 deltaparentfn=self.deltaparent,
3089 candeltafn=self.candelta,
3092 candeltafn=self.candelta,
3090 rawsizefn=self.rawsize,
3093 rawsizefn=self.rawsize,
3091 revdifffn=self.revdiff,
3094 revdifffn=self.revdiff,
3092 flagsfn=self.flags,
3095 flagsfn=self.flags,
3093 deltamode=deltamode,
3096 deltamode=deltamode,
3094 revisiondata=revisiondata,
3097 revisiondata=revisiondata,
3095 assumehaveparentrevisions=assumehaveparentrevisions,
3098 assumehaveparentrevisions=assumehaveparentrevisions,
3096 sidedata_helpers=sidedata_helpers,
3099 sidedata_helpers=sidedata_helpers,
3097 debug_info=debug_info,
3100 debug_info=debug_info,
3098 )
3101 )
3099
3102
3100 DELTAREUSEALWAYS = b'always'
3103 DELTAREUSEALWAYS = b'always'
3101 DELTAREUSESAMEREVS = b'samerevs'
3104 DELTAREUSESAMEREVS = b'samerevs'
3102 DELTAREUSENEVER = b'never'
3105 DELTAREUSENEVER = b'never'
3103
3106
3104 DELTAREUSEFULLADD = b'fulladd'
3107 DELTAREUSEFULLADD = b'fulladd'
3105
3108
3106 DELTAREUSEALL = {b'always', b'samerevs', b'never', b'fulladd'}
3109 DELTAREUSEALL = {b'always', b'samerevs', b'never', b'fulladd'}
3107
3110
3108 def clone(
3111 def clone(
3109 self,
3112 self,
3110 tr,
3113 tr,
3111 destrevlog,
3114 destrevlog,
3112 addrevisioncb=None,
3115 addrevisioncb=None,
3113 deltareuse=DELTAREUSESAMEREVS,
3116 deltareuse=DELTAREUSESAMEREVS,
3114 forcedeltabothparents=None,
3117 forcedeltabothparents=None,
3115 sidedata_helpers=None,
3118 sidedata_helpers=None,
3116 ):
3119 ):
3117 """Copy this revlog to another, possibly with format changes.
3120 """Copy this revlog to another, possibly with format changes.
3118
3121
3119 The destination revlog will contain the same revisions and nodes.
3122 The destination revlog will contain the same revisions and nodes.
3120 However, it may not be bit-for-bit identical due to e.g. delta encoding
3123 However, it may not be bit-for-bit identical due to e.g. delta encoding
3121 differences.
3124 differences.
3122
3125
3123 The ``deltareuse`` argument control how deltas from the existing revlog
3126 The ``deltareuse`` argument control how deltas from the existing revlog
3124 are preserved in the destination revlog. The argument can have the
3127 are preserved in the destination revlog. The argument can have the
3125 following values:
3128 following values:
3126
3129
3127 DELTAREUSEALWAYS
3130 DELTAREUSEALWAYS
3128 Deltas will always be reused (if possible), even if the destination
3131 Deltas will always be reused (if possible), even if the destination
3129 revlog would not select the same revisions for the delta. This is the
3132 revlog would not select the same revisions for the delta. This is the
3130 fastest mode of operation.
3133 fastest mode of operation.
3131 DELTAREUSESAMEREVS
3134 DELTAREUSESAMEREVS
3132 Deltas will be reused if the destination revlog would pick the same
3135 Deltas will be reused if the destination revlog would pick the same
3133 revisions for the delta. This mode strikes a balance between speed
3136 revisions for the delta. This mode strikes a balance between speed
3134 and optimization.
3137 and optimization.
3135 DELTAREUSENEVER
3138 DELTAREUSENEVER
3136 Deltas will never be reused. This is the slowest mode of execution.
3139 Deltas will never be reused. This is the slowest mode of execution.
3137 This mode can be used to recompute deltas (e.g. if the diff/delta
3140 This mode can be used to recompute deltas (e.g. if the diff/delta
3138 algorithm changes).
3141 algorithm changes).
3139 DELTAREUSEFULLADD
3142 DELTAREUSEFULLADD
3140 Revision will be re-added as if their were new content. This is
3143 Revision will be re-added as if their were new content. This is
3141 slower than DELTAREUSEALWAYS but allow more mechanism to kicks in.
3144 slower than DELTAREUSEALWAYS but allow more mechanism to kicks in.
3142 eg: large file detection and handling.
3145 eg: large file detection and handling.
3143
3146
3144 Delta computation can be slow, so the choice of delta reuse policy can
3147 Delta computation can be slow, so the choice of delta reuse policy can
3145 significantly affect run time.
3148 significantly affect run time.
3146
3149
3147 The default policy (``DELTAREUSESAMEREVS``) strikes a balance between
3150 The default policy (``DELTAREUSESAMEREVS``) strikes a balance between
3148 two extremes. Deltas will be reused if they are appropriate. But if the
3151 two extremes. Deltas will be reused if they are appropriate. But if the
3149 delta could choose a better revision, it will do so. This means if you
3152 delta could choose a better revision, it will do so. This means if you
3150 are converting a non-generaldelta revlog to a generaldelta revlog,
3153 are converting a non-generaldelta revlog to a generaldelta revlog,
3151 deltas will be recomputed if the delta's parent isn't a parent of the
3154 deltas will be recomputed if the delta's parent isn't a parent of the
3152 revision.
3155 revision.
3153
3156
3154 In addition to the delta policy, the ``forcedeltabothparents``
3157 In addition to the delta policy, the ``forcedeltabothparents``
3155 argument controls whether to force compute deltas against both parents
3158 argument controls whether to force compute deltas against both parents
3156 for merges. By default, the current default is used.
3159 for merges. By default, the current default is used.
3157
3160
3158 See `revlogutil.sidedata.get_sidedata_helpers` for the doc on
3161 See `revlogutil.sidedata.get_sidedata_helpers` for the doc on
3159 `sidedata_helpers`.
3162 `sidedata_helpers`.
3160 """
3163 """
3161 if deltareuse not in self.DELTAREUSEALL:
3164 if deltareuse not in self.DELTAREUSEALL:
3162 raise ValueError(
3165 raise ValueError(
3163 _(b'value for deltareuse invalid: %s') % deltareuse
3166 _(b'value for deltareuse invalid: %s') % deltareuse
3164 )
3167 )
3165
3168
3166 if len(destrevlog):
3169 if len(destrevlog):
3167 raise ValueError(_(b'destination revlog is not empty'))
3170 raise ValueError(_(b'destination revlog is not empty'))
3168
3171
3169 if getattr(self, 'filteredrevs', None):
3172 if getattr(self, 'filteredrevs', None):
3170 raise ValueError(_(b'source revlog has filtered revisions'))
3173 raise ValueError(_(b'source revlog has filtered revisions'))
3171 if getattr(destrevlog, 'filteredrevs', None):
3174 if getattr(destrevlog, 'filteredrevs', None):
3172 raise ValueError(_(b'destination revlog has filtered revisions'))
3175 raise ValueError(_(b'destination revlog has filtered revisions'))
3173
3176
3174 # lazydelta and lazydeltabase controls whether to reuse a cached delta,
3177 # lazydelta and lazydeltabase controls whether to reuse a cached delta,
3175 # if possible.
3178 # if possible.
3176 oldlazydelta = destrevlog._lazydelta
3179 oldlazydelta = destrevlog._lazydelta
3177 oldlazydeltabase = destrevlog._lazydeltabase
3180 oldlazydeltabase = destrevlog._lazydeltabase
3178 oldamd = destrevlog._deltabothparents
3181 oldamd = destrevlog._deltabothparents
3179
3182
3180 try:
3183 try:
3181 if deltareuse == self.DELTAREUSEALWAYS:
3184 if deltareuse == self.DELTAREUSEALWAYS:
3182 destrevlog._lazydeltabase = True
3185 destrevlog._lazydeltabase = True
3183 destrevlog._lazydelta = True
3186 destrevlog._lazydelta = True
3184 elif deltareuse == self.DELTAREUSESAMEREVS:
3187 elif deltareuse == self.DELTAREUSESAMEREVS:
3185 destrevlog._lazydeltabase = False
3188 destrevlog._lazydeltabase = False
3186 destrevlog._lazydelta = True
3189 destrevlog._lazydelta = True
3187 elif deltareuse == self.DELTAREUSENEVER:
3190 elif deltareuse == self.DELTAREUSENEVER:
3188 destrevlog._lazydeltabase = False
3191 destrevlog._lazydeltabase = False
3189 destrevlog._lazydelta = False
3192 destrevlog._lazydelta = False
3190
3193
3191 destrevlog._deltabothparents = forcedeltabothparents or oldamd
3194 destrevlog._deltabothparents = forcedeltabothparents or oldamd
3192
3195
3193 self._clone(
3196 self._clone(
3194 tr,
3197 tr,
3195 destrevlog,
3198 destrevlog,
3196 addrevisioncb,
3199 addrevisioncb,
3197 deltareuse,
3200 deltareuse,
3198 forcedeltabothparents,
3201 forcedeltabothparents,
3199 sidedata_helpers,
3202 sidedata_helpers,
3200 )
3203 )
3201
3204
3202 finally:
3205 finally:
3203 destrevlog._lazydelta = oldlazydelta
3206 destrevlog._lazydelta = oldlazydelta
3204 destrevlog._lazydeltabase = oldlazydeltabase
3207 destrevlog._lazydeltabase = oldlazydeltabase
3205 destrevlog._deltabothparents = oldamd
3208 destrevlog._deltabothparents = oldamd
3206
3209
3207 def _clone(
3210 def _clone(
3208 self,
3211 self,
3209 tr,
3212 tr,
3210 destrevlog,
3213 destrevlog,
3211 addrevisioncb,
3214 addrevisioncb,
3212 deltareuse,
3215 deltareuse,
3213 forcedeltabothparents,
3216 forcedeltabothparents,
3214 sidedata_helpers,
3217 sidedata_helpers,
3215 ):
3218 ):
3216 """perform the core duty of `revlog.clone` after parameter processing"""
3219 """perform the core duty of `revlog.clone` after parameter processing"""
3217 write_debug = None
3220 write_debug = None
3218 if self._debug_delta:
3221 if self._debug_delta:
3219 write_debug = tr._report
3222 write_debug = tr._report
3220 deltacomputer = deltautil.deltacomputer(
3223 deltacomputer = deltautil.deltacomputer(
3221 destrevlog,
3224 destrevlog,
3222 write_debug=write_debug,
3225 write_debug=write_debug,
3223 )
3226 )
3224 index = self.index
3227 index = self.index
3225 for rev in self:
3228 for rev in self:
3226 entry = index[rev]
3229 entry = index[rev]
3227
3230
3228 # Some classes override linkrev to take filtered revs into
3231 # Some classes override linkrev to take filtered revs into
3229 # account. Use raw entry from index.
3232 # account. Use raw entry from index.
3230 flags = entry[0] & 0xFFFF
3233 flags = entry[0] & 0xFFFF
3231 linkrev = entry[4]
3234 linkrev = entry[4]
3232 p1 = index[entry[5]][7]
3235 p1 = index[entry[5]][7]
3233 p2 = index[entry[6]][7]
3236 p2 = index[entry[6]][7]
3234 node = entry[7]
3237 node = entry[7]
3235
3238
3236 # (Possibly) reuse the delta from the revlog if allowed and
3239 # (Possibly) reuse the delta from the revlog if allowed and
3237 # the revlog chunk is a delta.
3240 # the revlog chunk is a delta.
3238 cachedelta = None
3241 cachedelta = None
3239 rawtext = None
3242 rawtext = None
3240 if deltareuse == self.DELTAREUSEFULLADD:
3243 if deltareuse == self.DELTAREUSEFULLADD:
3241 text = self._revisiondata(rev)
3244 text = self._revisiondata(rev)
3242 sidedata = self.sidedata(rev)
3245 sidedata = self.sidedata(rev)
3243
3246
3244 if sidedata_helpers is not None:
3247 if sidedata_helpers is not None:
3245 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
3248 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
3246 self, sidedata_helpers, sidedata, rev
3249 self, sidedata_helpers, sidedata, rev
3247 )
3250 )
3248 flags = flags | new_flags[0] & ~new_flags[1]
3251 flags = flags | new_flags[0] & ~new_flags[1]
3249
3252
3250 destrevlog.addrevision(
3253 destrevlog.addrevision(
3251 text,
3254 text,
3252 tr,
3255 tr,
3253 linkrev,
3256 linkrev,
3254 p1,
3257 p1,
3255 p2,
3258 p2,
3256 cachedelta=cachedelta,
3259 cachedelta=cachedelta,
3257 node=node,
3260 node=node,
3258 flags=flags,
3261 flags=flags,
3259 deltacomputer=deltacomputer,
3262 deltacomputer=deltacomputer,
3260 sidedata=sidedata,
3263 sidedata=sidedata,
3261 )
3264 )
3262 else:
3265 else:
3263 if destrevlog._lazydelta:
3266 if destrevlog._lazydelta:
3264 dp = self.deltaparent(rev)
3267 dp = self.deltaparent(rev)
3265 if dp != nullrev:
3268 if dp != nullrev:
3266 cachedelta = (dp, bytes(self._chunk(rev)))
3269 cachedelta = (dp, bytes(self._chunk(rev)))
3267
3270
3268 sidedata = None
3271 sidedata = None
3269 if not cachedelta:
3272 if not cachedelta:
3270 rawtext = self._revisiondata(rev)
3273 rawtext = self._revisiondata(rev)
3271 sidedata = self.sidedata(rev)
3274 sidedata = self.sidedata(rev)
3272 if sidedata is None:
3275 if sidedata is None:
3273 sidedata = self.sidedata(rev)
3276 sidedata = self.sidedata(rev)
3274
3277
3275 if sidedata_helpers is not None:
3278 if sidedata_helpers is not None:
3276 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
3279 (sidedata, new_flags) = sidedatautil.run_sidedata_helpers(
3277 self, sidedata_helpers, sidedata, rev
3280 self, sidedata_helpers, sidedata, rev
3278 )
3281 )
3279 flags = flags | new_flags[0] & ~new_flags[1]
3282 flags = flags | new_flags[0] & ~new_flags[1]
3280
3283
3281 with destrevlog._writing(tr):
3284 with destrevlog._writing(tr):
3282 destrevlog._addrevision(
3285 destrevlog._addrevision(
3283 node,
3286 node,
3284 rawtext,
3287 rawtext,
3285 tr,
3288 tr,
3286 linkrev,
3289 linkrev,
3287 p1,
3290 p1,
3288 p2,
3291 p2,
3289 flags,
3292 flags,
3290 cachedelta,
3293 cachedelta,
3291 deltacomputer=deltacomputer,
3294 deltacomputer=deltacomputer,
3292 sidedata=sidedata,
3295 sidedata=sidedata,
3293 )
3296 )
3294
3297
3295 if addrevisioncb:
3298 if addrevisioncb:
3296 addrevisioncb(self, rev, node)
3299 addrevisioncb(self, rev, node)
3297
3300
3298 def censorrevision(self, tr, censornode, tombstone=b''):
3301 def censorrevision(self, tr, censornode, tombstone=b''):
3299 if self._format_version == REVLOGV0:
3302 if self._format_version == REVLOGV0:
3300 raise error.RevlogError(
3303 raise error.RevlogError(
3301 _(b'cannot censor with version %d revlogs')
3304 _(b'cannot censor with version %d revlogs')
3302 % self._format_version
3305 % self._format_version
3303 )
3306 )
3304 elif self._format_version == REVLOGV1:
3307 elif self._format_version == REVLOGV1:
3305 rewrite.v1_censor(self, tr, censornode, tombstone)
3308 rewrite.v1_censor(self, tr, censornode, tombstone)
3306 else:
3309 else:
3307 rewrite.v2_censor(self, tr, censornode, tombstone)
3310 rewrite.v2_censor(self, tr, censornode, tombstone)
3308
3311
3309 def verifyintegrity(self, state):
3312 def verifyintegrity(self, state):
3310 """Verifies the integrity of the revlog.
3313 """Verifies the integrity of the revlog.
3311
3314
3312 Yields ``revlogproblem`` instances describing problems that are
3315 Yields ``revlogproblem`` instances describing problems that are
3313 found.
3316 found.
3314 """
3317 """
3315 dd, di = self.checksize()
3318 dd, di = self.checksize()
3316 if dd:
3319 if dd:
3317 yield revlogproblem(error=_(b'data length off by %d bytes') % dd)
3320 yield revlogproblem(error=_(b'data length off by %d bytes') % dd)
3318 if di:
3321 if di:
3319 yield revlogproblem(error=_(b'index contains %d extra bytes') % di)
3322 yield revlogproblem(error=_(b'index contains %d extra bytes') % di)
3320
3323
3321 version = self._format_version
3324 version = self._format_version
3322
3325
3323 # The verifier tells us what version revlog we should be.
3326 # The verifier tells us what version revlog we should be.
3324 if version != state[b'expectedversion']:
3327 if version != state[b'expectedversion']:
3325 yield revlogproblem(
3328 yield revlogproblem(
3326 warning=_(b"warning: '%s' uses revlog format %d; expected %d")
3329 warning=_(b"warning: '%s' uses revlog format %d; expected %d")
3327 % (self.display_id, version, state[b'expectedversion'])
3330 % (self.display_id, version, state[b'expectedversion'])
3328 )
3331 )
3329
3332
3330 state[b'skipread'] = set()
3333 state[b'skipread'] = set()
3331 state[b'safe_renamed'] = set()
3334 state[b'safe_renamed'] = set()
3332
3335
3333 for rev in self:
3336 for rev in self:
3334 node = self.node(rev)
3337 node = self.node(rev)
3335
3338
3336 # Verify contents. 4 cases to care about:
3339 # Verify contents. 4 cases to care about:
3337 #
3340 #
3338 # common: the most common case
3341 # common: the most common case
3339 # rename: with a rename
3342 # rename: with a rename
3340 # meta: file content starts with b'\1\n', the metadata
3343 # meta: file content starts with b'\1\n', the metadata
3341 # header defined in filelog.py, but without a rename
3344 # header defined in filelog.py, but without a rename
3342 # ext: content stored externally
3345 # ext: content stored externally
3343 #
3346 #
3344 # More formally, their differences are shown below:
3347 # More formally, their differences are shown below:
3345 #
3348 #
3346 # | common | rename | meta | ext
3349 # | common | rename | meta | ext
3347 # -------------------------------------------------------
3350 # -------------------------------------------------------
3348 # flags() | 0 | 0 | 0 | not 0
3351 # flags() | 0 | 0 | 0 | not 0
3349 # renamed() | False | True | False | ?
3352 # renamed() | False | True | False | ?
3350 # rawtext[0:2]=='\1\n'| False | True | True | ?
3353 # rawtext[0:2]=='\1\n'| False | True | True | ?
3351 #
3354 #
3352 # "rawtext" means the raw text stored in revlog data, which
3355 # "rawtext" means the raw text stored in revlog data, which
3353 # could be retrieved by "rawdata(rev)". "text"
3356 # could be retrieved by "rawdata(rev)". "text"
3354 # mentioned below is "revision(rev)".
3357 # mentioned below is "revision(rev)".
3355 #
3358 #
3356 # There are 3 different lengths stored physically:
3359 # There are 3 different lengths stored physically:
3357 # 1. L1: rawsize, stored in revlog index
3360 # 1. L1: rawsize, stored in revlog index
3358 # 2. L2: len(rawtext), stored in revlog data
3361 # 2. L2: len(rawtext), stored in revlog data
3359 # 3. L3: len(text), stored in revlog data if flags==0, or
3362 # 3. L3: len(text), stored in revlog data if flags==0, or
3360 # possibly somewhere else if flags!=0
3363 # possibly somewhere else if flags!=0
3361 #
3364 #
3362 # L1 should be equal to L2. L3 could be different from them.
3365 # L1 should be equal to L2. L3 could be different from them.
3363 # "text" may or may not affect commit hash depending on flag
3366 # "text" may or may not affect commit hash depending on flag
3364 # processors (see flagutil.addflagprocessor).
3367 # processors (see flagutil.addflagprocessor).
3365 #
3368 #
3366 # | common | rename | meta | ext
3369 # | common | rename | meta | ext
3367 # -------------------------------------------------
3370 # -------------------------------------------------
3368 # rawsize() | L1 | L1 | L1 | L1
3371 # rawsize() | L1 | L1 | L1 | L1
3369 # size() | L1 | L2-LM | L1(*) | L1 (?)
3372 # size() | L1 | L2-LM | L1(*) | L1 (?)
3370 # len(rawtext) | L2 | L2 | L2 | L2
3373 # len(rawtext) | L2 | L2 | L2 | L2
3371 # len(text) | L2 | L2 | L2 | L3
3374 # len(text) | L2 | L2 | L2 | L3
3372 # len(read()) | L2 | L2-LM | L2-LM | L3 (?)
3375 # len(read()) | L2 | L2-LM | L2-LM | L3 (?)
3373 #
3376 #
3374 # LM: length of metadata, depending on rawtext
3377 # LM: length of metadata, depending on rawtext
3375 # (*): not ideal, see comment in filelog.size
3378 # (*): not ideal, see comment in filelog.size
3376 # (?): could be "- len(meta)" if the resolved content has
3379 # (?): could be "- len(meta)" if the resolved content has
3377 # rename metadata
3380 # rename metadata
3378 #
3381 #
3379 # Checks needed to be done:
3382 # Checks needed to be done:
3380 # 1. length check: L1 == L2, in all cases.
3383 # 1. length check: L1 == L2, in all cases.
3381 # 2. hash check: depending on flag processor, we may need to
3384 # 2. hash check: depending on flag processor, we may need to
3382 # use either "text" (external), or "rawtext" (in revlog).
3385 # use either "text" (external), or "rawtext" (in revlog).
3383
3386
3384 try:
3387 try:
3385 skipflags = state.get(b'skipflags', 0)
3388 skipflags = state.get(b'skipflags', 0)
3386 if skipflags:
3389 if skipflags:
3387 skipflags &= self.flags(rev)
3390 skipflags &= self.flags(rev)
3388
3391
3389 _verify_revision(self, skipflags, state, node)
3392 _verify_revision(self, skipflags, state, node)
3390
3393
3391 l1 = self.rawsize(rev)
3394 l1 = self.rawsize(rev)
3392 l2 = len(self.rawdata(node))
3395 l2 = len(self.rawdata(node))
3393
3396
3394 if l1 != l2:
3397 if l1 != l2:
3395 yield revlogproblem(
3398 yield revlogproblem(
3396 error=_(b'unpacked size is %d, %d expected') % (l2, l1),
3399 error=_(b'unpacked size is %d, %d expected') % (l2, l1),
3397 node=node,
3400 node=node,
3398 )
3401 )
3399
3402
3400 except error.CensoredNodeError:
3403 except error.CensoredNodeError:
3401 if state[b'erroroncensored']:
3404 if state[b'erroroncensored']:
3402 yield revlogproblem(
3405 yield revlogproblem(
3403 error=_(b'censored file data'), node=node
3406 error=_(b'censored file data'), node=node
3404 )
3407 )
3405 state[b'skipread'].add(node)
3408 state[b'skipread'].add(node)
3406 except Exception as e:
3409 except Exception as e:
3407 yield revlogproblem(
3410 yield revlogproblem(
3408 error=_(b'unpacking %s: %s')
3411 error=_(b'unpacking %s: %s')
3409 % (short(node), stringutil.forcebytestr(e)),
3412 % (short(node), stringutil.forcebytestr(e)),
3410 node=node,
3413 node=node,
3411 )
3414 )
3412 state[b'skipread'].add(node)
3415 state[b'skipread'].add(node)
3413
3416
3414 def storageinfo(
3417 def storageinfo(
3415 self,
3418 self,
3416 exclusivefiles=False,
3419 exclusivefiles=False,
3417 sharedfiles=False,
3420 sharedfiles=False,
3418 revisionscount=False,
3421 revisionscount=False,
3419 trackedsize=False,
3422 trackedsize=False,
3420 storedsize=False,
3423 storedsize=False,
3421 ):
3424 ):
3422 d = {}
3425 d = {}
3423
3426
3424 if exclusivefiles:
3427 if exclusivefiles:
3425 d[b'exclusivefiles'] = [(self.opener, self._indexfile)]
3428 d[b'exclusivefiles'] = [(self.opener, self._indexfile)]
3426 if not self._inline:
3429 if not self._inline:
3427 d[b'exclusivefiles'].append((self.opener, self._datafile))
3430 d[b'exclusivefiles'].append((self.opener, self._datafile))
3428
3431
3429 if sharedfiles:
3432 if sharedfiles:
3430 d[b'sharedfiles'] = []
3433 d[b'sharedfiles'] = []
3431
3434
3432 if revisionscount:
3435 if revisionscount:
3433 d[b'revisionscount'] = len(self)
3436 d[b'revisionscount'] = len(self)
3434
3437
3435 if trackedsize:
3438 if trackedsize:
3436 d[b'trackedsize'] = sum(map(self.rawsize, iter(self)))
3439 d[b'trackedsize'] = sum(map(self.rawsize, iter(self)))
3437
3440
3438 if storedsize:
3441 if storedsize:
3439 d[b'storedsize'] = sum(
3442 d[b'storedsize'] = sum(
3440 self.opener.stat(path).st_size for path in self.files()
3443 self.opener.stat(path).st_size for path in self.files()
3441 )
3444 )
3442
3445
3443 return d
3446 return d
3444
3447
3445 def rewrite_sidedata(self, transaction, helpers, startrev, endrev):
3448 def rewrite_sidedata(self, transaction, helpers, startrev, endrev):
3446 if not self.hassidedata:
3449 if not self.hassidedata:
3447 return
3450 return
3448 # revlog formats with sidedata support does not support inline
3451 # revlog formats with sidedata support does not support inline
3449 assert not self._inline
3452 assert not self._inline
3450 if not helpers[1] and not helpers[2]:
3453 if not helpers[1] and not helpers[2]:
3451 # Nothing to generate or remove
3454 # Nothing to generate or remove
3452 return
3455 return
3453
3456
3454 new_entries = []
3457 new_entries = []
3455 # append the new sidedata
3458 # append the new sidedata
3456 with self._writing(transaction):
3459 with self._writing(transaction):
3457 ifh, dfh, sdfh = self._writinghandles
3460 ifh, dfh, sdfh = self._writinghandles
3458 dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
3461 dfh.seek(self._docket.sidedata_end, os.SEEK_SET)
3459
3462
3460 current_offset = sdfh.tell()
3463 current_offset = sdfh.tell()
3461 for rev in range(startrev, endrev + 1):
3464 for rev in range(startrev, endrev + 1):
3462 entry = self.index[rev]
3465 entry = self.index[rev]
3463 new_sidedata, flags = sidedatautil.run_sidedata_helpers(
3466 new_sidedata, flags = sidedatautil.run_sidedata_helpers(
3464 store=self,
3467 store=self,
3465 sidedata_helpers=helpers,
3468 sidedata_helpers=helpers,
3466 sidedata={},
3469 sidedata={},
3467 rev=rev,
3470 rev=rev,
3468 )
3471 )
3469
3472
3470 serialized_sidedata = sidedatautil.serialize_sidedata(
3473 serialized_sidedata = sidedatautil.serialize_sidedata(
3471 new_sidedata
3474 new_sidedata
3472 )
3475 )
3473
3476
3474 sidedata_compression_mode = COMP_MODE_INLINE
3477 sidedata_compression_mode = COMP_MODE_INLINE
3475 if serialized_sidedata and self.hassidedata:
3478 if serialized_sidedata and self.hassidedata:
3476 sidedata_compression_mode = COMP_MODE_PLAIN
3479 sidedata_compression_mode = COMP_MODE_PLAIN
3477 h, comp_sidedata = self.compress(serialized_sidedata)
3480 h, comp_sidedata = self.compress(serialized_sidedata)
3478 if (
3481 if (
3479 h != b'u'
3482 h != b'u'
3480 and comp_sidedata[0] != b'\0'
3483 and comp_sidedata[0] != b'\0'
3481 and len(comp_sidedata) < len(serialized_sidedata)
3484 and len(comp_sidedata) < len(serialized_sidedata)
3482 ):
3485 ):
3483 assert not h
3486 assert not h
3484 if (
3487 if (
3485 comp_sidedata[0]
3488 comp_sidedata[0]
3486 == self._docket.default_compression_header
3489 == self._docket.default_compression_header
3487 ):
3490 ):
3488 sidedata_compression_mode = COMP_MODE_DEFAULT
3491 sidedata_compression_mode = COMP_MODE_DEFAULT
3489 serialized_sidedata = comp_sidedata
3492 serialized_sidedata = comp_sidedata
3490 else:
3493 else:
3491 sidedata_compression_mode = COMP_MODE_INLINE
3494 sidedata_compression_mode = COMP_MODE_INLINE
3492 serialized_sidedata = comp_sidedata
3495 serialized_sidedata = comp_sidedata
3493 if entry[8] != 0 or entry[9] != 0:
3496 if entry[8] != 0 or entry[9] != 0:
3494 # rewriting entries that already have sidedata is not
3497 # rewriting entries that already have sidedata is not
3495 # supported yet, because it introduces garbage data in the
3498 # supported yet, because it introduces garbage data in the
3496 # revlog.
3499 # revlog.
3497 msg = b"rewriting existing sidedata is not supported yet"
3500 msg = b"rewriting existing sidedata is not supported yet"
3498 raise error.Abort(msg)
3501 raise error.Abort(msg)
3499
3502
3500 # Apply (potential) flags to add and to remove after running
3503 # Apply (potential) flags to add and to remove after running
3501 # the sidedata helpers
3504 # the sidedata helpers
3502 new_offset_flags = entry[0] | flags[0] & ~flags[1]
3505 new_offset_flags = entry[0] | flags[0] & ~flags[1]
3503 entry_update = (
3506 entry_update = (
3504 current_offset,
3507 current_offset,
3505 len(serialized_sidedata),
3508 len(serialized_sidedata),
3506 new_offset_flags,
3509 new_offset_flags,
3507 sidedata_compression_mode,
3510 sidedata_compression_mode,
3508 )
3511 )
3509
3512
3510 # the sidedata computation might have move the file cursors around
3513 # the sidedata computation might have move the file cursors around
3511 sdfh.seek(current_offset, os.SEEK_SET)
3514 sdfh.seek(current_offset, os.SEEK_SET)
3512 sdfh.write(serialized_sidedata)
3515 sdfh.write(serialized_sidedata)
3513 new_entries.append(entry_update)
3516 new_entries.append(entry_update)
3514 current_offset += len(serialized_sidedata)
3517 current_offset += len(serialized_sidedata)
3515 self._docket.sidedata_end = sdfh.tell()
3518 self._docket.sidedata_end = sdfh.tell()
3516
3519
3517 # rewrite the new index entries
3520 # rewrite the new index entries
3518 ifh.seek(startrev * self.index.entry_size)
3521 ifh.seek(startrev * self.index.entry_size)
3519 for i, e in enumerate(new_entries):
3522 for i, e in enumerate(new_entries):
3520 rev = startrev + i
3523 rev = startrev + i
3521 self.index.replace_sidedata_info(rev, *e)
3524 self.index.replace_sidedata_info(rev, *e)
3522 packed = self.index.entry_binary(rev)
3525 packed = self.index.entry_binary(rev)
3523 if rev == 0 and self._docket is None:
3526 if rev == 0 and self._docket is None:
3524 header = self._format_flags | self._format_version
3527 header = self._format_flags | self._format_version
3525 header = self.index.pack_header(header)
3528 header = self.index.pack_header(header)
3526 packed = header + packed
3529 packed = header + packed
3527 ifh.write(packed)
3530 ifh.write(packed)
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now