mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
Merge branch 'main' into all-contributors/add-jeffbanks
This commit is contained in:
commit
ee8cfee6a0
@ -9,7 +9,7 @@
|
||||
"imageSize": 50,
|
||||
"commit": false,
|
||||
"commitConvention": "angular",
|
||||
"contributorsPerLine": 7,
|
||||
"contributorsPerLine": 6,
|
||||
"contributorsSortAlphabetically": false,
|
||||
"linkToUsage": false,
|
||||
"skipCi": true,
|
||||
@ -80,6 +80,284 @@
|
||||
"tool",
|
||||
"userTesting"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hemidactylus",
|
||||
"name": "Stefano Lottini",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/14221764?v=4",
|
||||
"profile": "https://github.com/hemidactylus",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "phact",
|
||||
"name": "Sebastián Estévez",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1313220?v=4",
|
||||
"profile": "https://github.com/phact",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "yabinmeng",
|
||||
"name": "yabinmeng",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/16789452?v=4",
|
||||
"profile": "https://github.com/yabinmeng",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "eolivelli",
|
||||
"name": "Enrico Olivelli",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/9469110?v=4",
|
||||
"profile": "http://eolivelli.blogspot.it/",
|
||||
"contributions": [
|
||||
"test",
|
||||
"code",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lhotari",
|
||||
"name": "Lari Hotari",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/66864?v=4",
|
||||
"profile": "https://github.com/lhotari",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"code",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "mfleming",
|
||||
"name": "Matt Fleming",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/94254?v=4",
|
||||
"profile": "http://www.codeblueprint.co.uk",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "tjake",
|
||||
"name": "Jake Luciani",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/44456?v=4",
|
||||
"profile": "https://github.com/tjake",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lakshmi-M18",
|
||||
"name": "Lakshmi Manjunatha",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/89935678?v=4",
|
||||
"profile": "https://github.com/lakshmi-M18",
|
||||
"contributions": [
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "pingtimeout",
|
||||
"name": "Pierre Laporte",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1159578?v=4",
|
||||
"profile": "http://www.pingtimeout.fr",
|
||||
"contributions": [
|
||||
"ideas",
|
||||
"bug"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "tatu-at-datastax",
|
||||
"name": "Tatu Saloranta",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/87213665?v=4",
|
||||
"profile": "https://github.com/tatu-at-datastax",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "alexott",
|
||||
"name": "Alex Ott",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/30342?v=4",
|
||||
"profile": "http://alexott.net",
|
||||
"contributions": [
|
||||
"platform",
|
||||
"bug",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jeffreyscarpenter",
|
||||
"name": "Jeffrey Carpenter",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/12115970?v=4",
|
||||
"profile": "https://github.com/jeffreyscarpenter",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"test",
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "yassermohamed81",
|
||||
"name": "yassermohamed81",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/53837411?v=4",
|
||||
"profile": "https://github.com/yassermohamed81",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Pierrotws",
|
||||
"name": "Pierre Sauvage",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/6002161?v=4",
|
||||
"profile": "https://github.com/Pierrotws",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dougwettlaufer",
|
||||
"name": "Doug Wettlaufer",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/45750136?v=4",
|
||||
"profile": "https://github.com/dougwettlaufer",
|
||||
"contributions": [
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jeromatron",
|
||||
"name": "Jeremy Hanna",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/254887?v=4",
|
||||
"profile": "http://jeromatron.blogspot.com",
|
||||
"contributions": [
|
||||
"test",
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "alicel",
|
||||
"name": "Alice Lottini",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/2972347?v=4",
|
||||
"profile": "https://github.com/alicel",
|
||||
"contributions": [
|
||||
"bug",
|
||||
"ideas",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "EricBorczuk",
|
||||
"name": "Eric Borczuk",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/4205492?v=4",
|
||||
"profile": "https://github.com/EricBorczuk",
|
||||
"contributions": [
|
||||
"code",
|
||||
"review",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "weideng1",
|
||||
"name": "weideng1",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5520525?v=4",
|
||||
"profile": "https://github.com/weideng1",
|
||||
"contributions": [
|
||||
"test",
|
||||
"ideas",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ivansenic",
|
||||
"name": "Ivan Senic",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/10600041?v=4",
|
||||
"profile": "https://github.com/ivansenic",
|
||||
"contributions": [
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "justinchuch",
|
||||
"name": "Justin Chu",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/15710241?v=4",
|
||||
"profile": "https://justinchuch.wordpress.com/",
|
||||
"contributions": [
|
||||
"code",
|
||||
"test",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ds-steven-matison",
|
||||
"name": "Steven Matison",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/70520951?v=4",
|
||||
"profile": "https://ds-steven-matison.github.io/",
|
||||
"contributions": [
|
||||
"test",
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "szimmer1",
|
||||
"name": "shahar z",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/8455475?v=4",
|
||||
"profile": "https://github.com/szimmer1",
|
||||
"contributions": [
|
||||
"ideas",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ncarvind",
|
||||
"name": "ncarvind",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/70302571?v=4",
|
||||
"profile": "https://github.com/ncarvind",
|
||||
"contributions": [
|
||||
"code",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "MMirelli",
|
||||
"name": "Massimiliano Mirelli",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/22191891?v=4",
|
||||
"profile": "https://github.com/MMirelli",
|
||||
"contributions": [
|
||||
"platform"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "derrickCos",
|
||||
"name": "Derrick Cosmas",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/25781387?v=4",
|
||||
"profile": "https://github.com/derrickCos",
|
||||
"contributions": [
|
||||
"code",
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "grighetto",
|
||||
"name": "Gianluca Righetto",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/413792?v=4",
|
||||
"profile": "https://github.com/grighetto",
|
||||
"contributions": [
|
||||
"platform"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "BrynCooke",
|
||||
"name": "Bryn Cooke",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/747836?v=4",
|
||||
"profile": "https://github.com/BrynCooke",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -130,9 +130,47 @@ For recognizing contributions, please follow [this documentation](https://allcon
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jshook"><img src="https://avatars.githubusercontent.com/u/2148847?v=4?s=50" width="50px;" alt="Jonathan Shook"/><br /><sub><b>Jonathan Shook</b></sub></a><br /><a href="#mentoring-jshook" title="Mentoring">🧑🏫</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/msmygit"><img src="https://avatars.githubusercontent.com/u/19366623?v=4?s=50" width="50px;" alt="Madhavan"/><br /><sub><b>Madhavan</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=msmygit" title="Code">💻</a> <a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Amsmygit" title="Bug reports">🐛</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=msmygit" title="Documentation">📖</a> <a href="#ideas-msmygit" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-msmygit" title="Answering Questions">💬</a> <a href="#research-msmygit" title="Research">🔬</a> <a href="https://github.com/nosqlbench/nosqlbench/pulls?q=is%3Apr+reviewed-by%3Amsmygit" title="Reviewed Pull Requests">👀</a> <a href="#tool-msmygit" title="Tools">🔧</a> <a href="#userTesting-msmygit" title="User Testing">📓</a> <a href="#talk-msmygit" title="Talks">📢</a> <a href="#tutorial-msmygit" title="Tutorials">✅</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/msmygit"><img src="https://avatars.githubusercontent.com/u/19366623?v=4?s=50" width="50px;" alt="Madhavan"/><br /><sub><b>Madhavan</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=msmygit" title="Code">💻</a> <a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Amsmygit" title="Bug reports">🐛</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=msmygit" title="Documentation">📖</a> <a href="#ideas-msmygit" title="Ideas, Planning, & Feedback">🤔</a> <a href="#question-msmygit" title="Answering Questions">💬</a> <a href="#research-msmygit" title="Research">🔬</a> <a href="https://github.com/nosqlbench/nosqlbench/pulls?q=is%3Apr+reviewed-by%3Amsmygit" title="Reviewed Pull Requests">👀</a> <a href="#tool-msmygit" title="Tools">🔧</a> <a href="#userTesting-msmygit" title="User Testing">📓</a> <a href="#talk-msmygit" title="Talks">📢</a> <a href="#tutorial-msmygit" title="Tutorials">✅</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MikeYaacoubStax"><img src="https://avatars.githubusercontent.com/u/117678633?v=4?s=50" width="50px;" alt="MikeYaacoubStax"/><br /><sub><b>MikeYaacoubStax</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/pulls?q=is%3Apr+reviewed-by%3AMikeYaacoubStax" title="Reviewed Pull Requests">👀</a> <a href="#tool-MikeYaacoubStax" title="Tools">🔧</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://jjbanks.com"><img src="https://avatars.githubusercontent.com/u/4078933?v=4?s=50" width="50px;" alt="Jeff Banks"/><br /><sub><b>Jeff Banks</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=jeffbanks" title="Code">💻</a> <a href="#mentoring-jeffbanks" title="Mentoring">🧑🏫</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=jeffbanks" title="Tests">⚠️</a> <a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Ajeffbanks" title="Bug reports">🐛</a> <a href="#business-jeffbanks" title="Business development">💼</a> <a href="#content-jeffbanks" title="Content">🖋</a> <a href="#data-jeffbanks" title="Data">🔣</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=jeffbanks" title="Documentation">📖</a> <a href="#design-jeffbanks" title="Design">🎨</a> <a href="#example-jeffbanks" title="Examples">💡</a> <a href="#ideas-jeffbanks" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-jeffbanks" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-jeffbanks" title="Maintenance">🚧</a> <a href="#platform-jeffbanks" title="Packaging/porting to new platform">📦</a> <a href="#plugin-jeffbanks" title="Plugin/utility libraries">🔌</a> <a href="#projectManagement-jeffbanks" title="Project Management">📆</a> <a href="#research-jeffbanks" title="Research">🔬</a> <a href="https://github.com/nosqlbench/nosqlbench/pulls?q=is%3Apr+reviewed-by%3Ajeffbanks" title="Reviewed Pull Requests">👀</a> <a href="#security-jeffbanks" title="Security">🛡️</a> <a href="#tool-jeffbanks" title="Tools">🔧</a> <a href="#userTesting-jeffbanks" title="User Testing">📓</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/hemidactylus"><img src="https://avatars.githubusercontent.com/u/14221764?v=4?s=50" width="50px;" alt="Stefano Lottini"/><br /><sub><b>Stefano Lottini</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Ahemidactylus" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/phact"><img src="https://avatars.githubusercontent.com/u/1313220?v=4?s=50" width="50px;" alt="Sebastián Estévez"/><br /><sub><b>Sebastián Estévez</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Aphact" title="Bug reports">🐛</a> <a href="#design-phact" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/yabinmeng"><img src="https://avatars.githubusercontent.com/u/16789452?v=4?s=50" width="50px;" alt="yabinmeng"/><br /><sub><b>yabinmeng</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Ayabinmeng" title="Bug reports">🐛</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=yabinmeng" title="Tests">⚠️</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="http://eolivelli.blogspot.it/"><img src="https://avatars.githubusercontent.com/u/9469110?v=4?s=50" width="50px;" alt="Enrico Olivelli"/><br /><sub><b>Enrico Olivelli</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=eolivelli" title="Tests">⚠️</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=eolivelli" title="Code">💻</a> <a href="https://github.com/nosqlbench/nosqlbench/pulls?q=is%3Apr+reviewed-by%3Aeolivelli" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/lhotari"><img src="https://avatars.githubusercontent.com/u/66864?v=4?s=50" width="50px;" alt="Lari Hotari"/><br /><sub><b>Lari Hotari</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Alhotari" title="Bug reports">🐛</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=lhotari" title="Code">💻</a> <a href="https://github.com/nosqlbench/nosqlbench/pulls?q=is%3Apr+reviewed-by%3Alhotari" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="http://www.codeblueprint.co.uk"><img src="https://avatars.githubusercontent.com/u/94254?v=4?s=50" width="50px;" alt="Matt Fleming"/><br /><sub><b>Matt Fleming</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Amfleming" title="Bug reports">🐛</a> <a href="#design-mfleming" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/tjake"><img src="https://avatars.githubusercontent.com/u/44456?v=4?s=50" width="50px;" alt="Jake Luciani"/><br /><sub><b>Jake Luciani</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Atjake" title="Bug reports">🐛</a> <a href="#ideas-tjake" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/lakshmi-M18"><img src="https://avatars.githubusercontent.com/u/89935678?v=4?s=50" width="50px;" alt="Lakshmi Manjunatha"/><br /><sub><b>Lakshmi Manjunatha</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Alakshmi-M18" title="Bug reports">🐛</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="16.66%"><a href="http://www.pingtimeout.fr"><img src="https://avatars.githubusercontent.com/u/1159578?v=4?s=50" width="50px;" alt="Pierre Laporte"/><br /><sub><b>Pierre Laporte</b></sub></a><br /><a href="#ideas-pingtimeout" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Apingtimeout" title="Bug reports">🐛</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/tatu-at-datastax"><img src="https://avatars.githubusercontent.com/u/87213665?v=4?s=50" width="50px;" alt="Tatu Saloranta"/><br /><sub><b>Tatu Saloranta</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=tatu-at-datastax" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="http://alexott.net"><img src="https://avatars.githubusercontent.com/u/30342?v=4?s=50" width="50px;" alt="Alex Ott"/><br /><sub><b>Alex Ott</b></sub></a><br /><a href="#platform-alexott" title="Packaging/porting to new platform">📦</a> <a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Aalexott" title="Bug reports">🐛</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=alexott" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/jeffreyscarpenter"><img src="https://avatars.githubusercontent.com/u/12115970?v=4?s=50" width="50px;" alt="Jeffrey Carpenter"/><br /><sub><b>Jeffrey Carpenter</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Ajeffreyscarpenter" title="Bug reports">🐛</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=jeffreyscarpenter" title="Tests">⚠️</a> <a href="#maintenance-jeffreyscarpenter" title="Maintenance">🚧</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/yassermohamed81"><img src="https://avatars.githubusercontent.com/u/53837411?v=4?s=50" width="50px;" alt="yassermohamed81"/><br /><sub><b>yassermohamed81</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=yassermohamed81" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/Pierrotws"><img src="https://avatars.githubusercontent.com/u/6002161?v=4?s=50" width="50px;" alt="Pierre Sauvage"/><br /><sub><b>Pierre Sauvage</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=Pierrotws" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/dougwettlaufer"><img src="https://avatars.githubusercontent.com/u/45750136?v=4?s=50" width="50px;" alt="Doug Wettlaufer"/><br /><sub><b>Doug Wettlaufer</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=dougwettlaufer" title="Tests">⚠️</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="http://jeromatron.blogspot.com"><img src="https://avatars.githubusercontent.com/u/254887?v=4?s=50" width="50px;" alt="Jeremy Hanna"/><br /><sub><b>Jeremy Hanna</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=jeromatron" title="Tests">⚠️</a> <a href="#ideas-jeromatron" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/alicel"><img src="https://avatars.githubusercontent.com/u/2972347?v=4?s=50" width="50px;" alt="Alice Lottini"/><br /><sub><b>Alice Lottini</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/issues?q=author%3Aalicel" title="Bug reports">🐛</a> <a href="#ideas-alicel" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=alicel" title="Tests">⚠️</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/EricBorczuk"><img src="https://avatars.githubusercontent.com/u/4205492?v=4?s=50" width="50px;" alt="Eric Borczuk"/><br /><sub><b>Eric Borczuk</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=EricBorczuk" title="Code">💻</a> <a href="https://github.com/nosqlbench/nosqlbench/pulls?q=is%3Apr+reviewed-by%3AEricBorczuk" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=EricBorczuk" title="Tests">⚠️</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/weideng1"><img src="https://avatars.githubusercontent.com/u/5520525?v=4?s=50" width="50px;" alt="weideng1"/><br /><sub><b>weideng1</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=weideng1" title="Tests">⚠️</a> <a href="#ideas-weideng1" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=weideng1" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/ivansenic"><img src="https://avatars.githubusercontent.com/u/10600041?v=4?s=50" width="50px;" alt="Ivan Senic"/><br /><sub><b>Ivan Senic</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=ivansenic" title="Tests">⚠️</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://justinchuch.wordpress.com/"><img src="https://avatars.githubusercontent.com/u/15710241?v=4?s=50" width="50px;" alt="Justin Chu"/><br /><sub><b>Justin Chu</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=justinchuch" title="Code">💻</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=justinchuch" title="Tests">⚠️</a> <a href="https://github.com/nosqlbench/nosqlbench/pulls?q=is%3Apr+reviewed-by%3Ajustinchuch" title="Reviewed Pull Requests">👀</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://ds-steven-matison.github.io/"><img src="https://avatars.githubusercontent.com/u/70520951?v=4?s=50" width="50px;" alt="Steven Matison"/><br /><sub><b>Steven Matison</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=ds-steven-matison" title="Tests">⚠️</a> <a href="#ideas-ds-steven-matison" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/szimmer1"><img src="https://avatars.githubusercontent.com/u/8455475?v=4?s=50" width="50px;" alt="shahar z"/><br /><sub><b>shahar z</b></sub></a><br /><a href="#ideas-szimmer1" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=szimmer1" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/ncarvind"><img src="https://avatars.githubusercontent.com/u/70302571?v=4?s=50" width="50px;" alt="ncarvind"/><br /><sub><b>ncarvind</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=ncarvind" title="Code">💻</a> <a href="https://github.com/nosqlbench/nosqlbench/commits?author=ncarvind" title="Tests">⚠️</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/MMirelli"><img src="https://avatars.githubusercontent.com/u/22191891?v=4?s=50" width="50px;" alt="Massimiliano Mirelli"/><br /><sub><b>Massimiliano Mirelli</b></sub></a><br /><a href="#platform-MMirelli" title="Packaging/porting to new platform">📦</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/derrickCos"><img src="https://avatars.githubusercontent.com/u/25781387?v=4?s=50" width="50px;" alt="Derrick Cosmas"/><br /><sub><b>Derrick Cosmas</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=derrickCos" title="Code">💻</a> <a href="#ideas-derrickCos" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/grighetto"><img src="https://avatars.githubusercontent.com/u/413792?v=4?s=50" width="50px;" alt="Gianluca Righetto"/><br /><sub><b>Gianluca Righetto</b></sub></a><br /><a href="#platform-grighetto" title="Packaging/porting to new platform">📦</a></td>
|
||||
<td align="center" valign="top" width="16.66%"><a href="https://github.com/BrynCooke"><img src="https://avatars.githubusercontent.com/u/747836?v=4?s=50" width="50px;" alt="Bryn Cooke"/><br /><sub><b>Bryn Cooke</b></sub></a><br /><a href="https://github.com/nosqlbench/nosqlbench/commits?author=BrynCooke" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -32,8 +32,10 @@ import org.apache.pulsar.client.admin.PulsarAdminBuilder;
|
||||
import org.apache.pulsar.client.api.*;
|
||||
import org.apache.pulsar.common.schema.KeyValueEncodingType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class PulsarSpace implements AutoCloseable {
|
||||
|
||||
@ -50,9 +52,18 @@ public class PulsarSpace implements AutoCloseable {
|
||||
private PulsarAdmin pulsarAdmin;
|
||||
private Schema<?> pulsarSchema;
|
||||
|
||||
private final ConcurrentHashMap<String, Producer<?>> producers = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<String, Consumer<?>> consumers = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<String, Reader<?>> readers = new ConcurrentHashMap<>();
|
||||
public record ProducerCacheKey(String producerName, String topicName) {
|
||||
}
|
||||
|
||||
private final ConcurrentHashMap<ProducerCacheKey, Producer<?>> producers = new ConcurrentHashMap<>();
|
||||
|
||||
public record ConsumerCacheKey(String consumerName, String subscriptionName, List<String> topicNameList, String topicPattern) {
|
||||
}
|
||||
private final ConcurrentHashMap<ConsumerCacheKey, Consumer<?>> consumers = new ConcurrentHashMap<>();
|
||||
|
||||
public record ReaderCacheKey(String readerName, String topicName, String startMsgPosStr) {
|
||||
}
|
||||
private final ConcurrentHashMap<ReaderCacheKey, Reader<?>> readers = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public PulsarSpace(String spaceName, NBConfiguration cfg) {
|
||||
@ -89,13 +100,11 @@ public class PulsarSpace implements AutoCloseable {
|
||||
public int getProducerSetCnt() { return producers.size(); }
|
||||
public int getConsumerSetCnt() { return consumers.size(); }
|
||||
public int getReaderSetCnt() { return readers.size(); }
|
||||
public Producer<?> getProducer(String name) { return producers.get(name); }
|
||||
public void setProducer(String name, Producer<?> producer) { producers.put(name, producer); }
|
||||
public Consumer<?> getConsumer(String name) { return consumers.get(name); }
|
||||
public void setConsumer(String name, Consumer<?> consumer) { consumers.put(name, consumer); }
|
||||
public Producer<?> getProducer(ProducerCacheKey key, Supplier<Producer<?>> producerSupplier) { return producers.computeIfAbsent(key, __ -> producerSupplier.get()); }
|
||||
|
||||
public Reader<?> getReader(String name) { return readers.get(name); }
|
||||
public void setReader(String name, Reader<?> reader) { readers.put(name, reader); }
|
||||
public Consumer<?> getConsumer(ConsumerCacheKey key, Supplier<Consumer<?>> consumerSupplier) { return consumers.computeIfAbsent(key, __ -> consumerSupplier.get()); }
|
||||
|
||||
public Reader<?> getReader(ReaderCacheKey key, Supplier<Reader<?>> readerSupplier) { return readers.computeIfAbsent(key, __ -> readerSupplier.get()); }
|
||||
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,6 @@ import java.util.*;
|
||||
import java.util.function.LongFunction;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, PulsarSpace> implements NBNamedElement {
|
||||
@ -239,10 +238,8 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
PulsarAdapterUtil.PRODUCER_CONF_STD_KEY.producerName.label,
|
||||
cycleProducerName);
|
||||
|
||||
String producerCacheKey = PulsarAdapterUtil.buildCacheKey(producerName, topicName);
|
||||
Producer<?> producer = pulsarSpace.getProducer(producerCacheKey);
|
||||
|
||||
if (producer == null) {
|
||||
PulsarSpace.ProducerCacheKey producerCacheKey = new PulsarSpace.ProducerCacheKey(producerName, topicName);
|
||||
return pulsarSpace.getProducer(producerCacheKey, () -> {
|
||||
PulsarClient pulsarClient = pulsarSpace.getPulsarClient();
|
||||
|
||||
// Get other possible producer settings that are set at global level
|
||||
@ -262,21 +259,17 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
producerBuilder = producerBuilder.producerName(producerName);
|
||||
}
|
||||
|
||||
producer = producerBuilder.create();
|
||||
pulsarSpace.setProducer(producerCacheKey, producer);
|
||||
|
||||
Producer<?> producer = producerBuilder.create();
|
||||
pulsarAdapterMetrics.registerProducerApiMetrics(producer,
|
||||
getPulsarAPIMetricsPrefix(
|
||||
PulsarAdapterUtil.PULSAR_API_TYPE.PRODUCER.label,
|
||||
producerName,
|
||||
topicName));
|
||||
}
|
||||
catch (PulsarClientException ple) {
|
||||
return producer;
|
||||
} catch (PulsarClientException ple) {
|
||||
throw new PulsarAdapterUnexpectedException("Failed to create a Pulsar producer.");
|
||||
}
|
||||
}
|
||||
|
||||
return producer;
|
||||
});
|
||||
}
|
||||
|
||||
private List<String> getEffectiveConsumerTopicNameList(String cycleTopicNameListStr) {
|
||||
@ -296,24 +289,6 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
return effectiveTopicNameList;
|
||||
}
|
||||
|
||||
private Pattern getEffectiveConsumerTopicPattern(String cycleTopicPatternStr) {
|
||||
String effectiveTopicPatternStr = getEffectiveConValue(
|
||||
PulsarAdapterUtil.CONF_GATEGORY.Consumer.label,
|
||||
PulsarAdapterUtil.CONSUMER_CONF_STD_KEY.topicsPattern.label,
|
||||
cycleTopicPatternStr);
|
||||
|
||||
Pattern topicsPattern;
|
||||
try {
|
||||
if (!StringUtils.isBlank(effectiveTopicPatternStr))
|
||||
topicsPattern = Pattern.compile(effectiveTopicPatternStr);
|
||||
else
|
||||
topicsPattern = null;
|
||||
} catch (PatternSyntaxException pse) {
|
||||
topicsPattern = null;
|
||||
}
|
||||
return topicsPattern;
|
||||
}
|
||||
|
||||
private SubscriptionType getEffectiveSubscriptionType(String cycleSubscriptionType) {
|
||||
String subscriptionTypeStr = getEffectiveConValue(
|
||||
PulsarAdapterUtil.CONF_GATEGORY.Consumer.label,
|
||||
@ -344,11 +319,10 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
|
||||
List<String> topicNameList = getEffectiveConsumerTopicNameList(cycleTopicNameListStr);
|
||||
|
||||
String topicPatternStr = getEffectiveConValue(
|
||||
String topicPatternStr = StringUtils.trimToNull(getEffectiveConValue(
|
||||
PulsarAdapterUtil.CONF_GATEGORY.Consumer.label,
|
||||
PulsarAdapterUtil.CONSUMER_CONF_STD_KEY.topicsPattern.label,
|
||||
cycleTopicPatternStr);
|
||||
Pattern topicPattern = getEffectiveConsumerTopicPattern(cycleTopicPatternStr);
|
||||
cycleTopicPatternStr));
|
||||
|
||||
String subscriptionName = getEffectiveConValue(
|
||||
PulsarAdapterUtil.CONF_GATEGORY.Consumer.label,
|
||||
@ -368,28 +342,14 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
"creating multiple consumers of \"Exclusive\" subscription type under the same subscription name");
|
||||
}
|
||||
|
||||
if ( (topicNameList.isEmpty() && (topicPattern == null)) ||
|
||||
(!topicNameList.isEmpty() && (topicPattern != null)) ) {
|
||||
if ( (topicNameList.isEmpty() && (topicPatternStr == null)) ||
|
||||
(!topicNameList.isEmpty() && (topicPatternStr != null)) ) {
|
||||
throw new PulsarAdapterInvalidParamException(
|
||||
"Invalid combination of topic name(s) and topic patterns; only specify one parameter!");
|
||||
}
|
||||
|
||||
boolean multiTopicConsumer = (topicNameList.size() > 1 || (topicPattern != null));
|
||||
|
||||
String consumerTopicListString;
|
||||
if (!topicNameList.isEmpty()) {
|
||||
consumerTopicListString = String.join("|", topicNameList);
|
||||
} else {
|
||||
consumerTopicListString = topicPatternStr;
|
||||
}
|
||||
|
||||
String consumerCacheKey = PulsarAdapterUtil.buildCacheKey(
|
||||
consumerName,
|
||||
subscriptionName,
|
||||
consumerTopicListString);
|
||||
Consumer<?> consumer = pulsarSpace.getConsumer(consumerCacheKey);
|
||||
|
||||
if (consumer == null) {
|
||||
return pulsarSpace.getConsumer(
|
||||
new PulsarSpace.ConsumerCacheKey(consumerName, subscriptionName, topicNameList, topicPatternStr), () -> {
|
||||
PulsarClient pulsarClient = pulsarSpace.getPulsarClient();
|
||||
|
||||
// Get other possible consumer settings that are set at global level
|
||||
@ -417,6 +377,7 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
consumerConfToLoad.remove(PulsarAdapterUtil.CONSUMER_CONF_STD_KEY.negativeAckRedeliveryBackoff.label);
|
||||
consumerConfToLoad.remove(PulsarAdapterUtil.CONSUMER_CONF_STD_KEY.ackTimeoutRedeliveryBackoff.label);
|
||||
|
||||
boolean multiTopicConsumer = (topicNameList.size() > 1 || (topicPatternStr != null));
|
||||
if (!multiTopicConsumer) {
|
||||
assert (topicNameList.size() == 1);
|
||||
consumerBuilder = pulsarClient.newConsumer(pulsarSpace.getPulsarSchema());
|
||||
@ -429,6 +390,7 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
consumerBuilder.topics(topicNameList);
|
||||
}
|
||||
else {
|
||||
Pattern topicPattern = Pattern.compile(topicPatternStr);
|
||||
consumerBuilder.topicsPattern(topicPattern);
|
||||
}
|
||||
}
|
||||
@ -465,22 +427,22 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
consumerBuilder.keySharedPolicy(keySharedPolicy);
|
||||
}
|
||||
|
||||
consumer = consumerBuilder.subscribe();
|
||||
pulsarSpace.setConsumer(consumerCacheKey, consumer);
|
||||
Consumer<?> consumer = consumerBuilder.subscribe();
|
||||
|
||||
String consumerTopicListString = (!topicNameList.isEmpty()) ? String.join("|", topicNameList) : topicPatternStr;
|
||||
pulsarAdapterMetrics.registerConsumerApiMetrics(
|
||||
consumer,
|
||||
getPulsarAPIMetricsPrefix(
|
||||
PulsarAdapterUtil.PULSAR_API_TYPE.CONSUMER.label,
|
||||
consumerName,
|
||||
consumerTopicListString));
|
||||
|
||||
return consumer;
|
||||
}
|
||||
catch (PulsarClientException ple) {
|
||||
throw new PulsarAdapterUnexpectedException("Failed to create a Pulsar consumer!");
|
||||
}
|
||||
}
|
||||
|
||||
return consumer;
|
||||
});
|
||||
}
|
||||
|
||||
private static Range[] parseRanges(String ranges) {
|
||||
@ -528,10 +490,7 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
throw new RuntimeException("Reader:: Invalid value for reader start message position!");
|
||||
}
|
||||
|
||||
String readerCacheKey = PulsarAdapterUtil.buildCacheKey(topicName, readerName, startMsgPosStr);
|
||||
Reader<?> reader = pulsarSpace.getReader(readerCacheKey);
|
||||
|
||||
if (reader == null) {
|
||||
return pulsarSpace.getReader(new PulsarSpace.ReaderCacheKey(readerName, topicName, startMsgPosStr), () -> {
|
||||
PulsarClient pulsarClient = pulsarSpace.getPulsarClient();;
|
||||
|
||||
Map<String, Object> readerConf = pulsarSpace.getPulsarNBClientConf().getReaderConfMapTgt();
|
||||
@ -558,17 +517,12 @@ public abstract class PulsarBaseOpDispenser extends BaseOpDispenser<PulsarOp, P
|
||||
// startMsgId = MessageId.latest;
|
||||
//}
|
||||
|
||||
reader = readerBuilder.startMessageId(startMsgId).create();
|
||||
|
||||
return readerBuilder.startMessageId(startMsgId).create();
|
||||
} catch (PulsarClientException ple) {
|
||||
ple.printStackTrace();
|
||||
throw new RuntimeException("Unable to create a Pulsar reader!");
|
||||
}
|
||||
|
||||
pulsarSpace.setReader(readerCacheKey, reader);
|
||||
}
|
||||
|
||||
return reader;
|
||||
});
|
||||
}
|
||||
//
|
||||
//////////////////////////////////////
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package io.nosqlbench.adapter.pulsar.util;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.nosqlbench.adapter.pulsar.exception.PulsarAdapterInvalidParamException;
|
||||
import io.nosqlbench.adapter.pulsar.exception.PulsarAdapterUnexpectedException;
|
||||
@ -23,6 +24,8 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.pulsar.client.api.Schema;
|
||||
import org.apache.pulsar.common.schema.SchemaInfo;
|
||||
import org.apache.pulsar.common.schema.SchemaType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
@ -30,7 +33,11 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -60,9 +67,6 @@ public class PulsarAdapterUtil {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
public static boolean isValidDocLevelParam(String param) {
|
||||
return Arrays.stream(DOC_LEVEL_PARAMS.values()).anyMatch(t -> t.label.equals(param));
|
||||
}
|
||||
|
||||
///////
|
||||
// Message processing sequence error simulation types
|
||||
@ -77,29 +81,21 @@ public class PulsarAdapterUtil {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private static final Map<String, MSG_SEQ_ERROR_SIMU_TYPE> MAPPING = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (MSG_SEQ_ERROR_SIMU_TYPE simuType : values()) {
|
||||
MAPPING.put(simuType.label, simuType);
|
||||
MAPPING.put(simuType.label.toLowerCase(), simuType);
|
||||
MAPPING.put(simuType.label.toUpperCase(), simuType);
|
||||
MAPPING.put(simuType.name(), simuType);
|
||||
MAPPING.put(simuType.name().toLowerCase(), simuType);
|
||||
MAPPING.put(simuType.name().toUpperCase(), simuType);
|
||||
}
|
||||
}
|
||||
private static final Map<String, MSG_SEQ_ERROR_SIMU_TYPE> MAPPING = Stream.of(values())
|
||||
.flatMap(simuType ->
|
||||
Stream.of(simuType.label,
|
||||
simuType.label.toLowerCase(),
|
||||
simuType.label.toUpperCase(),
|
||||
simuType.name(),
|
||||
simuType.name().toLowerCase(),
|
||||
simuType.name().toUpperCase())
|
||||
.distinct().map(key -> Map.entry(key, simuType)))
|
||||
.collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
|
||||
public static Optional<MSG_SEQ_ERROR_SIMU_TYPE> parseSimuType(String simuTypeString) {
|
||||
return Optional.ofNullable(MAPPING.get(simuTypeString.trim()));
|
||||
}
|
||||
}
|
||||
public static boolean isValidSeqErrSimuType(String item) {
|
||||
return Arrays.stream(MSG_SEQ_ERROR_SIMU_TYPE.values()).anyMatch(t -> t.label.equals(item));
|
||||
}
|
||||
public static String getValidSeqErrSimuTypeList() {
|
||||
return Arrays.stream(MSG_SEQ_ERROR_SIMU_TYPE.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
///////
|
||||
// Valid Pulsar API type
|
||||
@ -113,12 +109,15 @@ public class PulsarAdapterUtil {
|
||||
PULSAR_API_TYPE(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private static final Set<String> LABELS = Stream.of(values()).map(v -> v.label).collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
public static boolean isValidLabel(String label) {
|
||||
return LABELS.contains(label);
|
||||
}
|
||||
}
|
||||
public static boolean isValidPulsarApiType(String param) {
|
||||
return Arrays.stream(PULSAR_API_TYPE.values()).anyMatch(t -> t.label.equals(param));
|
||||
}
|
||||
public static String getValidPulsarApiTypeList() {
|
||||
return Arrays.stream(PULSAR_API_TYPE.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
return PULSAR_API_TYPE.isValidLabel(param);
|
||||
}
|
||||
|
||||
|
||||
@ -136,14 +135,16 @@ public class PulsarAdapterUtil {
|
||||
CONF_GATEGORY(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private static final Set<String> LABELS = Stream.of(values()).map(v -> v.label).collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
public static boolean isValidLabel(String label) {
|
||||
return LABELS.contains(label);
|
||||
}
|
||||
}
|
||||
public static boolean isValidConfCategory(String item) {
|
||||
return Arrays.stream(CONF_GATEGORY.values()).anyMatch(t -> t.label.equals(item));
|
||||
return CONF_GATEGORY.isValidLabel(item);
|
||||
}
|
||||
public static String getValidConfCategoryList() {
|
||||
return Arrays.stream(CONF_GATEGORY.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
///////
|
||||
// Valid persistence type
|
||||
public enum PERSISTENT_TYPES {
|
||||
@ -156,9 +157,6 @@ public class PulsarAdapterUtil {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
public static boolean isValidPersistenceType(String type) {
|
||||
return Arrays.stream(PERSISTENT_TYPES.values()).anyMatch(t -> t.label.equals(type));
|
||||
}
|
||||
|
||||
///////
|
||||
// Valid Pulsar client configuration (activity-level settings)
|
||||
@ -194,9 +192,6 @@ public class PulsarAdapterUtil {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
public static boolean isValidClientConfItem(String item) {
|
||||
return Arrays.stream(CLNT_CONF_KEY.values()).anyMatch(t -> t.label.equals(item));
|
||||
}
|
||||
|
||||
///////
|
||||
// Standard producer configuration (activity-level settings)
|
||||
@ -222,9 +217,6 @@ public class PulsarAdapterUtil {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
public static boolean isStandardProducerConfItem(String item) {
|
||||
return Arrays.stream(PRODUCER_CONF_STD_KEY.values()).anyMatch(t -> t.label.equals(item));
|
||||
}
|
||||
|
||||
// compressionType
|
||||
public enum COMPRESSION_TYPE {
|
||||
@ -239,12 +231,12 @@ public class PulsarAdapterUtil {
|
||||
COMPRESSION_TYPE(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private final static String TYPE_LIST = Stream.of(COMPRESSION_TYPE.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
}
|
||||
public static boolean isValidCompressionType(String item) {
|
||||
return Arrays.stream(COMPRESSION_TYPE.values()).anyMatch(t -> t.label.equals(item));
|
||||
}
|
||||
|
||||
public static String getValidCompressionTypeList() {
|
||||
return Arrays.stream(COMPRESSION_TYPE.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
return COMPRESSION_TYPE.TYPE_LIST;
|
||||
}
|
||||
|
||||
///////
|
||||
@ -284,9 +276,6 @@ public class PulsarAdapterUtil {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
public static boolean isStandardConsumerConfItem(String item) {
|
||||
return Arrays.stream(CONSUMER_CONF_STD_KEY.values()).anyMatch(t -> t.label.equals(item));
|
||||
}
|
||||
|
||||
///////
|
||||
// Custom consumer configuration (activity-level settings)
|
||||
@ -301,9 +290,16 @@ public class PulsarAdapterUtil {
|
||||
CONSUMER_CONF_CUSTOM_KEY(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private static final Set<String> LABELS = Stream.of(values()).map(v -> v.label).collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
public static boolean isValidLabel(String label) {
|
||||
return LABELS.contains(label);
|
||||
}
|
||||
|
||||
}
|
||||
public static boolean isCustomConsumerConfItem(String item) {
|
||||
return Arrays.stream(CONSUMER_CONF_CUSTOM_KEY.values()).anyMatch(t -> t.label.equals(item));
|
||||
return CONSUMER_CONF_CUSTOM_KEY.isValidLabel(item);
|
||||
}
|
||||
|
||||
// subscriptionTyp
|
||||
@ -318,12 +314,21 @@ public class PulsarAdapterUtil {
|
||||
SUBSCRIPTION_TYPE(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private static final Set<String> LABELS = Stream.of(values()).map(v -> v.label)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
public static boolean isValidLabel(String label) {
|
||||
return LABELS.contains(label);
|
||||
}
|
||||
|
||||
private final static String TYPE_LIST = Stream.of(COMPRESSION_TYPE.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
}
|
||||
public static boolean isValidSubscriptionType(String item) {
|
||||
return Arrays.stream(SUBSCRIPTION_TYPE.values()).anyMatch(t -> t.label.equals(item));
|
||||
return SUBSCRIPTION_TYPE.isValidLabel(item);
|
||||
}
|
||||
public static String getValidSubscriptionTypeList() {
|
||||
return Arrays.stream(SUBSCRIPTION_TYPE.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
return SUBSCRIPTION_TYPE.TYPE_LIST;
|
||||
}
|
||||
|
||||
// subscriptionInitialPosition
|
||||
@ -336,12 +341,12 @@ public class PulsarAdapterUtil {
|
||||
SUBSCRIPTION_INITIAL_POSITION(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
public static boolean isValidSubscriptionInitialPosition(String item) {
|
||||
return Arrays.stream(SUBSCRIPTION_INITIAL_POSITION.values()).anyMatch(t -> t.label.equals(item));
|
||||
|
||||
private final static String TYPE_LIST = Stream.of(COMPRESSION_TYPE.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
|
||||
}
|
||||
public static String getValidSubscriptionInitialPositionList() {
|
||||
return Arrays.stream(SUBSCRIPTION_INITIAL_POSITION.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
return SUBSCRIPTION_INITIAL_POSITION.TYPE_LIST;
|
||||
}
|
||||
|
||||
// regexSubscriptionMode
|
||||
@ -355,12 +360,12 @@ public class PulsarAdapterUtil {
|
||||
REGEX_SUBSCRIPTION_MODE(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private final static String TYPE_LIST = Stream.of(COMPRESSION_TYPE.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
}
|
||||
public static boolean isValidRegexSubscriptionMode(String item) {
|
||||
return Arrays.stream(REGEX_SUBSCRIPTION_MODE.values()).anyMatch(t -> t.label.equals(item));
|
||||
}
|
||||
|
||||
public static String getValidRegexSubscriptionModeList() {
|
||||
return Arrays.stream(REGEX_SUBSCRIPTION_MODE.values()).map(t -> t.label).collect(Collectors.joining(", "));
|
||||
return REGEX_SUBSCRIPTION_MODE.TYPE_LIST;
|
||||
}
|
||||
|
||||
///////
|
||||
@ -383,9 +388,6 @@ public class PulsarAdapterUtil {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
public static boolean isStandardReaderConfItem(String item) {
|
||||
return Arrays.stream(READER_CONF_STD_KEY.values()).anyMatch(t -> t.label.equals(item));
|
||||
}
|
||||
|
||||
///////
|
||||
// Custom reader configuration (activity-level settings)
|
||||
@ -400,9 +402,6 @@ public class PulsarAdapterUtil {
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
public static boolean isCustomReaderConfItem(String item) {
|
||||
return Arrays.stream(READER_CONF_CUSTOM_KEY.values()).anyMatch(t -> t.label.equals(item));
|
||||
}
|
||||
|
||||
///////
|
||||
// Valid read positions for a Pulsar reader
|
||||
@ -415,156 +414,84 @@ public class PulsarAdapterUtil {
|
||||
READER_MSG_POSITION_TYPE(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
private static final Set<String> LABELS = Stream.of(values()).map(v -> v.label)
|
||||
.collect(Collectors.toUnmodifiableSet());
|
||||
|
||||
public static boolean isValidLabel(String label) {
|
||||
return LABELS.contains(label);
|
||||
}
|
||||
}
|
||||
public static boolean isValideReaderStartPosition(String item) {
|
||||
return Arrays.stream(READER_MSG_POSITION_TYPE.values()).anyMatch(t -> t.label.equals(item));
|
||||
return READER_MSG_POSITION_TYPE.isValidLabel(item);
|
||||
}
|
||||
|
||||
private static final Map<String, Schema<?>> PRIMITIVE_SCHEMA_TYPE_MAPPING = Stream.of(SchemaType.values())
|
||||
.filter(SchemaType::isPrimitive)
|
||||
.collect(Collectors.toUnmodifiableMap(schemaType -> schemaType.name().toUpperCase(),
|
||||
schemaType -> Schema.getSchema(SchemaInfo.builder().type(schemaType).build())));
|
||||
|
||||
///////
|
||||
// Primitive Schema type
|
||||
public static boolean isPrimitiveSchemaTypeStr(String typeStr) {
|
||||
boolean isPrimitive = false;
|
||||
|
||||
// Use "BYTES" as the default type if the type string is not explicitly specified
|
||||
if (StringUtils.isBlank(typeStr)) {
|
||||
typeStr = "BYTES";
|
||||
}
|
||||
|
||||
if (typeStr.equalsIgnoreCase("BOOLEAN") || typeStr.equalsIgnoreCase("INT8") ||
|
||||
typeStr.equalsIgnoreCase("INT16") || typeStr.equalsIgnoreCase("INT32") ||
|
||||
typeStr.equalsIgnoreCase("INT64") || typeStr.equalsIgnoreCase("FLOAT") ||
|
||||
typeStr.equalsIgnoreCase("DOUBLE") || typeStr.equalsIgnoreCase("BYTES") ||
|
||||
typeStr.equalsIgnoreCase("DATE") || typeStr.equalsIgnoreCase("TIME") ||
|
||||
typeStr.equalsIgnoreCase("TIMESTAMP") || typeStr.equalsIgnoreCase("INSTANT") ||
|
||||
typeStr.equalsIgnoreCase("LOCAL_DATE") || typeStr.equalsIgnoreCase("LOCAL_TIME") ||
|
||||
typeStr.equalsIgnoreCase("LOCAL_DATE_TIME")) {
|
||||
isPrimitive = true;
|
||||
}
|
||||
|
||||
return isPrimitive;
|
||||
return StringUtils.isBlank(typeStr) || PRIMITIVE_SCHEMA_TYPE_MAPPING.containsKey(typeStr.toUpperCase());
|
||||
}
|
||||
|
||||
public static Schema<?> getPrimitiveTypeSchema(String typeStr) {
|
||||
Schema<?> schema;
|
||||
|
||||
if (StringUtils.isBlank(typeStr)) {
|
||||
typeStr = "BYTES";
|
||||
String lookupKey = StringUtils.isBlank(typeStr) ? "BYTES" : typeStr.toUpperCase();
|
||||
Schema<?> schema = PRIMITIVE_SCHEMA_TYPE_MAPPING.get(lookupKey);
|
||||
if (schema == null) {
|
||||
throw new PulsarAdapterInvalidParamException("Invalid Pulsar primitive schema type string : " + typeStr);
|
||||
}
|
||||
|
||||
switch (typeStr.toUpperCase()) {
|
||||
case "BOOLEAN":
|
||||
schema = Schema.BOOL;
|
||||
break;
|
||||
case "INT8":
|
||||
schema = Schema.INT8;
|
||||
break;
|
||||
case "INT16":
|
||||
schema = Schema.INT16;
|
||||
break;
|
||||
case "INT32":
|
||||
schema = Schema.INT32;
|
||||
break;
|
||||
case "INT64":
|
||||
schema = Schema.INT64;
|
||||
break;
|
||||
case "FLOAT":
|
||||
schema = Schema.FLOAT;
|
||||
break;
|
||||
case "DOUBLE":
|
||||
schema = Schema.DOUBLE;
|
||||
break;
|
||||
case "DATE":
|
||||
schema = Schema.DATE;
|
||||
break;
|
||||
case "TIME":
|
||||
schema = Schema.TIME;
|
||||
break;
|
||||
case "TIMESTAMP":
|
||||
schema = Schema.TIMESTAMP;
|
||||
break;
|
||||
case "INSTANT":
|
||||
schema = Schema.INSTANT;
|
||||
break;
|
||||
case "LOCAL_DATE":
|
||||
schema = Schema.LOCAL_DATE;
|
||||
break;
|
||||
case "LOCAL_TIME":
|
||||
schema = Schema.LOCAL_TIME;
|
||||
break;
|
||||
case "LOCAL_DATE_TIME":
|
||||
schema = Schema.LOCAL_DATE_TIME;
|
||||
break;
|
||||
case "BYTES":
|
||||
schema = Schema.BYTES;
|
||||
break;
|
||||
// Report an error if non-valid, non-empty schema type string is provided
|
||||
default:
|
||||
throw new PulsarAdapterInvalidParamException("Invalid Pulsar primitive schema type string : " + typeStr);
|
||||
}
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
///////
|
||||
// Complex strut type: Avro or Json
|
||||
public static boolean isAvroSchemaTypeStr(String typeStr) {
|
||||
return (StringUtils.isNotBlank(typeStr) && typeStr.equalsIgnoreCase("AVRO"));
|
||||
return "AVRO".equalsIgnoreCase(typeStr);
|
||||
}
|
||||
|
||||
// automatic decode the type from the Registry
|
||||
public static boolean isAutoConsumeSchemaTypeStr(String typeStr) {
|
||||
return (StringUtils.isNotBlank(typeStr) && typeStr.equalsIgnoreCase("AUTO_CONSUME"));
|
||||
return "AUTO_CONSUME".equalsIgnoreCase(typeStr);
|
||||
}
|
||||
public static Schema<?> getAvroSchema(String typeStr, String definitionStr) {
|
||||
String schemaDefinitionStr = definitionStr;
|
||||
String filePrefix = "file://";
|
||||
Schema<?> schema;
|
||||
|
||||
private static final Map<String, Schema<?>> AVRO_SCHEMA_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
public static Schema<?> getAvroSchema(String typeStr, final String definitionStr) {
|
||||
// Check if payloadStr points to a file (e.g. "file:///path/to/a/file")
|
||||
if (isAvroSchemaTypeStr(typeStr)) {
|
||||
if (StringUtils.isBlank(schemaDefinitionStr)) {
|
||||
throw new PulsarAdapterInvalidParamException(
|
||||
"Schema definition must be provided for \"Avro\" schema type!");
|
||||
if (StringUtils.isBlank(definitionStr)) {
|
||||
throw new PulsarAdapterInvalidParamException("Schema definition must be provided for \"Avro\" schema type!");
|
||||
}
|
||||
else if (schemaDefinitionStr.startsWith(filePrefix)) {
|
||||
try {
|
||||
Path filePath = Paths.get(URI.create(schemaDefinitionStr));
|
||||
schemaDefinitionStr = Files.readString(filePath, StandardCharsets.US_ASCII);
|
||||
return AVRO_SCHEMA_CACHE.computeIfAbsent(definitionStr, __ -> {
|
||||
String schemaDefinitionStr = definitionStr;
|
||||
if (schemaDefinitionStr.startsWith("file://")) {
|
||||
try {
|
||||
Path filePath = Paths.get(URI.create(schemaDefinitionStr));
|
||||
schemaDefinitionStr = Files.readString(filePath, StandardCharsets.UTF_8);
|
||||
} catch (IOException ioe) {
|
||||
throw new PulsarAdapterUnexpectedException("Error reading the specified \"Avro\" schema definition file: " + definitionStr + ": " + ioe.getMessage());
|
||||
}
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
throw new PulsarAdapterUnexpectedException(
|
||||
"Error reading the specified \"Avro\" schema definition file: " + definitionStr + ": " + ioe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
schema = PulsarAvroSchemaUtil.GetSchema_PulsarAvro("NBAvro", schemaDefinitionStr);
|
||||
return PulsarAvroSchemaUtil.GetSchema_PulsarAvro("NBAvro", schemaDefinitionStr);
|
||||
});
|
||||
} else {
|
||||
throw new PulsarAdapterInvalidParamException("Trying to create a \"Avro\" schema for a non-Avro schema type string: " + typeStr);
|
||||
}
|
||||
else {
|
||||
throw new PulsarAdapterInvalidParamException(
|
||||
"Trying to create a \"Avro\" schema for a non-Avro schema type string: " + typeStr);
|
||||
}
|
||||
|
||||
return schema;
|
||||
}
|
||||
|
||||
///////
|
||||
// Generate effective key string
|
||||
public static String buildCacheKey(String... keyParts) {
|
||||
// Ignore blank keyPart
|
||||
String joinedKeyStr =
|
||||
Stream.of(keyParts)
|
||||
.filter(s -> !StringUtils.isBlank(s))
|
||||
.collect(Collectors.joining(","));
|
||||
|
||||
return Base64.getEncoder().encodeToString(joinedKeyStr.getBytes());
|
||||
}
|
||||
|
||||
///////
|
||||
// Convert JSON string to a key/value map
|
||||
public static Map<String, String> convertJsonToMap(String jsonStr) throws Exception {
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
return mapper.readValue(jsonStr, Map.class);
|
||||
private static final ObjectMapper JACKSON_OBJECT_MAPPER = new ObjectMapper();
|
||||
private static final TypeReference<Map<String, String>> MAP_TYPE_REF = new TypeReference<>() {};
|
||||
|
||||
public static Map<String, String> convertJsonToMap(String jsonStr) throws IOException {
|
||||
return JACKSON_OBJECT_MAPPER.readValue(jsonStr, MAP_TYPE_REF);
|
||||
}
|
||||
|
||||
|
||||
///////
|
||||
// Get full namespace name (<tenant>/<namespace>) from a Pulsar topic URI
|
||||
public static String getFullNamespaceName(String topicUri) {
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2022 nosqlbench
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.nosqlbench.adapter.pulsar.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class MessageSequenceNumberSendingHandlerTest {
|
||||
MessageSequenceNumberSendingHandler sequenceNumberSendingHandler = new MessageSequenceNumberSendingHandler();
|
||||
|
||||
@Test
|
||||
void shouldAddMonotonicSequence() {
|
||||
for (long l = 1; l <= 100; l++) {
|
||||
assertEquals(l, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.emptySet()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInjectMessageLoss() {
|
||||
assertEquals(1L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.emptySet()));
|
||||
assertEquals(3L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.singleton(PulsarAdapterUtil.MSG_SEQ_ERROR_SIMU_TYPE.MsgLoss), 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInjectMessageDuplication() {
|
||||
assertEquals(1L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.emptySet()));
|
||||
assertEquals(1L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.singleton(PulsarAdapterUtil.MSG_SEQ_ERROR_SIMU_TYPE.MsgDup), 100));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInjectMessageOutOfOrder() {
|
||||
assertEquals(1L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.emptySet()));
|
||||
assertEquals(4L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.singleton(PulsarAdapterUtil.MSG_SEQ_ERROR_SIMU_TYPE.OutOfOrder), 100));
|
||||
assertEquals(2L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.emptySet()));
|
||||
assertEquals(3L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.emptySet()));
|
||||
assertEquals(5L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.emptySet()));
|
||||
assertEquals(6, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.emptySet()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInjectOneOfTheSimulatedErrorsRandomly() {
|
||||
Set<PulsarAdapterUtil.MSG_SEQ_ERROR_SIMU_TYPE> allErrorTypes = new HashSet<>(Arrays.asList(PulsarAdapterUtil.MSG_SEQ_ERROR_SIMU_TYPE.values()));
|
||||
|
||||
assertEquals(1L, sequenceNumberSendingHandler.getNextSequenceNumber(Collections.emptySet()));
|
||||
long previousSequenceNumber = 1L;
|
||||
int outOfSequenceInjectionCounter = 0;
|
||||
int messageDupCounter = 0;
|
||||
int messageLossCounter = 0;
|
||||
int successCounter = 0;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
long nextSequenceNumber = sequenceNumberSendingHandler.getNextSequenceNumber(allErrorTypes);
|
||||
if (nextSequenceNumber >= previousSequenceNumber + 3) {
|
||||
outOfSequenceInjectionCounter++;
|
||||
} else if (nextSequenceNumber <= previousSequenceNumber) {
|
||||
messageDupCounter++;
|
||||
} else if (nextSequenceNumber >= previousSequenceNumber + 2) {
|
||||
messageLossCounter++;
|
||||
} else if (nextSequenceNumber == previousSequenceNumber + 1) {
|
||||
successCounter++;
|
||||
}
|
||||
previousSequenceNumber = nextSequenceNumber;
|
||||
}
|
||||
assertTrue(outOfSequenceInjectionCounter > 0);
|
||||
assertTrue(messageDupCounter > 0);
|
||||
assertTrue(messageLossCounter > 0);
|
||||
assertEquals(1000, outOfSequenceInjectionCounter + messageDupCounter + messageLossCounter + successCounter);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (c) 2022 nosqlbench
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package io.nosqlbench.adapter.pulsar.util;
|
||||
|
||||
import com.codahale.metrics.Counter;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class ReceivedMessageSequenceTrackerTest {
|
||||
Counter msgErrOutOfSeqCounter = new Counter();
|
||||
Counter msgErrDuplicateCounter = new Counter();
|
||||
Counter msgErrLossCounter = new Counter();
|
||||
ReceivedMessageSequenceTracker messageSequenceTracker = new ReceivedMessageSequenceTracker(msgErrOutOfSeqCounter, msgErrDuplicateCounter, msgErrLossCounter, 20, 20);
|
||||
|
||||
@Test
|
||||
void shouldCountersBeZeroWhenSequenceDoesntContainGaps() {
|
||||
// when
|
||||
for (long l = 0; l < 100L; l++) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
messageSequenceTracker.close();
|
||||
// then
|
||||
assertEquals(0, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(0, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(0, msgErrLossCounter.getCount());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {10L, 11L, 19L, 20L, 21L, 100L})
|
||||
void shouldDetectMsgLossWhenEverySecondMessageIsLost(long totalMessages) {
|
||||
doShouldDetectMsgLoss(totalMessages, 2);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {10L, 11L, 19L, 20L, 21L, 100L})
|
||||
void shouldDetectMsgLossWhenEveryThirdMessageIsLost(long totalMessages) {
|
||||
doShouldDetectMsgLoss(totalMessages, 3);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {20L, 21L, 40L, 41L, 42L, 43L, 100L})
|
||||
void shouldDetectMsgLossWhenEvery21stMessageIsLost(long totalMessages) {
|
||||
doShouldDetectMsgLoss(totalMessages, 21);
|
||||
}
|
||||
|
||||
private void doShouldDetectMsgLoss(long totalMessages, int looseEveryNthMessage) {
|
||||
int messagesLost = 0;
|
||||
// when
|
||||
boolean lastMessageWasLost = false;
|
||||
for (long l = 0; l < totalMessages; l++) {
|
||||
if (l % looseEveryNthMessage == 1) {
|
||||
messagesLost++;
|
||||
lastMessageWasLost = true;
|
||||
continue;
|
||||
} else {
|
||||
lastMessageWasLost = false;
|
||||
}
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
if (lastMessageWasLost) {
|
||||
messageSequenceTracker.sequenceNumberReceived(totalMessages);
|
||||
}
|
||||
messageSequenceTracker.close();
|
||||
// then
|
||||
assertEquals(0, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(0, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(messagesLost, msgErrLossCounter.getCount());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {10L, 11L, 19L, 20L, 21L, 100L})
|
||||
void shouldDetectMsgDuplication(long totalMessages) {
|
||||
int messagesDuplicated = 0;
|
||||
// when
|
||||
for (long l = 0; l < totalMessages; l++) {
|
||||
if (l % 2 == 1) {
|
||||
messagesDuplicated++;
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
if (totalMessages % 2 == 0) {
|
||||
messageSequenceTracker.sequenceNumberReceived(totalMessages);
|
||||
}
|
||||
if (totalMessages < 2 * messageSequenceTracker.getMaxTrackOutOfOrderSequenceNumbers()) {
|
||||
messageSequenceTracker.close();
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals(0, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(messagesDuplicated, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(0, msgErrLossCounter.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDetectSingleMessageOutOfSequence() {
|
||||
// when
|
||||
for (long l = 0; l < 10L; l++) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
messageSequenceTracker.sequenceNumberReceived(10L);
|
||||
messageSequenceTracker.sequenceNumberReceived(12L);
|
||||
messageSequenceTracker.sequenceNumberReceived(11L);
|
||||
for (long l = 13L; l < 100L; l++) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals(1, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(0, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(0, msgErrLossCounter.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDetectMultipleMessagesOutOfSequence() {
|
||||
// when
|
||||
for (long l = 0; l < 10L; l++) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
messageSequenceTracker.sequenceNumberReceived(10L);
|
||||
messageSequenceTracker.sequenceNumberReceived(14L);
|
||||
messageSequenceTracker.sequenceNumberReceived(13L);
|
||||
messageSequenceTracker.sequenceNumberReceived(11L);
|
||||
messageSequenceTracker.sequenceNumberReceived(12L);
|
||||
for (long l = 15L; l < 100L; l++) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
|
||||
// then
|
||||
assertEquals(2, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(0, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(0, msgErrLossCounter.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDetectIndividualMessageLoss() {
|
||||
// when
|
||||
for (long l = 0; l < 100L; l++) {
|
||||
if (l != 11L) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
}
|
||||
messageSequenceTracker.close();
|
||||
|
||||
// then
|
||||
assertEquals(0, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(0, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(1, msgErrLossCounter.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDetectGapAndMessageDuplication() {
|
||||
// when
|
||||
for (long l = 0; l < 100L; l++) {
|
||||
if (l != 11L) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
if (l == 12L) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
}
|
||||
messageSequenceTracker.close();
|
||||
|
||||
// then
|
||||
assertEquals(0, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(1, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(1, msgErrLossCounter.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDetectGapAndMessageDuplicationTimes2() {
|
||||
// when
|
||||
for (long l = 0; l < 100L; l++) {
|
||||
if (l != 11L) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
if (l == 12L) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
}
|
||||
messageSequenceTracker.close();
|
||||
|
||||
// then
|
||||
assertEquals(0, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(2, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(1, msgErrLossCounter.getCount());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void shouldDetectDelayedOutOfOrderDelivery() {
|
||||
// when
|
||||
for (long l = 0; l < 5 * messageSequenceTracker.getMaxTrackOutOfOrderSequenceNumbers(); l++) {
|
||||
if (l != 10) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
if (l == messageSequenceTracker.getMaxTrackOutOfOrderSequenceNumbers() * 2) {
|
||||
messageSequenceTracker.sequenceNumberReceived(10);
|
||||
}
|
||||
}
|
||||
messageSequenceTracker.close();
|
||||
|
||||
// then
|
||||
assertEquals(1, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(0, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(0, msgErrLossCounter.getCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDetectDelayedOutOfOrderDeliveryOf2ConsecutiveSequenceNumbers() {
|
||||
// when
|
||||
for (long l = 0; l < 5 * messageSequenceTracker.getMaxTrackOutOfOrderSequenceNumbers(); l++) {
|
||||
if (l != 10 && l != 11) {
|
||||
messageSequenceTracker.sequenceNumberReceived(l);
|
||||
}
|
||||
if (l == messageSequenceTracker.getMaxTrackOutOfOrderSequenceNumbers() * 2) {
|
||||
messageSequenceTracker.sequenceNumberReceived(10);
|
||||
messageSequenceTracker.sequenceNumberReceived(11);
|
||||
}
|
||||
}
|
||||
messageSequenceTracker.close();
|
||||
|
||||
// then
|
||||
assertEquals(2, msgErrOutOfSeqCounter.getCount());
|
||||
assertEquals(0, msgErrDuplicateCounter.getCount());
|
||||
assertEquals(0, msgErrLossCounter.getCount());
|
||||
}
|
||||
}
|
@ -501,7 +501,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<propertiesEncoding>ISO-8859-1</propertiesEncoding>
|
||||
</configuration>
|
||||
@ -535,7 +534,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<configuration>
|
||||
<debug>true</debug>
|
||||
<target>17</target>
|
||||
@ -551,7 +549,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M6</version>
|
||||
<configuration>
|
||||
<argLine>-ea ${argLine}</argLine>
|
||||
<systemPropertyVariables>
|
||||
@ -576,7 +573,6 @@
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.8</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
@ -627,7 +623,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>3.0.0-M6</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>run-tests</id>
|
||||
@ -655,7 +650,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<configuration>
|
||||
<release>17</release>
|
||||
<doctitle>${javadoc.name}</doctitle>
|
||||
@ -686,7 +680,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
@ -702,7 +695,6 @@
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>1.6.13</version>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<serverId>ossrh</serverId>
|
||||
@ -714,7 +706,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
@ -744,7 +735,6 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.0.0-M3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enforce-java</id>
|
||||
@ -768,18 +758,18 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.4.2</version>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-release-plugin</artifactId>
|
||||
<version>3.0.0-M6</version>
|
||||
<version>3.0.0-M7</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.6</version>
|
||||
<version>3.0.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@ -789,27 +779,27 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M4</version>
|
||||
<version>3.0.0-M8</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>3.0.0-M4</version>
|
||||
<version>3.0.0-M8</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.4.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<version>3.2.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.sonatype.plugins</groupId>
|
||||
<artifactId>nexus-staging-maven-plugin</artifactId>
|
||||
<version>1.6.8</version>
|
||||
<version>1.6.13</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.antlr</groupId>
|
||||
@ -819,43 +809,43 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-enforcer-plugin</artifactId>
|
||||
<version>3.0.0-M3</version>
|
||||
<version>3.2.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<version>3.2.0</version>
|
||||
</plugin>
|
||||
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<version>3.3.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>org.jacoco.ant</artifactId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>${jacoco.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<version>3.3.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-install-plugin</artifactId>
|
||||
<version>3.0.0-M1</version>
|
||||
<version>3.1.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<version>3.0.0-M1</version>
|
||||
<version>3.0.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
Loading…
Reference in New Issue
Block a user