Compare commits

..

358 Commits

Author SHA1 Message Date
Aph-CUG 0b794c9ab9 增加一个link_buf类,以及log写入机制 2024-08-27 09:20:02 +08:00
V_Galaxy 7be8e6b1dd
feat(common): add a tool method encode (common #146, #2647)
Co-authored-by: John <thespica@qq.com>
2024-08-24 16:07:26 +08:00
V_Galaxy 0b24aca3cd
chore(store): translate CJK comments to English for store-dist, store-grpc, store-node, store-rocksdb, store-test (#2645)
Co-authored-by: Peng Junzhi <78788603+Pengzna@users.noreply.github.com>
2024-08-23 14:35:16 +08:00
imbajin f88fad4711
Merge pull request #2646 from apache/fixup-commons
chore(ci): disable merge button & rename ci job name
2024-08-23 11:00:23 +08:00
VGalaxies a767d73182 setup 2024-08-22 20:09:42 +08:00
imbajin 0a0f2c3bfa
Merge pull request #2628 from apache/intro-commons-v2
**TODO:**
After this PR merged, change the README in commons & pin a [issue](https://github.com/hugegraph/hugegraph-hubble/issues/371) to notify all users/devs to know the context (also update the repo description...)

Finally, we may need start a discussion for marking commons repo in achieved status
2024-08-22 19:07:20 +08:00
V_Galaxy 7dc6a86a7d
chore(dist): intro additional Dockerfile to build the server image & skip init-hstore backend (#2642) 2024-08-22 14:04:06 +08:00
VGalaxies b087f085c1 chore(commons): basic adapt for commons migration 2024-08-21 16:09:00 +08:00
YangJiaqi 58f58ee094
fix(hstore): enable JRaft MaxBodySize config (#2633)
* enable JRaft MaxBodySize config
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.apache.hugegraph.store.node.AppConfig$Raft': Unsatisfied dependency expressed through field 'maxBodySize'; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "512*1024"

---------

Co-authored-by: V_Galaxy <vgalaxies@apache.org>
2024-08-18 14:47:11 +08:00
YangJiaqi ba5b89e374
fix(hstore): print time for hstore gc log #2636 2024-08-17 11:39:30 +08:00
V_Galaxy 1c577de9ba
chore(api): support ignore graphspaces segment in url (#2612)
For forwards compatibility with the "graphspace" mode

---------

Co-authored-by: imbajin <jin@apache.org>
2024-08-13 20:56:53 +08:00
V_Galaxy 4f0e4442ab
fix: correct server docker copy source path (#2637) 2024-08-13 20:53:20 +08:00
YangJiaqi a038d2341c
fix(hstore): JRaft maxEntriesSize configuration parameters do not take effect (#2630)
Co-authored-by: imbajin <jin@apache.org>
2024-08-11 13:04:34 +08:00
V_Galaxy df921e915d
refact(server): enlarge bytes write limit & remove param `big` when encode/decode string id length (#2622)
As title, change limit:
- vid max to 16KB
- eid max to 64kb (128k as backup)
- property max to 10MB (keep consistent)

fix #1593 #2291

---------

Co-authored-by: imbajin <jin@apache.org>
2024-08-10 17:02:30 +08:00
V_Galaxy 7df736a77c
chore(hstore): translate CJK comments to English (#2616)
* trans server-core
2024-08-10 15:31:25 +08:00
V_Galaxy c231a6fddb
chore(store): translate CJK comments to English for store-cli, store-client, store-common, store-core (#2623)
* fixup Chinese punctuation
2024-08-10 12:47:09 +08:00
V_Galaxy 2e27c583b4
chore(pd): translate CJK punctuations to English (#2625) 2024-08-10 12:16:51 +08:00
VGalaxies 459d4413b4 Merge remote-tracking branch 'commons/migrate-commons' into intro-commons-v2 2024-08-10 12:14:58 +08:00
V_Galaxy dc3070f45b
chore(dist): tar source and binary package for hugegraph with pd-store (#2594)
tar source and binary package for hugegraph with pd-store
2024-08-06 21:21:14 +08:00
VGalaxies 162a104ebd git mv to hugegraph-commons 2024-08-03 20:34:23 +08:00
YangJiaqi 91f5b33bac
fix(hstore): JRaft Timer Metrics BUG (#2602) 2024-08-02 23:47:56 +08:00
John 53f0e18216
doc(server): enhance rest-server.properties comment (#2610)
---------

Co-authored-by: imbajin <jin@apache.org>
2024-08-02 19:14:25 +08:00
haohao0103 3427f42b81
refact(pd): remove redundant property in LogMeta & PartitionMeta (#2598)
Co-authored-by: V_Galaxy <vgalaxies@apache.org>
2024-08-02 18:37:06 +08:00
haohao0103 24ebe9da26
fix(pd/store): log files do not scroll with the process (#2589)
close #2581 GRPC Java defaults to using java. til.rogging (JUL) as its logging framework,

---------

Co-authored-by: VGalaxies <vgalaxies@apache.org>
2024-08-02 17:58:12 +08:00
imbajin 7b9fd21d2a
chore: enable up-to-date for UI(CI) (#2609) 2024-08-02 11:21:54 +08:00
V_Galaxy d36e05ece8
chore: temporarily ignore failure core tests for hstore & simplify ci name (#2599)
* ignore tests for hstore rename ci
2024-07-31 16:40:53 +08:00
haohao0103 9baef8b255
fix(commons):fixed memory leaks occur in HugeGraph Server during data writing (#144)
* #2578
fixed memory leaks occur in HugeGraph Server during data writing
2024-07-30 17:46:59 +08:00
haohao0103 86e1003c16
fix(pd): partition IDs always empty in Shards List (#2596) 2024-07-22 15:15:00 +08:00
Peng Junzhi edb59ebaeb
feat(store): integrate rest of store-test submodule (#2563)
Co-authored-by: imbajin <jin@apache.org>
2024-07-20 18:10:38 +08:00
V_Galaxy 73a4c9d028
chore: intro `editorconfig-maven-plugin` for verifying code style defined in `.editorconfig` (#2591)
* exclude .flattened-pom.xml
2024-07-17 16:03:27 +08:00
V_Galaxy d6bc24e0f2
fix(dist): update build artifact path for docker deployment (#2590)
* fix path
2024-07-16 20:25:02 +08:00
haohao0103 5dfcc3f694
feat: support disable RocksDB auto-compaction by configuration (#2586) 2024-07-16 16:40:44 +08:00
haohao0103 899dc8e0f0
doc(pd): add `initial-store-count` comments in `application.yml` (#2587)
PD cluster will assess the overall health of the cluster. If the number of store nodes is less than the initial-store-count, the cluster will be unavailable
2024-07-16 16:33:58 +08:00
haohao0103 85e096698a
refact: enhance cache invalidation of the partition -> leader shard in ClientCache (#2588) 2024-07-15 23:07:30 +08:00
V_Galaxy bd83741f24
chore: minor improve for pom properties (#2574) 2024-07-15 14:59:10 +08:00
V_Galaxy 882f3b7d65
feat(dist): support docker deployment for PD and Store (#2573)
Co-authored-by: imbajin <jin@apache.org>
2024-07-15 11:12:25 +08:00
HaoJin Yang 03b40a5244
fix(server): random generate default value (#2568)
Co-authored-by: imbajin <jin@apache.org>
2024-07-14 17:05:35 +08:00
V_Galaxy cedc000215
chore: upgrade revision to 1.5.0 (#2585)
* set revision to 1.5.0
2024-07-13 17:00:43 +08:00
V_Galaxy 9f89afc39a
feat(server): support new backend Hstore (#2560)
subtask of #2483
2024-07-10 16:35:44 +08:00
Frosky Lrupotkin 37e71c4858
chore: migrate the `hg-style.xml` to `.editorconfig` (#2561) 2024-06-28 22:34:07 +08:00
Peng Junzhi e82a91ca1a
feat(store): integrate store-dist and store-cli submodule (#2562)
* refact: prepare for integrating rest of store module

* feat(store): integrate store-dist and store-cli submodule

* fix(store): support and fix for store-dist and store-cli submodule

* fix(store): update deps

* fix(store): update deps

* reformat hg-store-cli

---------

Co-authored-by: VGalaxies <vgalaxies@apache.org>
2024-06-25 00:07:02 +08:00
V_Galaxy 1e9752109e
chore: intro `install-dist` module in root (#2552)
* init dist in root

* adapt path & regenerate deps

* add comment

* add comment

* fix pd dir

* fix server dir

* improve hugegraph-pd/.gitignore

* improve

* rename dist -> install-dist

* fix path

* regenerate known dependencies
2024-06-13 17:06:37 +08:00
V_Galaxy 506850caea
chore: reset license header for file declared in LICENSE (#2550) 2024-06-11 10:08:23 +08:00
sheli00 1a8959575c
feat(store): integrate `store-node` submodule (#2537) 2024-06-11 00:19:07 +08:00
Peng Junzhi ac93deebc6
feat(store): integrate `store-core` submodule (#2548)
* feat(store): integrate store-core submodule
2024-06-07 17:25:42 +08:00
Zee Huang 93c2e08780
Update 'How to Contribute' link and remove duplicate 'Guidelines' link in README (#143)
* Update 'How to Contribute' link and remove duplicate 'Guidelines' link in README

This PR makes the following changes to the README file to streamline the contribution guidelines and avoid redundancy:

- Updated the 'How to Contribute' link to ensure it directs contributors to the correct resource.
- Removed the 'Guidelines' link as it duplicated the information provided in 'How to Contribute'.

* Update contribution link from markdown to website

- Changed the contribution guide link in the README.md from the markdown file to the corresponding section on the official website.
- This change ensures that the link remains stable and is not impacted by the frequent changes to Markdown files.
2024-05-28 15:22:43 +08:00
V_Galaxy b056c5facd
chore(pd): translate CJK comments to English (#2536) 2024-05-13 16:16:02 +08:00
V_Galaxy c1e8ea5aba
feat(server): integrate `server-hstore` into hugegraph (#2534)
subtask of #2265

When introducing hstore, server-core needs corresponding modifications. Except for BytesBuffer.java in hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/serializer/, other files should be consistent with the pd-store branch.

---------

Co-authored-by: imbajin <jin@apache.org>
2024-05-06 20:09:12 +08:00
V_Galaxy 253b8d38b8
feat(pd): integrate `pd-dist` into hugegraph & add core tests, client tests, and REST tests for PD (#2532)
subtask of #2265

---------

Co-authored-by: imbajin <jin@apache.org>
2024-05-06 20:08:48 +08:00
V_Galaxy 2b3bc4f28b
feat(pd): integrate `pd-service` into hugegraph (#2528)
subtask of #2265

For detailed module analysis documentation, please refer to fs doc/link/wiki

TODO: Update the getPomVersion implement in the common-module

---------

Co-authored-by: imbajin <jin@apache.org>
2024-04-22 14:53:45 +08:00
V_Galaxy 43cae1d2e3
feat(pd): integrate `pd-core` into hugegraph (#2478)
The corresponding tests will be merged after pd-service

subtask of https://github.com/apache/incubator-hugegraph/issues/2265

---

During the code review, I found the following issues:

1. Similar functionality appears multiple times, such as stub connection-related code, with redundancy between `PDClient.StubProxy` and `AbstractClientStubProxy`.
2. Package partitioning:
    1. `PDPulse`, `PDPulseImpl` should in `pulse`
    2. `PDWatch`, `PDWatchImpl` should in `watch`
3. Unused code, see below

---------

Co-authored-by: imbajin <jin@apache.org>
2024-04-19 23:27:46 +08:00
Peng Junzhi b4bc1f066a
feat(store): integrate `store-rocksdb` submodule (#2513)
TODO: delete "hugegraph-store/hg-store-rocksdb/src/main/java/place-holder.txt" later

---------

Co-authored-by: imbajin <jin@apache.org>
2024-04-19 11:11:44 +08:00
Hongjun Li 7d335b2c72
chore: config *.md max length (#2525) 2024-04-16 21:15:39 +08:00
Emmanuel Ferdman 543bbfeb74
fix: update resource references (#2522) 2024-04-16 15:10:49 +08:00
Liu Xiao 906112c080
chore: make IDEA support IssueNavigationLink and add icon (#2521) 2024-04-15 15:31:12 +08:00
V_Galaxy 6be756919b
fix(server): avoid overriding backend config in gremlin example script (#2519) 2024-04-14 23:57:07 +08:00
V_Galaxy 3783247c74
fix(server): switch rocksdb backend to memory when executing gremlin example (#2518) 2024-04-12 16:32:08 +08:00
imbajin 1228dec04d fix: maven rat plugin exist partial failure
fix: maven rat plugin exist partial failure
2024-04-05 23:53:09 +08:00
Peng Junzhi d0a3ccc045 feat(store): integrate `store-test` submodule 2024-04-05 23:53:09 +08:00
Peng Junzhi 6c72ca5f63 feat(store): integrate `store-client` submodule 2024-04-05 23:53:09 +08:00
Peng Junzhi f0d9d12ca7 feat(store): integrate `store-grpc` submodule 2024-04-05 23:53:09 +08:00
Peng Junzhi e605f732e2 feat(store): integrate `store-common` submodule 2024-04-05 23:53:09 +08:00
Peng Junzhi 52f3d64b6a refact: prepare for integrating store modules 2024-04-05 23:53:09 +08:00
VGalaxies 3a1618faa2 feat(pd): integrate `pd-client` submodule 2024-04-04 17:37:15 +08:00
VGalaxies bd1d9db77b feat(pd): integrate `pd-test` submodule
prepare tests for `pd-common`
2024-04-04 17:37:15 +08:00
VGalaxies b5d9dd2f02 feat(pd): integrate `pd-common` submodule 2024-04-04 17:37:15 +08:00
VGalaxies a560a6efee feat(pd): integrate `pd-grpc` submodule 2024-04-04 17:37:15 +08:00
VGalaxies 37e4405c04 refact: prepare for integrating pd modules
1. prepare pom and CI for pd-client, pd-common, pd-grpc and pd-test
2. drop support for java8
2024-04-04 17:37:15 +08:00
Peng Junzhi 483bca52ef
chore: remove required ci with java8 (#2503) 2024-04-03 23:17:30 +08:00
Simon Cheung 27cf52b007
chore: add swagger-ui LICENSE relative files (#2495)
* Create LICENSE-swagger-ui.txt
* Update NOTICE
2024-03-30 14:17:17 +08:00
imbajin 6a4041e21c chore: upgrade to 1.3.0 (last major version support Java8)
fix
2024-03-22 10:51:57 +08:00
imbajin 713d88d1fd refact: enhance auth logic
fix
2024-03-22 10:51:57 +08:00
imbajin ef8f6128a3 fix: multi graph error in rocksdb with same path/fd 2024-03-22 10:51:57 +08:00
SunnyBoy-WYH 277f76ef03
chore(server): clear context after req done (#2470)
Co-authored-by: vaughn.zhang <vaughn.zhang@zoom.us>
Co-authored-by: imbajin <jin@apache.org>
2024-03-19 17:43:33 +08:00
Bond 7b33574fd0
feat: added the OpenTelemetry trace support (#2477)
TODO: we need enhance our shell experience
---------

Co-authored-by: imbajin <jin@apache.org>
Co-authored-by: VGalaxies <vgalaxies@apache.org>
2024-03-15 17:30:16 +08:00
imbajin c883f56a4e
chore: disable clean flatten for deploy (#141) 2024-03-13 20:27:00 +08:00
小宇 0cfd8daed3
feat: support user defined RestClientConfig/HTTPClient params (#140)
- add builderCallback param for client to add custom config
- add params connectTimeout and readTimeout to instead the param time
- update version to 1.3.0

---------

Co-authored-by: imbajin <jin@apache.org>
2024-03-13 20:13:01 +08:00
vaughn c09982b0df
fix(auth): enhance the URL check (#2422)
Co-authored-by: imbajin <jin@apache.org>
2024-03-09 21:04:30 +08:00
V_Galaxy eb6570c992
fix(server): 'serverStarted' error when execute gremlin example (#2473) 2024-03-05 15:21:42 +08:00
SunnyBoy-WYH 6861ed5e94
fix(server): fix the bug which promtheus cant collect hg metric (#2462) 2024-03-03 13:05:10 +08:00
SunnyBoy-WYH 3f127f01f1
fix(server): add tip for gremlin api NPE with empty query (#2467)
fix #2426
2024-03-02 01:23:01 +08:00
Hongjun Li 2e3adcde02
chore: Add a newline formatting configuration and a comment for warning (#2464)
- Add a newline formatting configuration
- Add a comment for the IDEA unsupported warning about `continuation_indent_size`
2024-02-29 20:35:52 +08:00
Hongjun Li 47a68f098a
chore: refine the hg-style.xml specification (#2457)
- Change the maximum wrap text length for XML to 120 (via `hg-style.xml`)
- Add a blank line between method definitions, inner class definitions, and static code blocks (via `hg-style.xml`)
- Add `<p>` tags to Javadoc blank lines (via `hg-style.xml`)
- `.xml` file leaves a blank line at the end (via `.editorconfig`)
- Class declaration requires a blank line before and after each line (via `hg-style.xml`)
- Javadoc line comment not in line (via `hg-style.xml`)
- `.properties` file leaves empty lines (via `hg-style.xml`)
- `.yaml` file braces `{}`, brackets `[]` remove spaces (via `hg-style.xml`)
2024-02-27 12:53:29 +08:00
Z-HUANT d0f63c8ac3
feat(api): optimize adjacent-edges query (#2408)
Relevant issue: #2255

Gremlin Query: For adjacency edge queries, if a vertex does not belong to the adjacent vertices of this edge, filter out that vertex.

---------

Co-authored-by: imbajin <jin@apache.org>
2024-02-26 12:29:13 +08:00
M dfee5bf6aa
fix(server): remove extra blank lines (#2459)
* remove extra blank lines in api

* remove extra blank lines in core

* remove extra blank lines in scylladb
2024-02-25 11:45:00 +08:00
Jermy Li eef3b355f6
chore: unify to call SchemaLabel.getLabelId() (#2458)
Change-Id: I31bcc0d1ee99f3c443f8f4f0d458e06ca89977ef
2024-02-24 22:45:23 +08:00
V_Galaxy bc421bb197
chore: improve license header checker confs and pre-check header when validating (#2445)
* improve license header checker confs

* typo

* verify -> validate

* update rat exclude files

* empty commit

* update rat exclude files

* update rat exclude files
2024-02-23 16:42:01 +08:00
V_Galaxy f6da2ee6cb
fix: protobuf file header (#2448) 2024-02-23 16:39:30 +08:00
M e79f1a5e73
fix(server): clean up the code (#2456)
- replace `size() == 0` with `isEmpty()`
- remove unnecessary unboxing
- remove unnecessary boxing
- replace for loop with enhanced for loop
- replace lambda with method reference
2024-02-22 17:26:15 +08:00
M 5cb9aad6ee
fix: format and clean code in modules (#2439)
Format & clean code in submodels:

1. API
2. Scylladb
3. Postgresql
4. Rocksdb
5. Palo
6. Mysql
7. Hbase
8. Cassandra
9. Test

---------

Co-authored-by: imbajin <jin@apache.org>
2024-02-20 17:22:54 +08:00
M 0b70e897f0
fix: format and clean code in core module (#2440) 2024-02-20 17:22:28 +08:00
M 0ee9a9b788
fix: format and clean code in dist and example modules (#2441) 2024-02-20 17:22:07 +08:00
M 75867796b7
fix(server): unify the license headers (#2438)
subtask of #2435

---------

Co-authored-by: imbajin <jin@apache.org>
Co-authored-by: VGalaxies <vgalaxies@apache.org>
2024-02-07 12:53:57 +08:00
Peng Junzhi 3f7dc2a8b2
fix(server): make CacheManager constructor private to satisfy the singleton pattern (#2432) 2024-02-01 23:58:44 +08:00
SunnyBoy-WYH 1d4532cd62
chore(server): update swagger info for default server profile (#2423) 2024-01-28 14:03:38 +08:00
Dandelion b980df8697
fix(chore): remove zgc in dockerfile for ARM env (#2421)
* remove zgc

* Apply suggestions from code review

Co-authored-by: imbajin <jin@apache.org>

* add comment for hugegraph-server.sh

* fix enable-auth.sh

* init store in entrypoint

* use flag file to skip re-init

* delete tar.gz

* simply dockerfile

* mvn optimize

* simply dockerfile

* add init log in docker

---------

Co-authored-by: imbajin <jin@apache.org>
2024-01-26 16:48:41 +08:00
Z-HUANT 1dd0580d30
fix(server): reinitialize the progress to set up graph auth friendly (#2411) 2024-01-17 20:56:25 +08:00
Dandelion de5904a600
feat: support docker use the auth when starting (#2403)
- allow user to set env for docker to set auth mode
- download keystore when package
- fix a curl error (also use curl first in `function` download)

---------

Co-authored-by: imbajin <jin@apache.org>
2024-01-15 20:50:24 +08:00
imbajin 57cd0e8dd7
doc: enhance NOTICE info to keep it clear (#2409) 2024-01-09 18:44:08 +08:00
Caican Cai 7965aac70d
chore: add license link (#2398) 2024-01-04 12:50:24 +08:00
xiaoleizi2016 cf9ba8b310
fix(core): task restore interrupt problem on restart server (#2401)
* Update StandardTaskScheduler.java
2023-12-29 12:04:54 +08:00
SunnyBoy-WYH 7635c67865
chore(server): update license for 1.2.0 (#2391)
---------

Co-authored-by: liuxiao <liuxiao2103@qq.com>
Co-authored-by: Simon Cheung <ming@apache.org>
2023-12-19 15:22:35 +08:00
V_Galaxy 965d6c137a
fix: incorrect path in hugegraph assembly scripts (#2392)
* fix: typo

* fix: assembly hugegraph path

* reset
2023-12-18 12:33:33 +08:00
Dandelion cb4427d9f1
doc: adjust docker desc in readme (#2390)
* fix(dist): update relative path for the 1.2.0

* add docker policy and run server in daemon

* fix: use tail to avoid container exit

* adjuest the order of quick start

* Update hugegraph-server/hugegraph-dist/docker/scripts/detect-storage.groovy

* adjust desc

* Update README.md

* Update pom.xml

---------

Co-authored-by: imbajin <jin@apache.org>
2023-12-17 15:59:28 +08:00
小宇 33fa9ed45d
update licence (#139) 2023-12-17 15:35:03 +08:00
vaughn 4346b44f80
fix: TinkerPop unit test lack some lables (#2387) 2023-12-14 17:59:31 +08:00
Dandelion 2c6fcdc719
add maven args for stage or other args (#2386) 2023-12-13 16:00:50 +08:00
imbajin 44f99e968c
doc: update README for release (#138) 2023-12-12 17:21:28 +08:00
conghuhu b52517cc47
feat(core): add IntMapByDynamicHash V1 implement (#2377)
* feat(WIP): add IntMapByDynamicHash (#2294)

* feat: add values & keys in IntMapByDynamicHash

* add some basic comment & fix some style

* feat: fix pr review

* fix: fix some review

---------

Co-authored-by: imbajin <jin@apache.org>
2023-12-12 12:25:51 +08:00
imbajin bd5d68f0f2
refact(rocksdb): clean & reformat some code (#2200)
* chore: merge master to clean-rocksdb for synchronization (#2383)

---------

Co-authored-by: V_Galaxy <dyc1904821183@gmail.com>
2023-12-11 22:21:08 +08:00
V_Galaxy bfe9fae150
chore: reset hugegraph version to 1.2.0 (#2382)
* chore: reset version to 1.2.0

* chore: add README for three submodules

* fix: README.md

* fix: README.md

* fix: README.md

* fix: README.md
2023-12-09 22:02:49 +08:00
M c997f35b04
fix(api): correct the vertex id in the edge-existence api (#2380) 2023-12-08 15:59:28 +08:00
小宇 47aa8be850
refact(api): update common 1.2 & fix jersey client code problem (#2365)
* update common version and fix rest client problem

* use stage

* fix dependency issue

* test

* test

* test

* test

* fix

* chore:  improve the ci logic

* fix core-version

* Empty test

* fix code issue

* fix: 3rd party changes

* code optimize

* refactor the AbsJerseyRestClient

* fix code issue

---------

Co-authored-by: imbajin <jin@apache.org>
2023-12-07 12:26:22 +08:00
Simon Cheung e8fb2696d6
chore: fix curl failed to request https urls (#2378) 2023-12-05 21:50:02 +08:00
小宇 dcf3752515
fix the json param convert (#137) 2023-12-05 10:56:12 +08:00
imbajin 10f0a87c7b
refact(common): rename jsonutil to avoid conflicts with server (#136)
fix https://github.com/apache/incubator-hugegraph/actions/runs/7082354080/job/19273001614?pr=2365

Also add some comment for it
2023-12-04 14:55:56 +08:00
Jermy Li 20d1e5228e
chore: move server info into GlobalMasterInfo (#2370)
* chore: move server info into GlobalMasterInfo

Change-Id: Id854892333115fd45d7c8b9799d255627541b2ad

* fix testClearAndInit() and export GlobalMasterInfo

Change-Id: Ic2878c5359e7f55fcd11986aa0bf79241c7ee9ab

* enhence ServerInfoManager.heartbeat()

Change-Id: I6932893c4be8331547f3b721083ca00430f85e58

* move RoleElectionStateMachineTest to UnitTestSuite

Change-Id: I7b3e8e2867dcf1063a726c8005f1c34dbd218f7c
2023-12-04 12:43:32 +08:00
Jermy Li 8c93652de7
fix: Assert.assertThrows() should check result of exceptionConsumer (#135)
* fix: Assert.assertThrows() should check result of exceptionConsumer

* fix some warnings

* remove assertThrowsFuture() from Assert
2023-11-30 16:25:31 +08:00
M ed493f3093
feat: optimize perf for adjacency-edges query (#2242) 2023-11-29 21:44:29 +08:00
haohao0103 d376b02dc5
fix HBase PrefixFilter bug (#2364)
* #2177

* #2177

* #2177

* #2177

* #2177

* #2177
2023-11-29 19:11:28 +08:00
lzyxx 197e8a00ed
chore(ci): add stage profile settings (#2361)
* Update LICENSE

* Update install-cassandra.sh

* add stage profile settings

* Update ci.yml

* Update ci.yml

* Update ci.yml

* Update licence-checker.yml

---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-28 17:33:56 +08:00
SunnyBoy-WYH 0c01475843
feat(server):swagger support auth for standardAuth mode (#2360)
* feat(server):swagger support auth for standardAuth mode and try to fix arthas odd test

* chore(api): update api version & swagger token auth mode
2023-11-28 17:01:54 +08:00
imbajin c0ea21eed6
chore: disable raft test in normal PR due to timeout problem (#2349)
And replace it in pd/store module
2023-11-24 19:59:24 +08:00
小宇 5ad55fb82f
feat(common): replace jersey dependencies with OkHttp (Breaking Change) (#133)
* remove jersey

* Update ci.yml

* refact: replace params okhttp3.Headers to internal RestHeaders

* fix: licence dependency

* fix: test error

* fix: code format issue

* fix: unit test error


---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-22 09:37:02 +08:00
Chong Shen 12b4940563
fix(api): remove redirect-to-master from synchronous Gremlin (#2356)
* fix: remove redirect master role to align with behaviour of VertexApi and EdgeApi

* chore: add back necessary annotation
2023-11-22 09:33:04 +08:00
Dandelion 25301f6228
feat: adapt Dockerfile for new project structure (#2344)
* feat: dockerfile adapt the project structure

* change the version

---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-13 19:30:24 +08:00
imbajin a6e1f232c2
fix(api): refactor/downgrade record logic for slow log (#2347)
* fix(api): refactor/downgrade record logic for slow log

add some TODOs & assign @SunnyBoy-WYH to address it

* fix typo

* enhance the perf
2023-11-13 18:03:21 +08:00
imbajin a7ad7ea100 Update PerfExampleBase.java 2023-11-13 12:50:49 +08:00
imbajin a9445ca3c3 fix(api): clean some code for release
separate from slow log
2023-11-13 12:50:49 +08:00
V_Galaxy bce6d058f5
refact: adjust project structure for merge PD & Store[Breaking Change] (#2338)
## Purpose of the PR

Subtask of #2265.

Adjust the project structure of this repository to include three sub-modules: hugegraph-server, hugegraph-pd, hugegraph-store at the root level.

## Main Changes

Roll back to the moment when https://github.com/apache/incubator-hugegraph/pull/2266 was merged on `pd-store` and incorporate the latest changes in `master`.

For more detailed information, please refer to https://github.com/apache/incubator-hugegraph/pull/2266#issue-1834369489.


---------

Co-authored-by: M <87920097+msgui@users.noreply.github.com>
2023-11-08 18:08:08 +08:00
SunnyBoy-WYH 69e6b461ad
feat(api): support recording slow query log (#2327)
* chore(api): code style for cr

---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-06 14:34:12 +08:00
SunnyBoy-WYH 4d5f4195db
chore(api): add swagger desc for Arthas & Metric & Cypher & White API (#2337)
add swagger belong for arthas API

---------

Co-authored-by: imbajin <jin@apache.org>
2023-11-06 14:15:32 +08:00
lzyxx 70ab14e3e6
feat(cassandra): adapt cassandra from 3.11.12 to 4.0.10 (#2300) 2023-10-28 23:58:17 +08:00
conghuhu e90489f361
fix(core): handle schema Cache expandCapacity concurrent problem (#2332) 2023-10-25 17:25:07 +08:00
Wu Chencan 8db0a9b195
feat(core): support batch+parallel edges traverse (#2312)
## Main Changes

- Enhance Consumers.java, supporting ExceptionHandle and `Future` to handle InterruptedException when awaiting
- Add Nested Iterator Edge and support batch execution
- Support batch execution & thread parallel in KoutTraverser and Kneighbor
2023-10-24 19:33:24 +08:00
Dandelion b43526da60
fix: always wait for storage if rocksdb is selected (#2333) 2023-10-24 17:24:43 +08:00
Dandelion d4b95ca323
feat: support Cassandra with docker-compose in server (#2307)
## Main Changes

1. change the dockerfile, adding the shell to wait for storage backend and use a docker-entrypoint.sh to manage the starting process.
2. delete a deprecated class in  gremlin-console.sh (reference: [doc of ScriptExecutor](https://tinkerpop.apache.org/javadocs/3.2.3/full/org/apache/tinkerpop/gremlin/groovy/jsr223/ScriptExecutor.html))
3. add a healthy check in docker-compose
4. add an example folder where we can put all the template docker-compose.yml here
5. add `*swagger-ui*` in gitignore, which appears after you compile the source code locally.

---------

Co-authored-by: imbajin <jin@apache.org>
2023-10-23 16:29:42 +08:00
Dandelion 73329ce4f5
doc: README.md tiny improve (#2331) 2023-10-23 16:17:36 +08:00
SunnyBoy-WYH 869fc81811
feat(api): support embedded arthas agent in hugegraph-server (#2278) 2023-10-20 10:15:51 +08:00
Jermy Li 45636a0489
README.md tiny improve (#2320) 2023-10-13 13:47:01 +08:00
SunnyBoy-WYH fc9bc2866e
feat(api): support metric API Prometheus format & add statistic metric api (#2286) 2023-10-08 20:21:09 +08:00
SunnyBoy-WYH 30ef2f7c6b
feat: support White IP List (#2299)
tips:
- this feat works when auth mode was set.
- this feat works when white ip status was enabled.

because now PD is unavailable,just use java list; when pd ready , we can checkout pd.
2023-10-02 13:25:45 +08:00
Dandelion d7c1c2149c
doc: update README about start server with example graph (#2315) 2023-10-02 13:14:01 +08:00
M b49be05171
add: dependency-review (#134)
* add: dependency-review

* tiny improve

* fix

Co-authored-by: imbajin <jin@apache.org>

---------

Co-authored-by: imbajin <jin@apache.org>
2023-09-20 17:47:01 +08:00
M 4ceef1ab0c
fix: base-ref/head-ref missed in dependency-review on master (#2308) 2023-09-11 10:48:37 +08:00
Wu Chencan 8e99d85d33
feat(api-core): support label & property filtering for both edge and vertex & support kout dfs mode (#2295)
- Support label & property filtering for both edge and vertex and the filtering is implemented in Kout Post and Kneighbor - Post Apis, reducing unnecessary graph searches through pruning
- Support Kout dfs mode in Kout Post Api

Originally only edge label filtering was supported, now label and property filtering for edge and vertex is supported.
- add classes VEStepEntity and VEStep to support serialization in request
- add class Steps to support filtering of edge and vertex in runtime(core)
- add new method edgesOfVertex(Id source, Steps steps) to support label and property filtering for both edge and vertex in HugeTraverser.java

---------

Co-authored-by: imbajin <jin@apache.org>
2023-09-10 16:47:45 +08:00
Dandelion 1d0969dede
fix(dist): avoid var PRELOAD cover environmnet vars (#2302)
Update hugegraph-dist/src/assembly/static/bin/start-hugegraph.sh

---------

Co-authored-by: imbajin <jin@apache.org>
2023-09-08 22:07:57 +08:00
Chong Shen aaf67cf81c
fix(core): close flat mapper iterator after usage (#2281)
close [Bug] FlatMapperIterator should be closed after usage #2280
2023-08-29 16:09:31 +08:00
Dandelion 8a515f20db
feat(dist): support pre-load test graph data in docker container (#2241)
- Provide the related conf and groovy for user to pre load some data.
- Change the start-hugegraph.sh to get the environment variables to decide to pre-load or not.

---------

Co-authored-by: imbajin <jin@apache.org>
2023-08-28 15:36:21 +08:00
V_Galaxy 77c76124af
chore(dist): replace wget to curl to download swagger-ui (#2277)
Main Changes:
1. replace `wget` by `curl` when downloading `swagger-ui`
2. silence the output of `curl` and `tar` commands
3. reuse the existing `v4.15.5.tar.gz` before downloading
4. avoid downloading `swagger-ui` in non-Linux platforms to prevent build failures (there might be a cross-platform build approach available 🤔)
5. wrapp the script content within `<![CDATA[ ... ]]>` blocks ensures that the script retains its original format when generating the `dist.sh` script (also suppresses automatic indentation)
6. remove intermediate files at the end of the script

**An alternative approach**, during the generation of the `dist.sh` script, only the `${final.name}` property from the build process is utilized. It might be possible to separately store a `dist.sh` script within hugegraph-dist, then use `sed` during the build process to replace the value of `${final.name}`, **thereby avoiding the need to embed script content within the pom file**.

---------

Co-authored-by: imbajin <jin@apache.org>
2023-08-25 15:20:44 +08:00
lzyxx 4d7ad86776
fix checkstyle: Update StandardStateMachineCallback.java (#2290)
During the compilation of your code, an informational message was displayed indicating an issue with the file /home/lzy/hugegraph/hugegraph-core/src/main/java/org/apache/hugegraph/masterelection/StandardStateMachineCallback.java at line 36. The specific problem was that the length of this line exceeded 100 characters, with a total of 101 characters.

To address this issue, I have made modifications to this class. I have split the originally long line into multiple lines to ensure that each line's length adheres to the coding standards' specified limits. This action not only aligns with the requirements of the code style, but also improves the readability and maintainability of the code.
2023-08-22 14:07:34 +08:00
DanGuge d12f5734e6
feat(api&core): in oltp apis, add statistics info and support full info about vertices and edges (#2262)
* chore: improve gitignore file

* feat: add ApiMeasure to collect runtime data

ApiMeasure will count the number of vertices and edges traversed at runtime, and the time the api takes to execute

* feat: Add ApiMeasure to JsonSerializer and Modify the Serializer interface

* JsonSerializer: return measure information in api response

* Serializer: fit the feature that returns complete information about vertices and edges

* refactor: format code based on hugegraph-style.xml

* feat: Add statistics information in all oltp restful apis response and Support full information about vertices and edges

Statistics information:

* add vertexIterCounter and edgeIterCounter in HugeTraverser.java to track traversed vertices and edges at run time

* modify all oltp restful apis to add statistics information in response

Full information about vertices and edges:

* add 'with_vertex' and 'with_edge' parameter option in apis

* modify oltp apis to support vertex and edge information in api response

* add EdgeRecord in HugeTraverser.java to record edges at run time and generate the edge information returned in api response

* modify Path and PathSet in HugeTraverser.java to support full edge information storage

* modify all traversers to support track of edge information at run time

* fix: numeric cast

* fix: Jaccard Similarity api test

* fix: adjust the code style and naming convention

* Empty commit

* Empty commit

* fix:
1. change System.currentTimeMillis() to System.nanoTime();
2. modify addCount()

* fix: rollback change in .gitignore

* fix: rollback ServerOptions.java code style

* fix: rollback API.java code style and add exception in else branch

* fix: fix code style

* fix: name style & code style
* rename edgeRecord to edgeResults
* fix Request class code style in SameNeighborsAPI.java
2023-08-19 13:41:08 +08:00
ustcer c31a53641f
add some construction methods for more convenient use (#132)
Co-authored-by: chengxin05 <chengxin05@baidu.com>
2023-07-19 21:06:52 +08:00
zoulei 297e491232
fix commons dependency conflict (#131)
* fix commons dependency conflict
* upgrade commons version to 1.0.1
* upgrade grpc-core version to 1.28.1

Co-authored-by: imbajin <jin@apache.org>
2023-04-21 00:07:05 +08:00
imbajin 82f2a6539f Update license-checker.yml 2023-02-10 14:46:48 +08:00
imbajin f9593d494b chore: refactor the license check CI 2023-02-10 14:46:48 +08:00
Simon Cheung 6aa01af49e Update NOTICE 2023-02-09 19:19:11 +08:00
Simon 6f9493a517 1 2023-02-09 19:19:11 +08:00
imbajin e1cb3eb16c
chore(license): fix 3rd party refer code (#127)
* fix 3rd party refer in LICENSE
* add sky-walking action to check license header
* Update pom.xml
2023-02-04 01:52:42 +08:00
imbajin 8724b12032 chore: fix copyright year and format 2023-01-14 02:07:18 +08:00
imbajin 1f64e8afb0 chore: remove copyright in file header & fix some files 2023-01-14 02:07:18 +08:00
imbajin c28f8c8977 chore: add DISCLAIMER & NOTICE & LICENSE file to binary package 2023-01-14 02:07:18 +08:00
imbajin e339fed6c9 fix(dist): generate doc & exit script when upload files failed 2023-01-14 02:07:18 +08:00
imbajin e400e4d22b
refact(test): download binary file for https test (#126) 2023-01-13 23:44:21 +08:00
青年 0239a1e174
fix: add style files back (#125)
* add style
* Update .gitattributes

Co-authored-by: imbajin <jin@apache.org>
2023-01-01 13:18:07 +08:00
imbajin 9463119a67
chore: update release script & add mailing lists (#123) 2022-12-15 16:14:29 +08:00
imbajin a40774e484
chore: prepare for release v1.0.0 (#122) 2022-12-06 15:41:56 +08:00
imbajin c86e38a8ac
chore: enable rebase option (#121) 2022-12-05 00:05:14 +08:00
seagle 37e221a712
delete blankspace of licenses filename (#120)
Co-authored-by: yuanbingze <yuanbingze@yy.com>
2022-11-30 15:45:16 +08:00
青年 5bc993fe79
manifest version use project.version (#119) 2022-11-23 21:17:02 +08:00
Simon Cheung 4dbe157ecb
Add thrid-party dependency licenses (#117)
* add dep licenses

* Update LICENSE-JavaHamcrest.txt

Co-authored-by: imbajin <jin@apache.org>
2022-11-09 21:58:18 +08:00
imbajin caa4b26a98
refact: address some code alert (#115) 2022-11-09 17:50:27 +08:00
Simon Cheung 952975a3c7
add dep check ci (#116) 2022-11-08 21:13:45 +08:00
青年 7347b17a47
fix apache revision (#114) 2022-11-04 20:56:00 +08:00
青年 16602cc839
support custom content-type (#113)
* support custom content-type

* support custom content-type v2
2022-11-01 18:16:44 +08:00
imbajin 4361a51d9d
chore: fix missing mail address & other configs (#112) 2022-10-27 00:39:09 +08:00
imbajin dc3e9e2bbd
chore: enable ci in all prs (#111) 2022-10-26 19:38:51 +08:00
imbajin ae54f28308
refact: upgrade a string of dependencies to address CVEs report & clean code (#110)
Note: after use junit-2.13, some assert-api's error messages has changed, check it in other repos (and avoid use long & fixed error message)
2022-10-26 19:02:36 +08:00
imbajin b783da5bde
feat(apache): support check license header with RAT (#108)
use "mvn apache-rat:check" to see the report, and use find ./ -name rat.txt -print0 | xargs -0 -I file cat file > merged-rat.txt
2022-10-20 12:18:49 +08:00
imbajin be72d20f8a
chore: setup for apache maven release (#107) 2022-10-19 23:42:31 +08:00
imbajin e85ab38c6b
refact: clean code & typo & update the name of getTimeZone (#105)
* refact:  clean code & typo & update the name of getTimeZone

Typo: getTimeZome() -> getTimeZone()

And we need check/update the class used it later

* Update RestClient.java
2022-09-15 16:36:13 +08:00
ShouJing 3b1bcb1a99
rename package name `com.baidu` to `org.apache` (#104) 2022-09-08 17:28:03 +08:00
DamonXue(Fibonacci) 42ef9c4d95
chore: upgrade CodeQL version to v2 (#106) 2022-09-06 19:14:59 +08:00
seagle 09b18191ed
update checkstyle (#97)
Co-authored-by: yuanbingze <yuanbingze@yy.com>
Co-authored-by: imbajin <jin@apache.org>
2022-06-13 20:37:54 +08:00
imbajin 745bd861af
chore: use .asf.yaml for apache workflow rule (#98)
* add asf.yaml file

* Update .asf.yaml

* add required
2022-06-07 09:54:42 +08:00
Jermy Li 4af14a9998
add Cnm and Anm to CollectionUtil (#101)
* add Cmn to CollectionUtil

Change-Id: I873e5c41229a8743ca5753d11c3b5e608b2e9298

* add Anm function

Change-Id: Idcb24ba80c61fb53c9744d7ab5d2a379e16a4ad3
2022-05-27 14:21:09 +08:00
Jermy Li 589ee2ca10
support assert-throws return future (#102)
Change-Id: I8fe115a7518dd84e22c9e28f777515e74e48d5d2
2022-05-27 14:19:10 +08:00
imbajin db84121d5d
refact: unify pom & remove useless file (#100) 2022-04-29 12:33:19 +08:00
Jermy Li deac513c43
improve Whitebox.setInternalState() (#99)
* add Whitebox.setInternalFinalState()

* delete Whitebox.setInternalFinalState() method since ineffective
2022-04-27 10:27:59 +08:00
zyxxoo f2e838443d
version 2.1.2 (#96) 2022-04-11 16:11:14 +08:00
zyxxoo d0e5971c7e
fix: can't delete conf file when drop graph (#93) 2022-03-21 19:47:40 +08:00
imbajin 88d2f897ed
chore: support code security check with codeQL (#94) 2022-03-21 17:24:35 +08:00
imbajin 05fe7a4c92
chore: use cla assistant to support robot pr (#92)
Co-authored-by: imbajin <imbajin@users.noreply.github.com>
2022-03-03 19:27:08 +08:00
zyxxoo 4b21e94ad2
chore: support java 11 (#83)
* chore: support java 17

* fix: unitest

* fix: server JAX-B API not found warning

* chore: improve code

* fix: hugeconfig test

* chore: resolve conflict

* fix: version unit test

* chore: improve code

* chore: improve impl version

* chore: improve code

* refactor: hugeconfig get

* chore: improve code
2022-01-14 10:55:34 +08:00
Jermy Li d695bd494d
fix some test cases naming (#90)
Change-Id: I89eaf2b7ff13e6909e057970542fff60ab552785
2021-12-21 20:59:44 +08:00
zhoney 922a4f6334
upgrade log4j to version 2.17.0 (#89) 2021-12-21 17:51:38 +08:00
coderzc 8f0f2ba012
release maven package by actions (#88) 2021-12-21 14:12:35 +08:00
zhoney 4a1926fe40
improve java doc (#87) 2021-12-17 17:43:29 +08:00
Jermy Li fbb743afeb
bump up version to 2.0.0 (#86)
* refactor license module

Change-Id: Ia4041f88994490c1bc0519e0f8ff01d27577bafb
2021-12-17 10:57:40 +08:00
zhoney 3b8933c3d3
fix log4j error (#85) 2021-12-15 20:30:27 +08:00
Jermy Li f5383d5541
Merge pull request #84 (merge rpc module into commons)
refact(rpc): merge rpc module into commons
2021-12-07 16:26:18 +08:00
imbajin ee08712120 chore: new pom & README for module 2021-12-07 14:38:05 +08:00
imbajin 24c3390379 chore: merge license & checkstyle & ci
1. root pom.xml, license, checkstyle, ci,
2021-12-01 20:38:09 +08:00
imbajin 0789b1c8c1 merge rpc module into commons 2021-11-30 15:48:37 +08:00
imbajin c572c2bedd first rename 2021-11-30 15:29:35 +08:00
guoygang 1d27452994
add bearer token support (#81) 2021-11-02 19:43:38 +08:00
imbajin 53c6503cde
chore: update ubuntu version for ci actions (#79) 2021-10-09 11:40:54 +08:00
coderzc 3881b86697
fix: unable to close the rpc thread pool at destroy (#3) 2021-07-28 11:23:55 +08:00
imbajin 49e8599d8f
chore: add issue template & auto stale issues and pr (#78) 2021-07-02 16:35:24 +08:00
ShouJing 535ae072f4
add Auth Context to store request header(Authorization) (#76) 2021-06-24 16:00:29 +08:00
Linary efa8e97c4f
chore: use github action to run ci (#77) 2021-06-23 16:57:12 +08:00
dependabot[bot] 9101842200
Bump jackson.version from 2.10.2 to 2.12.1 (#63)
Bumps `jackson.version` from 2.10.2 to 2.12.1.

Updates `jackson-annotations` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson/releases)
- [Commits](https://github.com/FasterXML/jackson/commits)

Updates `jackson-core` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson-core/releases)
- [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.10.2...jackson-core-2.12.1)

Updates `jackson-databind` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson/releases)
- [Commits](https://github.com/FasterXML/jackson/commits)

Updates `jackson-module-jaxb-annotations` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson-modules-base/releases)
- [Commits](https://github.com/FasterXML/jackson-modules-base/compare/jackson-modules-base-2.10.2...jackson-modules-base-2.12.1)

Updates `jackson-jaxrs-base` from 2.10.2 to 2.12.1
- [Release notes](https://github.com/FasterXML/jackson-jaxrs-providers/releases)
- [Commits](https://github.com/FasterXML/jackson-jaxrs-providers/compare/jackson-jaxrs-providers-2.10.2...jackson-jaxrs-providers-2.12.1)

Updates `jackson-jaxrs-json-provider` from 2.10.2 to 2.12.1

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-03 16:06:27 +08:00
dependabot[bot] 27dfd9d5a2
Bump commons-io from 2.4 to 2.7 (#75)
Bumps commons-io from 2.4 to 2.7.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-03 15:50:56 +08:00
houzhizhen 74b954acf2
disable delimiter parsing when construct from MapConfiguration (#74) 2021-04-26 16:16:31 +08:00
Linary f72fac400f
Improve some license params (#73) 2021-04-16 14:58:22 +08:00
Linary 185a926a94
Fix senstive mail address (#71) 2021-04-15 18:05:21 +08:00
shzcore aecaf4e86a
remove inner hostname from cacerts.jks (#72) 2021-04-15 16:54:02 +08:00
Jermy Li fe190141cc
improve profile performance (#69)
* improve profile performance
* support profile nested class
* support total_wasted time
* calculate totalChildrenWasted time for echarts
* only profile super class in the same package
* improve perf through local-tree,local-timer,local-stack
* improve test case
* add Stopwatch remove-child test
* fix can't profile parent class with 2 class not in the same package
* add totalChildrenTimes
* improve LocalTimer perf
* add PerfUtil.useLightStopwatch(true)
* define behavior of switching light-stopwatch process
* ignore other threads if profileSingleThread(true) with multi-threads
* improve the empty judgment the first call in useLightStopwatch()

Change-Id: Id1ae075ddffec77b95b31142d7ebcdae87371943
2021-04-13 14:53:42 +08:00
Jermy Li d51efb6120
add some test cases for util package (#70)
* add check for CollectionUtil.subSet from > to

Change-Id: I32d83f5738250eca23ae16c2ccbf52059a874bf6
2021-04-12 16:28:18 +08:00
Jermy Li 6c800388a1
support random port to start rpc server (#2)
* add rpc.server_adaptive_port option
* use bolt v1.6.2 instead of v1.5.6 to get RemotingServer.port()
2021-03-25 14:06:05 +08:00
Jermy Li 159143c04d
add rpc framework based on sofa-rpc (#1)
* add rpc framework based on sofa-rpc
* allowed to start server or client separately
* add destroy() method for rpc client
* complete the supplement of test cases
* remove sleep in destroy-server and improve comments of test block
* add fanout exception test case
* travis use oraclejdk8
* fix log4j config and remove test/resources from pom to avoid including log4j2.xml in tar

Co-authored-by: Jermy Li <lizhangmei@baidu.com>
Co-authored-by: xuliguov5 <xuliguo@baidu.com>
2021-03-23 18:59:43 +08:00
Linary 265f74bb5f
Add checkstyle plugin (#67) 2021-03-19 21:21:25 +08:00
Jermy Li 98844d8c2a
add UnitUtil class (#66)
* upgrede version to 1.8.6

Change-Id: I67c7b38979b2c0603878d48929247ec0282d10d9
2021-03-19 20:44:46 +08:00
liningrui 3914813fb8 Add checkstyle plugin 2021-03-17 15:21:59 +08:00
liningrui 1114e94924 First commit 2021-03-16 18:56:15 +08:00
Linary 42e5260ba5
Add Class.class as an accept data type in TypedOption (#65) 2021-03-07 16:42:38 +08:00
Jermy Li ccc4d3bd6a
add LimitIterator class (#62)
* bump up version 1.8.4

Change-Id: I5d150e0c30f83200880cf8dd95e6e4b3678137b0
2021-03-01 21:46:06 +08:00
Jermy Li cde7763cc2
fix BatchMapperIterator stopped when fetched none in the middle batch (#64)
Change-Id: I658d8e95a68c8a9494efa98e88f350cf6d65b021
2021-02-25 20:05:39 +08:00
Linary c80f959579
Implement PausableScheduledThreadPool (#61) 2021-02-03 22:03:37 +08:00
houzhizhen f4e861b3a8
add BarrierEvent (#60) 2021-01-11 18:01:35 +08:00
Linary 37de7be0ee
Improve SafeDateFormat by joda DateTimeFormatter (#59)
Fix #58
2020-12-14 15:14:50 +08:00
zhoney 9962e0c9c9
fix https+auth bug (#57)
Change-Id: Ic791c21271c9c9ca60b0ff4294feb5fe2165452a
2020-11-17 17:19:23 +08:00
Linary 2d4a8eebf8
Upgrade version to 1.8.0 for release (#55) 2020-11-05 17:35:59 +08:00
Jermy Li 630e19f8bc
fix LockManager get/create race condition (#53)
* fix LockManager get/create race condition

Change-Id: I524a2d4d13a99f3943bfa0e4a44aa0ccf9c573a1

* add unit test

Change-Id: I17abf10b3c4e7f41fdd82ce9a9423b9ffc5a07fd

* fix not clear test license

Change-Id: I41f463a7e42a9b205c251ebc906cc850cdd4b7af
2020-07-24 08:50:03 +08:00
dependabot[bot] 9f329f5f3a
Bump log4j2.version from 2.8.2 to 2.13.3 (#52)
Bumps `log4j2.version` from 2.8.2 to 2.13.3.

Updates `log4j-api` from 2.8.2 to 2.13.3

Updates `log4j-core` from 2.8.2 to 2.13.3

Updates `log4j-slf4j-impl` from 2.8.2 to 2.13.3

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-07-02 12:05:58 +08:00
Linary 544599e316
Fix HugeConfig save to file is empty (#51) 2020-07-01 20:53:47 +08:00
Jermy Li b4fb1f7443
refactor RestClient as interface (#49)
Change-Id: Ib7153dc7b8d3bf3df9d19662b54cb05ff14c032b
2020-06-19 20:07:27 +08:00
zhoney 034e1a2513
Add dateutil (#48)
Change-Id: I783d4ba2af19114dafd921c4468d4dbb640964c1
2020-06-15 14:01:07 +08:00
shzcore c2c5ba4689
add https support (#47) 2020-06-11 21:46:38 +08:00
Jermy Li 0d90ae4331
add encodeSignedB64() method (#46)
Change-Id: I771dfaeb923b6f13c14ec1a66df6142eaf2e42ae
2020-03-19 16:06:19 +08:00
Linary fffccf1b2f
Upgrade jackson version to 2.10.2 (#45) 2020-02-23 20:37:09 +08:00
Linary 0a71d120f9
Add nodes and data size to extra param (#44) 2020-02-04 17:45:01 +08:00
Jermy Li 4bd64ce8b5 fix iterators may not be closed (#43)
Change-Id: I3709d96fd2114fa782d6f28f8853b32d65fbd22b
2020-01-08 15:13:38 +08:00
Jermy Li 24b8a33e9c support assert range conditions (#41)
add methods to Assert class:
  assertGt()
  assertGte()
  assertLt()
  assertLte()
  assertContains()

Change-Id: If4c5df19c937a8bb06fcdd60122ac54ab04f501b
2020-01-01 01:17:03 +08:00
Jermy Li 8268b755ef add generic parameter for RowLock (#42)
Change-Id: I309b89846ca15d58ea39095d406a0b0b5de510e7
2019-12-31 15:06:33 +08:00
Jermy Li d78b728aa2 Split ConfigOption read into two steps: parse() and convert() (#40)
also fix ConfigConvOption/ConfigListConvOption read bug

fix: github.com/hugegraph/hugegraph/issues/774
Change-Id: I716c9f187128be9b0d173f152da05e5bdc2208a3
2019-12-31 14:17:25 +08:00
zhoney 49bff5eadc Support RowLock in LockGroup (#39)
Change-Id: Ic25b7d81b5dd5ddc9d85b057e5f00a00763460c7
2019-10-11 20:07:27 +08:00
zhoney 4eda6313eb Support keyLock in LockGroup (#38)
Change-Id: I43360da8b4c701bf02d635a7270af96a433ca5c7
2019-09-25 21:17:19 +08:00
Linary 0ff4b0e234
Extract license common structures (#36) 2019-09-06 10:14:23 +08:00
Jermy Li 41bc25ce85 support calling superclass method for Whitebox.invoke() (#37)
Change-Id: I36b460d1a95b4f063ccd329d2058e4e80ebb71c0
2019-09-05 14:41:19 +08:00
Jermy Li f8e65f83bd add Bytes.toHex() method (#35)
Change-Id: I613cf44728b347634bda726c3376a6fe1f4d4b2f
2019-08-15 17:20:24 +08:00
zhoney cc463411ea improve LongEncoding.decodeSortable() (#34)
Change-Id: I7962ffe9f55a2ef33752a414262e89d5a7918cc1
2019-07-22 11:17:53 +08:00
Jermy Li 0436a14591 add methods Bytes.contains() & Bytes.indexOf() (#33)
Change-Id: I2ddca3eb233a9f9f9610850ceff3a7fadd1bb784
2019-07-17 21:46:50 +08:00
Linary ce75fb96e0 Enhance split in StringUtil (#32) 2019-07-09 21:12:56 +08:00
Linary 88d8838209 Support show time in readable format (#31) 2019-07-01 17:39:53 +08:00
zhoney b525aef026 add maxValueOf() for NumericUtil (#30)
Change-Id: Ie34be6a9aa187691b004391f956891b8c55554fb
2019-06-26 17:56:27 +08:00
Linary 85a6b7e24d Enhance ExecutorUtil to create ScheduledThreadPool (#29) 2019-06-24 15:18:21 +08:00
Jermy Li 48a39fcef8 improve exception message for InvocationTargetException (#28)
Change-Id: Id2bb1d4b90d1f091f4949d7ba4cb6d7df9efb8b0
2019-06-24 15:07:56 +08:00
Jermy Li 2f453c0af9 support typed option (#27)
Change-Id: I845d3e0f59b3de4eb086a57f206a02fae0aae549
2019-06-17 15:13:07 +08:00
Linary 64bd1543e8 RestClient support to close idle connection periodically (#26) 2019-06-11 18:43:20 +08:00
Linary 1a66a60897 Enhance toList and add toSet in CollectionUtil (#25) 2019-05-29 20:07:59 +08:00
Jermy Li 0822dd93f6 let subclass of ConfigOption be able to override parent options (#24)
also implement ConfigOption.toString()

Change-Id: I1f1fd5eeaa80252fc093e7cba5af525a32a23c99
2019-05-28 16:40:43 +08:00
Jermy Li 5ea077f13e add support of sortable negative number for NumericUtil (#23)
Change-Id: I93290d3c1f9f89913d31ec2e5b4293d4a1d1ce1f
2019-05-21 12:06:42 +08:00
Jermy Li 194ed53b85 add Whitebox.invoke() method (#22)
Change-Id: If246e9193a4c61621c942f4b88a703c28c9d2846
2019-05-07 14:35:33 +08:00
liningrui 1eb2414134 Add OrderLimitMap
Change-Id: I66956a0098373a9e8999a335c1d158b6aa482bb6
2019-04-17 19:26:42 +08:00
liningrui 87c5826480 Let RestClient can reuse connections
Implement #14

Change-Id: I49c0675566145e233e40f25fe0c30c9614bf2c14
2019-04-17 19:25:35 +08:00
Zhangmei Li 306b4f1829 fix NPE in EventHub.destroy()
fix: #18
Change-Id: I30f12a583c8168045a2b240995c5277b0efbaa4c
2019-04-08 16:17:59 +08:00
Zhangmei Li 95530cc4b3 add PerfUtil.clear()/Bytes.concat()/CollectionUtil.randomSet()
also add some unit tests: HugeConfigTest, PerfUtilTest,
NumericUtilTest, ReflectionUtilTest and TimeUtilTest.

Change-Id: Ida64154a0bdee62e281585836c5e7ccfc6061c06
2019-03-01 20:02:21 +08:00
zhangyi51 5bac575b29 Set origin iterator last one if all iterators of extendable iterator are empty
implemented: #360

Change-Id: I5586ea3626816c085af788830917759f653ed0c4
2019-02-28 21:54:48 +08:00
Zhangmei Li 5f6012cbe4 Support for sortable base64 encoding
implement #11

Change-Id: I39b8f26d025e095d9d654f655657df6d6dc2543f
2018-12-25 19:56:32 +08:00
liningrui bbbc8e70f5 Add CollectionUtil.sortByValue()
Change-Id: I9152cc7d8fc5a23e3407118ed09c9b6ac116eed9
2018-12-25 16:09:44 +08:00
liningrui 6f20cb8bdc Fix dependency conflict "InjectionManagerFactory not found"
Fix #9

Change-Id: I83f2074c431994f72a62e37ab4a6086c3142a1b5
2018-12-24 15:19:33 +08:00
liningrui 476bb78315 Add CollectionUtilTest to UnitTestSuite
Change-Id: I36f632f0e0b8e6680d4fe16b30cf54e87ef01780
2018-12-17 17:17:26 +08:00
Zhangmei Li 146e4bc362 add api for setting thread pool name
Change-Id: I93aeddc6783e6b03d2aa31aa8ca42059e253ba81
2018-10-23 10:39:25 +08:00
zhangyi51 904f4260b9 README improve
Change-Id: I4550093fb02a0156bc353ef33eaad97f3e63fb12
2018-10-15 10:20:42 +08:00
liningrui 16fbcb354d Optimize intersect action
improve #2

Change-Id: I9c4daeaf812ffdae84a83b2bc94bb114461bda45
2018-10-11 22:33:40 +08:00
Zhangmei Li 591d3f3834 HugeGraph-1399: let EventHub.notify() return Future to sync
Change-Id: If7412da120c9652946a9aff41b0df5571fac3145
2018-10-10 09:46:11 +08:00
zhangyi51 07793f9971 HugeGraph-622: Bump up to version 1.5.0
Change-Id: Id1a905adf907370a5e8c30ba0ae7a8327c519daf
2018-08-09 09:56:11 +08:00
zhangyi51 1c7c839d45 hugegraph-1364 add LICENSE for hugegraph-common
Change-Id: I1e494152aeef3c4ff2bd9a09aeb3ab64303eec29
2018-08-09 09:56:11 +08:00
liningrui a4121451ce HugeGraph-1349: Add some badges(licence, build, coverage and maven) in README
Change-Id: I4d8498adbcf4289ecc897ffe629080cd524d5004
2018-08-09 09:56:11 +08:00
zhangyi51 553cd60b8f hugegraph-889 add ACCEPTED to POST, PUT and DELETE for async
Change-Id: If0acdc33acb4ac1e50295d920e0b77b35d11b12f
2018-08-09 09:56:10 +08:00
liningrui 1db56cfd86 HugeGraph-1341: Upgrade version to 1.4.8(1.4.7 failed deploying to maven respority)
Change-Id: I7fedf79f96607a3e07cceba4bfa263ce56f36f71
2018-08-09 09:56:10 +08:00
Zhangmei Li 9db431015a HugeGraph-1336: move common tests from hugegraph-test to hugegraph-common
Change-Id: Id6698c6fa83a0a9338e6dba02180bd8ce0e73c4d
2018-08-09 09:56:10 +08:00
zhangyi51 eed956d931 hugegraph-81 add github link to README
Change-Id: I16f47975372a5cb88b3890407a6e9d5fd79e19f9
2018-08-09 09:56:10 +08:00
liningrui 50c7738056 HugeGraph-1312: Add config to deploy to sonatype maven respority
Change-Id: I981ecc2486b8091b6c1b039d79da9c05ee3aaa14
2018-08-09 09:56:10 +08:00
Zhangmei Li 92ad62a9fb HugeGraph-1330: add support for 128bits hash
Change-Id: I51b46d3a88e472757e4ca45e73e7d6011150ef2f
2018-08-09 09:56:09 +08:00
liningrui 4aae65cd4d HugeGraph-81: Small optimization of package structure
Change-Id: I84109719a0064ea0d53c26843fbe435b84655912
2018-08-09 09:56:09 +08:00
Zhangmei Li 8c76d5b0cf HugeGraph-1309: add remove() support to WrappedIterator
Change-Id: Iec68a94fed485852af8d1c838630a108794aac99
2018-08-09 09:56:09 +08:00
liningrui daa967d74d HugeGraph-1301: Move SafeDateFormat class to hugegraph-common module
Change-Id: I8bc07f5b01b400d48393a1dc744c1de2853e392f
2018-08-09 09:56:09 +08:00
liningrui 544b94c919 HugeGraph-1257: Let jersey client use preemptive credentials
Change-Id: Ica97e912e905c0c7ee1353e603651794408564d1
2018-08-09 09:56:09 +08:00
zhangyi51 140cf845b5 hugegraph-1234 add subset util
Change-Id: I1f7a0f5b989191459ae3409d1aeaeaefe2c10c92
2018-08-09 09:56:09 +08:00
Zhangmei Li 9346717bde HugeGraph-1236: add getMap() to HugeConfig
Change-Id: I46d3ea398246e771936a3f4c75adbcdd31d7ad98
2018-08-09 09:56:08 +08:00
liningrui d6d92e4896 HugeGraph-1229: add README.md for project hugegraph-common
Change-Id: Ic881b001c08e47e1fa6ead49ca064ecefd215691
2018-08-09 09:56:08 +08:00
liningrui aa222c4893 HugeGraph-1229: add README.md for project hugegraph-common
Change-Id: Ic1d328b03a1d7eb91d76af615d4146d3f175ef79
2018-08-09 09:56:08 +08:00
liningrui c2db8f55d6 HugeGraph-81: Fixed bug that message and cause placed error
Change-Id: Ic408f158cd814edcd5edffc21bc09ba347da9a8f
2018-08-09 09:56:08 +08:00
Liu Jie 887a4d5a9a HugeGraph-1196: Fix grammer at exits method
Change-Id: Iad9cc2b819684140a0a4509dd6c3331b4dcf86b8
2018-08-09 09:56:08 +08:00
liningrui 5183fb054a HugeGraph-1208: Move compareNumber() from core to common module
Change-Id: I426651f98c7645ccdfc20f04310769eacb6d442a
2018-08-09 09:56:08 +08:00
Liu Jie 1bf8d9e4c0 HugeGraph-1191: rewrite exception handling mechanism at register method
Change-Id: I041f1792f2a4806e73d2ebb93a2b019d9ad73b0b
2018-08-09 09:56:08 +08:00
Zhangmei Li 56a60dca53 HugeGraph-1190: add OptionSpace.keys() method
Change-Id: If43dbfce1926fea95ca99c63b0d5c5531bcd639c
2018-08-09 09:56:07 +08:00
liningrui 12c65918b3 HugeGraph-1183: Add common RestClient for server and client
Change-Id: Iec3c1d11bb57b913f5837af42050bb5b8b8c3705
2018-08-09 09:56:07 +08:00
liningrui cb33bbd436 HugeGraph-1174: Let config reload if some options contains comma
Change-Id: I1e6dd2124aa9f9c3d1a52160b58cbad90cd0c941
2018-08-09 09:56:07 +08:00
liningrui 154e03054e HugeGraph-1171: Modify the way for config options registration
Change-Id: I99a7dec4ac72ee5afa5ed9945fd27a9f536b57cd
2018-08-09 09:56:07 +08:00
Zhangmei Li 8d8333980c HugeGraph-1158: awllow empty Iterator add to ExtendableIterator
Change-Id: Ieabd7a243105c6875fe9adbcebb466daa73ff427
2018-08-09 09:56:07 +08:00
Zhangmei Li fde9c72a0f HugeGraph-1110: let iterators implement AutoCloseable and Metadatable
Change-Id: I5c5f0fe6cafd0dfdc33404613a071927332c6211
2018-08-09 09:56:07 +08:00
Zhangmei Li 749a2d9d1f HugeGraph-1097: fix check error when HugeConfig(Configuration config) with list options
Change-Id: I7a3d0c6a017513368717bed4b32f4501bc2a9049
2018-08-09 09:56:06 +08:00
Zhangmei Li 2ae8e1571b HugeGraph-1097: fix missing check for duplicated options
Change-Id: I542998a0024d83706b0d8c485b4ec8ef40fd310f
2018-08-09 09:56:06 +08:00
Zhangmei Li 8219a10e74 HugeGraph-1075: add allowValues() to OptionChecker
Change-Id: I7752b039c3d8332550e4daf9852bdf7f7610d161
2018-08-09 09:56:06 +08:00
Zhangmei Li 9f994b33de HugeGraph-1000: allow non-check of config options
Change-Id: Ida0a2d88818f0ca53e9ddf886cff88e7ceb52ed8
2018-08-09 09:56:06 +08:00
Zhangmei Li fe8b51d072 HugeGraph-976: add filter-iterator
Change-Id: I8291be7576b0fd1536cc5425c09e26dfda5c4ff0
2018-08-09 09:56:06 +08:00
liningrui 24ff820174 HugeGraph-994: Fixed bug that some key has more than one value will throw an assert exception
Change-Id: I72301a594afe311a6d744514fb8791ec6d6fc954
2018-08-09 09:56:06 +08:00
liningrui 8a44989e32 HugeGraph-990: Fixed bug that compile error when building project
Change-Id: I398165b3b022e55290781b366e2d008f516dfb46
2018-08-09 09:56:06 +08:00
Zhangmei Li 7789bc87d8 HugeGraph-989: add toHex()/fromHex() to class Bytes
Change-Id: I3ef03ea58cdf2fe379e1dbf5b3e0877b4c379745
2018-08-09 09:56:05 +08:00
liningrui 65032356e9 HugeGraph-986: Let prefixOf support generic type
Change-Id: I7f02d3c3556ae6ae9f63888af7f33fe52e505862
2018-08-09 09:56:05 +08:00
liningrui 1804fa7ee1 HugeGraph-984: Fixed bug that multi graphs has same name config option will be overrided
Change-Id: Ia35570b52e00407de7e29e6e38aaf55a88f72c7a
2018-08-09 09:56:05 +08:00
Zhangmei Li 3d3da162de HugeGraph-978: add prefixWith() for bytes
Change-Id: I17a493ef0097f9208f4cfa3aad8bbd159283f4bb
2018-08-09 09:56:05 +08:00
Zhangmei Li b01f3a35df HugeGraph-975: support conversion: number <==> bytes
Change-Id: I8da23ab89f0e3eda99ec744904dd7ef06571a8e2
2018-08-09 09:56:05 +08:00
liningrui 094f8bb56b HugeGraph-935: Add a method 'allUnique'
Change-Id: Iebbcb8acb90844e82ae8e70b559a600543aaf6d8
2018-08-09 09:56:05 +08:00
zhangyi51 d8d4b3eba5 hugegraph-911 add prefixOf method into CollectionUtil
Change-Id: Ia917fc5ec5492547dee6b0477d9c3f947cddb71f
2018-08-09 09:56:04 +08:00
liningrui 5e003a7f2f HugeGraph-830: Catch IOException if create new socket connection failed. Note that, we should try to avoid catch Throwable since it not only catch all exceptions but also catch errors.
Change-Id: I72ae39058d737b1bbbeb70f4f05737fe95ed4ffc
2018-08-09 09:56:04 +08:00
Zhangmei Li 5195740642 HugeGraph-762: add isSimpleType() method to class ReflectionUtil
Change-Id: I7372c982dda9241d3d7d7b688d37d0403268e173
2018-08-09 09:56:04 +08:00
Zhangmei Li 12c53cc17b fix EventHub bugs: HugeGraph-732 and HugeGraph-733
Change-Id: I9395193680b986e543a0af3c08ce434b2b0e329c
2018-08-09 09:56:04 +08:00
Zhangmei Li 4d6c421358 HugeGraph-726: add toList(array) method into class CollectionUtil
Change-Id: Ia8a06f002e66f11935986284f587563ebc0c2257
2018-08-09 09:56:04 +08:00
liningrui 281aab85f2 HugeGraph-645: Add space line between license and package for hugegraph-common
Change-Id: I92a66e429382695b0f2a5742fb16299faace1616
2018-08-09 09:56:01 +08:00
liningrui ca0a9832a6 HugeGraph-596: Passed env varibale from BCLOUD to agile module for hugegraph-common module
Change-Id: Id3b89cccd310625826ca8fc2502133146221b138
2018-08-09 09:55:36 +08:00
liningrui b4a6cc9ab4 HugeGraph-596: fixed bug that hugegraph-common deploy before merge
Change-Id: Ia52ab72006bd8a2ba58254fbf4266f1555ebb8cd
2018-08-09 09:55:36 +08:00
liningrui c24069ee26 HugeGraph-625: fixed bug that there is a line length of more than 80 characters in the license information for hugegraph-common
Change-Id: Ic7cecaa7535f149060701fa16ff8e80f06cf363a
2018-08-09 09:55:33 +08:00
Zhangmei Li 504069e17f HugeGraph-623: rename LoggerFactory.getLogger() to Log.logger()
Change-Id: If9c03e3588334207870d710eba63f8bbf983e14e
2018-08-09 09:54:45 +08:00
Zhangmei Li 705c27b986 HugeGraph-555: add lockAll() for KeyLock
Change-Id: Iac0a396077658b82b67547e3eea5793d54fa01fd
2018-08-09 09:54:45 +08:00
Liu Jie f6cdc8a3ca HugeGraph-547: replace tilNextMillis by tillNextMills as the later is more meaningfull
Change-Id: I4505c1335bfc6eeb03658597f6f6ae5e994a2cf2
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:54:45 +08:00
Zhangmei Li 8bdac2c758 HugeGraph-525: add the const NAME of component hugegraph-common into CommonVersion
Change-Id: I5bcd766bb3435de98833759efcba5d3fa0650499
2018-08-09 09:54:45 +08:00
Zhangmei Li a200deab56 HugeGraph-131: clean up some warnings in LockGroup
Change-Id: I55a359b799119c04ea0e89d013f1c034453c2ba4
2018-08-09 09:54:45 +08:00
Zhangmei Li 5cda854e8d HugeGraph-525: add vertion check util
Change-Id: I57305dd209416620758b5bf183e791f8734af711
2018-08-09 09:54:45 +08:00
Liu Jie f33c09385d HugeGraph-532: Rewrite checksocket class
Change-Id: Iadae3837c2e9e0fddadbebbee097000c281e267c
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:54:44 +08:00
Liu Jie dec8fe9a84 HugeGraph-531: Fix typo at OptionHolder class
Change-Id: I19ea584802edd469d503b9fb57f630bf0c660487
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:54:44 +08:00
liningrui dfd3190392 HugeGraph-527: First add the version to the common module.
Change-Id: I2fd816ba13978d3d4cf2cb7a9724fe2d5f29a010
2018-08-09 09:54:44 +08:00
liningrui b76e0eaeab HugeGraph-527: add customized implemention version to manifest.mf
Change-Id: I569d82397408fb255d8ad9653e8b561ba1a60c1e
2018-08-09 09:54:44 +08:00
zhangyi51 6052985c15 hugegraph-502
add read write lock support

Change-Id: Ic339f5d81c9f475ee11ada38167fe42169c10971
2018-08-09 09:54:44 +08:00
liningrui e05d13098a HugeGraph-482: upgrade log4j to log4j2
Change-Id: If0bfaf91c45eac055e3f851b7f1dd5647d58d175
2018-08-09 09:54:44 +08:00
zhangyi51 9faea02296 hugegraph-499
trivial grammar change.

Change-Id: Ice29a709b9a5b5d7f2f7838d79541f63cf00a0c5
2018-08-09 09:54:43 +08:00
Zhangmei Li 5252a7e481 HugeGraph-410: improve code style
Change-Id: Idce80465ea4cbe92ac836bbc8d293e77ad7c7c5c
2018-08-09 09:54:41 +08:00
Zhangmei Li 0c580690cc HugeGraph-501: fix EventHub ConcurrentModificationException
Change-Id: Idedff1ca762cd56f171152174bdbfb0bef4b8d4f
2018-08-09 09:53:56 +08:00
Liu Jie 315000a600 HugeGraph-503: using bit shift whenever, if not affect the code readability.
Change-Id: Ib36dc135241f77c99d39d458ee144dbe888c541b
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:53:56 +08:00
Liu Jie d3960c1da4 Always define long variable endwith 'L' indicator.
Change-Id: I5f4d4d5c823ea4e14a135b59fb2384299686b4d5
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:53:56 +08:00
Liu Jie 9778a8b4b3 HugeGrap-499: fix english grammer in lock
Change-Id: I36c123eb7dfb101f99a176fcd9b2ee1f0f0211d7
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:53:55 +08:00
Liu Jie 171e723f50 HugeGraph-494: refine logic of lock() menthod
Change-Id: Ic5298b36ecf68f3a2b87b35bd793953e6505a9ae
Signed-off-by: Liu Jie <liujie23@baidu.com>
2018-08-09 09:53:55 +08:00
zhangyi51 9a1417f3dc HugeGraph-487
Add lockManager for mutual exclusion of thread in long time operation.

Change-Id: I155e2b6bb6fffe88e4985c85d8ff68f9c49d04be
2018-08-09 09:53:55 +08:00
Zhangmei Li 9cc9cad29a HugeGraph-476: add destroy() method
Change-Id: I745465ef6f3942f1e6774bacc1e59a1e5a0b200e
2018-08-09 09:53:55 +08:00
Zhangmei Li e88f54a21e HugeGraph-462: add event manager
Change-Id: I471a115fca5c84f8f25c7026fe834be305ab39b6
2018-08-09 09:53:55 +08:00
zhangyi51 ec2599db9a HugeGraph-369
Add lockManager for mutual exclusion of thread in long time operation.

Change-Id: I155e2b6bb6fffe88e4965c85d8ff68f9c49d04be
2018-08-09 09:53:55 +08:00
Zhangmei Li d592690cf7 HugeGraph-254: improve utils class perf with final(inline)
Change-Id: I625be2f4691a7821dbf3107d0f28ce079d46dfee
2018-08-09 09:53:51 +08:00
liningrui 36959044a1 HugeGraph-410: fixed code style of hugegraph-common
Change-Id: I8e123a315e483ed66658ce93c3eaffa61d94cfb3
2018-08-09 09:52:44 +08:00
Zhangmei Li 7bdf878dd4 HugeGraph-407: add KeyLock class
Change-Id: I655bdf4da20e0c6b6d7796958485ab066f0020f1
2018-08-09 09:52:44 +08:00
liningrui 5603b9c6a3 HugeGraph-326: add slf4j-api that has been mistakenly deleted
Change-Id: I7fd0d4ee3b6957878ed2850dd389dd78f42de71e
2018-08-09 09:52:44 +08:00
liningrui cccef5d575 HugeGraph-357: modify return type of TriFunction
Change-Id: I8cfd2dce48e2901af4773ea0c8d867edd6d21562
2018-08-09 09:52:44 +08:00
liningrui db55e237a5 HugeGraph-351: fixed bug that CoreOption constructor has been removed
Change-Id: I04cc0107aec90440ee2ae8c5c6add8a7c787f4f4
2018-08-09 09:52:44 +08:00
liningrui 3e5f626d11 HugeGraph-351: code format and clean up some warnings
Change-Id: I16d328738ead94efcad9d82bb8f27be2c4ca84a9
2018-08-09 09:52:43 +08:00
liningrui 5f305526d7 HugeGraph-344: add distributionManagement to deploy baidu maven repository
Change-Id: I198cd1e8a7d34a85d08b93261f33f07bb29335c9
2018-08-09 09:52:43 +08:00
liningrui a5fa9016ec HugeGraph-341: First commit hugegraph-common code
Change-Id: Icc8f9121d56679b266459125afc33180d8b568bf
2018-08-09 09:52:28 +08:00
951 changed files with 38544 additions and 4636 deletions

View File

@ -28,20 +28,21 @@ github:
del_branch_on_merge: true
#labels:
enabled_merge_buttons:
merge: true
merge: false
rebase: true
squash: true
protected_branches:
master:
required_status_checks:
# strict means "Require branches to be up-to-date before merging".
# strict means "Require PR to be up-to-date before merging". (enable when branch unstable)
strict: false
# contexts are the names of checks that must pass (now only enable the basic check)
contexts:
- Analyze (java)
- CodeQL
- check-license
- build (memory, 11)
- build-server (memory, 11)
- build-commons (11)
required_pull_request_reviews:
dismiss_stale_reviews: true
require_code_owner_reviews: false

View File

@ -21,6 +21,10 @@ root = true
charset = utf-8
end_of_line = lf
insert_final_newline = true
max_line_length = 100
ij_wrap_on_typing = true
ij_visual_guides = 100
[*.{java,xml,py}]
indent_style = space
@ -32,3 +36,64 @@ continuation_indent_size = 8
[*.md]
max_line_length = off
[*.java]
ij_java_doc_add_p_tag_on_empty_lines = true
ij_java_doc_do_not_wrap_if_one_line = true
ij_java_annotation_parameter_wrap = normal
ij_java_align_multiline_annotation_parameters = true
ij_java_class_count_to_use_import_on_demand = 100
ij_java_names_count_to_use_import_on_demand = 100
ij_java_imports_layout = $*, |, java.**, |, javax.**, |, org.**, |, com.**, |, *
ij_java_line_comment_at_first_column = false
ij_java_align_multiline_chained_methods = true
ij_java_align_multiline_parameters_in_calls = true
ij_java_align_multiline_binary_operation = true
ij_java_align_multiline_assignment = true
ij_java_align_multiline_ternary_operation = true
ij_java_align_multiline_throws_list = true
ij_java_align_multiline_extends_list = true
ij_java_align_multiline_array_initializer_expression = true
ij_java_call_parameters_wrap = normal
ij_java_method_parameters_wrap = normal
ij_java_resource_list_wrap = normal
ij_java_extends_list_wrap = normal
ij_java_throws_list_wrap = normal
ij_java_method_call_chain_wrap = normal
ij_java_binary_operation_wrap = normal
ij_java_ternary_operation_wrap = normal
ij_java_for_statement_wrap = normal
ij_java_array_initializer_wrap = normal
ij_java_assignment_wrap = normal
ij_java_assert_statement_wrap = normal
ij_java_if_brace_force = if_multiline
ij_java_do_while_brace_force = always
ij_java_while_brace_force = if_multiline
ij_java_for_brace_force = if_multiline
ij_java_wrap_long_lines = true
ij_java_parameter_annotation_wrap = normal
ij_java_enum_constants_wrap = split_into_lines
ij_java_keep_blank_lines_in_declarations = 1
ij_java_keep_blank_lines_in_code = 1
ij_java_keep_blank_lines_between_package_declaration_and_header = 1
ij_java_keep_blank_lines_before_right_brace = 1
ij_java_blank_lines_around_class = 1
ij_java_blank_lines_after_class_header = 1
ij_smart_tabs = true
[*.xml]
max_line_length = 120
ij_visual_guides = 120
ij_xml_text_wrap = off
ij_xml_space_inside_empty_tag = true
[.yaml]
ij_yaml_spaces_within_braces = false
ij_yaml_spaces_within_brackets = false
[.properties]
ij_properties_keep_blank_lines = true

8
.gitattributes vendored
View File

@ -5,8 +5,12 @@
apache-release.sh export-ignore
.licenserc.yaml export-ignore
.editorconfig export-ignore
hugegraph-store/hg-store-dist/src/assembly/static/bin/libjemalloc.so export-ignore
hugegraph-store/hg-store-dist/src/assembly/static/bin/libjemalloc_aarch64.so export-ignore
# ignored directory
.github/ export-ignore
hugegraph-dist/scripts/ export-ignore
#assembly/ export-ignore
.idea/ export-ignore
install-dist/scripts/ export-ignore
hugegraph-commons/hugegraph-dist/ export-ignore
docker/ export-ignore

View File

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
env:
USE_STAGE: 'true' # Whether to include the stage repository.
SCRIPT_DEPENDENCY: hugegraph-server/hugegraph-dist/scripts/dependency
SCRIPT_DEPENDENCY: install-dist/scripts/dependency
steps:
- name: Checkout source
uses: actions/checkout@v4
@ -32,7 +32,7 @@ jobs:
- name: mvn install
run: |
mvn install -DskipTests=true -ntp
mvn install -Dmaven.test.skip=true -ntp
- name: generate current dependencies
run: |
bash $SCRIPT_DEPENDENCY/regenerate_known_dependencies.sh current-dependencies.txt
@ -49,7 +49,8 @@ jobs:
uses: actions/dependency-review-action@v3
# Refer: https://github.com/actions/dependency-review-action
with:
fail-on-severity: low
# TODO: reset critical to low before releasing
fail-on-severity: critical
# Action will fail if dependencies don't match the list
#allow-licenses: Apache-2.0, MIT
#deny-licenses: GPL-3.0, AGPL-1.0, AGPL-3.0, LGPL-2.0, CC-BY-3.0

64
.github/workflows/commons-ci.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: "HugeGraph-Commons CI"
on:
workflow_dispatch:
push:
branches:
- master
- /^release-.*$/
- /^test-.*$/
pull_request:
jobs:
build-commons:
runs-on: ubuntu-latest
env:
# TODO: reset use stage to false later
USE_STAGE: 'true' # Whether to include the stage repository.
strategy:
fail-fast: false
matrix:
JAVA_VERSION: ['11']
steps:
- name: Install JDK ${{ matrix.JAVA_VERSION }}
uses: actions/setup-java@v3
with:
java-version: ${{ matrix.JAVA_VERSION }}
distribution: 'zulu'
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 2
- name: Use staged maven repo settings
if: ${{ env.USE_STAGE == 'true' }}
run: |
cp $HOME/.m2/settings.xml /tmp/settings.xml
cp -vf .github/configs/settings.xml $HOME/.m2/settings.xml && cat $HOME/.m2/settings.xml
- name: Compile
run: |
mvn compile -Dmaven.javadoc.skip=true -ntp
- name: Run common test
run: |
mvn test -pl hugegraph-commons/hugegraph-common -Dtest=UnitTestSuite
- name: Run rpc test
run: |
mvn test -pl hugegraph-commons/hugegraph-rpc -Dtest=UnitTestSuite
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0
with:
file: target/jacoco.xml

View File

@ -1,4 +1,4 @@
name: "License checker"
name: "License Checker"
on:
push:

View File

@ -1,4 +1,4 @@
name: "hugegraph-pd-store-ci"
name: "HugeGraph-PD & Store & Hstore CI"
on:
push:
@ -14,7 +14,8 @@ jobs:
runs-on: ubuntu-latest
env:
# TODO: avoid duplicated env setup in pd & store
USE_STAGE: 'false' # Whether to include the stage repository.
# TODO: reset use stage to false later
USE_STAGE: 'true' # Whether to include the stage repository.
# TODO: remove outdated env
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
@ -44,30 +45,31 @@ jobs:
cp $HOME/.m2/settings.xml /tmp/settings.xml
mv -vf .github/configs/settings.xml $HOME/.m2/settings.xml
- name: Run common test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-common-test -DskipCommonsTests=true
- name: Run core test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-core-test -DskipCommonsTests=true
# The above tests do not require starting a PD instance.
- name: Package
run: |
mvn clean package -U -Dmaven.javadoc.skip=true -Dmaven.test.skip=true -ntp
- name: Run common test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-common-test
- name: Run core test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-core-test
# The above tests do not require starting a PD instance.
- name: Prepare env and service
run: |
$TRAVIS_DIR/start-pd.sh
- name: Run client test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-client-test
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-client-test -DskipCommonsTests=true
- name: Run rest test
run: |
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-rest-test
mvn test -pl hugegraph-pd/hg-pd-test -am -P pd-rest-test -DskipCommonsTests=true
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0
@ -78,7 +80,7 @@ jobs:
# TODO: avoid duplicated env setup
runs-on: ubuntu-latest
env:
USE_STAGE: 'false' # Whether to include the stage repository.
USE_STAGE: 'true' # Whether to include the stage repository.
# TODO: remove outdated env
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
@ -117,29 +119,29 @@ jobs:
$TRAVIS_DIR/start-pd.sh
$TRAVIS_DIR/start-store.sh
- name: Run common test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-common-test -DskipCommonsTests=true
- name: Run client test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-client-test -Dmaven.test.failure.ignore=true
mvn test -pl hugegraph-store/hg-store-test -am -P store-client-test -DskipCommonsTests=true
- name: Run core test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-core-test -Dmaven.test.failure.ignore=true
- name: Run common test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-common-test -Dmaven.test.failure.ignore=true
mvn test -pl hugegraph-store/hg-store-test -am -P store-core-test -DskipCommonsTests=true
- name: Run rocksdb test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-rocksdb-test -Dmaven.test.failure.ignore=true
mvn test -pl hugegraph-store/hg-store-test -am -P store-rocksdb-test -DskipCommonsTests=true
- name: Run server test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-server-test -Dmaven.test.failure.ignore=true
mvn test -pl hugegraph-store/hg-store-test -am -P store-server-test -DskipCommonsTests=true
- name: Run raftcore test
- name: Run raft-core test
run: |
mvn test -pl hugegraph-store/hg-store-test -am -P store-raftcore-test -Dmaven.test.failure.ignore=true
mvn test -pl hugegraph-store/hg-store-test -am -P store-raftcore-test -DskipCommonsTests=true
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3.0.0

View File

@ -1,4 +1,4 @@
name: "hugegraph-server-ci"
name: "HugeGraph-Server CI"
on:
push:
@ -9,11 +9,12 @@ on:
pull_request:
jobs:
build:
build-server:
# TODO: we need test & replace it to ubuntu-24.04 or ubuntu-latest
runs-on: ubuntu-20.04
env:
USE_STAGE: 'false' # Whether to include the stage repository.
# TODO: reset use stage to false later
USE_STAGE: 'true' # Whether to include the stage repository.
TRAVIS_DIR: hugegraph-server/hugegraph-dist/src/assembly/travis
REPORT_DIR: target/site/jacoco
BACKEND: ${{ matrix.BACKEND }}

2
.gitignore vendored
View File

@ -57,7 +57,7 @@ build/
*.pyc
# maven ignore
apache-hugegraph-incubating-*/
apache-hugegraph-*/
output/
*.war
*.zip

View File

@ -91,19 +91,15 @@ header: # `header` section is configurations for source codes license header.
- '**/META-INF/MANIFEST.MF'
- '.repository/**'
- '**/.flattened-pom.xml'
# TODO: temporarily added to the ignore list, need handle them before releases ( ↓ )
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/backend/id/SnowflakeIdGenerator.java'
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/traversal/optimize/HugeScriptTraversal.java'
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/Nameable.java'
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/type/define/Cardinality.java'
- 'hugegraph-server/hugegraph-core/src/main/java/org/apache/hugegraph/util/StringEncoding.java'
- 'hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/ProcessBasicSuite.java'
- 'hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/tinkerpop/StructureBasicSuite.java'
- 'hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherOpProcessor.java'
- 'hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/opencypher/CypherPlugin.java'
- 'hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/ProcfsEntry.java'
- 'hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/ProcfsReader.java'
- 'hugegraph-store/hg-store-node/src/main/java/org/apache/hugegraph/store/node/metrics/ProcfsSmaps.java'
# TODO: temporarily added to the ignore list, need handle them before releases ( ↑ )
comment: on-failure # on what condition license-eye will comment on the pull request, `on-failure`, `always`, `never`.
# license-location-threshold specifies the index threshold where the license header can be located,

View File

@ -6,7 +6,7 @@ Required:
* Java 11
* Maven 3.5+
To build without executing tests: `mvn clean package -DskipTests`
To build without executing tests: `mvn clean package -Dmaven.test.skip=true`
## Building in IDEA

View File

@ -0,0 +1,66 @@
# hugegraph-commons
[![License](https://img.shields.io/badge/license-Apache%202-0E78BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![codecov](https://codecov.io/gh/hugegraph/hugegraph-common/branch/master/graph/badge.svg)](https://codecov.io/gh/hugegraph/hugegraph-common)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.hugegraph/hugegraph-common/badge.svg)](https://mvnrepository.com/artifact/org.apache.hugegraph/hugegraph-common)
[![CodeQL](https://github.com/apache/incubator-hugegraph-commons/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/apache/incubator-hugegraph-commons/actions/workflows/codeql-analysis.yml)
[![hugegraph-commons ci](https://github.com/apache/incubator-hugegraph-commons/actions/workflows/ci.yml/badge.svg)](https://github.com/apache/incubator-hugegraph-commons/actions/workflows/ci.yml)
hugegraph-commons is a common module for [HugeGraph](https://github.com/apache/hugegraph) and its peripheral components.
hugegraph-commons encapsulates locks, configurations, events, iterators, rest and some
numeric or collection util classes to simplify the development of HugeGraph and its components.
## Components
- Lock: atomic lock, key lock, lock group and lock manger
- Config: register and load config option with security check
- Event: listening and notification, do something asynchronously
- Iterator: some iterators with extra functions, map, filter, extend, etc.
- Rest: RESTful client implemented on OkHttp, POST, PUT, GET and DELETE
- Util: performance analyzer, version checker, numeric and Collection utils, log and exception utils, etc.
- Rpc: rpc component for inner module communication, currently it's based on [Sofa-RPC](https://github.com/sofastack/sofa-rpc)
You could use import the dependencies in `maven` like this:
```xml
<dependency>
<groupId>org.apache.hugegraph</groupId>
<artifactId>hugegraph-common</artifactId>
<version>1.2.0</version>
</dependency>
```
## Learn More
The [doc page](https://hugegraph.apache.org/docs/) contains more information about hugegraph modules.
And here are links of other repositories:
1. [hugegraph-server](https://github.com/apache/hugegraph) (graph's core component - OLTP server)
2. [hugegraph-toolchain](https://github.com/apache/hugegraph-toolchain) (include loader/dashboard/tool/client)
3. [hugegraph-computer](https://github.com/apache/hugegraph-computer) (graph processing system - OLAP)
4. [hugegraph-website/doc](https://github.com/apache/hugegraph-doc) (include doc & website code)
## Contributing
- Welcome to contribute to HugeGraph, please see [How to Contribute](https://hugegraph.apache.org/docs/contribution-guidelines/contribute/) for more information.
- Note: It's recommended to use [GitHub Desktop](https://desktop.github.com/) to greatly simplify the PR and commit process.
- Thank you to all the people who already contributed to HugeGraph!
[![contributors graph](https://contrib.rocks/image?repo=apache/hugegraph-commons)](https://github.com/apache/incubator-hugegraph-commons/graphs/contributors)
## Licence
Same as HugeGraph, hugegraph-commons are also licensed under [Apache 2.0](./LICENSE) License.
### Contact Us
---
- [GitHub Issues](https://github.com/apache/incubator-hugegraph-commons/issues): Feedback on usage issues and functional requirements (quick response)
- Feedback Email: [dev@hugegraph.apache.org](mailto:dev@hugegraph.apache.org) ([subscriber](https://hugegraph.apache.org/docs/contribution-guidelines/subscribe/) only)
- WeChat public account: Apache HugeGraph, welcome to scan this QR code to follow us.
<img src="https://raw.githubusercontent.com/apache/incubator-hugegraph-doc/master/assets/images/wechat.png" alt="QR png" width="350"/>

View File

@ -0,0 +1,23 @@
# hugegraph-common
[![License](https://img.shields.io/badge/license-Apache%202-0E78BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![Build Status](https://travis-ci.org/hugegraph/hugegraph-common.svg?branch=master)](https://travis-ci.org/hugegraph/hugegraph-common)
[![codecov](https://codecov.io/gh/hugegraph/hugegraph-common/branch/master/graph/badge.svg)](https://codecov.io/gh/hugegraph/hugegraph-common)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.hugegraph/hugegraph-common/badge.svg)](https://mvnrepository.com/artifact/org.apache.hugegraph/hugegraph-common)
hugegraph-common is a common module for [HugeGraph](https://github.com/hugegraph/hugegraph) and its peripheral components.
hugegraph-common encapsulates locks, configurations, events, iterators, rest and some
numeric or collection util classes to simplify the development of HugeGraph and
its components.
## Components
- Lock: atomic lock, key lock, lock group and lock manger
- Config: register and load config option with security check
- Event: listening and notification, do something asynchronously
- Iterator: some iterators with extra functions, map, filter, extend, etc.
- Rest: RESTful client implemented on Jersey, POST, PUT, GET and DELETE
- Util: Performance analyzer, version checker, numeric and Collection utils, log and exception utils, etc.
## Licence
The same as HugeGraph, hugegraph-common is also licensed under Apache 2.0 License.

View File

@ -1,3 +1,4 @@
#!/usr/bin/env bash
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
@ -6,7 +7,7 @@
# (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
# 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,
@ -15,5 +16,8 @@
# limitations under the License.
#
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true
export MAVEN_HOME=/home/scmtools/buildkit/maven/apache-maven-3.3.9/
export JAVA_HOME=/home/scmtools/buildkit/java/jdk1.8.0_25/
export PATH=$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH
mvn clean test -Dtest=UnitTestSuite

View File

@ -0,0 +1,302 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.hugegraph</groupId>
<artifactId>hugegraph-commons</artifactId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>hugegraph-common</artifactId>
<name>${project.artifactId}</name>
<url>https://github.com/apache/incubator-hugegraph-commons/tree/master/hugegraph-common</url>
<description>
hugegraph-common is a common module for HugeGraph and its peripheral components.
hugegraph-common encapsulates locks, configurations, events, iterators, rest and some
numeric or collection util classes to simplify the development of HugeGraph and its
components.
</description>
<properties>
<!-- Use parent params -->
<lombok.version>1.18.8</lombok.version>
<okhttp.version>4.10.0</okhttp.version>
</properties>
<dependencies>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito.version}</version>
<scope>test</scope>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j2.version}</version>
</dependency>
<!-- Utility -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>${javax.json.version}</version>
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>${commons.configuration.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-configuration2</artifactId>
<version>${commons.configuration2.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
<exclusion>
<artifactId>commons-lang3</artifactId>
<groupId>org.apache.commons</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons.lang3.version}</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>${commons.beanutils.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>${commons.collections.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
<exclusions>
<exclusion>
<artifactId>jsr305</artifactId>
<groupId>com.google.code.findbugs</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>${jsr305.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.8</version>
</dependency>
<!-- javassist -->
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>${javassist.version}</version>
</dependency>
<!-- jackson -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
<version>${jackson.version}</version>
<exclusions>
<exclusion>
<artifactId>jakarta.xml.bind-api</artifactId>
<groupId>jakarta.xml.bind</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-base</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${sun.xml.version}</version>
<scope>runtime</scope>
<exclusions>
<exclusion>
<artifactId>jakarta.xml.bind-api</artifactId>
<groupId>jakarta.xml.bind</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp-bom</artifactId>
<version>${okhttp.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<outputDirectory>${project.parent.build.directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>apache-release</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -0,0 +1,82 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.concurrent;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.hugegraph.util.Log;
import org.slf4j.Logger;
public class AtomicLock {
private static final Logger LOG = Log.logger(LockManager.class);
private String name;
private AtomicReference<Thread> sign;
public AtomicLock(String name) {
this.name = name;
this.sign = new AtomicReference<>();
}
public boolean tryLock() {
Thread current = Thread.currentThread();
return this.sign.compareAndSet(null, current);
}
public void unlock() {
if (this.sign.get() == null) {
return;
}
Thread current = Thread.currentThread();
if (!this.sign.compareAndSet(current, null)) {
throw new RuntimeException(String.format(
"Thread '%s' trying to unlock '%s' " +
"which is held by other threads now.",
current.getName(), this.name));
}
}
public boolean lock(int retries) {
// The interval between retries is exponential growth, most wait
// interval is 2^(retries-1)s. If retries=0, don't retry.
if (retries < 0 || retries > 10) {
throw new IllegalArgumentException(String.format(
"Locking retry times should be in [0, 10], but got %d",
retries));
}
boolean isLocked = false;
try {
for (int i = 0; !(isLocked = this.tryLock()) && i < retries; i++) {
Thread.sleep(1000 * (1L << i));
}
} catch (InterruptedException ignored) {
LOG.info("Thread sleep is interrupted.");
}
return isLocked;
}
public String name() {
return this.name;
}
public void name(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.concurrent;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.hugegraph.util.E;
public class BarrierEvent {
private final Lock lock = new ReentrantLock();
private final Condition cond = lock.newCondition();
private volatile boolean signaled = false;
/**
* Wait forever until the signal is received.
* @throws InterruptedException if interrupted.
*/
public void await() throws InterruptedException {
this.lock.lock();
try {
while (!this.signaled) {
this.cond.await();
}
} finally {
this.lock.unlock();
}
}
/**
* Wait specified time in milliseconds.
* @param timeout: the time in millisecond to wait.
* @return true if signal is received, false if time out.
* @throws InterruptedException if interrupted.
*/
public boolean await(long timeout) throws InterruptedException {
E.checkArgument(timeout >= 0L,
"The time must be >= 0, but got '%d'.",
timeout);
long deadline = System.currentTimeMillis() + timeout;
this.lock.lock();
try {
while (!this.signaled) {
timeout = deadline - System.currentTimeMillis();
if (timeout > 0) {
this.cond.await(timeout, TimeUnit.MILLISECONDS);
}
if (System.currentTimeMillis() >= deadline) {
return this.signaled;
}
}
} finally {
this.lock.unlock();
}
return true;
}
public void reset() {
this.lock.lock();
try {
this.signaled = false;
} finally {
this.lock.unlock();
}
}
public void signal() {
this.lock.lock();
try {
this.signaled = true;
this.cond.signal();
} finally {
this.lock.unlock();
}
}
public void signalAll() {
this.lock.lock();
try {
this.signaled = true;
this.cond.signalAll();
} finally {
this.lock.unlock();
}
}
}

View File

@ -0,0 +1,144 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.concurrent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.Lock;
import org.apache.hugegraph.util.E;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Striped;
/**
* KeyLock provide an interface of segment lock
*/
public class KeyLock {
private Striped<Lock> locks;
public KeyLock() {
// The default size is availableProcessors() * 4
this(Runtime.getRuntime().availableProcessors() << 2);
}
public KeyLock(int size) {
this.locks = Striped.lock(size);
}
private int indexOf(Lock lock) {
for (int i = 0; i < this.locks.size(); i++) {
if (this.locks.getAt(i) == lock) {
return i;
}
}
return -1;
}
/**
* Lock an object
* @param key The object to lock
* @return The lock(locked) of passed key
*/
public final Lock lock(Object key) {
E.checkArgument(key != null, "Lock key can't be null");
Lock lock = this.locks.get(key);
lock.lock();
return lock;
}
/**
* Unlock an object
* @param key The object to unlock
*/
public final void unlock(Object key) {
E.checkArgument(key != null, "Unlock key can't be null");
this.locks.get(key).unlock();
}
/**
* Lock a list of object with sorted order
* @param keys The objects to lock
* @return The locks(locked) of keys
*/
public final List<Lock> lockAll(Object... keys) {
E.checkArgument(keys != null && keys.length > 0,
"Lock keys can't be null or empty");
List<Lock> locks = new ArrayList<>(keys.length);
for (Object key : keys) {
E.checkArgument(key != null, "Lock key can't be null");
Lock lock = this.locks.get(key);
locks.add(lock);
}
locks.sort((a, b) -> {
int diff = a.hashCode() - b.hashCode();
if (diff == 0 && a != b) {
diff = this.indexOf(a) - this.indexOf(b);
assert diff != 0;
}
return diff;
});
for (Lock lock : locks) {
lock.lock();
}
return Collections.unmodifiableList(locks);
}
/**
* Lock two objects with sorted order
* NOTE: This is to optimize the performance of lockAll(keys)
* @param key1 The first object
* @param key2 The second object
* @return locks for the two objects
*/
public List<Lock> lockAll(Object key1, Object key2) {
E.checkArgument(key1 != null, "Lock key can't be null");
E.checkArgument(key2 != null, "Lock key can't be null");
Lock lock1 = this.locks.get(key1);
Lock lock2 = this.locks.get(key2);
int diff = lock1.hashCode() - lock2.hashCode();
if (diff == 0 && lock1 != lock2) {
diff = this.indexOf(lock1) - this.indexOf(lock2);
assert diff != 0;
}
List<Lock> locks = diff > 0 ?
ImmutableList.of(lock2, lock1) :
ImmutableList.of(lock1, lock2);
for (Lock lock : locks) {
lock.lock();
}
return locks;
}
/**
* Unlock a list of object
* @param locks The locks to unlock
*/
public final void unlockAll(List<Lock> locks) {
E.checkArgument(locks != null, "Unlock locks can't be null");
for (int i = locks.size(); i > 0; i--) {
assert this.indexOf(locks.get(i - 1)) != -1;
locks.get(i - 1).unlock();
}
}
}

View File

@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.concurrent;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LockGroup {
private final String name;
private final Map<String, Object> locksMap;
public LockGroup(String lockGroup) {
this.name = lockGroup;
this.locksMap = new ConcurrentHashMap<>();
}
public Lock lock(String lockName) {
if (!this.locksMap.containsKey(lockName)) {
this.locksMap.putIfAbsent(lockName, new ReentrantLock());
}
return (Lock) this.locksMap.get(lockName);
}
public AtomicLock atomicLock(String lockName) {
if (!this.locksMap.containsKey(lockName)) {
this.locksMap.putIfAbsent(lockName, new AtomicLock(lockName));
}
return (AtomicLock) this.locksMap.get(lockName);
}
public ReadWriteLock readWriteLock(String lockName) {
if (!this.locksMap.containsKey(lockName)) {
this.locksMap.putIfAbsent(lockName, new ReentrantReadWriteLock());
}
return (ReadWriteLock) this.locksMap.get(lockName);
}
public KeyLock keyLock(String lockName) {
if (!this.locksMap.containsKey(lockName)) {
this.locksMap.putIfAbsent(lockName, new KeyLock());
}
return (KeyLock) this.locksMap.get(lockName);
}
public KeyLock keyLock(String lockName, int size) {
if (!this.locksMap.containsKey(lockName)) {
this.locksMap.putIfAbsent(lockName, new KeyLock(size));
}
return (KeyLock) this.locksMap.get(lockName);
}
public <K extends Comparable<K>> RowLock<K> rowLock(String lockName) {
if (!this.locksMap.containsKey(lockName)) {
this.locksMap.putIfAbsent(lockName, new RowLock<>());
}
Object value = this.locksMap.get(lockName);
@SuppressWarnings("unchecked")
RowLock<K> lock = (RowLock<K>) value;
return lock;
}
public String name() {
return this.name;
}
}

View File

@ -0,0 +1,71 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.concurrent;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class LockManager {
private static final LockManager INSTANCE = new LockManager();
public static LockManager instance() {
return INSTANCE;
}
private Map<String, LockGroup> lockGroupMap;
private LockManager() {
this.lockGroupMap = new ConcurrentHashMap<>();
}
public boolean exists(String group) {
return this.lockGroupMap.containsKey(group);
}
public LockGroup create(String group) {
if (exists(group)) {
throw new RuntimeException(String.format(
"LockGroup '%s' already exists", group));
}
LockGroup lockGroup = new LockGroup(group);
LockGroup previous = this.lockGroupMap.putIfAbsent(group, lockGroup);
if (previous != null) {
return previous;
}
return lockGroup;
}
public LockGroup get(String group) {
LockGroup lockGroup = this.lockGroupMap.get(group);
if (lockGroup == null) {
throw new RuntimeException(String.format(
"LockGroup '%s' does not exists", group));
}
return lockGroup;
}
public void destroy(String group) {
if (this.exists(group)) {
this.lockGroupMap.remove(group);
} else {
throw new RuntimeException(String.format(
"LockGroup '%s' does not exists", group));
}
}
}

View File

@ -0,0 +1,78 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.concurrent;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import org.apache.hugegraph.util.Log;
import org.slf4j.Logger;
public class PausableScheduledThreadPool extends ScheduledThreadPoolExecutor {
private static final Logger LOG = Log.logger(PausableScheduledThreadPool.class);
private volatile boolean paused = false;
public PausableScheduledThreadPool(int corePoolSize,
ThreadFactory factory) {
super(corePoolSize, factory);
}
public synchronized void pauseSchedule() {
this.paused = true;
LOG.info("PausableScheduledThreadPool was paused");
}
public synchronized void resumeSchedule() {
this.paused = false;
this.notifyAll();
LOG.info("PausableScheduledThreadPool was resumed");
}
@Override
protected void beforeExecute(Thread t, Runnable r) {
synchronized (this) {
while (this.paused) {
try {
this.wait();
} catch (InterruptedException e) {
LOG.warn("PausableScheduledThreadPool was interrupted");
}
}
}
super.beforeExecute(t, r);
}
@Override
public void shutdown() {
if (this.paused) {
this.resumeSchedule();
}
super.shutdown();
}
@Override
public List<Runnable> shutdownNow() {
if (this.paused) {
this.resumeSchedule();
}
return super.shutdownNow();
}
}

View File

@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.concurrent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.hugegraph.util.E;
public class RowLock<K extends Comparable<K>> {
private final Map<K, Lock> locks = new ConcurrentHashMap<>();
private final ThreadLocal<Map<K, LocalLock>> localLocks =
ThreadLocal.withInitial(HashMap::new);
public void lock(K key) {
E.checkArgument(key != null, "Lock key can't be null");
LocalLock localLock = this.localLocks.get().get(key);
if (localLock != null) {
localLock.lockCount++;
} else {
Lock current = new ReentrantLock();
Lock previous = this.locks.putIfAbsent(key, current);
if (previous != null) {
current = previous;
}
current.lock();
this.localLocks.get().put(key, new LocalLock(current));
}
}
public void unlock(K key) {
E.checkArgument(key != null, "Unlock key can't be null");
LocalLock localLock = this.localLocks.get().get(key);
if (localLock == null) {
return;
}
if (--localLock.lockCount == 0) {
this.locks.remove(key, localLock.current);
this.localLocks.get().remove(key);
localLock.current.unlock();
}
E.checkState(localLock.lockCount >= 0,
"The lock count must be >= 0, but got %s",
localLock.lockCount);
}
public void lockAll(Set<K> keys) {
E.checkArgument(keys != null && keys.size() > 0,
"Lock keys can't be null or empty");
List<K> list = new ArrayList<>(keys);
Collections.sort(list);
for (K key : list) {
this.lock(key);
}
}
public void unlockAll(Set<K> keys) {
E.checkArgument(keys != null && keys.size() > 0,
"Unlock keys can't be null or empty");
for (K key : keys) {
this.unlock(key);
}
}
private static class LocalLock {
private final Lock current;
private int lockCount;
private LocalLock(Lock current) {
this.current = current;
this.lockCount = 1;
}
}
}

View File

@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
import java.util.function.Function;
import org.apache.hugegraph.util.E;
import com.google.common.base.Predicate;
public class ConfigConvOption<T, R> extends TypedOption<T, R> {
private final Function<T, R> converter;
public ConfigConvOption(String name, String desc, Predicate<T> pred,
Function<T, R> convert, T value) {
this(name, false, desc, pred, convert, value);
}
@SuppressWarnings("unchecked")
public ConfigConvOption(String name, boolean required, String desc,
Predicate<T> pred, Function<T, R> convert,
T value) {
super(name, required, desc, pred, (Class<T>) value.getClass(), value);
E.checkNotNull(convert, "convert");
this.converter = convert;
}
@Override
public R convert(T value) {
return this.converter.apply(value);
}
}

View File

@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
public class ConfigException extends RuntimeException {
private static final long serialVersionUID = -8711375282196157058L;
public ConfigException(String message) {
super(message);
}
public ConfigException(String message, Throwable cause) {
super(message, cause);
}
public ConfigException(String message, Object... args) {
super(String.format(message, args));
}
public ConfigException(String message, Throwable cause, Object... args) {
super(String.format(message, args), cause);
}
}

View File

@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import org.apache.hugegraph.util.E;
import com.google.common.base.Predicate;
public class ConfigListConvOption<T, R> extends TypedOption<List<T>, List<R>> {
private final Class<T> elemClass;
private final Function<T, R> converter;
@SuppressWarnings("unchecked")
public ConfigListConvOption(String name, String desc,
Predicate<List<T>> pred, Function<T, R> convert,
T... values) {
this(name, false, desc, pred, convert, null, Arrays.asList(values));
}
@SuppressWarnings("unchecked")
public ConfigListConvOption(String name, boolean required, String desc,
Predicate<List<T>> pred, Function<T, R> convert,
Class<T> clazz, List<T> values) {
super(name, required, desc, pred,
(Class<List<T>>) values.getClass(), values);
E.checkNotNull(convert, "convert");
if (clazz == null && values.size() > 0) {
clazz = (Class<T>) values.get(0).getClass();
}
E.checkArgumentNotNull(clazz, "Element class can't be null");
this.elemClass = clazz;
this.converter = convert;
}
@Override
protected boolean forList() {
return true;
}
@Override
protected List<T> parse(String value) {
return ConfigListOption.convert(value, part -> {
return this.parse(part, this.elemClass);
});
}
@Override
public List<R> convert(List<T> values) {
List<R> results = new ArrayList<>(values.size());
for (T value : values) {
results.add(this.converter.apply(value));
}
return results;
}
}

View File

@ -0,0 +1,79 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import org.apache.hugegraph.util.E;
import com.google.common.base.Predicate;
public class ConfigListOption<T> extends ConfigOption<List<T>> {
private final Class<T> elemClass;
@SuppressWarnings("unchecked")
public ConfigListOption(String name, String desc,
Predicate<List<T>> pred, T... values) {
this(name, false, desc, pred, null, Arrays.asList(values));
}
@SuppressWarnings("unchecked")
public ConfigListOption(String name, boolean required, String desc,
Predicate<List<T>> pred, Class<T> clazz,
List<T> values) {
super(name, required, desc, pred,
(Class<List<T>>) values.getClass(), values);
if (clazz == null && values.size() > 0) {
clazz = (Class<T>) values.get(0).getClass();
}
E.checkArgumentNotNull(clazz, "Element class can't be null");
this.elemClass = clazz;
}
@Override
protected boolean forList() {
return true;
}
@Override
protected List<T> parse(String value) {
return convert(value, part -> this.parse(part, this.elemClass));
}
@SuppressWarnings("unchecked")
public static <T> List<T> convert(Object value, Function<String, ?> conv) {
if (value instanceof List) {
return (List<T>) value;
}
// If target data type is List, parse it as a list
String str = (String) value;
if (str.startsWith("[") && str.endsWith("]")) {
str = str.substring(1, str.length() - 1);
}
String[] parts = str.split(",");
List<T> results = new ArrayList<>(parts.length);
for (String part : parts) {
results.add((T) conv.apply(part.trim()));
}
return results;
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
import com.google.common.base.Predicate;
public class ConfigOption<T> extends TypedOption<T, T> {
public ConfigOption(String name, String desc, T value) {
this(name, desc, null, value);
}
@SuppressWarnings("unchecked")
public ConfigOption(String name, String desc, Predicate<T> pred, T value) {
this(name, false, desc, pred, (Class<T>) value.getClass(), value);
}
public ConfigOption(String name, boolean required, String desc,
Predicate<T> pred, Class<T> type, T value) {
super(name, required, desc, pred, type, value);
}
}

View File

@ -0,0 +1,216 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.apache.commons.configuration2.Configuration;
import org.apache.commons.configuration2.FileBasedConfiguration;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.YAMLConfiguration;
import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder;
import org.apache.commons.configuration2.builder.fluent.Configurations;
import org.apache.commons.configuration2.builder.fluent.Parameters;
import org.apache.commons.configuration2.ex.ConfigurationException;
import org.apache.commons.configuration2.io.FileHandler;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import org.slf4j.Logger;
public class HugeConfig extends PropertiesConfiguration {
private static final Logger LOG = Log.logger(HugeConfig.class);
private String configPath;
public HugeConfig(Configuration config) {
loadConfig(config);
this.configPath = null;
}
public HugeConfig(String configFile) {
loadConfig(loadConfigFile(configFile));
this.configPath = configFile;
}
public HugeConfig(Map<String, Object> propertyMap) {
if (propertyMap == null) {
throw new ConfigException("The property map is null");
}
for (Map.Entry<String, Object> kv : propertyMap.entrySet()) {
this.addProperty(kv.getKey(), kv.getValue());
}
this.checkRequiredOptions();
}
private void loadConfig(Configuration config) {
if (config == null) {
throw new ConfigException("The config object is null");
}
this.setLayoutIfNeeded(config);
this.append(config);
this.checkRequiredOptions();
}
private void setLayoutIfNeeded(Configuration conf) {
if (!(conf instanceof PropertiesConfiguration)) {
return;
}
PropertiesConfiguration propConf = (PropertiesConfiguration) conf;
this.setLayout(propConf.getLayout());
}
@SuppressWarnings("unchecked")
public <T, R> R get(TypedOption<T, R> option) {
Object value = this.getProperty(option.name());
if (value == null) {
return option.defaultValue();
}
return (R) value;
}
public Map<String, String> getMap(ConfigListOption<String> option) {
List<String> values = this.get(option);
Map<String, String> result = new HashMap<>();
for (String value : values) {
String[] pair = value.split(":", 2);
E.checkState(pair.length == 2,
"Invalid option format for '%s': %s(expect KEY:VALUE)",
option.name(), value);
result.put(pair[0].trim(), pair[1].trim());
}
return result;
}
@Override
public void addPropertyDirect(String key, Object value) {
TypedOption<?, ?> option = OptionSpace.get(key);
if (option == null) {
LOG.warn("The config option '{}' is redundant, " +
"please ensure it has been registered", key);
} else {
// The input value is String(parsed by PropertiesConfiguration)
value = this.validateOption(key, value);
}
if (this.containsKey(key) && value instanceof List) {
for (Object item : (List<?>) value) {
super.addPropertyDirect(key, item);
}
} else {
super.addPropertyDirect(key, value);
}
}
@Override
protected void addPropertyInternal(String key, Object value) {
this.addPropertyDirect(key, value);
}
private Object validateOption(String key, Object value) {
TypedOption<?, ?> option = OptionSpace.get(key);
if (value instanceof String) {
return option.parseConvert((String) value);
}
Class<?> dataType = option.dataType();
if (dataType.isInstance(value)) {
return value;
}
throw new IllegalArgumentException(
String.format("Invalid value for key '%s': '%s'", key, value));
}
private void checkRequiredOptions() {
// TODO: Check required options must be contained in this map
}
public void save(File copiedFile) throws ConfigurationException {
FileHandler fileHandler = new FileHandler(this);
fileHandler.save(copiedFile);
}
@Nullable
public File file() {
if (StringUtils.isEmpty(this.configPath)) {
return null;
}
return new File(this.configPath);
}
public void file(String path) {
this.configPath = path;
}
private static Configuration loadConfigFile(String path) {
E.checkNotNull(path, "config path");
E.checkArgument(!path.isEmpty(),
"The config path can't be empty");
File file = new File(path);
return loadConfigFile(file);
}
private static Configuration loadConfigFile(File configFile) {
E.checkArgument(configFile.exists() &&
configFile.isFile() &&
configFile.canRead(),
"Please specify a proper config file rather than: '%s'",
configFile.toString());
try {
String fileName = configFile.getName();
String fileExtension = FilenameUtils.getExtension(fileName);
Configuration config;
Configurations configs = new Configurations();
switch (fileExtension) {
case "yml":
case "yaml":
Parameters params = new Parameters();
FileBasedConfigurationBuilder<FileBasedConfiguration> builder =
new FileBasedConfigurationBuilder(YAMLConfiguration.class)
.configure(params.fileBased().setFile(configFile));
config = builder.getConfiguration();
break;
case "xml":
config = configs.xml(configFile);
break;
default:
config = configs.properties(configFile);
break;
}
return config;
} catch (ConfigurationException e) {
throw new ConfigException("Unable to load config: '%s'",
e, configFile);
}
}
}

View File

@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
public final class OptionChecker {
public static <O> Predicate<O> disallowEmpty() {
return o -> {
if (o == null) {
return false;
}
if (o instanceof String) {
return StringUtils.isNotBlank((String) o);
}
if (o.getClass().isArray() && (Array.getLength(o) == 0)) {
return false;
}
return !(o instanceof Iterable) || ((Iterable<?>) o).iterator().hasNext();
};
}
@SuppressWarnings("unchecked")
public static <O> Predicate<O> allowValues(O... values) {
return o -> o != null && Arrays.asList(values).contains(o);
}
@SuppressWarnings("unchecked")
public static <O> Predicate<List<O>> inValues(O... values) {
return o -> o != null && new HashSet<>(Arrays.asList(values)).containsAll(o);
}
public static <N extends Number> Predicate<N> positiveInt() {
return number -> number != null && number.longValue() > 0;
}
public static <N extends Number> Predicate<N> nonNegativeInt() {
return number -> number != null && number.longValue() >= 0;
}
public static <N extends Number> Predicate<N> rangeInt(N min, N max) {
return number -> {
if (number == null) {
return false;
}
long value = number.longValue();
return value >= min.longValue() && value <= max.longValue();
};
}
public static <N extends Number> Predicate<N> rangeDouble(N min, N max) {
return number -> {
if (number == null) {
return false;
}
double value = number.doubleValue();
return value >= min.doubleValue() && value <= max.doubleValue();
};
}
}

View File

@ -0,0 +1,59 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.hugegraph.util.Log;
import org.slf4j.Logger;
public class OptionHolder {
private static final Logger LOG = Log.logger(HugeConfig.class);
protected Map<String, TypedOption<?, ?>> options;
public OptionHolder() {
this.options = new HashMap<>();
}
protected void registerOptions() {
for (Field field : this.getClass().getFields()) {
if (!TypedOption.class.isAssignableFrom(field.getType())) {
// Skip if not option
continue;
}
try {
TypedOption<?, ?> option = (TypedOption<?, ?>) field.get(this);
// Fields of subclass first, don't overwrite by superclass
this.options.putIfAbsent(option.name(), option);
} catch (Exception e) {
LOG.error("Failed to register option: {}", field, e);
throw new ConfigException(
"Failed to register option: %s", field);
}
}
}
public Map<String, TypedOption<?, ?>> options() {
return Collections.unmodifiableMap(this.options);
}
}

View File

@ -0,0 +1,120 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import org.slf4j.Logger;
public final class OptionSpace {
private static final Logger LOG = Log.logger(OptionSpace.class);
private static final Map<String, Class<? extends OptionHolder>> HOLDERS;
private static final Map<String, TypedOption<?, ?>> OPTIONS;
private static final String INSTANCE_METHOD = "instance";
static {
HOLDERS = new ConcurrentHashMap<>();
OPTIONS = new ConcurrentHashMap<>();
}
public static void register(String module, String holder) {
ClassLoader classLoader = OptionSpace.class.getClassLoader();
Class<?> clazz;
try {
clazz = classLoader.loadClass(holder);
} catch (ClassNotFoundException e) {
throw new ConfigException(
"Failed to load class of option holder '%s'", e, holder);
}
// Check subclass
if (!OptionHolder.class.isAssignableFrom(clazz)) {
throw new ConfigException(
"Class '%s' is not a subclass of OptionHolder", holder);
}
OptionHolder instance = null;
Exception exception = null;
try {
Method method = clazz.getMethod(INSTANCE_METHOD);
if (!Modifier.isStatic(method.getModifiers())) {
throw new NoSuchMethodException(INSTANCE_METHOD);
}
instance = (OptionHolder) method.invoke(null);
if (instance == null) {
exception = new ConfigException(
"Returned null from %s() method",
INSTANCE_METHOD);
}
} catch (NoSuchMethodException e) {
LOG.warn("Class {} does not has static method {}.",
holder, INSTANCE_METHOD);
exception = e;
} catch (InvocationTargetException e) {
LOG.warn("Can't call static method {} from class {}.",
INSTANCE_METHOD, holder);
exception = e;
} catch (IllegalAccessException e) {
LOG.warn("Illegal access while calling method {} from class {}.",
INSTANCE_METHOD, holder);
exception = e;
}
if (exception != null) {
throw new ConfigException("Failed to instantiate option holder: %s",
exception, holder);
}
register(module, instance);
}
public static void register(String module, OptionHolder holder) {
// Check exists
if (HOLDERS.containsKey(module)) {
LOG.warn("Already registered option holder: {} ({})",
module, HOLDERS.get(module));
}
E.checkArgumentNotNull(holder, "OptionHolder can't be null");
HOLDERS.put(module, holder.getClass());
OPTIONS.putAll(holder.options());
LOG.debug("Registered options for OptionHolder: {}",
holder.getClass().getSimpleName());
}
public static Set<String> keys() {
return Collections.unmodifiableSet(OPTIONS.keySet());
}
public static boolean containKey(String key) {
return OPTIONS.containsKey(key);
}
public static TypedOption<?, ?> get(String key) {
return OPTIONS.get(key);
}
}

View File

@ -0,0 +1,194 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.config;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import org.apache.commons.configuration.PropertyConverter;
import org.slf4j.Logger;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
public class TypedOption<T, R> {
private static final Logger LOG = Log.logger(TypedOption.class);
private static final Set<Class<?>> ACCEPTED_DATA_TYPES;
private static final String ACCEPTED_DATA_TYPES_STRING;
static {
ACCEPTED_DATA_TYPES = ImmutableSet.of(
Boolean.class,
Short.class,
Integer.class,
Byte.class,
Long.class,
Float.class,
Double.class,
String.class,
String[].class,
Class.class,
List.class
);
ACCEPTED_DATA_TYPES_STRING = Joiner.on(", ").join(ACCEPTED_DATA_TYPES);
}
private final String name;
private final String desc;
private final boolean required;
private final Class<T> dataType;
private final T defaultValue;
private final Predicate<T> checkFunc;
@SuppressWarnings("unchecked")
public TypedOption(String name, boolean required, String desc,
Predicate<T> pred, Class<T> type, T value) {
E.checkNotNull(name, "name");
E.checkNotNull(type, "dataType");
this.name = name;
this.dataType = (Class<T>) this.checkAndAssignDataType(type);
this.defaultValue = value;
this.required = required;
this.desc = desc;
this.checkFunc = pred;
this.check(this.defaultValue);
}
private Class<?> checkAndAssignDataType(Class<T> dataType) {
for (Class<?> clazz : ACCEPTED_DATA_TYPES) {
if (clazz.isAssignableFrom(dataType)) {
return clazz;
}
}
String msg = String.format("Input data type '%s' doesn't belong " +
"to acceptable type set: [%s]",
dataType, ACCEPTED_DATA_TYPES_STRING);
throw new IllegalArgumentException(msg);
}
public String name() {
return this.name;
}
public Class<T> dataType() {
return this.dataType;
}
public String desc() {
return this.desc;
}
public boolean required() {
return this.required;
}
public R defaultValue() {
return this.convert(this.defaultValue);
}
public R parseConvert(String value) {
T parsed = this.parse(value);
this.check(parsed);
return this.convert(parsed);
}
@SuppressWarnings("unchecked")
protected T parse(String value) {
return (T) this.parse(value, this.dataType);
}
protected Object parse(String value, Class<?> dataType) {
if (dataType.equals(String.class)) {
return value;
} else if (dataType.equals(Class.class)) {
try {
if (value.startsWith("class")) {
value = value.substring("class".length()).trim();
}
return Class.forName(value);
} catch (ClassNotFoundException e) {
throw new ConfigException(
"Failed to parse Class from String '%s'", e, value);
}
} else if (List.class.isAssignableFrom(dataType)) {
E.checkState(this.forList(),
"List option can't be registered with class %s",
this.getClass().getSimpleName());
}
// Use PropertyConverter method `toXXX` convert value
String methodTo = "to" + dataType.getSimpleName();
try {
Method method = PropertyConverter.class.getMethod(
methodTo, Object.class);
return method.invoke(null, value);
} catch (ReflectiveOperationException e) {
LOG.error("Invalid type of value '{}' for option '{}'",
value, this.name, e);
throw new ConfigException(
"Invalid type of value '%s' for option '%s', " +
"expect '%s' type",
value, this.name, dataType.getSimpleName());
}
}
protected void check(Object value) {
E.checkNotNull(value, "value", this.name);
if (!this.dataType.isInstance(value)) {
throw new ConfigException(
"Invalid type of value '%s' for option '%s', " +
"expect type %s but got %s", value, this.name,
this.dataType.getSimpleName(),
value.getClass().getSimpleName());
}
if (this.checkFunc != null) {
@SuppressWarnings("unchecked")
T result = (T) value;
if (!this.checkFunc.apply(result)) {
throw new ConfigException("Invalid option value for '%s': %s",
this.name, value);
}
}
}
@SuppressWarnings("unchecked")
protected R convert(T value) {
return (R) value;
}
protected boolean forList() {
return false;
}
@Override
public String toString() {
return String.format("[%s]%s=%s", this.dataType.getSimpleName(),
this.name, this.defaultValue);
}
}

View File

@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.date;
import java.util.Date;
import java.util.TimeZone;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
/**
* The SafeDateFormat actually is a proxy for joda DateTimeFormatter
*/
public class SafeDateFormat {
private static final int ONE_HOUR_MS = 3600 * 1000;
private final String pattern;
private DateTimeFormatter formatter;
public SafeDateFormat(String pattern) {
this.pattern = pattern;
this.formatter = DateTimeFormat.forPattern(pattern);
}
public synchronized void setTimeZone(String zoneId) {
int hoursOffset = TimeZone.getTimeZone(zoneId).getRawOffset() /
ONE_HOUR_MS;
DateTimeZone zone = DateTimeZone.forOffsetHours(hoursOffset);
this.formatter = this.formatter.withZone(zone);
}
public TimeZone getTimeZone() {
return this.formatter.getZone().toTimeZone();
}
public Date parse(String source) {
return this.formatter.parseDateTime(source).toDate();
}
public String format(Date date) {
return this.formatter.print(date.getTime());
}
public Object toPattern() {
return this.pattern;
}
}

View File

@ -0,0 +1,71 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.event;
import java.util.Arrays;
import java.util.Collections;
import org.apache.hugegraph.util.E;
public class Event extends java.util.EventObject {
private static final long serialVersionUID = 1625973849208342813L;
private String name;
private Object[] args;
public Event(Object source, String event) {
this(source, event, Collections.emptyList().toArray());
}
public Event(Object source, String event, Object... args) {
super(source);
this.name = event;
this.args = args;
}
public String name() {
return this.name;
}
public Object[] args() {
return this.args;
}
public void checkArgs(Class<?>... classes) throws IllegalArgumentException {
E.checkArgument(this.args.length == classes.length,
"The args count of event '%s' should be %s(actual %s)",
this.name, classes.length, this.args.length);
int i = 0;
for (Class<?> c : classes) {
Object arg = this.args[i++];
if (arg == null) {
continue;
}
E.checkArgument(c.isAssignableFrom(arg.getClass()),
"The arg '%s'(%s) can't match %s",
arg, arg.getClass(), c);
}
}
@Override
public String toString() {
return String.format("Event{name='%s', args=%s}",
this.name, Arrays.asList(this.args));
}
}

View File

@ -0,0 +1,197 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.event;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.ExecutorUtil;
import org.apache.hugegraph.util.Log;
import org.slf4j.Logger;
import org.apache.hugegraph.iterator.ExtendableIterator;
import com.google.common.collect.ImmutableList;
public class EventHub {
private static final Logger LOG = Log.logger(EventHub.class);
public static final String EVENT_WORKER = "event-worker-%d";
public static final String ANY_EVENT = "*";
private static final List<EventListener> EMPTY = ImmutableList.of();
// Event executor
private static ExecutorService executor = null;
private String name;
private Map<String, List<EventListener>> listeners;
public EventHub() {
this("hub");
}
public EventHub(String name) {
this(name, 1, Runtime.getRuntime().availableProcessors() << 2);
}
public EventHub(String name, int threadSize) {
LOG.debug("Create new EventHub {},threadSize {}", name, threadSize);
this.name = name;
this.listeners = new ConcurrentHashMap<>();
EventHub.init(threadSize);
}
public EventHub(String name, int corePoolSize, int maximumPoolSize) {
LOG.debug("Create new EventHub {},corePoolSize {}, maximumPoolSize {}", name, corePoolSize, maximumPoolSize);
this.name = name;
this.listeners = new ConcurrentHashMap<>();
EventHub.init(corePoolSize, maximumPoolSize);
}
public static synchronized void init(int poolSize) {
if (executor != null) {
return;
}
LOG.debug("Init pool(size {}) for EventHub", poolSize);
executor = ExecutorUtil.newFixedThreadPool(poolSize, EVENT_WORKER);
}
public static synchronized void init(int corePoolSize, int maximumPoolSize) {
LOG.debug("Init corePoolSize {}, maximumPoolSize {} for EventHub", corePoolSize, maximumPoolSize);
if (executor != null) {
LOG.debug("EventHub executor already initialized");
return;
}
executor = ExecutorUtil.newDynamicThreadExecutor(EVENT_WORKER, corePoolSize, maximumPoolSize);
}
public static synchronized boolean destroy(long timeout)
throws InterruptedException {
E.checkState(executor != null, "EventHub has not been initialized");
LOG.debug("Destroy pool for EventHub");
executor.shutdown();
return executor.awaitTermination(timeout, TimeUnit.SECONDS);
}
private static ExecutorService executor() {
ExecutorService e = executor;
E.checkState(e != null, "The event executor has been destroyed");
return e;
}
public String name() {
return this.name;
}
public boolean containsListener(String event) {
List<EventListener> ls = this.listeners.get(event);
return ls != null && ls.size() > 0;
}
public List<EventListener> listeners(String event) {
List<EventListener> ls = this.listeners.get(event);
return ls == null ? EMPTY : Collections.unmodifiableList(ls);
}
public void listen(String event, EventListener listener) {
E.checkNotNull(event, "event");
E.checkNotNull(listener, "event listener");
if (!this.listeners.containsKey(event)) {
this.listeners.putIfAbsent(event, new CopyOnWriteArrayList<>());
}
List<EventListener> ls = this.listeners.get(event);
assert ls != null : this.listeners;
ls.add(listener);
}
public List<EventListener> unlisten(String event) {
List<EventListener> ls = this.listeners.remove(event);
return ls == null ? EMPTY : Collections.unmodifiableList(ls);
}
public int unlisten(String event, EventListener listener) {
List<EventListener> ls = this.listeners.get(event);
if (ls == null) {
return 0;
}
int count = 0;
while (ls.remove(listener)) {
count++;
}
return count;
}
public Future<Integer> notify(String event, @Nullable Object... args) {
@SuppressWarnings("resource")
ExtendableIterator<EventListener> all = new ExtendableIterator<>();
List<EventListener> ls = this.listeners.get(event);
if (ls != null && !ls.isEmpty()) {
all.extend(ls.iterator());
}
List<EventListener> lsAny = this.listeners.get(ANY_EVENT);
if (lsAny != null && !lsAny.isEmpty()) {
all.extend(lsAny.iterator());
}
if (!all.hasNext()) {
return CompletableFuture.completedFuture(0);
}
Event ev = new Event(this, event, args);
// The submit will catch params: `all`(Listeners) and `ev`(Event)
return executor().submit(() -> {
int count = 0;
// Notify all listeners, and ignore the results
while (all.hasNext()) {
try {
all.next().event(ev);
count++;
} catch (Throwable e) {
LOG.warn("Failed to handle event: {}", ev, e);
}
}
return count;
});
}
public Object call(String event, @Nullable Object... args) {
List<EventListener> ls = this.listeners.get(event);
if (ls == null) {
throw new RuntimeException("Not found listener for: " + event);
} else if (ls.size() != 1) {
throw new RuntimeException("Too many listeners for: " + event);
}
EventListener listener = ls.get(0);
return listener.event(new Event(this, event, args));
}
}

View File

@ -0,0 +1,27 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.event;
public interface EventListener extends java.util.EventListener {
/**
* The event callback
* @param event object
* @return event result
*/
Object event(Event event);
}

View File

@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.func;
public interface TriFunction<T1, T2, T3, R> {
R apply(T1 v1, T2 v2, T3 v3);
}

View File

@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.InsertionOrderUtil;
import com.google.common.collect.ImmutableList;
public class BatchMapperIterator<T, R> extends WrappedIterator<R> {
private final int batch;
private final Iterator<T> originIterator;
private final Function<List<T>, Iterator<R>> mapperCallback;
private Iterator<R> batchIterator;
public BatchMapperIterator(int batch, Iterator<T> origin,
Function<List<T>, Iterator<R>> mapper) {
E.checkArgument(batch > 0, "Expect batch > 0, but got %s", batch);
this.batch = batch;
this.originIterator = origin;
this.mapperCallback = mapper;
this.batchIterator = null;
}
@Override
protected Iterator<T> originIterator() {
return this.originIterator;
}
@Override
protected final boolean fetch() {
if (this.batchIterator != null && this.fetchFromBatch()) {
return true;
}
List<T> batch = this.nextBatch();
assert this.batchIterator == null;
while (!batch.isEmpty()) {
// Do fetch
this.batchIterator = this.mapperCallback.apply(batch);
if (this.batchIterator != null && this.fetchFromBatch()) {
return true;
}
// Try next batch
batch = this.nextBatch();
}
return false;
}
protected final List<T> nextBatch() {
if (!this.originIterator.hasNext()) {
return ImmutableList.of();
}
List<T> list = InsertionOrderUtil.newList();
for (int i = 0; i < this.batch && this.originIterator.hasNext(); i++) {
T next = this.originIterator.next();
list.add(next);
}
return list;
}
protected final boolean fetchFromBatch() {
E.checkNotNull(this.batchIterator, "mapper results");
while (this.batchIterator.hasNext()) {
R result = this.batchIterator.next();
if (result != null) {
assert this.current == none();
this.current = result;
return true;
}
}
this.resetBatchIterator();
return false;
}
protected final void resetBatchIterator() {
if (this.batchIterator == null) {
return;
}
close(this.batchIterator);
this.batchIterator = null;
}
}

View File

@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Iterator;
public interface CIter<R> extends Iterator<R>, AutoCloseable, Metadatable {
}

View File

@ -0,0 +1,98 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Deque;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedDeque;
import org.apache.hugegraph.util.E;
public class ExtendableIterator<T> extends WrappedIterator<T> {
private final Deque<Iterator<T>> itors;
private Iterator<T> currentIterator;
public ExtendableIterator() {
this.itors = new ConcurrentLinkedDeque<>();
this.currentIterator = null;
}
public ExtendableIterator(Iterator<T> iter) {
this();
this.extend(iter);
}
public ExtendableIterator(Iterator<T> itor1, Iterator<T> itor2) {
this();
this.extend(itor1);
this.extend(itor2);
}
public ExtendableIterator<T> extend(Iterator<T> iter) {
E.checkState(this.currentIterator == null,
"Can't extend iterator after iterating");
if (iter != null) {
this.itors.addLast(iter);
}
return this;
}
@Override
public void close() throws Exception {
for (Iterator<T> iter : this.itors) {
if (iter instanceof AutoCloseable) {
((AutoCloseable) iter).close();
}
}
}
@Override
protected Iterator<T> originIterator() {
return this.currentIterator;
}
@Override
protected boolean fetch() {
assert this.current == none();
if (this.itors.isEmpty()) {
return false;
}
if (this.currentIterator != null && this.currentIterator.hasNext()) {
this.current = this.currentIterator.next();
return true;
}
Iterator<T> first;
while ((first = this.itors.peekFirst()) != null && !first.hasNext()) {
if (first == this.itors.peekLast() && this.itors.size() == 1) {
this.currentIterator = first;
// The last one
return false;
}
close(this.itors.removeFirst());
}
assert first != null && first.hasNext();
this.currentIterator = first;
this.current = this.currentIterator.next();
return true;
}
}

View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Iterator;
import java.util.function.Function;
public class FilterIterator<T> extends WrappedIterator<T> {
private final Iterator<T> originIterator;
private final Function<T, Boolean> filterCallback;
public FilterIterator(Iterator<T> origin, Function<T, Boolean> filter) {
this.originIterator = origin;
this.filterCallback = filter;
}
@Override
protected Iterator<T> originIterator() {
return this.originIterator;
}
@Override
protected final boolean fetch() {
while (this.originIterator.hasNext()) {
T next = this.originIterator.next();
// Do filter
if (next != null && this.filterCallback.apply(next)) {
assert this.current == none();
this.current = next;
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,50 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Iterator;
import java.util.function.Function;
import org.apache.hugegraph.util.E;
public class FlatMapperFilterIterator<T, R> extends FlatMapperIterator<T, R> {
private final Function<R, Boolean> filterCallback;
public FlatMapperFilterIterator(Iterator<T> origin,
Function<T, Iterator<R>> mapper,
Function<R, Boolean> filter) {
super(origin, mapper);
this.filterCallback = filter;
}
@Override
protected final boolean fetchFromBatch() {
E.checkNotNull(this.batchIterator, "mapper results");
while (this.batchIterator.hasNext()) {
R result = this.batchIterator.next();
if (result != null && this.filterCallback.apply(result)) {
assert this.current == none();
this.current = result;
return true;
}
}
this.resetBatchIterator();
return false;
}
}

View File

@ -0,0 +1,89 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Iterator;
import java.util.function.Function;
import org.apache.hugegraph.util.E;
public class FlatMapperIterator<T, R> extends WrappedIterator<R> {
private final Iterator<T> originIterator;
private final Function<T, Iterator<R>> mapperCallback;
protected Iterator<R> batchIterator;
public FlatMapperIterator(Iterator<T> origin,
Function<T, Iterator<R>> mapper) {
this.originIterator = origin;
this.mapperCallback = mapper;
this.batchIterator = null;
}
@Override
public void close() throws Exception {
this.resetBatchIterator();
super.close();
}
@Override
protected Iterator<T> originIterator() {
return this.originIterator;
}
@Override
protected final boolean fetch() {
if (this.batchIterator != null && this.fetchFromBatch()) {
return true;
}
while (this.originIterator.hasNext()) {
T next = this.originIterator.next();
assert this.batchIterator == null;
// Do fetch
this.batchIterator = this.mapperCallback.apply(next);
if (this.batchIterator != null && this.fetchFromBatch()) {
return true;
}
}
return false;
}
protected boolean fetchFromBatch() {
E.checkNotNull(this.batchIterator, "mapper results");
while (this.batchIterator.hasNext()) {
R result = this.batchIterator.next();
if (result != null) {
assert this.current == none();
this.current = result;
return true;
}
}
this.resetBatchIterator();
return false;
}
protected final void resetBatchIterator() {
if (this.batchIterator == null) {
return;
}
close(this.batchIterator);
this.batchIterator = null;
}
}

View File

@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Iterator;
import java.util.function.Function;
public class LimitIterator<T> extends WrappedIterator<T> {
private final Iterator<T> originIterator;
private final Function<T, Boolean> filterCallback;
public LimitIterator(Iterator<T> origin, Function<T, Boolean> filter) {
this.originIterator = origin;
this.filterCallback = filter;
}
@Override
protected Iterator<T> originIterator() {
return this.originIterator;
}
@Override
protected final boolean fetch() {
while (this.originIterator.hasNext()) {
T next = this.originIterator.next();
if (next == null) {
continue;
}
// Do filter
boolean reachLimit = this.filterCallback.apply(next);
if (reachLimit) {
this.closeOriginIterator();
return false;
}
assert this.current == none();
this.current = next;
return true;
}
return false;
}
protected final void closeOriginIterator() {
if (this.originIterator == null) {
return;
}
close(this.originIterator);
}
}

View File

@ -0,0 +1,78 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.hugegraph.util.InsertionOrderUtil;
public class ListIterator<T> extends WrappedIterator<T> {
private final Iterator<T> originIterator;
private final Iterator<T> resultsIterator;
private final Collection<T> results;
public ListIterator(long capacity, Iterator<T> origin) {
List<T> results = InsertionOrderUtil.newList();
while (origin.hasNext()) {
if (capacity >= 0L && results.size() >= capacity) {
throw new IllegalArgumentException(
"The iterator exceeded capacity " + capacity);
}
results.add(origin.next());
}
this.originIterator = origin;
this.results = Collections.unmodifiableList(results);
this.resultsIterator = this.results.iterator();
}
public ListIterator(Collection<T> origin) {
this.originIterator = origin.iterator();
this.results = origin instanceof List ?
Collections.unmodifiableList((List<T>) origin) :
Collections.unmodifiableCollection(origin);
this.resultsIterator = this.results.iterator();
}
@Override
public void remove() {
this.resultsIterator.remove();
}
public Collection<T> list() {
return this.results;
}
@Override
protected boolean fetch() {
assert this.current == none();
if (!this.resultsIterator.hasNext()) {
return false;
}
this.current = this.resultsIterator.next();
return true;
}
@Override
protected Iterator<T> originIterator() {
return this.originIterator;
}
}

View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Iterator;
import java.util.function.Function;
public class MapperIterator<T, R> extends WrappedIterator<R> {
private final Iterator<T> originIterator;
private final Function<T, R> mapperCallback;
public MapperIterator(Iterator<T> origin, Function<T, R> mapper) {
this.originIterator = origin;
this.mapperCallback = mapper;
}
@Override
protected Iterator<T> originIterator() {
return this.originIterator;
}
@Override
protected final boolean fetch() {
while (this.originIterator.hasNext()) {
T next = this.originIterator.next();
R result = this.mapperCallback.apply(next);
if (result != null) {
assert this.current == none();
this.current = result;
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
public interface Metadatable {
Object metadata(String meta, Object... args);
}

View File

@ -0,0 +1,99 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.iterator;
import java.util.Iterator;
import java.util.NoSuchElementException;
public abstract class WrappedIterator<R> implements CIter<R> {
private static final Object NONE = new Object();
protected R current;
public WrappedIterator() {
this.current = none();
}
@Override
public boolean hasNext() {
if (this.current != none()) {
return true;
}
return this.fetch();
}
@Override
public R next() {
if (this.current == none()) {
this.fetch();
if (this.current == none()) {
throw new NoSuchElementException();
}
}
R current = this.current;
this.current = none();
return current;
}
@Override
public void remove() {
Iterator<?> iterator = this.originIterator();
if (iterator == null) {
throw new NoSuchElementException(
"The origin iterator can't be null for removing");
}
iterator.remove();
}
@Override
public void close() throws Exception {
Iterator<?> iterator = this.originIterator();
if (iterator instanceof AutoCloseable) {
((AutoCloseable) iterator).close();
}
}
@Override
public Object metadata(String meta, Object... args) {
Iterator<?> iterator = this.originIterator();
if (iterator instanceof Metadatable) {
return ((Metadatable) iterator).metadata(meta, args);
}
throw new IllegalStateException("Original iterator is not Metadatable");
}
@SuppressWarnings("unchecked")
protected static final <R> R none() {
return (R) NONE;
}
public static void close(Iterator<?> iterator) {
if (iterator instanceof AutoCloseable) {
try {
((AutoCloseable) iterator).close();
} catch (Exception e) {
throw new IllegalStateException("Failed to close iterator");
}
}
}
protected abstract Iterator<?> originIterator();
protected abstract boolean fetch();
}

View File

@ -0,0 +1,106 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.license;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.time.DateUtils;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
public class LicenseCommonParam {
@JsonProperty("subject")
private String subject;
@JsonProperty("issued_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date issuedTime = new Date();
@JsonProperty("not_before")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date notBefore = this.issuedTime;
@JsonProperty("not_after")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date notAfter = DateUtils.addDays(this.notBefore, 30);
@JsonProperty("consumer_type")
private String consumerType = "user";
@JsonProperty("consumer_amount")
private Integer consumerAmount = 1;
@JsonProperty("description")
private String description = "";
@JsonProperty("extra_params")
private List<LicenseExtraParam> extraParams;
public LicenseCommonParam() {
// pass
}
public LicenseCommonParam(String subject, String description,
Date issued, Date notBefore, Date notAfter,
String consumerType, int consumerAmount,
List<LicenseExtraParam> extraParams) {
this.subject = subject;
this.description = description;
this.issuedTime = issued;
this.notBefore = notBefore;
this.notAfter = notAfter;
this.consumerType = consumerType;
this.consumerAmount = consumerAmount;
this.extraParams = extraParams;
}
public String subject() {
return this.subject;
}
public Date issuedTime() {
return this.issuedTime;
}
public Date notBefore() {
return this.notBefore;
}
public Date notAfter() {
return this.notAfter;
}
public String consumerType() {
return this.consumerType;
}
public Integer consumerAmount() {
return this.consumerAmount;
}
public String description() {
return this.description;
}
public List<LicenseExtraParam> extraParams() {
return this.extraParams;
}
}

View File

@ -0,0 +1,61 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.license;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
public class LicenseCreateParam extends LicenseCommonParam {
@JsonProperty("private_alias")
private String privateAlias;
@JsonAlias("key_ticket")
@JsonProperty("key_password")
private String keyPassword;
@JsonAlias("store_ticket")
@JsonProperty("store_password")
private String storePassword;
@JsonProperty("privatekey_path")
private String privateKeyPath;
@JsonProperty("license_path")
private String licensePath;
public String privateAlias() {
return this.privateAlias;
}
public String keyPassword() {
return this.keyPassword;
}
public String storePassword() {
return this.storePassword;
}
public String privateKeyPath() {
return this.privateKeyPath;
}
public String licensePath() {
return this.licensePath;
}
}

View File

@ -0,0 +1,119 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.license;
import com.fasterxml.jackson.annotation.JsonProperty;
public class LicenseExtraParam {
public static final int NO_LIMIT = -1;
@JsonProperty("id")
private String id;
@JsonProperty("version")
private String version;
@JsonProperty("graphs")
private int graphs;
@JsonProperty("ip")
private String ip;
@JsonProperty("mac")
private String mac;
@JsonProperty("cpus")
private int cpus;
// The unit is MB
@JsonProperty("ram")
private int ram;
@JsonProperty("threads")
private int threads;
// The unit is MB
@JsonProperty("memory")
private int memory;
@JsonProperty("nodes")
private int nodes;
// The unit is MB
@JsonProperty("data_size")
private long dataSize;
@JsonProperty("vertices")
private long vertices;
@JsonProperty("edges")
private long edges;
public String id() {
return this.id;
}
public String version() {
return this.version;
}
public int graphs() {
return this.graphs;
}
public String ip() {
return this.ip;
}
public String mac() {
return this.mac;
}
public int cpus() {
return this.cpus;
}
public int ram() {
return this.ram;
}
public int threads() {
return this.threads;
}
public int memory() {
return this.memory;
}
public int nodes() {
return this.nodes;
}
public long dataSize() {
return this.dataSize;
}
public long vertices() {
return this.vertices;
}
public long edges() {
return this.edges;
}
}

View File

@ -0,0 +1,60 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.license;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
public class LicenseInstallParam {
@JsonProperty("subject")
private String subject;
@JsonProperty("public_alias")
private String publicAlias;
@JsonAlias("store_ticket")
@JsonProperty("store_password")
private String storePassword;
@JsonProperty("publickey_path")
private String publicKeyPath;
@JsonProperty("license_path")
private String licensePath;
public String subject() {
return this.subject;
}
public String publicAlias() {
return this.publicAlias;
}
public String storePassword() {
return this.storePassword;
}
public String licensePath() {
return this.licensePath;
}
public String publicKeyPath() {
return this.publicKeyPath;
}
}

View File

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.license;
public interface LicenseManager {
LicenseParams installLicense() throws Exception;
void uninstallLicense() throws Exception;
LicenseParams verifyLicense() throws Exception;
interface VerifyCallback {
void onVerifyLicense(LicenseParams params) throws Exception;
}
}

View File

@ -0,0 +1,30 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.license;
import org.apache.commons.lang.NotImplementedException;
import org.apache.hugegraph.license.LicenseManager.VerifyCallback;
public class LicenseManagerFactory {
public static LicenseManager create(LicenseInstallParam param,
VerifyCallback veryfyCallback) {
throw new NotImplementedException("No LicenseManager available");
}
}

View File

@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.license;
import java.util.Date;
import java.util.List;
public class LicenseParams extends LicenseCommonParam {
public LicenseParams() {
super();
}
public LicenseParams(String subject, String description,
Date issued, Date notBefore, Date notAfter,
String consumerType, int consumerAmount,
List<LicenseExtraParam> extraParams) {
super(subject, description, issued, notBefore, notAfter,
consumerType, consumerAmount, extraParams);
}
public LicenseExtraParam matchParam(String id) {
for (LicenseExtraParam param : this.extraParams()) {
if (param.id().equals(id)) {
return param;
}
}
return null;
}
}

View File

@ -0,0 +1,126 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.license;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class MachineInfo {
private List<String> ipAddressList;
private List<String> macAddressList;
public MachineInfo() {
this.ipAddressList = null;
this.macAddressList = null;
}
public List<String> getIpAddress() {
if (this.ipAddressList != null) {
return this.ipAddressList;
}
this.ipAddressList = new ArrayList<>();
List<InetAddress> inetAddresses = this.getLocalAllInetAddress();
if (inetAddresses != null && !inetAddresses.isEmpty()) {
this.ipAddressList = inetAddresses.stream()
.map(InetAddress::getHostAddress)
.distinct()
.map(String::toLowerCase)
.collect(Collectors.toList());
}
return this.ipAddressList;
}
public List<String> getMacAddress() {
if (this.macAddressList != null) {
return this.macAddressList;
}
this.macAddressList = new ArrayList<>();
List<InetAddress> inetAddresses = this.getLocalAllInetAddress();
if (inetAddresses != null && !inetAddresses.isEmpty()) {
// Get the Mac address of all network interfaces
List<String> list = new ArrayList<>();
Set<String> uniqueValues = new HashSet<>();
for (InetAddress inetAddress : inetAddresses) {
String macByInetAddress = this.getMacByInetAddress(inetAddress);
if (uniqueValues.add(macByInetAddress)) {
list.add(macByInetAddress);
}
}
this.macAddressList = list;
}
return this.macAddressList;
}
public List<InetAddress> getLocalAllInetAddress() {
Enumeration<NetworkInterface> interfaces;
try {
interfaces = NetworkInterface.getNetworkInterfaces();
} catch (SocketException e) {
throw new RuntimeException("Failed to get network interfaces");
}
List<InetAddress> result = new ArrayList<>();
while (interfaces.hasMoreElements()) {
NetworkInterface nw = interfaces.nextElement();
for (Enumeration<InetAddress> inetAddresses = nw.getInetAddresses();
inetAddresses.hasMoreElements(); ) {
InetAddress inetAddr = inetAddresses.nextElement();
if (!inetAddr.isLoopbackAddress() &&
!inetAddr.isLinkLocalAddress() &&
!inetAddr.isMulticastAddress()) {
result.add(inetAddr);
}
}
}
return result;
}
public String getMacByInetAddress(InetAddress inetAddr) {
byte[] mac;
try {
mac = NetworkInterface.getByInetAddress(inetAddr)
.getHardwareAddress();
} catch (Exception e) {
throw new RuntimeException(String.format(
"Failed to get mac address for inet address '%s'",
inetAddr));
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
if (i != 0) {
sb.append("-");
}
String temp = Integer.toHexString(mac[i] & 0xff);
if (temp.length() == 1) {
sb.append("0").append(temp);
} else {
sb.append(temp);
}
}
return sb.toString().toUpperCase();
}
}

View File

@ -0,0 +1,185 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.perf;
import java.util.List;
import org.apache.hugegraph.perf.PerfUtil.FastMap;
public final class LightStopwatch implements Stopwatch {
private long lastStartTime = -1L;
private long times = 0L;
private long totalCost = 0L;
private long totalChildrenTimes = -1L;
private final String name;
private final Path parent;
private final Path id;
private final FastMap<String, Stopwatch> children;
public LightStopwatch(String name, Stopwatch parent) {
this(name, parent.id());
parent.child(name, this);
}
public LightStopwatch(String name, Path parent) {
this.name = name;
this.parent = parent;
this.id = Stopwatch.id(parent, name);
this.children = new FastMap<>();
}
@Override
public Path id() {
return this.id;
}
@Override
public String name() {
return this.name;
}
@Override
public Path parent() {
return this.parent;
}
@Override
public void lastStartTime(long startTime) {
this.lastStartTime = startTime;
}
@Override
public void startTime(long startTime) {
this.times++;
this.lastStartTime = startTime;
}
@Override
public void endTime(long startTime) {
this.totalCost += PerfUtil.now() - this.lastStartTime;
}
@Override
public long times() {
return this.times;
}
@Override
public long totalTimes() {
if (this.totalChildrenTimes > 0L) {
return this.times + this.totalChildrenTimes;
}
return this.times;
}
@Override
public long totalChildrenTimes() {
return this.totalChildrenTimes;
}
@Override
public long totalCost() {
return this.totalCost;
}
@Override
public void totalCost(long totalCost) {
this.totalCost = totalCost;
}
@Override
public long minCost() {
return -1L;
}
@Override
public long maxCost() {
return -1L;
}
@Override
public long totalWasted() {
return 0L;
}
@Override
public long totalSelfWasted() {
return 0L;
}
@Override
public long totalChildrenWasted() {
return -1L;
}
@Override
public void fillChildrenTotal(List<Stopwatch> children) {
// Fill total times of children
this.totalChildrenTimes = children.stream().mapToLong(Stopwatch::totalTimes).sum();
}
@Override
public LightStopwatch copy() {
try {
return (LightStopwatch) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
@Override
public Stopwatch child(String name) {
return this.children.get(name);
}
@Override
public Stopwatch child(String name, Stopwatch watch) {
if (watch == null) {
return this.children.remove(name);
}
return this.children.put(name, watch);
}
@Override
public boolean empty() {
return this.children.size() == 0;
}
@Override
public void clear() {
this.lastStartTime = -1L;
this.times = 0L;
this.totalCost = 0L;
this.totalChildrenTimes = -1L;
this.children.clear();
}
@Override
public String toString() {
return String.format("{parent:%s,name:%s," +
"times:%s,totalChildrenTimes:%s,totalCost:%s}",
this.parent, this.name,
this.times, this.totalChildrenTimes,
this.totalCost);
}
}

View File

@ -0,0 +1,302 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.perf;
import java.util.List;
import java.util.function.BiFunction;
import org.apache.hugegraph.util.Log;
import org.slf4j.Logger;
import org.apache.hugegraph.testutil.Whitebox;
public final class NormalStopwatch implements Stopwatch {
private static final Logger LOG = Log.logger(Stopwatch.class);
private static final String MULTI_THREAD_ACCESS_ERROR =
"There may be multi-threaded access, ensure " +
"not call PerfUtil.profileSingleThread(true) when " +
"multithreading.";
private long lastStartTime = -1L;
private long times = 0L;
private long totalCost = 0L;
private long minCost = Long.MAX_VALUE;
private long maxCost = 0L;
private long totalSelfWasted = 0L;
private long totalChildrenWasted = -1L;
private long totalChildrenTimes = -1L;
private final String name;
private final Path parent;
private final Path id;
private final PerfUtil.FastMap<String, Stopwatch> children;
public NormalStopwatch(String name, Stopwatch parent) {
this(name, parent.id());
parent.child(name, this);
}
public NormalStopwatch(String name, Path parent) {
this.name = name;
this.parent = parent;
this.id = Stopwatch.id(parent, name);
this.children = new PerfUtil.FastMap<>();
}
@Override
public Path id() {
return this.id;
}
@Override
public String name() {
return this.name;
}
@Override
public Path parent() {
return this.parent;
}
@Override
public void lastStartTime(long startTime) {
this.lastStartTime = startTime;
}
@Override
public void startTime(long startTime) {
assert this.lastStartTime == -1L : MULTI_THREAD_ACCESS_ERROR;
this.times++;
this.lastStartTime = startTime;
long endTime = PerfUtil.now();
long wastedTime = endTime - startTime;
if (wastedTime <= 0L) {
wastedTime += eachStartWastedLost;
}
this.totalSelfWasted += wastedTime;
}
@Override
public void endTime(long startTime) {
assert startTime >= this.lastStartTime && this.lastStartTime != -1L :
MULTI_THREAD_ACCESS_ERROR;
long endTime = PerfUtil.now();
// The following code cost about 3ns~4ns
long wastedTime = endTime - startTime;
if (wastedTime <= 0L) {
wastedTime += eachEndWastedLost;
}
long cost = endTime - this.lastStartTime;
if (this.minCost > cost) {
this.minCost = cost;
}
if (this.maxCost < cost) {
this.maxCost = cost;
}
this.totalCost += cost;
this.totalSelfWasted += wastedTime;
this.lastStartTime = -1L;
}
@Override
public long times() {
return this.times;
}
@Override
public long totalCost() {
return this.totalCost;
}
@Override
public void totalCost(long totalCost) {
this.totalCost = totalCost;
}
@Override
public long minCost() {
return this.minCost;
}
@Override
public long maxCost() {
return this.maxCost;
}
@Override
public long totalTimes() {
if (this.totalChildrenTimes > 0L) {
return this.times + this.totalChildrenTimes;
}
return this.times;
}
@Override
public long totalChildrenTimes() {
return this.totalChildrenTimes;
}
@Override
public long totalWasted() {
if (this.totalChildrenWasted > 0L) {
return this.totalSelfWasted + this.totalChildrenWasted;
}
return this.totalSelfWasted;
}
@Override
public long totalSelfWasted() {
return this.totalSelfWasted;
}
@Override
public long totalChildrenWasted() {
return this.totalChildrenWasted;
}
@Override
public void fillChildrenTotal(List<Stopwatch> children) {
// Fill total wasted cost of children
this.totalChildrenWasted = children.stream().mapToLong(Stopwatch::totalWasted).sum();
// Fill total times of children
this.totalChildrenTimes = children.stream().mapToLong(Stopwatch::totalTimes).sum();
}
@Override
public Stopwatch copy() {
try {
return (Stopwatch) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
@Override
public Stopwatch child(String name) {
return this.children.get(name);
}
@Override
public Stopwatch child(String name, Stopwatch watch) {
if (watch == null) {
return this.children.remove(name);
}
return this.children.put(name, watch);
}
@Override
public boolean empty() {
return this.children.size() == 0;
}
@Override
public void clear() {
this.lastStartTime = -1L;
this.times = 0L;
this.totalCost = 0L;
this.minCost = Long.MAX_VALUE;
this.maxCost = 0L;
this.totalSelfWasted = 0L;
this.totalChildrenWasted = -1L;
this.totalChildrenTimes = -1L;
this.children.clear();
}
@Override
public String toString() {
return String.format("{parent:%s,name:%s," +
"times:%s,totalChildrenTimes:%s," +
"totalCost:%s,minCost:%s,maxCost:%s," +
"totalSelfWasted:%s,totalChildrenWasted:%s}",
this.parent, this.name,
this.times, this.totalChildrenTimes,
this.totalCost, this.minCost, this.maxCost,
this.totalSelfWasted, this.totalChildrenWasted);
}
private static long eachStartWastedLost = 0L;
private static long eachEndWastedLost = 0L;
protected static void initEachWastedLost() {
int times = 100000000;
PerfUtil.LocalStack<Stopwatch> callStack = Whitebox.getInternalState(
PerfUtil.instance(), "callStack");
long baseStart = PerfUtil.now();
for (int i = 0; i < times; i++) {
PerfUtil.instance();
}
long baseCost = PerfUtil.now() - baseStart;
BiFunction<String, Runnable, Long> testEachCost = (name, test) -> {
long start = PerfUtil.now();
test.run();
long end = PerfUtil.now();
long cost = end - start - baseCost;
if (cost < 0L) {
cost = 0L;
}
long eachCost = cost / times;
LOG.info("Wasted time test: cost={}ms, base_cost={}ms, {}={}ns",
cost / 1000000.0, baseCost / 1000000.0, name, eachCost);
return eachCost;
};
String startName = "each_start_cost";
eachStartWastedLost = testEachCost.apply(startName, () -> {
Stopwatch watch = PerfUtil.instance().start(startName);
PerfUtil.instance().end(startName);
for (int i = 0; i < times; i++) {
// Test call start()
PerfUtil.instance().start(startName);
// Mock end()
watch.lastStartTime(-1L);
callStack.pop();
}
});
String endName = "each_end_cost";
eachEndWastedLost = testEachCost.apply(endName, () -> {
Stopwatch watch = PerfUtil.instance().start(endName);
PerfUtil.instance().end(endName);
for (int i = 0; i < times; i++) {
// Mock start()
callStack.push(watch);
watch.lastStartTime(0L);
// Test call start()
PerfUtil.instance().end(endName);
watch.totalCost(0L);
}
});
}
}

View File

@ -0,0 +1,687 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.perf;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.Log;
import org.apache.hugegraph.util.ReflectionUtil;
import org.apache.hugegraph.func.TriFunction;
import org.apache.hugegraph.testutil.Assert.ThrowableConsumer;
import org.apache.hugegraph.perf.Stopwatch.Path;
import com.google.common.reflect.ClassPath.ClassInfo;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
public final class PerfUtil {
private static final Logger LOG = Log.logger(PerfUtil.class);
private static final int DEFAULT_CAPACITY = 1024;
private static final ThreadLocal<PerfUtil> INSTANCE = new ThreadLocal<>();
private static PerfUtil SINGLE_INSTANCE = null;
private static Thread SINGLE_THREAD = null;
private static LocalTimer LOCAL_TIMER = null;
private static boolean LIGHT_WATCH = false;
private final Map<Path, Stopwatch> stopwatches;
private final LocalStack<Stopwatch> callStack;
private final Stopwatch root;
private PerfUtil() {
this.stopwatches = new HashMap<>(DEFAULT_CAPACITY);
this.callStack = new LocalStack<>(DEFAULT_CAPACITY);
this.root = newStopwatch(Path.ROOT_NAME, Path.EMPTY);
}
public static PerfUtil instance() {
if (SINGLE_INSTANCE != null &&
SINGLE_THREAD == Thread.currentThread()) {
// Return the only one instance for single thread, for performance
return SINGLE_INSTANCE;
}
PerfUtil p = INSTANCE.get();
if (p == null) {
p = new PerfUtil();
INSTANCE.set(p);
}
return p;
}
public static void profileSingleThread(boolean yes) {
SINGLE_INSTANCE = yes ? PerfUtil.instance() : null;
SINGLE_THREAD = yes ? Thread.currentThread() : null;
}
public static void useLocalTimer(boolean yes) {
if (yes) {
if (LOCAL_TIMER != null) {
return;
}
LOCAL_TIMER = new LocalTimer();
try {
LOCAL_TIMER.startTimeUpdateLoop();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (!LIGHT_WATCH) {
NormalStopwatch.initEachWastedLost();
}
} else {
if (LOCAL_TIMER == null) {
return;
}
try {
LOCAL_TIMER.stop();
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
LOCAL_TIMER = null;
}
}
}
public static void useLightStopwatch(boolean yes) {
if (yes != LIGHT_WATCH) {
PerfUtil instance = INSTANCE.get();
boolean empty = instance == null || instance.empty();
String message = "Please call clear() before switching " +
"light-stopwatch due to there is dirty watch";
E.checkArgument(empty, message);
}
LIGHT_WATCH = yes;
}
protected static long now() {
if (LOCAL_TIMER != null) {
return LOCAL_TIMER.now();
}
// System.nanoTime() cost about 40 ns each call
return System.nanoTime();
}
protected static Stopwatch newStopwatch(String name, Path parent) {
return LIGHT_WATCH ? new LightStopwatch(name, parent) :
new NormalStopwatch(name, parent);
}
protected static Stopwatch newStopwatch(String name, Stopwatch parent) {
return LIGHT_WATCH ? new LightStopwatch(name, parent) :
new NormalStopwatch(name, parent);
}
public Stopwatch start(String name) {
long start = now();
Stopwatch parent = this.callStack.empty() ?
this.root : this.callStack.peek();
// Get watch by name from local tree
Stopwatch watch = parent.child(name);
if (watch == null) {
watch = newStopwatch(name, parent);
assert !this.stopwatches.containsKey(watch.id()) : watch;
this.stopwatches.put(watch.id(), watch);
}
this.callStack.push(watch);
watch.startTime(start);
return watch;
}
public Stopwatch start2(String name) {
long start = now(); // cost 70 ns with System.nanoTime()
Path parent = this.callStack.empty() ?
Path.EMPTY : this.callStack.peek().id();
Path id = Stopwatch.id(parent, name); // cost 130
// Get watch by id from global map
Stopwatch watch = this.stopwatches.get(id); // cost 170
if (watch == null) {
watch = newStopwatch(name, parent);
this.stopwatches.put(watch.id(), watch); // cost 180
}
this.callStack.push(watch); // cost 190
watch.startTime(start);
return watch;
}
public void end(String name) {
long start = LIGHT_WATCH ? 0L : now();
Stopwatch watch = this.callStack.pop();
if (watch == null || watch.name() != name) {
throw new IllegalArgumentException("Invalid watch name: " + name);
}
watch.endTime(start);
}
public boolean empty() {
return this.stopwatches.isEmpty() && this.root.empty();
}
public void clear() {
String error = "Can't be cleared when the call has not ended yet";
E.checkState(this.callStack.empty(), error);
this.stopwatches.clear();
this.root.clear();
}
public void profilePackage(String... packages) throws Throwable {
Set<String> loadedClasses = new HashSet<>();
Function<String, Boolean> inPackage = (cls) -> {
for (String pkg : packages) {
if (cls.startsWith(pkg)) {
return true;
}
}
return false;
};
ThrowableConsumer<String> profileClassIfPresent = (cls) -> {
if (!loadedClasses.contains(cls)) {
// Profile super class
for (String s : ReflectionUtil.superClasses(cls)) {
if (!loadedClasses.contains(s) && inPackage.apply(s)) {
profileClass(s);
loadedClasses.add(s);
}
}
// Profile self class
profileClass(cls);
loadedClasses.add(cls);
}
};
Iterator<ClassInfo> classes = ReflectionUtil.classes(packages);
while (classes.hasNext()) {
String cls = classes.next().getName();
// Profile self class
profileClassIfPresent.accept(cls);
// Profile nested class
for (String s : ReflectionUtil.nestedClasses(cls)) {
profileClassIfPresent.accept(s);
}
}
}
public void profileClass(String... classes) throws Throwable {
ClassPool classPool = ClassPool.getDefault();
for (String cls : classes) {
CtClass ctClass = classPool.get(cls);
List<CtMethod> methods = ReflectionUtil.getMethodsAnnotatedWith(
ctClass, Watched.class, false);
for (CtMethod method : methods) {
profile(method);
}
// Load class and make it effective
if (!methods.isEmpty()) {
ctClass.toClass();
}
}
}
private void profile(CtMethod ctMethod)
throws CannotCompileException, ClassNotFoundException {
final String START =
"org.apache.hugegraph.perf.PerfUtil.instance().start(\"%s\");";
final String END =
"org.apache.hugegraph.perf.PerfUtil.instance().end(\"%s\");";
Watched annotation = (Watched) ctMethod.getAnnotation(Watched.class);
String name = annotation.value();
if (name.isEmpty()) {
name = ctMethod.getName();
}
if (!annotation.prefix().isEmpty()) {
name = annotation.prefix() + "." + name;
}
ctMethod.insertBefore(String.format(START, name));
// Insert as a finally-statement
ctMethod.insertAfter(String.format(END, name), true);
LOG.debug("Profiled for: '{}' [{}]", name, ctMethod.getLongName());
}
@Override
public String toString() {
return this.stopwatches.toString();
}
public String toJson() {
StringBuilder sb = new StringBuilder(8 + this.stopwatches.size() * 96);
sb.append('{');
for (Map.Entry<Path, Stopwatch> w : this.stopwatches.entrySet()) {
sb.append('"');
sb.append(w.getKey());
sb.append('"');
sb.append(':');
sb.append(w.getValue().toJson());
sb.append(',');
}
if (!this.stopwatches.isEmpty()) {
sb.deleteCharAt(sb.length() - 1);
}
sb.append('}');
return sb.toString();
}
// TODO: move toECharts() method out of this class
public String toECharts() {
TriFunction<Integer, Integer, List<Stopwatch>, String> formatLevel = (
totalDepth, depth, items) -> {
float factor = 100.0f / (totalDepth + 1);
float showFactor = 1 + (totalDepth - depth) / (float) depth;
float radiusFrom = depth * factor;
float radiusTo = depth * factor + factor;
if (depth == 1) {
radiusFrom = 0;
}
StringBuilder sb = new StringBuilder(8 + items.size() * 128);
sb.append('{');
sb.append("name: 'Total Cost',");
sb.append("type: 'pie',");
sb.append(String.format("radius: ['%s%%', '%s%%'],",
radiusFrom, radiusTo));
sb.append(String.format(
"label: {normal: {position: 'inner', formatter:" +
"function(params) {" +
" if (params.percent > %s) return params.data.name;" +
" else return '';" +
"}}},", showFactor));
sb.append("data: [");
items.sort((i, j) -> i.id().compareTo(j.id()));
for (Stopwatch w : items) {
sb.append('{');
sb.append("id:'");
sb.append(w.id());
sb.append("',");
sb.append("name:'");
sb.append(w.name());
sb.append("',");
sb.append("value:");
// w.totalCost() - w.totalWasted() ?
sb.append(w.totalCost());
sb.append(',');
sb.append("cost:");
sb.append(w.totalCost() / 1000000.0);
sb.append(',');
sb.append("minCost:");
sb.append(w.minCost());
sb.append(',');
sb.append("maxCost:");
sb.append(w.maxCost());
sb.append(',');
sb.append("wasted:");
sb.append(w.totalWasted() / 1000000.0);
sb.append(',');
sb.append("selfWasted:");
sb.append(w.totalSelfWasted() / 1000000.0);
sb.append(',');
sb.append("times:");
sb.append(w.times());
sb.append(',');
sb.append("totalTimes:");
sb.append(w.totalTimes());
sb.append('}');
sb.append(',');
}
if (!items.isEmpty()) {
sb.deleteCharAt(sb.length() - 1);
}
sb.append("]}");
return sb.toString();
};
BiConsumer<List<Stopwatch>, List<Stopwatch>> fillChildrenTotal =
(itemsOfLn, itemsOfLnParent) -> {
for (Stopwatch parent : itemsOfLnParent) {
List<Stopwatch> children = itemsOfLn.stream().filter(c -> {
return c.parent().equals(parent.id());
}).collect(Collectors.toList());
parent.fillChildrenTotal(children);
}
};
BiConsumer<List<Stopwatch>, List<Stopwatch>> fillOther =
(itemsOfLn, itemsOfLnParent) -> {
for (Stopwatch parent : itemsOfLnParent) {
Stream<Stopwatch> children = itemsOfLn.stream().filter(c -> {
return c.parent().equals(parent.id());
});
// Fill other cost
long sumCost = children.mapToLong(Stopwatch::totalCost).sum();
long otherCost = parent.totalCost() - sumCost;
if (otherCost > 0L) {
Stopwatch other = newStopwatch("~", parent.id());
other.totalCost(otherCost);
itemsOfLn.add(other);
}
}
};
Map<Path, Stopwatch> items = this.stopwatches;
Map<Integer, List<Stopwatch>> levelItems = new HashMap<>();
int maxDepth = 0;
for (Map.Entry<Path, Stopwatch> e : items.entrySet()) {
int depth = e.getKey().toString().split("/").length;
List<Stopwatch> levelItem = levelItems.get(depth);
if (levelItem == null) {
levelItem = new LinkedList<>();
levelItems.putIfAbsent(depth, levelItem);
}
levelItem.add(e.getValue().copy());
if (depth > maxDepth) {
maxDepth = depth;
}
}
// Fill wasted cost from the outermost to innermost
for (int i = maxDepth; i > 0; i--) {
assert levelItems.containsKey(i) : i;
List<Stopwatch> itemsOfI = levelItems.get(i);
List<Stopwatch> itemsOfParent = levelItems.get(i - 1);
if (itemsOfParent != null) {
// Fill total value of children
fillChildrenTotal.accept(itemsOfI, itemsOfParent);
}
}
StringBuilder sb = new StringBuilder(8 + items.size() * 128);
// Output results header
sb.append("{");
sb.append("tooltip: {trigger: 'item', " +
"formatter: function(params) {" +
" return params.data.name + ' ' + params.percent + '% <br/>'" +
" + 'cost: ' + params.data.cost + ' (ms) <br/>'" +
" + 'min cost: ' + params.data.minCost + ' (ns) <br/>'" +
" + 'max cost: ' + params.data.maxCost + ' (ns) <br/>'" +
" + 'wasted: ' + params.data.wasted + ' (ms) <br/>'" +
" + 'self wasted: ' + params.data.selfWasted + ' (ms) <br/>'" +
" + 'times: ' + params.data.times + '<br/>'" +
" + 'total times: ' + params.data.totalTimes + '<br/>'" +
" + 'path: ' + params.data.id + '<br/>';" +
"}");
sb.append("},");
sb.append("series: [");
// Output results data
for (int i = 1; i <= maxDepth; i++) {
assert levelItems.containsKey(i) : i;
List<Stopwatch> itemsOfI = levelItems.get(i);
List<Stopwatch> itemsOfParent = levelItems.get(i - 1);
if (itemsOfParent != null) {
// Fill other cost for non-root level, ignore root level (i=1)
fillOther.accept(itemsOfI, itemsOfParent);
}
// Output items of level I
sb.append(formatLevel.apply(maxDepth, i, itemsOfI));
sb.append(',');
}
if (!items.isEmpty()) {
sb.deleteCharAt(sb.length() - 1);
}
sb.append("]}");
return sb.toString();
}
public static final class LocalTimer {
// Header: 4 bytes classptr + 8 bytes markword
private volatile long padding11 = 0L;
private volatile long padding12 = 0L;
private volatile long padding13 = 0L;
private volatile long padding14 = 0L;
private volatile long padding15 = 0L;
private volatile long padding16 = 0L; // the 1st 64 bytes
private volatile long time = 0L;
private volatile long padding21 = 0L;
private volatile long padding22 = 0L;
private volatile long padding23 = 0L;
private volatile long padding24 = 0L;
private volatile long padding25 = 0L;
private volatile long padding26 = 0L;
private volatile long padding27 = 0L; // the 2nd 64 bytes
private volatile boolean running = false;
private Thread thread = null;
public long now() {
// Read current ns time (be called frequently)
return this.time;
}
public void startTimeUpdateLoop() throws InterruptedException {
assert this.thread == null;
assert this.preventOptimizePadding() == 0L;
this.running = true;
CountDownLatch started = new CountDownLatch(1);
this.thread = new Thread(() -> {
started.countDown();
while (this.running) {
this.time = System.nanoTime();
// Prevent frequent updates for perf (5.2s => 3.6s for 8kw)
Thread.yield();
}
}, "LocalTimer");
this.thread.setDaemon(true);
this.thread.start();
started.await();
}
public void stop() throws InterruptedException {
this.running = false;
if (this.thread != null) {
this.thread.join();
}
}
public long preventOptimizePadding() {
long p1 = this.padding11 + this.padding12 + this.padding13 +
this.padding14 + this.padding15 + this.padding16;
long p2 = this.padding21 + this.padding22 + this.padding23 +
this.padding24 + this.padding25 + this.padding26 +
this.padding27;
return p1 + p2;
}
}
public static final class LocalStack<T> {
private final Object[] elementData;
private int elementCount;
public LocalStack(int capacity) {
this.elementData = new Object[capacity];
this.elementCount = 0;
}
int size() {
return this.elementCount;
}
boolean empty() {
return this.elementCount == 0;
}
public void push(T elem) {
this.elementData[this.elementCount++] = elem;
}
public T pop() {
if (this.elementCount == 0) {
throw new EmptyStackException();
}
this.elementCount--;
@SuppressWarnings("unchecked")
T elem = (T) this.elementData[this.elementCount];
this.elementData[this.elementCount] = null;
return elem;
}
public T peek() {
if (this.elementCount == 0) {
throw new EmptyStackException();
}
@SuppressWarnings("unchecked")
T elem = (T) this.elementData[this.elementCount - 1];
return elem;
}
}
public static final class FastMap<K, V> {
private final Map<K, V> hashMap;
private K key1;
private K key2;
private K key3;
private V val1;
private V val2;
private V val3;
public FastMap() {
this.hashMap = new HashMap<>();
}
public int size() {
return this.hashMap.size();
}
public boolean containsKey(Object key) {
return this.hashMap.containsKey(key);
}
public V get(Object key) {
if (key == this.key1) {
return this.val1;
} else if (key == this.key2) {
return this.val2;
} else if (key == this.key3) {
return this.val3;
}
return this.hashMap.get(key);
}
public V put(K key, V value) {
if (this.key1 == null) {
this.key1 = key;
this.val1 = value;
} else if (this.key2 == null) {
this.key2 = key;
this.val2 = value;
} else if (this.key3 == null) {
this.key3 = key;
this.val3 = value;
}
return this.hashMap.put(key, value);
}
public V remove(Object key) {
if (key == this.key1) {
this.key1 = null;
this.val1 = null;
} else if (key == this.key2) {
this.key2 = null;
this.val2 = null;
} else if (key == this.key3) {
this.key3 = null;
this.val3 = null;
}
return this.hashMap.remove(key);
}
public void clear() {
this.key1 = null;
this.key2 = null;
this.key3 = null;
this.val1 = null;
this.val2 = null;
this.val3 = null;
this.hashMap.clear();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.CONSTRUCTOR })
public @interface Watched {
String value() default "";
String prefix() default "";
}
}

View File

@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.perf;
import java.util.List;
public interface Stopwatch extends Cloneable {
Path id();
String name();
Path parent();
void startTime(long startTime);
void endTime(long startTime);
void lastStartTime(long startTime);
long times();
long totalTimes();
long totalChildrenTimes();
long totalCost();
void totalCost(long otherCost);
long minCost();
long maxCost();
long totalWasted();
long totalSelfWasted();
long totalChildrenWasted();
void fillChildrenTotal(List<Stopwatch> children);
Stopwatch copy();
Stopwatch child(String name);
Stopwatch child(String name, Stopwatch watch);
boolean empty();
void clear();
default String toJson() {
int len = 200 + this.name().length() + this.parent().length();
StringBuilder sb = new StringBuilder(len);
sb.append("{");
sb.append("\"parent\":\"").append(this.parent()).append("\"");
sb.append(",\"name\":\"").append(this.name()).append("\"");
sb.append(",\"times\":").append(this.times());
sb.append(",\"total_cost\":").append(this.totalCost());
sb.append(",\"min_cost\":").append(this.minCost());
sb.append(",\"max_cost\":").append(this.maxCost());
sb.append(",\"total_self_wasted\":").append(this.totalSelfWasted());
sb.append(",\"total_children_wasted\":").append(
this.totalChildrenWasted());
sb.append(",\"total_children_times\":").append(
this.totalChildrenTimes());
sb.append("}");
return sb.toString();
}
static Path id(Path parent, String name) {
if (parent == Path.EMPTY && name == Path.ROOT_NAME) {
return Path.EMPTY;
}
return new Path(parent, name);
}
final class Path implements Comparable<Path> {
public static final String ROOT_NAME = "root";
public static final Path EMPTY = new Path("");
private final String path;
public Path(String self) {
this.path = self;
}
public Path(Path parent, String name) {
if (parent == EMPTY) {
this.path = name;
} else {
this.path = parent.path + '/' + name;
}
}
public int length() {
return this.path.length();
}
@Override
public int hashCode() {
return this.path.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this.hashCode() != obj.hashCode()) {
return false;
}
if (!(obj instanceof Path)) {
return false;
}
Path other = (Path) obj;
return this.path.equals(other.path);
}
@Override
public int compareTo(Path other) {
return this.path.compareTo(other.path);
}
@Override
public String toString() {
return this.path;
}
public boolean endsWith(String name) {
return this.path.endsWith(name);
}
}
}

View File

@ -0,0 +1,490 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.rest;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.hugegraph.util.JsonUtilCommon;
import org.jetbrains.annotations.NotNull;
import com.google.common.collect.ImmutableMap;
import lombok.SneakyThrows;
import okhttp3.ConnectionPool;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okio.BufferedSink;
import okio.GzipSink;
import okio.Okio;
/**
* This class provides an abstract implementation of the RestClient interface.
* It provides methods for making HTTP requests (GET, POST, PUT, DELETE) to a REST API.
* Note: It uses the OkHttp library to make these requests for now.
*/
public abstract class AbstractRestClient implements RestClient {
private final ThreadLocal<String> authContext;
private final OkHttpClient client;
private final String baseUrl;
public AbstractRestClient(String url, int timeout) {
this(url, RestClientConfig.builder().timeout(timeout).build());
}
public AbstractRestClient(String url, String user, String password, int timeout) {
this(url, RestClientConfig.builder()
.user(user)
.password(password)
.timeout(timeout)
.build());
}
public AbstractRestClient(String url, int timeout, int idleTime,
int maxConns, int maxConnsPerRoute) {
this(url, RestClientConfig.builder()
.idleTime(idleTime)
.timeout(timeout)
.maxConns(maxConns)
.maxConnsPerRoute(maxConnsPerRoute)
.build());
}
public AbstractRestClient(String url, String user, String password, int timeout,
int maxConns, int maxConnsPerRoute,
String trustStoreFile, String trustStorePassword) {
this(url, RestClientConfig.builder()
.user(user).password(password)
.timeout(timeout)
.maxConns(maxConns)
.maxConnsPerRoute(maxConnsPerRoute)
.trustStoreFile(trustStoreFile)
.trustStorePassword(trustStorePassword)
.build());
}
public AbstractRestClient(String url, String token, int timeout,
int maxConns, int maxConnsPerRoute,
String trustStoreFile, String trustStorePassword) {
this(url, RestClientConfig.builder()
.token(token)
.timeout(timeout)
.maxConns(maxConns)
.maxConnsPerRoute(maxConnsPerRoute)
.trustStoreFile(trustStoreFile)
.trustStorePassword(trustStorePassword)
.build());
}
public AbstractRestClient(String url, RestClientConfig config) {
this.baseUrl = url;
this.client = buildOkHttpClient(config);
this.authContext = new InheritableThreadLocal<>();
}
private static RequestBody buildRequestBody(Object body, RestHeaders headers) {
String contentType = parseContentType(headers);
String bodyContent;
if (RestHeaders.APPLICATION_JSON.equals(contentType)) {
if (body == null) {
bodyContent = "{}";
} else if (body instanceof String) {
bodyContent = (String) body;
} else {
bodyContent = JsonUtilCommon.toJson(body);
}
} else {
bodyContent = String.valueOf(body);
}
RequestBody requestBody = RequestBody.create(bodyContent.getBytes(),
MediaType.parse(contentType));
if (headers != null &&
"gzip".equals(headers.get(RestHeaders.CONTENT_ENCODING))) {
requestBody = gzipBody(requestBody);
}
return requestBody;
}
private static RequestBody gzipBody(final RequestBody body) {
return new RequestBody() {
@Override
public MediaType contentType() {
return body.contentType();
}
@Override
public long contentLength() {
return -1; // We don't know the compressed length in advance!
}
@Override
public void writeTo(@NotNull BufferedSink sink) throws IOException {
BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
body.writeTo(gzipSink);
gzipSink.close();
}
};
}
private static String parseContentType(RestHeaders headers) {
if (headers != null) {
String contentType = headers.get(RestHeaders.CONTENT_TYPE);
if (contentType != null) {
return contentType;
}
}
return RestHeaders.APPLICATION_JSON;
}
private OkHttpClient buildOkHttpClient(RestClientConfig config) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (config.getTimeout() != null) {
builder.connectTimeout(config.getTimeout(), TimeUnit.MILLISECONDS)
.readTimeout(config.getTimeout(), TimeUnit.MILLISECONDS);
}
if (config.getConnectTimeout() != null) {
builder.connectTimeout(config.getConnectTimeout(), TimeUnit.MILLISECONDS);
}
if (config.getReadTimeout() != null) {
builder.readTimeout(config.getReadTimeout(), TimeUnit.MILLISECONDS);
}
if (config.getMaxIdleConns() != null || config.getIdleTime() != null) {
ConnectionPool connectionPool = new ConnectionPool(config.getMaxIdleConns(),
config.getIdleTime(),
TimeUnit.SECONDS);
builder.connectionPool(connectionPool);
}
// auth header interceptor
if (StringUtils.isNotBlank(config.getUser()) &&
StringUtils.isNotBlank(config.getPassword())) {
builder.addInterceptor(new OkHttpBasicAuthInterceptor(config.getUser(),
config.getPassword()));
}
if (StringUtils.isNotBlank(config.getToken())) {
builder.addInterceptor(new OkHttpTokenInterceptor(config.getToken()));
}
// ssl
configSsl(builder, this.baseUrl, config.getTrustStoreFile(),
config.getTrustStorePassword());
// Execute builder callback before builder.build() for user configs
if (config.getBuilderCallback() != null) {
config.getBuilderCallback().accept(builder);
}
OkHttpClient okHttpClient = builder.build();
if (config.getMaxConns() != null) {
okHttpClient.dispatcher().setMaxRequests(config.getMaxConns());
}
if (config.getMaxConnsPerRoute() != null) {
okHttpClient.dispatcher().setMaxRequestsPerHost(config.getMaxConnsPerRoute());
}
return okHttpClient;
}
@SneakyThrows
private void configSsl(OkHttpClient.Builder builder, String url, String trustStoreFile,
String trustStorePass) {
if (StringUtils.isBlank(trustStoreFile) || StringUtils.isBlank(trustStorePass)) {
return;
}
X509TrustManager trustManager = trustManagerForCertificates(trustStoreFile, trustStorePass);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{trustManager}, null);
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
builder.sslSocketFactory(sslSocketFactory, trustManager)
.hostnameVerifier(new HostNameVerifier(url));
}
@Override
public RestResult post(String path, Object object) {
return this.post(path, object, null, null);
}
@Override
public RestResult post(String path, Object object, RestHeaders headers) {
return this.post(path, object, headers, null);
}
@Override
public RestResult post(String path, Object object, Map<String, Object> params) {
return this.post(path, object, null, params);
}
private Request.Builder genRequestBuilder(String path, String id, RestHeaders headers,
Map<String, Object> params) {
HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(this.baseUrl))
.newBuilder()
.addPathSegments(path);
if (id != null) {
urlBuilder.addPathSegment(id);
}
if (params != null) {
params.forEach((name, value) -> {
if (value == null) {
return;
}
if (value instanceof Collection) {
for (Object i : (Collection<?>) value) {
urlBuilder.addQueryParameter(name, String.valueOf(i));
}
} else {
urlBuilder.addQueryParameter(name, String.valueOf(value));
}
});
}
Request.Builder builder = newRequestBuilder().url(urlBuilder.build());
if (headers != null) {
builder.headers(headers.toOkHttpHeader());
}
this.attachAuthToRequest(builder);
return builder;
}
/**
* In order to provide subclasses with overloading opportunities
*/
protected Request.Builder newRequestBuilder() {
return new Request.Builder();
}
@SneakyThrows
@Override
public RestResult post(String path, Object object, RestHeaders headers,
Map<String, Object> params) {
Request.Builder requestBuilder = genRequestBuilder(path, null, headers, params);
requestBuilder.post(buildRequestBody(object, headers));
try (Response response = request(requestBuilder)) {
checkStatus(response, 200, 201, 202);
return new RestResult(response);
}
}
@Override
public RestResult put(String path, String id, Object object) {
return this.put(path, id, object, ImmutableMap.of());
}
@Override
public RestResult put(String path, String id, Object object, RestHeaders headers) {
return this.put(path, id, object, headers, null);
}
@Override
public RestResult put(String path, String id, Object object, Map<String, Object> params) {
return this.put(path, id, object, null, params);
}
@SneakyThrows
@Override
public RestResult put(String path, String id, Object object,
RestHeaders headers,
Map<String, Object> params) {
Request.Builder requestBuilder = genRequestBuilder(path, id, headers, params);
requestBuilder.put(buildRequestBody(object, headers));
try (Response response = request(requestBuilder)) {
checkStatus(response, 200, 202);
return new RestResult(response);
}
}
@Override
public RestResult get(String path) {
return this.get(path, null, ImmutableMap.of());
}
@Override
public RestResult get(String path, Map<String, Object> params) {
return this.get(path, null, params);
}
@Override
public RestResult get(String path, String id) {
return this.get(path, id, ImmutableMap.of());
}
@SneakyThrows
private RestResult get(String path, String id, Map<String, Object> params) {
Request.Builder requestBuilder = genRequestBuilder(path, id, null, params);
try (Response response = request(requestBuilder)) {
checkStatus(response, 200);
return new RestResult(response);
}
}
@Override
public RestResult delete(String path, Map<String, Object> params) {
return this.delete(path, null, params);
}
@Override
public RestResult delete(String path, String id) {
return this.delete(path, id, ImmutableMap.of());
}
@SneakyThrows
private RestResult delete(String path, String id,
Map<String, Object> params) {
Request.Builder requestBuilder = genRequestBuilder(path, id, null, params);
requestBuilder.delete();
try (Response response = request(requestBuilder)) {
checkStatus(response, 204, 202);
return new RestResult(response);
}
}
protected abstract void checkStatus(Response response, int... statuses);
@SneakyThrows
protected Response request(Request.Builder requestBuilder) {
return this.client.newCall(requestBuilder.build()).execute();
}
@SneakyThrows
@Override
public void close() {
if (this.client != null) {
this.client.dispatcher().executorService().shutdown();
this.client.connectionPool().evictAll();
if (this.client.cache() != null) {
this.client.cache().close();
}
}
}
public static String encode(String raw) {
try {
return URLEncoder.encode(raw, StandardCharsets.UTF_8.toString()).replace("+", "%2B");
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Failed to encode string: " + raw, e);
}
}
public void resetAuthContext() {
this.authContext.remove();
}
public String getAuthContext() {
return this.authContext.get();
}
public void setAuthContext(String auth) {
this.authContext.set(auth);
}
private void attachAuthToRequest(Request.Builder builder) {
// Add auth header
String auth = this.getAuthContext();
if (StringUtils.isNotEmpty(auth)) {
builder.addHeader(RestHeaders.AUTHORIZATION, auth);
}
}
@SneakyThrows
private X509TrustManager trustManagerForCertificates(String trustStoreFile,
String trustStorePass) {
char[] password = trustStorePass.toCharArray();
// load keyStore
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
try (FileInputStream in = new FileInputStream(trustStoreFile)) {
keyStore.load(in, password);
}
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:" +
Arrays.toString(trustManagers));
}
return (X509TrustManager) trustManagers[0];
}
public static class HostNameVerifier implements HostnameVerifier {
private final String url;
public HostNameVerifier(String url) {
if (!url.startsWith("http://") && !url.startsWith("https://")) {
url = "http://" + url;
}
url = URI.create(url).getHost();
this.url = url;
}
@Override
public boolean verify(String hostname, SSLSession session) {
if (!this.url.isEmpty() && this.url.endsWith(hostname)) {
return true;
} else {
HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
return verifier.verify(hostname, session);
}
}
}
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.rest;
public class ClientException extends RuntimeException {
private static final long serialVersionUID = 814572040103754705L;
public ClientException(String message, Throwable cause) {
super(message, cause);
}
public ClientException(String message, Object... args) {
super(String.format(message, args));
}
public ClientException(String message, Throwable cause, Object... args) {
super(String.format(message, args), cause);
}
}

View File

@ -0,0 +1,47 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.rest;
import java.io.IOException;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class OkHttpBasicAuthInterceptor implements Interceptor {
private final String credentials;
public OkHttpBasicAuthInterceptor(String user, String password) {
this.credentials = Credentials.basic(user, password);
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (request.header(RestHeaders.AUTHORIZATION) == null) {
Request authenticatedRequest = request.newBuilder()
.header(RestHeaders.AUTHORIZATION,
this.credentials)
.build();
return chain.proceed(authenticatedRequest);
}
return chain.proceed(request);
}
}

View File

@ -0,0 +1,50 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.rest;
import static org.apache.hugegraph.rest.RestHeaders.AUTHORIZATION;
import static org.apache.hugegraph.rest.RestHeaders.BEARER_PREFIX;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class OkHttpTokenInterceptor implements Interceptor {
private final String token;
public OkHttpTokenInterceptor(String token) {
this.token = token;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (request.header(AUTHORIZATION) == null) {
Request authenticatedRequest = request.newBuilder()
.header(AUTHORIZATION,
BEARER_PREFIX + this.token)
.build();
return chain.proceed(authenticatedRequest);
}
return chain.proceed(request);
}
}

View File

@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.rest;
import java.util.Map;
public interface RestClient {
/**
* Post method
*/
RestResult post(String path, Object object);
RestResult post(String path, Object object, RestHeaders headers);
RestResult post(String path, Object object, Map<String, Object> params);
RestResult post(String path, Object object, RestHeaders headers, Map<String, Object> params);
/**
* Put method
*/
RestResult put(String path, String id, Object object);
RestResult put(String path, String id, Object object, RestHeaders headers);
RestResult put(String path, String id, Object object, Map<String, Object> params);
RestResult put(String path, String id, Object object, RestHeaders headers,
Map<String, Object> params);
/**
* Get method
*/
RestResult get(String path);
RestResult get(String path, Map<String, Object> params);
RestResult get(String path, String id);
/**
* Delete method
*/
RestResult delete(String path, Map<String, Object> params);
RestResult delete(String path, String id);
void close();
}

View File

@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.rest;
import java.util.function.Consumer;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import okhttp3.OkHttpClient;
@Builder
@Getter
@Setter
@SuppressWarnings("unused")
public class RestClientConfig {
private String user;
private String password;
private String token;
/**
* @deprecated use connectTimeout and readTimeout instead
*/
@Deprecated
private Integer timeout;
/** unit in milliseconds */
private Integer connectTimeout;
/** unit in milliseconds */
private Integer readTimeout;
private Integer maxConns;
private Integer maxConnsPerRoute;
// unit in seconds
private Integer idleTime = 30;
private Integer maxIdleConns = 5;
private String trustStoreFile;
private String trustStorePassword;
private Consumer<OkHttpClient.Builder> builderCallback;
}

View File

@ -0,0 +1,90 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.rest;
import java.util.Date;
import java.util.Iterator;
import kotlin.Pair;
public class RestHeaders {
public static final String CONTENT_TYPE = "Content-Type";
public static final String CONTENT_ENCODING = "Content-Encoding";
public static final String AUTHORIZATION = "Authorization";
public static final String APPLICATION_JSON = "application/json";
public static final String BEARER_PREFIX = "Bearer ";
private final okhttp3.Headers.Builder headersBuilder;
public RestHeaders() {
this.headersBuilder = new okhttp3.Headers.Builder();
}
public static RestHeaders convertToRestHeaders(okhttp3.Headers headers) {
RestHeaders restHeaders = new RestHeaders();
if (headers != null) {
Iterator<Pair<String, String>> iter = headers.iterator();
while (iter.hasNext()) {
Pair<String, String> pair = iter.next();
restHeaders.add(pair.getFirst(), pair.getSecond());
}
}
return restHeaders;
}
public String get(String key) {
return this.headersBuilder.get(key);
}
public Date getDate(String key) {
return this.headersBuilder.build().getDate(key);
}
public RestHeaders add(String key, String value) {
this.headersBuilder.add(key, value);
return this;
}
public RestHeaders add(String key, Date value) {
this.headersBuilder.add(key, value);
return this;
}
@Override
public int hashCode() {
return this.toOkHttpHeader().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof RestHeaders) {
return this.toOkHttpHeader().equals(((RestHeaders) obj).toOkHttpHeader());
}
return false;
}
public okhttp3.Headers toOkHttpHeader() {
return this.headersBuilder.build();
}
}

View File

@ -0,0 +1,114 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.rest;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import okhttp3.Response;
public class RestResult {
private static final ObjectMapper MAPPER = new ObjectMapper();
private final int status;
private final RestHeaders headers;
private final String content;
public RestResult(Response response) {
this(response.code(), getResponseContent(response),
RestHeaders.convertToRestHeaders(response.headers()));
}
public RestResult(int status, String content, RestHeaders headers) {
this.status = status;
this.headers = headers;
this.content = content;
}
@SneakyThrows
private static String getResponseContent(Response response) {
return response.body().string();
}
public static void registerModule(Module module) {
MAPPER.registerModule(module);
}
public int status() {
return this.status;
}
public RestHeaders headers() {
return this.headers;
}
public String content() {
return this.content;
}
public <T> T readObject(Class<T> clazz) {
try {
return MAPPER.readValue(this.content, clazz);
} catch (Exception e) {
throw new SerializeException("Failed to deserialize: %s", e, this.content);
}
}
@SuppressWarnings("deprecation")
public <T> List<T> readList(String key, Class<T> clazz) {
try {
JsonNode root = MAPPER.readTree(this.content);
JsonNode element = root.get(key);
if (element == null) {
throw new SerializeException("Can't find value of the key: %s in json.", key);
}
JavaType type = MAPPER.getTypeFactory()
.constructParametrizedType(ArrayList.class,
List.class, clazz);
return MAPPER.convertValue(element, type);
} catch (IOException e) {
throw new SerializeException("Failed to deserialize %s", e, this.content);
}
}
@SuppressWarnings("deprecation")
public <T> List<T> readList(Class<T> clazz) {
JavaType type = MAPPER.getTypeFactory()
.constructParametrizedType(ArrayList.class,
List.class, clazz);
try {
return MAPPER.readValue(this.content, type);
} catch (IOException e) {
throw new SerializeException("Failed to deserialize %s", e, this.content);
}
}
@Override
public String toString() {
return String.format("{status=%s, headers=%s, content=%s}", this.status, this.headers,
this.content);
}
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.rest;
public class SerializeException extends ClientException {
private static final long serialVersionUID = -4622753445618619311L;
public SerializeException(String message, Throwable e) {
super(message, e);
}
public SerializeException(String message, Object... args) {
super(message, args);
}
public SerializeException(String message, Throwable e, Object... args) {
super(message, e, args);
}
}

View File

@ -0,0 +1,164 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.testutil;
import java.util.function.Consumer;
import java.util.function.Function;
import org.hamcrest.BaseMatcher;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Description;
public class Assert extends org.junit.Assert {
@FunctionalInterface
public interface ThrowableRunnable {
void run() throws Throwable;
}
@FunctionalInterface
public interface ThrowableConsumer<T> {
void accept(T t) throws Throwable;
}
public static void assertThrows(Class<? extends Throwable> clazz,
ThrowableRunnable runnable,
Consumer<Throwable> exceptionConsumer) {
Throwable expectedException = assertThrows(clazz, runnable);
assert expectedException != null;
exceptionConsumer.accept(expectedException);
}
public static Throwable assertThrows(Class<? extends Throwable> clazz,
ThrowableRunnable runnable) {
try {
// expect throwing here
runnable.run();
} catch (Throwable e) {
if (!clazz.isInstance(e)) {
// exception type not matched
Assert.fail(String.format("Bad exception type %s(expected %s)",
e.getClass().getName(), clazz.getName()));
}
return e;
}
// no exception
Assert.fail(String.format("No exception was thrown(expected %s)",
clazz.getName()));
// unavailable
assert false;
return null;
}
public static void assertEquals(byte expected, Object actual) {
org.junit.Assert.assertEquals(expected, actual);
}
public static void assertEquals(short expected, Object actual) {
org.junit.Assert.assertEquals(expected, actual);
}
public static void assertEquals(char expected, Object actual) {
org.junit.Assert.assertEquals(expected, actual);
}
public static void assertEquals(int expected, Object actual) {
org.junit.Assert.assertEquals(expected, actual);
}
public static void assertEquals(long expected, Object actual) {
org.junit.Assert.assertEquals(expected, actual);
}
public static void assertEquals(float expected, Object actual) {
org.junit.Assert.assertEquals(expected, actual);
}
public static void assertEquals(double expected, Object actual) {
org.junit.Assert.assertEquals(expected, actual);
}
@SuppressWarnings("deprecation")
public static void assertGt(Number expected, Object actual) {
org.junit.Assert.assertThat(actual, new NumberMatcher(expected, cmp -> {
return cmp > 0;
}, ">"));
}
@SuppressWarnings("deprecation")
public static void assertGte(Number expected, Object actual) {
org.junit.Assert.assertThat(actual, new NumberMatcher(expected, cmp -> {
return cmp >= 0;
}, ">="));
}
@SuppressWarnings("deprecation")
public static void assertLt(Number expected, Object actual) {
org.junit.Assert.assertThat(actual, new NumberMatcher(expected, cmp -> {
return cmp < 0;
}, "<"));
}
@SuppressWarnings("deprecation")
public static void assertLte(Number expected, Object actual) {
org.junit.Assert.assertThat(actual, new NumberMatcher(expected, cmp -> {
return cmp <= 0;
}, "<="));
}
@SuppressWarnings("deprecation")
public static void assertContains(String sub, String actual) {
org.junit.Assert.assertThat(actual, CoreMatchers.containsString(sub));
}
@SuppressWarnings("deprecation")
public static void assertInstanceOf(Class<?> clazz, Object object) {
org.junit.Assert.assertThat(object, CoreMatchers.instanceOf(clazz));
}
private static class NumberMatcher extends BaseMatcher<Object> {
private final String symbol;
private final Number expected;
private final Function<Integer, Boolean> cmp;
NumberMatcher(Number expected, Function<Integer, Boolean> cmp, String symbol) {
this.expected = expected;
this.cmp = cmp;
this.symbol = symbol;
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(Object actual) {
Assert.assertInstanceOf(this.expected.getClass(), actual);
Assert.assertInstanceOf(Comparable.class, actual);
int cmp = ((Comparable<Number>) actual).compareTo(this.expected);
return this.cmp.apply(cmp);
}
@Override
public void describeTo(Description desc) {
desc.appendText("a number ").appendText(this.symbol)
.appendText(" ").appendText(this.expected.toString());
}
}
}

View File

@ -0,0 +1,184 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.testutil;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import org.apache.hugegraph.util.E;
import com.google.common.primitives.Primitives;
public class Whitebox {
public static final char SEPARATOR = '.';
public static void setInternalState(Object target,
String fieldName, Object value) {
assert target != null;
assert fieldName != null;
int sep = fieldName.lastIndexOf(SEPARATOR);
if (sep > 0) {
String prefix = fieldName.substring(0, sep);
Object result = getInternalState(target, prefix);
E.checkArgument(result != null,
"Can't set value on null field: `%s.%s`",
target, prefix);
target = result;
fieldName = fieldName.substring(sep + 1);
}
Class<?> c = target instanceof Class<?> ?
(Class<?>) target : target.getClass();
try {
Field f = getFieldFromHierarchy(c, fieldName);
f.setAccessible(true);
f.set(target, value);
} catch (Exception e) {
throw new RuntimeException(String.format(
"Can't set value of '%s' against object '%s'",
fieldName, target), e);
}
}
public static <T> T getInternalState(Object target, String fieldName) {
assert fieldName != null;
int sep = fieldName.indexOf(SEPARATOR);
if (sep > 0) {
String field = fieldName.substring(0, sep);
Object value = getInternalState(target, field);
field = fieldName.substring(sep + 1);
return getInternalState(value, field);
}
Class<?> c = target instanceof Class<?> ?
(Class<?>) target : target.getClass();
try {
Field f = getFieldFromHierarchy(c, fieldName);
f.setAccessible(true);
@SuppressWarnings("unchecked")
T result = (T) f.get(target);
return result;
} catch (Exception e) {
throw new RuntimeException(String.format(
"Unable to get internal state on field '%s' of %s",
fieldName, target), e);
}
}
private static Field getFieldFromHierarchy(Class<?> clazz, String field) {
Field f = getField(clazz, field);
while (f == null && clazz != Object.class) {
clazz = clazz.getSuperclass();
f = getField(clazz, field);
}
if (f == null) {
throw new RuntimeException(String.format(
"Not declared field '%s' in class '%s'",
field, clazz.getSimpleName()));
}
return f;
}
private static Field getField(Class<?> clazz, String field) {
try {
return clazz.getDeclaredField(field);
} catch (NoSuchFieldException e) {
return null;
}
}
public static <T> T invokeStatic(Class<?> clazz, String methodName,
Object... args) {
return invoke(clazz, methodName, (Object) null, args);
}
public static <T> T invokeStatic(Class<?> clazz, Class<?>[] classes,
String methodName, Object... args) {
return invoke(clazz, classes, methodName, (Object) null, args);
}
public static <T> T invoke(Object owner, String field,
String methodName, Object... args) {
Object self = getInternalState(owner, field);
Objects.requireNonNull(self);
return invoke(self.getClass(), methodName, self, args);
}
public static <T> T invoke(Object owner, String field, Class<?>[] classes,
String methodName, Object... args) {
Object self = getInternalState(owner, field);
Objects.requireNonNull(self);
return invoke(self.getClass(), classes, methodName, self, args);
}
public static <T> T invoke(Class<?> clazz, String methodName,
Object self, Object... args) {
Class<?>[] classes = new Class<?>[args.length];
int i = 0;
for (Object arg : args) {
E.checkArgument(arg != null, "The argument can't be null");
classes[i++] = Primitives.unwrap(arg.getClass());
}
return invoke(clazz, classes, methodName, self, args);
}
public static <T> T invoke(Class<?> clazz, Class<?>[] classes,
String methodName, Object self, Object... args) {
Method method = method(clazz, methodName, classes);
try {
method.setAccessible(true);
@SuppressWarnings("unchecked")
T result = (T) method.invoke(self, args);
return result;
} catch (IllegalAccessException e) {
throw new RuntimeException(String.format(
"Can't invoke method '%s' of class '%s': %s",
methodName, clazz, e.getMessage()), e);
} catch (InvocationTargetException e) {
Throwable target = e.getTargetException();
if (target instanceof RuntimeException) {
throw (RuntimeException) target;
}
throw new RuntimeException(String.format(
"Can't invoke method '%s' of class '%s': %s",
methodName, clazz, target.getMessage()), target);
}
}
public static Method method(Class<?> clazz, String methodName,
Class<?>[] argsClasses) {
try {
return clazz.getDeclaredMethod(methodName, argsClasses);
} catch (NoSuchMethodException e) {
Class<?> superclass = clazz.getSuperclass();
if (superclass != null) {
try {
return method(superclass, methodName, argsClasses);
} catch (Exception ignored) {
// pass
}
}
throw new RuntimeException(String.format(
"Can't find method '%s' with args %s of class '%s'",
methodName, Arrays.asList(argsClasses), clazz), e);
}
}
}

View File

@ -0,0 +1,103 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.util.Arrays;
import java.util.Comparator;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import com.google.common.primitives.UnsignedBytes;
/**
* TODO: extends com.google.common.primitives.Bytes
*/
public final class Bytes {
public static final long BASE = 1024L;
public static final long KB = BASE;
public static final long MB = KB * BASE;
public static final long GB = MB * BASE;
public static final long TB = GB * KB;
public static final long PB = GB * MB;
public static final long EB = GB * GB;
private static final Comparator<byte[]> CMP = UnsignedBytes.lexicographicalComparator();
public static int compare(byte[] bytes1, byte[] bytes2) {
return CMP.compare(bytes1, bytes2);
}
public static byte[] concat(byte[] bytes1, byte[] bytes2) {
byte[] result = new byte[bytes1.length + bytes2.length];
System.arraycopy(bytes1, 0, result, 0, bytes1.length);
System.arraycopy(bytes2, 0, result, bytes1.length, bytes2.length);
return result;
}
public static boolean prefixWith(byte[] bytes, byte[] prefix) {
if (bytes.length < prefix.length) {
return false;
}
for (int i = 0; i < prefix.length; i++) {
if (bytes[i] != prefix[i]) {
return false;
}
}
return true;
}
public static boolean contains(byte[] bytes, byte value) {
for (byte b : bytes) {
if (b == value) {
return true;
}
}
return false;
}
public static int indexOf(byte[] bytes, byte value) {
for (int i = 0; i < bytes.length; i++) {
if (bytes[i] == value) {
return i;
}
}
return -1;
}
public static boolean equals(byte[] bytes1, byte[] bytes2) {
return Arrays.equals(bytes1, bytes2);
}
public static String toHex(byte b) {
return toHex(new byte[]{b});
}
public static String toHex(byte[] bytes) {
return new String(Hex.encodeHex(bytes));
}
public static byte[] fromHex(String hex) {
try {
return Hex.decodeHex(hex.toCharArray());
} catch (DecoderException e) {
throw new RuntimeException("Failed to decode hex: " + hex, e);
}
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import static java.lang.System.exit;
import java.net.InetAddress;
import java.net.Socket;
public final class CheckSocket {
public static void main(String[] args) {
try {
// Check if the socket connection can be closed normally
new Socket(InetAddress.getByName(args[0]), Integer.parseInt(args[1])).close();
exit(0);
} catch (Exception e) {
e.printStackTrace();
exit(-1);
}
}
}

View File

@ -0,0 +1,448 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.lang.reflect.Array;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
public final class CollectionUtil {
public static <T> Set<T> toSet(Object object) {
E.checkNotNull(object, "object");
Set<T> set = InsertionOrderUtil.newSet();
fillCollection(set, object);
return set;
}
public static <T> List<T> toList(Object object) {
E.checkNotNull(object, "object");
List<T> list = new ArrayList<>();
fillCollection(list, object);
return list;
}
@SuppressWarnings("unchecked")
private static <T> void fillCollection(Collection<T> collection,
Object object) {
if (object.getClass().isArray()) {
int length = Array.getLength(object);
for (int i = 0; i < length; i++) {
collection.add((T) Array.get(object, i));
}
} else if (object instanceof Collection) {
collection.addAll((Collection<T>) object);
} else {
collection.add((T) object);
}
}
public static <T> boolean prefixOf(List<T> prefix, List<T> all) {
E.checkNotNull(prefix, "prefix");
E.checkNotNull(all, "all");
if (prefix.size() > all.size()) {
return false;
}
for (int i = 0; i < prefix.size(); i++) {
T first = prefix.get(i);
T second = all.get(i);
if (first == second) {
continue;
}
if (first == null || !first.equals(second)) {
return false;
}
}
return true;
}
public static Set<Integer> randomSet(int min, int max, int count) {
E.checkArgument(max > min, "Invalid min/max: %s/%s", min, max);
E.checkArgument(0 < count && count <= max - min,
"Invalid count %s", count);
Set<Integer> randoms = new HashSet<>();
while (randoms.size() < count) {
randoms.add(ThreadLocalRandom.current().nextInt(min, max));
}
return randoms;
}
public static boolean allUnique(Collection<?> collection) {
HashSet<Object> set = new HashSet<>(collection.size());
for (Object elem : collection) {
if (!set.add(elem)) {
return false;
}
}
return true;
}
/**
* Get sub-set of a set.
* @param original original set
* @param from index of start position
* @param to index of end position(exclude), but -1 means the last element
* @param <T> element type of set
* @return sub-set of original set [from, to)
*/
public static <T> Set<T> subSet(Set<T> original, int from, int to) {
E.checkArgument(from >= 0,
"Invalid from parameter of subSet(): %s", from);
if (to < 0) {
to = original.size();
} else {
E.checkArgument(to >= from,
"Invalid to parameter of subSet(): %s", to);
}
List<T> list = new ArrayList<>(original);
return new LinkedHashSet<>(list.subList(from, to));
}
public static <T> Set<T> union(Collection<T> first, Collection<T> second) {
E.checkNotNull(first, "first");
E.checkNotNull(second, "second");
HashSet<T> results = new HashSet<>(first);
results.addAll(second);
return results;
}
/**
* Find the intersection of two collections, the original collections
* will not be modified
* @param first the first collection
* @param second the second collection
* @param <T> element type of collection
* @return intersection of the two collections
*/
public static <T> Collection<T> intersect(Collection<T> first,
Collection<T> second) {
E.checkNotNull(first, "first");
E.checkNotNull(second, "second");
HashSet<T> results;
if (first instanceof HashSet) {
@SuppressWarnings("unchecked")
HashSet<T> clone = (HashSet<T>) ((HashSet<T>) first).clone();
results = clone;
} else {
results = new HashSet<>(first);
}
results.retainAll(second);
return results;
}
/**
* Find the intersection of two collections, note that the first collection
* will be modified and store the results
* @param first the first collection, it will be modified
* @param second the second collection
* @param <T> element type of collection
* @return intersection of the two collections
*/
public static <T> Collection<T> intersectWithModify(Collection<T> first,
Collection<T> second) {
E.checkNotNull(first, "first");
E.checkNotNull(second, "second");
first.retainAll(second);
return first;
}
public static <T> boolean hasIntersection(List<T> first, Set<T> second) {
E.checkNotNull(first, "first");
E.checkNotNull(second, "second");
for (T firstElem : first) {
if (second.contains(firstElem)) {
return true;
}
}
return false;
}
public static <T> boolean hasIntersection(Set<T> first, Set<T> second) {
E.checkNotNull(first, "first");
E.checkNotNull(second, "second");
if (first.size() <= second.size()) {
for (T firstElem : first) {
if (second.contains(firstElem)) {
return true;
}
}
} else {
for (T secondElem : second) {
if (first.contains(secondElem)) {
return true;
}
}
}
return false;
}
public static <K extends Comparable<? super K>, V> Map<K, V> sortByKey(
Map<K, V> map, boolean incr) {
List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet());
if (incr) {
list.sort(Map.Entry.comparingByKey());
} else {
list.sort(Collections.reverseOrder(Map.Entry.comparingByKey()));
}
Map<K, V> result = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(
Map<K, V> map, boolean incr) {
List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet());
if (incr) {
list.sort(Map.Entry.comparingByValue());
} else {
list.sort(Collections.reverseOrder(Map.Entry.comparingByValue()));
}
Map<K, V> result = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
/**
* Cross combine the A(n, n) combinations of each part in parts
* @param parts a list of part, like [{a,b}, {1,2}, {x,y}]
* @return List<List<Integer>> all combinations like
* [{a,b,1,2,x,y}, {a,b,1,2,y,x}, {a,b,2,1,x,y}, {a,b,2,1,y,x}...]
*/
public static <T> List<List<T>> crossCombineParts(List<List<T>> parts) {
List<List<T>> results = new ArrayList<>();
Deque<List<T>> selected = new ArrayDeque<>();
crossCombineParts(parts, 0, selected, results);
return results;
}
private static <T> void crossCombineParts(List<List<T>> parts,
int level,
Deque<List<T>> selected,
List<List<T>> results) {
assert level < parts.size();
List<T> part = parts.get(level);
for (List<T> combination : anm(part)) {
selected.addLast(combination);
if (level < parts.size() - 1) {
crossCombineParts(parts, level + 1, selected, results);
} else if (level == parts.size() - 1) {
results.add(flatToList(selected));
}
selected.removeLast();
}
}
private static <T> List<T> flatToList(Deque<List<T>> parts) {
List<T> list = new ArrayList<>();
for (List<T> part : parts) {
list.addAll(part);
}
return list;
}
/**
* Traverse C(n, m) combinations of a list
* @param all list to contain all items for combination
* @param n m of C(n, m)
* @param m n of C(n, m)
* @return List<List<T>> all combinations
*/
public static <T> List<List<T>> cnm(List<T> all, int n, int m) {
List<List<T>> combs = new ArrayList<>();
cnm(all, n, m, comb -> {
combs.add(comb);
return false;
});
return combs;
}
/**
* Traverse C(n, m) combinations of a list to find first matched
* result combination and call back with the result.
* @param all list to contain all items for combination
* @param n m of C(n, m)
* @param m n of C(n, m)
* @return true if matched any kind of items combination else false, the
* callback can always return false if you want to traverse all combinations
*/
public static <T> boolean cnm(List<T> all, int n, int m,
Function<List<T>, Boolean> callback) {
return cnm(all, n, m, 0, null, callback);
}
/**
* Traverse C(n, m) combinations of a list to find first matched
* result combination and call back with the result.
* @param all list to contain all items for combination
* @param n n of C(n, m)
* @param m m of C(n, m)
* @param current current position in list
* @param selected list to contain selected items
* @return true if matched any kind of items combination else false, the
* callback can always return false if you want to traverse all combinations
*/
private static <T> boolean cnm(List<T> all, int n, int m,
int current, List<T> selected,
Function<List<T>, Boolean> callback) {
assert n <= all.size();
assert m <= n;
assert current <= all.size();
if (selected == null) {
selected = new ArrayList<>(m);
}
if (m == 0) {
assert selected.size() > 0 : selected;
// All n items are selected
List<T> tmpResult = Collections.unmodifiableList(selected);
return callback.apply(tmpResult);
}
if (n == m) {
// No choice, select all n items, we don't update the `result` here
List<T> tmpResult = new ArrayList<>(selected);
tmpResult.addAll(all.subList(current, all.size()));
return callback.apply(tmpResult);
}
if (current >= all.size()) {
// Reach the end of items
return false;
}
// Select current item, continue to select C(m-1, n-1)
int index = selected.size();
selected.add(all.get(current));
++current;
if (cnm(all, n - 1, m - 1, current, selected, callback)) {
// NOTE: we can pop the tailing items if want to keep result clear
return true;
}
// Not select current item, pop it and continue to select C(m-1, n)
selected.remove(index);
assert selected.size() == index : selected;
return cnm(all, n - 1, m, current, selected, callback);
}
/**
* Traverse A(n, m) combinations of a list with n = m = all.size()
* @param all list to contain all items for combination
* @return List<List<T>> all combinations
*/
public static <T> List<List<T>> anm(List<T> all) {
return anm(all, all.size(), all.size());
}
/**
* Traverse A(n, m) combinations of a list
* @param all list to contain all items for combination
* @param n m of A(n, m)
* @param m n of A(n, m)
* @return List<List<T>> all combinations
*/
public static <T> List<List<T>> anm(List<T> all, int n, int m) {
List<List<T>> combs = new ArrayList<>();
anm(all, n, m, comb -> {
combs.add(comb);
return false;
});
return combs;
}
/**
* Traverse A(n, m) combinations of a list to find first matched
* result combination and call back with the result.
* @param all list to contain all items for combination
* @param n m of A(n, m)
* @param m n of A(n, m)
* @return true if matched any kind of items combination else false, the
* callback can always return false if you want to traverse all combinations
*/
public static <T> boolean anm(List<T> all, int n, int m,
Function<List<T>, Boolean> callback) {
return anm(all, n, m, null, callback);
}
/**
* Traverse A(n, m) combinations of a list to find first matched
* result combination and call back with the result.
* @param all list to contain all items for combination
* @param n m of A(n, m)
* @param m n of A(n, m)
* @param selected list to contain selected items
* @return true if matched any kind of items combination else false, the
* callback can always return false if you want to traverse all combinations
*/
private static <T> boolean anm(List<T> all, int n, int m,
List<Integer> selected,
Function<List<T>, Boolean> callback) {
assert n <= all.size();
assert m <= n;
if (selected == null) {
selected = new ArrayList<>(m);
}
if (m == 0) {
// All n items are selected
List<T> tmpResult = new ArrayList<>();
for (int i : selected) {
tmpResult.add(all.get(i));
}
return callback.apply(tmpResult);
}
for (int i = 0; i < all.size(); i++) {
if (selected.contains(i)) {
continue;
}
int index = selected.size();
selected.add(i);
// Select current item, continue to select A(m-1, n-1)
if (anm(all, n - 1, m - 1, selected, callback)) {
return true;
}
selected.remove(index);
assert selected.size() == index : selected;
}
return false;
}
}

View File

@ -0,0 +1,77 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.hugegraph.date.SafeDateFormat;
import com.google.common.collect.ImmutableMap;
public final class DateUtil {
public static final Date DATE_ZERO = new Date(0L);
private static final Map<String, String> VALID_DFS = ImmutableMap.of(
"^\\d{4}-\\d{1,2}-\\d{1,2}",
"yyyy-MM-dd",
"^\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{2}:\\d{2}:\\d{2}",
"yyyy-MM-dd HH:mm:ss",
"^\\d{4}-\\d{1,2}-\\d{1,2}\\s\\d{2}:\\d{2}:\\d{2}\\.\\d{1,3}",
"yyyy-MM-dd HH:mm:ss.SSS"
);
private static final Map<String, SafeDateFormat> DATE_FORMATS = new ConcurrentHashMap<>();
public static Date parse(String value) {
for (Map.Entry<String, String> entry : VALID_DFS.entrySet()) {
if (value.matches(entry.getKey())) {
return parse(value, entry.getValue());
}
}
throw new IllegalArgumentException(String.format(
"Expected date format is: %s, but got '%s'", VALID_DFS.values(), value));
}
public static Date parse(String value, String df) {
SafeDateFormat dateFormat = getDateFormat(df);
return dateFormat.parse(value);
}
public static Date now() {
return new Date();
}
private static SafeDateFormat getDateFormat(String df) {
SafeDateFormat dateFormat = DATE_FORMATS.get(df);
if (dateFormat == null) {
dateFormat = new SafeDateFormat(df);
SafeDateFormat previous = DATE_FORMATS.putIfAbsent(df, dateFormat);
if (previous != null) {
dateFormat = previous;
}
}
return dateFormat;
}
public static Object toPattern(String df) {
SafeDateFormat dateFormat = getDateFormat(df);
return dateFormat.toPattern();
}
}

View File

@ -0,0 +1,66 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.util.Collection;
import javax.annotation.Nullable;
import com.google.common.base.Preconditions;
public final class E {
public static void checkNotNull(Object object, String elem) {
Preconditions.checkNotNull(object, "The '%s' can't be null", elem);
}
public static void checkNotNull(Object object, String elem, String owner) {
Preconditions.checkNotNull(object,
"The '%s' of '%s' can't be null",
elem, owner);
}
public static void checkNotEmpty(Collection<?> collection, String elem) {
Preconditions.checkArgument(!collection.isEmpty(),
"The '%s' can't be empty", elem);
}
public static void checkNotEmpty(Collection<?> collection, String elem, String owner) {
Preconditions.checkArgument(!collection.isEmpty(),
"The '%s' of '%s' can't be empty",
elem, owner);
}
public static void checkArgument(boolean expression,
@Nullable String message,
@Nullable Object... args) {
Preconditions.checkArgument(expression, message, args);
}
public static void checkArgumentNotNull(Object object,
@Nullable String message,
@Nullable Object... args) {
Preconditions.checkArgument(object != null, message, args);
}
public static void checkState(boolean expression,
@Nullable String message,
@Nullable Object... args) {
Preconditions.checkState(expression, message, args);
}
}

View File

@ -0,0 +1,49 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
public final class ExceptionUtil {
public static Throwable rootCause(Throwable e) {
Throwable cause = e;
while (cause.getCause() != null) {
cause = cause.getCause();
}
return cause;
}
public static RuntimeException transToRuntimeException(Throwable e) {
if (e instanceof RuntimeException) {
return (RuntimeException) e;
}
return new RuntimeException(rootCause(e).getMessage(), e);
}
public static <T> T futureGet(Future<T> future) {
try {
return future.get();
} catch (InterruptedException e) {
throw ExceptionUtil.transToRuntimeException(e);
} catch (ExecutionException e) {
throw ExceptionUtil.transToRuntimeException(e.getCause());
}
}
}

View File

@ -0,0 +1,111 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.hugegraph.concurrent.PausableScheduledThreadPool;
public final class ExecutorUtil {
public static ThreadPoolExecutor newDynamicThreadExecutor(String name,
int corePoolSize,
int maximumPoolSize) {
long keepAliveTime = 60L;
TimeUnit unit = TimeUnit.SECONDS;
ThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern(name)
.build();
CustomBlockingQueue<Runnable> workQueue = new CustomBlockingQueue<>();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
factory,
new ThreadPoolExecutor.CallerRunsPolicy()
);
workQueue.setThreadPoolExecutor(threadPoolExecutor);
return threadPoolExecutor;
}
static class CustomBlockingQueue<E> extends LinkedBlockingQueue<E> {
private ThreadPoolExecutor threadPoolExecutor;
public void setThreadPoolExecutor(ThreadPoolExecutor threadPoolExecutor) {
this.threadPoolExecutor = threadPoolExecutor;
}
@Override
public boolean offer(E e) {
if (threadPoolExecutor.getPoolSize() < threadPoolExecutor.getMaximumPoolSize()) {
return false;
}
return super.offer(e);
}
}
public static ExecutorService newFixedThreadPool(String name) {
return newFixedThreadPool(1, name);
}
public static ExecutorService newFixedThreadPool(int size, String name) {
ThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern(name)
.build();
return Executors.newFixedThreadPool(size, factory);
}
public static ScheduledExecutorService newScheduledThreadPool(String name) {
return newScheduledThreadPool(1, name);
}
public static ScheduledExecutorService newScheduledThreadPool(int size,
String name) {
ThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern(name)
.build();
return Executors.newScheduledThreadPool(size, factory);
}
public static PausableScheduledThreadPool newPausableScheduledThreadPool(
String name) {
return newPausableScheduledThreadPool(1, name);
}
public static PausableScheduledThreadPool newPausableScheduledThreadPool(
int size, String name) {
ThreadFactory factory = new BasicThreadFactory.Builder()
.namingPattern(name)
.build();
return new PausableScheduledThreadPool(size, factory);
}
}

View File

@ -0,0 +1,44 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.nio.charset.Charset;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
public final class HashUtil {
private static final Charset CHARSET = Charsets.UTF_8;
public static byte[] hash(byte[] bytes) {
return Hashing.murmur3_32().hashBytes(bytes).asBytes();
}
public static String hash(String value) {
return Hashing.murmur3_32().hashString(value, CHARSET).toString();
}
public static byte[] hash128(byte[] bytes) {
return Hashing.murmur3_128().hashBytes(bytes).asBytes();
}
public static String hash128(String value) {
return Hashing.murmur3_128().hashString(value, CHARSET).toString();
}
}

View File

@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class InsertionOrderUtil {
public static <K, V> Map<K, V> newMap() {
return new LinkedHashMap<>();
}
public static <K, V> Map<K, V> newMap(int initialCapacity) {
return new LinkedHashMap<>(initialCapacity);
}
public static <K, V> Map<K, V> newMap(Map<K, V> origin) {
return new LinkedHashMap<>(origin);
}
public static <V> Set<V> newSet() {
return new LinkedHashSet<>();
}
public static <V> Set<V> newSet(int initialCapacity) {
return new LinkedHashSet<>(initialCapacity);
}
public static <V> Set<V> newSet(Set<V> origin) {
return new LinkedHashSet<>(origin);
}
public static <V> List<V> newList() {
return new ArrayList<>();
}
public static <V> List<V> newList(int initialCapacity) {
return new ArrayList<>(initialCapacity);
}
public static <V> List<V> newList(List<V> origin) {
return new ArrayList<>(origin);
}
}

View File

@ -0,0 +1,94 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.io.IOException;
import org.apache.hugegraph.rest.SerializeException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Utility class for JSON operations.
*/
public final class JsonUtilCommon {
/**
* ObjectMapper instance used for JSON operations.
*/
private static final ObjectMapper MAPPER = new ObjectMapper();
/**
* Registers a module with the ObjectMapper.
*
* @param module the module to register
*/
public static void registerModule(Module module) {
MAPPER.registerModule(module);
}
/**
* Converts an object to a JSON string.
*
* @param object the object to convert
* @return the JSON string representation of the object
* @throws SerializeException if the object cannot be serialized
*/
public static String toJson(Object object) {
try {
return MAPPER.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new SerializeException("Failed to serialize object '%s'", e, object);
}
}
/**
* Converts a JSON string to an object of the specified class.
*
* @param json the JSON string
* @param clazz the class of the object
* @return the object represented by the JSON string
* @throws SerializeException if the JSON string cannot be deserialized
*/
public static <T> T fromJson(String json, Class<T> clazz) {
try {
return MAPPER.readValue(json, clazz);
} catch (IOException e) {
throw new SerializeException("Failed to deserialize json '%s'", e, json);
}
}
/**
* Converts a JsonNode to an object of the specified class.
*
* @param node the JsonNode
* @param clazz the class of the object
* @return the object represented by the JsonNode
* @throws SerializeException if the JsonNode cannot be deserialized
*/
public static <T> T convertValue(JsonNode node, Class<T> clazz) {
try {
return MAPPER.convertValue(node, clazz);
} catch (IllegalArgumentException e) {
throw new SerializeException("Failed to deserialize json node '%s'", e, node);
}
}
}

View File

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class Log {
public static Logger logger(String name) {
return LoggerFactory.getLogger(name);
}
public static Logger logger(Class<?> clazz) {
return LoggerFactory.getLogger(clazz);
}
}

View File

@ -0,0 +1,151 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
public final class LongEncoding {
private static final String B64_SYMBOLS =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~";
private static final String LENGTH_SYMBOLS = "0123456789ABCDEF";
private static final char SORTABLE_NEG = LENGTH_SYMBOLS.charAt(0);
private static final char SIGNED_NEG = '-';
private static final long FULL_LONG = Long.MIN_VALUE;
public static String encodeNumber(Object number) {
Number num = NumericUtil.convertToNumber(number);
long value = NumericUtil.numberToSortableLong(num);
return encodeSortable(value);
}
public static Number decodeNumber(String str, Class<?> clazz) {
long value = decodeSortable(str);
return NumericUtil.sortableLongToNumber(value, clazz);
}
public static String encodeSortable(long num) {
boolean negative = false;
if (num < 0L) {
negative = true;
num += FULL_LONG;
}
String encoded = encode(num, B64_SYMBOLS);
int length = encoded.length();
E.checkArgument(length <= LENGTH_SYMBOLS.length(),
"Length symbols can't represent encoded number '%s'",
encoded);
StringBuilder sb = new StringBuilder(length + 2);
if (negative) {
sb.append(SORTABLE_NEG);
}
char len = LENGTH_SYMBOLS.charAt(length);
sb.append(len);
sb.append(encoded);
return sb.toString();
}
public static long decodeSortable(String str) {
E.checkArgument(str.length() >= 2,
"Length of sortable encoded string must be >=2");
boolean negative = str.charAt(0) == SORTABLE_NEG;
int lengthPos = 0;
if (negative) {
lengthPos = 1;
}
int length = B64_SYMBOLS.indexOf(str.charAt(lengthPos));
E.checkArgument(length == str.length() - lengthPos - 1,
"Can't decode illegal string '%s' with wrong length",
str);
String encoded = str.substring(lengthPos + 1);
long value = decode(encoded, B64_SYMBOLS);
if (negative) {
value -= FULL_LONG;
}
return value;
}
public static String encodeSignedB64(long value) {
boolean negative = false;
if (value < 0L) {
negative = true;
if (value == FULL_LONG) {
return "-80000000000";
}
value = -value;
}
assert value >= 0L : value;
String encoded = encodeB64(value);
return negative ? SIGNED_NEG + encoded : encoded;
}
public static long decodeSignedB64(String value) {
boolean negative = false;
if (!value.isEmpty() && value.charAt(0) == SIGNED_NEG) {
negative = true;
value = value.substring(1);
}
long decoded = decodeB64(value);
return negative ? -decoded : decoded;
}
public static boolean validB64Char(char c) {
return B64_SYMBOLS.indexOf(c) != -1;
}
public static String encodeB64(long num) {
return encode(num, B64_SYMBOLS);
}
public static long decodeB64(String str) {
return decode(str, B64_SYMBOLS);
}
public static long decode(String encoded, String symbols) {
final int B = symbols.length();
E.checkArgument(B > 0, "The symbols parameter can't be empty");
long num = 0L;
for (char ch : encoded.toCharArray()) {
num *= B;
int pos = symbols.indexOf(ch);
if (pos < 0) {
throw new NumberFormatException(String.format(
"Can't decode symbol '%s' in string '%s'",
ch, encoded));
}
num += pos;
}
return num;
}
public static String encode(long num, String symbols) {
final int B = symbols.length();
E.checkArgument(num >= 0L, "Expected non-negative number: %s", num);
E.checkArgument(B > 0, "The symbols parameter can't be empty");
StringBuilder sb = new StringBuilder();
do {
sb.append(symbols.charAt((int) (num % B)));
num /= B;
} while (num != 0L);
return sb.reverse().toString();
}
}

View File

@ -0,0 +1,372 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.function.Function;
/**
* This file is copied verbatim from Apache Lucene NumericUtils.java
* Only the double/float to sortable long/int conversions are retained.
*/
public final class NumericUtil {
private static final long FULL_LONG = Long.MIN_VALUE;
private static final int FULL_INT = Integer.MIN_VALUE;
private static final byte FULL_BYTE = Byte.MIN_VALUE;
private NumericUtil() {
}
/**
* Converts a <code>double</code> value to a sortable signed
* <code>long</code>. The value is converted by getting their IEEE 754
* floating-point &quot;double format&quot; bit layout and then some bits
* are swapped, to be able to compare the result as long. By this the
* precision is not reduced, but the value can be easily used as a long. The
* sort order (including {@link Double#NaN}) is defined by
* {@link Double#compareTo}; {@code NaN} is greater than positive infinity.
* @param value input double value
* @return output sortable long value
* @see #sortableLongToDouble
*/
public static long doubleToSortableLong(double value) {
return sortableDoubleBits(Double.doubleToLongBits(value));
}
/**
* Converts a sortable <code>long</code> back to a <code>double</code>.
* @param value input double value
* @return output sortable long value
* @see #doubleToSortableLong
*/
public static double sortableLongToDouble(long value) {
return Double.longBitsToDouble(sortableDoubleBits(value));
}
/**
* Converts a <code>float</code> value to a sortable signed
* <code>int</code>. The value is converted by getting their IEEE 754
* floating-point &quot;float format&quot; bit layout and then some bits are
* swapped, to be able to compare the result as int. By this the precision
* is not reduced, but the value can be easily used as an int. The sort order
* (including {@link Float#NaN}) is defined by {@link Float#compareTo};
* {@code NaN} is greater than positive infinity.
* @param value input float value
* @return output sortable int value
* @see #sortableIntToFloat
*/
public static int floatToSortableInt(float value) {
return sortableFloatBits(Float.floatToIntBits(value));
}
/**
* Converts a sortable <code>int</code> back to a <code>float</code>.
* @param value input int value
* @return output sortable float value
* @see #floatToSortableInt
*/
public static float sortableIntToFloat(int value) {
return Float.intBitsToFloat(sortableFloatBits(value));
}
/**
* Converts IEEE 754 representation of a double to sortable order (or back
* to the original)
* @param bits The long format of a double value
* @return The sortable long value
*/
public static long sortableDoubleBits(long bits) {
return bits ^ ((bits >> 63) & 0x7fffffffffffffffL);
}
/**
* Converts IEEE 754 representation of a float to sortable order (or back to
* the original)
* @param bits The int format of a float value
* @return The sortable int value
*/
public static int sortableFloatBits(int bits) {
/*
* Convert to its inverse digits if negative else keep the origin
* NOTE: (bits >> 31) is 0x00000000 if bits >= 0
* (bits >> 31) is 0xFFFFFFFF if bits < 0
*/
return bits ^ ((bits >> 31) & 0x7fffffff);
}
public static long numberToSortableLong(Number number) {
if (number instanceof Double) {
return doubleToSortableLong(number.doubleValue());
} else if (number instanceof Float) {
return floatToSortableInt(number.floatValue());
} else if (number instanceof Long || number instanceof Integer ||
number instanceof Short || number instanceof Byte) {
return number.longValue();
} else if (number instanceof BigDecimal) {
BigDecimal bd = (BigDecimal) number;
boolean intNumber = bd.stripTrailingZeros().scale() <= 0;
return intNumber ? bd.longValueExact() :
doubleToSortableLong(bd.doubleValue());
}
// TODO: support other number types
throw unsupportedNumberType(number);
}
public static Number sortableLongToNumber(long value, Class<?> clazz) {
assert NumericUtil.isNumber(clazz);
if (clazz == Double.class) {
return sortableLongToDouble(value);
} else if (clazz == Float.class) {
return sortableIntToFloat((int) value);
} else if (clazz == Long.class) {
return value;
} else if (clazz == Integer.class) {
return (int) value;
} else if (clazz == Short.class) {
return (short) value;
} else if (clazz == Byte.class) {
return (byte) value;
}
// TODO: support other number types
throw unsupportedNumberType(clazz);
}
public static byte[] numberToSortableBytes(Number number) {
if (number instanceof Long) {
return longToSortableBytes(number.longValue());
} else if (number instanceof Double) {
long value = doubleToSortableLong(number.doubleValue());
return longToSortableBytes(value);
} else if (number instanceof Float) {
int value = floatToSortableInt(number.floatValue());
return intToSortableBytes(value);
} else if (number instanceof Integer || number instanceof Short) {
return intToSortableBytes(number.intValue());
} else if (number instanceof Byte) {
return byteToSortableBytes(number.byteValue());
}
// TODO: support other number types
throw unsupportedNumberType(number);
}
public static Number sortableBytesToNumber(byte[] bytes, Class<?> clazz) {
assert NumericUtil.isNumber(clazz);
if (clazz == Long.class) {
return sortableBytesToLong(bytes);
} else if (clazz == Double.class) {
return sortableLongToDouble(sortableBytesToLong(bytes));
} else if (clazz == Float.class) {
return sortableIntToFloat(sortableBytesToInt(bytes));
} else if (clazz == Integer.class) {
return sortableBytesToInt(bytes);
} else if (clazz == Short.class) {
return (short) sortableBytesToInt(bytes);
} else if (clazz == Byte.class) {
return sortableBytesToByte(bytes);
}
// TODO: support other number types
throw unsupportedNumberType(clazz);
}
public static Number minValueOf(Class<?> clazz) {
E.checkArgumentNotNull(clazz, "The clazz can't be null");
if (Long.class.isAssignableFrom(clazz) ||
Double.class.isAssignableFrom(clazz)) {
return Long.MIN_VALUE;
}
if (Integer.class.isAssignableFrom(clazz) ||
Short.class.isAssignableFrom(clazz) ||
Float.class.isAssignableFrom(clazz)) {
return Integer.MIN_VALUE;
}
if (Byte.class.isAssignableFrom(clazz)) {
return Byte.MIN_VALUE;
}
// TODO: support other number types
throw unsupportedNumberType(clazz);
}
public static Number maxValueOf(Class<?> clazz) {
E.checkArgumentNotNull(clazz, "The clazz can't be null");
if (Long.class.isAssignableFrom(clazz) ||
Double.class.isAssignableFrom(clazz)) {
return Long.MAX_VALUE;
}
if (Integer.class.isAssignableFrom(clazz) ||
Float.class.isAssignableFrom(clazz) ||
Short.class.isAssignableFrom(clazz)) {
return Integer.MAX_VALUE;
}
if (Byte.class.isAssignableFrom(clazz)) {
return Byte.MAX_VALUE;
}
// TODO: support other number types
throw unsupportedNumberType(clazz);
}
public static byte[] longToSortableBytes(long value) {
return longToBytes(value + FULL_LONG);
}
public static long sortableBytesToLong(byte[] bytes) {
return bytesToLong(bytes) - FULL_LONG;
}
public static byte[] intToSortableBytes(int value) {
return intToBytes(value + FULL_INT);
}
public static int sortableBytesToInt(byte[] bytes) {
return bytesToInt(bytes) - FULL_INT;
}
public static byte[] byteToSortableBytes(byte value) {
value += FULL_BYTE;
return new byte[]{value};
}
public static byte sortableBytesToByte(byte[] bytes) {
assert bytes.length == 1;
byte value = bytes[0];
value -= FULL_BYTE;
return value;
}
public static byte[] longToBytes(long value) {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.putLong(value);
return buffer.array();
}
public static long bytesToLong(byte[] bytes) {
assert bytes.length == Long.BYTES;
return ByteBuffer.wrap(bytes).getLong();
}
public static byte[] intToBytes(int value) {
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.putInt(value);
return buffer.array();
}
public static int bytesToInt(byte[] bytes) {
assert bytes.length == Integer.BYTES;
return ByteBuffer.wrap(bytes).getInt();
}
public static boolean isNumber(Object value) {
if (value == null) {
return false;
}
return isNumber(value.getClass());
}
public static boolean isNumber(Class<?> clazz) {
if (clazz.isPrimitive()) {
return clazz == int.class || clazz == long.class ||
clazz == float.class || clazz == double.class ||
clazz == short.class || clazz == byte.class;
}
return Number.class.isAssignableFrom(clazz);
}
public static Number convertToNumber(Object value) {
if (value == null) {
return null;
}
Number number;
if (isNumber(value)) {
number = (Number) value;
} else {
if (value instanceof Date) {
number = ((Date) value).getTime();
} else {
// TODO: add some more types to convert
number = new BigDecimal(value.toString());
}
}
return number;
}
/**
* Compare object with a number, the object should be a number,
* or it can be converted to a BigDecimal
* @param first might be number or string
* @param second must be number
* @return 0 if first is numerically equal to second;
* a negative int if first is numerically less than second;
* a positive int if first is numerically greater than second.
*/
public static int compareNumber(Object first, Number second) {
if (first == null) {
E.checkArgument(first != null,
"The first parameter can't be null");
}
if (second == null) {
E.checkArgument(second != null,
"The second parameter can't be null");
}
if (first instanceof Number && first instanceof Comparable &&
first.getClass().equals(second.getClass())) {
@SuppressWarnings("unchecked")
Comparable<Number> cmpFirst = (Comparable<Number>) first;
return cmpFirst.compareTo(second);
}
Function<Object, BigDecimal> toBig = (number) -> {
try {
return new BigDecimal(number.toString());
} catch (NumberFormatException e) {
throw new IllegalArgumentException(String.format(
"Can't compare between '%s' and '%s', " +
"they must be numbers", first, second));
}
};
BigDecimal n1 = toBig.apply(first);
BigDecimal n2 = toBig.apply(second);
return n1.compareTo(n2);
}
private static IllegalArgumentException unsupportedNumberType(Class<?> c) {
return new IllegalArgumentException(String.format(
"Unsupported number type: %s", c.getSimpleName()));
}
private static IllegalArgumentException unsupportedNumberType(Number num) {
return new IllegalArgumentException(String.format(
"Unsupported number type: %s(%s)",
num.getClass().getSimpleName(), num));
}
}

View File

@ -0,0 +1,103 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.base.Functions;
import com.google.common.collect.Ordering;
public class OrderLimitMap<K extends Comparable<K>, V extends Comparable<V>> extends TreeMap<K, V> {
private static final long serialVersionUID = 756490437953358633L;
private final int capacity;
private final Map<K, V> valueMap;
private static <V extends Comparable<V>> Ordering<? super V> incr() {
return Ordering.from(Comparable::compareTo);
}
private static <V extends Comparable<V>> Ordering<? super V> decr() {
return Ordering.from((V o1, V o2) -> -o1.compareTo(o2));
}
public OrderLimitMap(int capacity) {
this(capacity, false);
}
public OrderLimitMap(int capacity, boolean incr) {
this(capacity, incr ? incr() : decr(), new HashMap<>());
}
private OrderLimitMap(int capacity, Ordering<? super V> ordering,
HashMap<K, V> valueMap) {
/*
* onResultOf: for getting the value for the key from value map
* compound: keep insertion order
*/
super(ordering.onResultOf(Functions.forMap(valueMap))
.compound(Ordering.natural()));
E.checkArgument(capacity > 0, "The capacity must be > 0");
this.capacity = capacity;
this.valueMap = valueMap;
}
@Override
public V put(K k, V v) {
if (this.valueMap.containsKey(k)) {
super.remove(k);
} else if (this.valueMap.size() >= this.capacity) {
K key = super.lastKey();
super.remove(key);
this.valueMap.remove(key);
}
this.valueMap.put(k, v);
return super.put(k, v);
}
@Override
public V get(Object key) {
return this.valueMap.get(key);
}
@Override
public V getOrDefault(Object key, V defaultValue) {
return this.valueMap.getOrDefault(key, defaultValue);
}
@Override
public boolean containsKey(Object key) {
return this.valueMap.containsKey(key);
}
public Map<K, V> topN(int n) {
E.checkArgument(n > 0, "'N' Must be positive, but got '%s'", n);
Map<K, V> top = InsertionOrderUtil.newMap();
int i = 0;
for (Map.Entry<K, V> entry : this.entrySet()) {
top.put(entry.getKey(), entry.getValue());
if (++i >= n) {
break;
}
}
return top;
}
}

View File

@ -0,0 +1,124 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.hugegraph.iterator.ExtendableIterator;
import com.google.common.collect.Lists;
import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
public final class ReflectionUtil {
public static boolean isSimpleType(Class<?> type) {
return type.isPrimitive() ||
type.equals(String.class) ||
type.equals(Boolean.class) ||
type.equals(Character.class) ||
NumericUtil.isNumber(type);
}
public static List<Method> getMethodsAnnotatedWith(
Class<?> type,
Class<? extends Annotation> annotation,
boolean withSuperClass) {
final List<Method> methods = new LinkedList<>();
Class<?> klass = type;
do {
for (Method method : klass.getDeclaredMethods()) {
if (method.isAnnotationPresent(annotation)) {
methods.add(method);
}
}
klass = klass.getSuperclass();
} while (klass != Object.class && withSuperClass);
return methods;
}
public static List<CtMethod> getMethodsAnnotatedWith(
CtClass type,
Class<? extends Annotation> annotation,
boolean withSuperClass)
throws NotFoundException {
final List<CtMethod> methods = new LinkedList<>();
CtClass klass = type;
do {
for (CtMethod method : klass.getDeclaredMethods()) {
if (method.hasAnnotation(annotation)) {
methods.add(method);
}
}
klass = klass.getSuperclass();
} while (klass != null && withSuperClass);
return methods;
}
public static Iterator<ClassInfo> classes(String... packages)
throws IOException {
ClassPath path = ClassPath.from(ReflectionUtil.class.getClassLoader());
ExtendableIterator<ClassInfo> results = new ExtendableIterator<>();
for (String p : packages) {
results.extend(path.getTopLevelClassesRecursive(p).iterator());
}
return results;
}
public static List<String> superClasses(String clazz)
throws NotFoundException {
CtClass klass = ClassPool.getDefault().get(clazz);
CtClass parent = klass.getSuperclass();
List<String> results = new LinkedList<>();
while (parent != null) {
results.add(parent.getName());
parent = parent.getSuperclass();
}
return Lists.reverse(results);
}
public static List<String> nestedClasses(String clazz)
throws NotFoundException {
CtClass klass = ClassPool.getDefault().get(clazz);
List<String> results = new LinkedList<>();
for (CtClass nested : klass.getNestedClasses()) {
results.add(nested.getName());
}
return results;
}
public static String packageName(String clazz) {
int offset = clazz.lastIndexOf(".");
if (offset > 0) {
return clazz.substring(0, offset);
}
return "";
}
}

View File

@ -0,0 +1,123 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
public final class StringUtil {
public static Chars[] splitToCharsArray(String text, String delimiter) {
E.checkArgument(delimiter.length() > 0,
"The delimiter can't be empty");
Chars[] buffer = new Chars[text.length()];
int count = Chars.split(text, delimiter, buffer);
if (count == buffer.length) {
return buffer;
}
Chars[] result = new Chars[count];
System.arraycopy(buffer, 0, result, 0, count);
return result;
}
public static String[] split(String text, String delimiter) {
E.checkArgument(delimiter.length() > 0,
"The delimiter can't be empty");
Chars[] buffer = new Chars[text.length()];
int count = Chars.split(text, delimiter, buffer);
String[] result = new String[count];
for (int i = 0; i < count; i++) {
result[i] = buffer[i].toString();
}
return result;
}
public static class Chars implements CharSequence {
private final char[] chars;
private final int start;
private final int end;
public Chars(char[] chars, int start, int end) {
E.checkArgument(0 < start && start < chars.length || start == 0,
"Invalid start parameter %s", start);
E.checkArgument(start <= end && end <= chars.length,
"Invalid end parameter %s", end);
this.chars = chars;
this.start = start;
this.end = end;
}
@Override
public int length() {
return this.end - this.start;
}
@Override
public char charAt(int index) {
return this.chars[this.start + index];
}
@Override
public CharSequence subSequence(int start, int end) {
return new Chars(this.chars, this.start + start, this.start + end);
}
@Override
public boolean equals(Object object) {
if (!(object instanceof Chars)) {
return false;
}
Chars other = (Chars) object;
return this.toString().equals(other.toString());
}
@Override
public int hashCode() {
return this.toString().hashCode();
}
@Override
public String toString() {
return new String(this.chars, this.start, this.length());
}
public static Chars of(String string) {
return new Chars(string.toCharArray(), 0, string.length());
}
public static Chars[] of(String... strings) {
Chars[] results = new Chars[strings.length];
for (int i = 0; i < strings.length; i++) {
results[i] = Chars.of(strings[i]);
}
return results;
}
public static int split(String text, String delimiter, Chars[] buffer) {
int count = 0;
int from = 0;
char[] chars = text.toCharArray();
for (int to; (to = text.indexOf(delimiter, from)) >= 0;
from = to + delimiter.length()) {
buffer[count++] = new Chars(chars, from, to);
}
if (from < text.length()) {
buffer[count++] = new Chars(chars, from, text.length());
}
return count;
}
}
}

View File

@ -0,0 +1,59 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.time.Duration;
import java.util.Date;
public final class TimeUtil {
@SuppressWarnings("deprecation")
public static long BASE_TIME = new Date(2017 - 1900, 10, 28).getTime();
public static long timeGen() {
return System.currentTimeMillis() - BASE_TIME;
}
public static long timeGen(Date date) {
return date.getTime() - BASE_TIME;
}
public static long timeGen(long time) {
return time - BASE_TIME;
}
public static long tillNextMillis(long lastTimestamp) {
long timestamp = timeGen();
while (timestamp <= lastTimestamp) {
timestamp = timeGen();
}
return timestamp;
}
public static String readableTime(long time) {
if (time > 60 * 1000) {
// Remove the milliseconds part
time = time / 1000 * 1000;
}
Duration duration = Duration.ofMillis(time);
return duration.toString()
.substring(2)
.replaceAll("(\\d[HMS])(?!$)", "$1 ")
.toLowerCase();
}
}

View File

@ -0,0 +1,181 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
public final class UnitUtil {
public static double bytesToMB(long bytes) {
return doubleWith2Scale(bytes / (double) Bytes.MB);
}
public static double bytesToGB(long bytes) {
return doubleWith2Scale(bytes / (double) Bytes.GB);
}
public static double doubleWith2Scale(double value) {
BigDecimal decimal = new BigDecimal(value);
return decimal.setScale(2, RoundingMode.HALF_UP).doubleValue();
}
public static String bytesToReadableString(long bytes) {
// NOTE: FileUtils.byteCountToDisplaySize() lost decimal precision
final String[] units = {"B", "KB", "MB", "GB", "TB", "PB", "EB"};
if (bytes <= 0L) {
return "0 B";
}
int i = (int) (Math.log(bytes) / Math.log(1024));
E.checkArgument(i < units.length,
"The bytes parameter is out of %s unit: %s",
units[units.length - 1], bytes);
double value = bytes / Math.pow(1024, i);
if (value % 1L == 0L) {
return ((long) value) + " " + units[i];
} else {
return doubleWith2Scale(value) + " " + units[i];
}
}
public static long bytesFromReadableString(String valueWithUnit) {
int spacePos = valueWithUnit.indexOf(" ");
E.checkArgument(spacePos >= 0,
"Invalid readable bytes '%s', " +
"expect format like '10 MB'", valueWithUnit);
String unit = valueWithUnit.substring(spacePos + 1);
long factor;
switch (unit.trim().toUpperCase()) {
case "B":
case "BYTE":
case "BYTES":
factor = 1L;
break;
case "KB":
case "KIB":
factor = Bytes.KB;
break;
case "MB":
case "MIB":
factor = Bytes.MB;
break;
case "GB":
case "GIB":
factor = Bytes.GB;
break;
case "TB":
case "TIB":
factor = Bytes.TB;
break;
case "PB":
case "PIB":
factor = Bytes.PB;
break;
case "EB":
case "EIB":
factor = Bytes.EB;
break;
default:
throw new IllegalArgumentException("Unrecognized unit " + unit);
}
double value;
try {
value = Double.parseDouble(valueWithUnit.substring(0, spacePos));
} catch (Exception e) {
throw new IllegalArgumentException(String.format(
"Invalid parameter(not number): '%s'", valueWithUnit), e);
}
value = value * factor;
E.checkArgument(value <= Long.MAX_VALUE,
"The value %s from parameter '%s' is out of range",
value, valueWithUnit);
return (long) value;
}
public static String timestampToReadableString(long time) {
Duration duration = Duration.ofMillis(time);
long days = duration.toDays();
long hours = duration.toHours();
long minutes = duration.toMinutes();
long seconds = duration.getSeconds();
if (days > 0) {
return String.format("%dd%dh%dm%ds",
days,
hours % 24,
minutes % 60,
seconds % 60);
} else if (hours > 0) {
return String.format("%dh%dm%ds",
hours,
minutes % 60,
seconds % 60);
} else if (minutes > 0) {
return String.format("%dm%ds",
minutes,
seconds % 60);
} else if (seconds > 0) {
long ms = duration.toMillis() % 1000L;
if (ms > 0L) {
return String.format("%ds%dms", seconds, ms);
} else {
return String.format("%ds", seconds);
}
} else {
return String.format("%dms", duration.toMillis());
}
}
public static long timestampFromReadableString(String valueWithUnit) {
long ms = 0L;
// Adapt format 'nDnHnMnS' to 'PnYnMnDTnHnMnS'
String formatDuration = valueWithUnit.toUpperCase();
if (formatDuration.indexOf('D') >= 0) {
// Contains days
assert !formatDuration.contains("MS");
formatDuration = "P" + formatDuration.replace("D", "DT");
} else {
// Not exists days
int msPos = formatDuration.indexOf("MS");
// If contains ms, remove the ms part
if (msPos >= 0) {
int sPos = formatDuration.indexOf("S");
if (0 <= sPos && sPos < msPos) {
// If contains second part
sPos += 1;
ms = Long.parseLong(formatDuration.substring(sPos, msPos));
ms %= 1000L;
formatDuration = formatDuration.substring(0, sPos);
} else {
// Not contains second part, only exists ms
ms = Long.parseLong(formatDuration.substring(0, msPos));
return ms;
}
} else {
assert formatDuration.endsWith("S");
}
formatDuration = "PT" + formatDuration;
}
Duration duration = Duration.parse(formatDuration);
return duration.toMillis() + ms;
}
}

View File

@ -0,0 +1,236 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Objects;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
public final class VersionUtil {
/**
* Compare if a version is inside a range [begin, end)
* @param version The version to be compared
* @param begin The lower bound of the range
* @param end The upper bound of the range
* @return true if belong to the range, otherwise false
*/
public static boolean match(Version version, String begin, String end) {
E.checkArgumentNotNull(version, "The version to match is null");
return version.compareTo(new Version(begin)) >= 0 &&
version.compareTo(new Version(end)) < 0;
}
/**
* Compare if a version is greater than the other one (inclusive)
* @param version The version to be compared
* @param other The lower bound of the range
* @return true if it's greater than the other, otherwise false
*/
public static boolean gte(String version, String other) {
E.checkArgumentNotNull(version, "The version to match is null");
return new Version(version).compareTo(new Version(other)) >= 0;
}
/**
* Check whether a component version is matched expected range,
* throw an exception if it's not matched.
* @param version The version to be checked
* @param begin The lower bound of the range
* @param end The upper bound of the range
* @param component The owner component of version
*/
public static void check(Version version, String begin, String end,
String component) {
E.checkState(VersionUtil.match(version, begin, end),
"The version %s of '%s' is not in [%s, %s)",
version, component, begin, end);
}
/**
* Get implementation version from manifest in jar
* @param clazz The class to be load from jar package
* @return The implementation version
*/
public static String getImplementationVersion(Class<?> clazz) {
/*
* We don't use Package.getImplementationVersion() due to
* a duplicate package would override the origin package info.
*/
String className = clazz.getSimpleName() + ".class";
String classPath = Objects.requireNonNull(clazz.getResource(className)).toString();
if (!classPath.startsWith("jar:file:")) {
// Class not from JAR
return null;
}
int offset = classPath.lastIndexOf("!");
assert offset > 0;
// Get manifest file path
String manifestPath = classPath.substring(0, offset + 1);
return getImplementationVersion(manifestPath);
}
public static String getImplementationVersion(String manifestPath) {
manifestPath += "/META-INF/MANIFEST.MF";
Manifest manifest;
try {
manifest = new Manifest(new URL(manifestPath).openStream());
} catch (IOException ignored) {
return null;
}
return manifest.getMainAttributes()
.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
}
/**
* Get version from pom.xml
* @return The pom version
*/
public static String getPomVersion() {
String cmd = "mvn help:evaluate -Dexpression=project.version " +
"-q -DforceStdout";
Process process = null;
InputStreamReader isr = null;
try {
process = Runtime.getRuntime().exec(cmd);
process.waitFor();
isr = new InputStreamReader(process.getInputStream());
BufferedReader br = new BufferedReader(isr);
return br.readLine();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (isr != null) {
try {
isr.close();
} catch (Exception ignored) {
// pass
}
}
// Destroy child process
if (process != null) {
process.destroy();
}
}
}
public static class Version implements Comparable<Version> {
public static Version of(Class<?> clazz) {
return Version.of(clazz, null);
}
public static Version of(Class<?> clazz, String defaultValue) {
String v = getImplementationVersion(clazz);
if (v == null) {
v = defaultValue;
}
return v == null ? null : new Version(v);
}
public static Version of(String version) {
return new Version(version);
}
/************************** Version define **************************/
private final String version;
private final int[] parts;
public Version(String version) {
E.checkArgumentNotNull(version, "The version is null");
E.checkArgument(version.matches("[0-9]+(\\.[0-9]+)*"),
"Invalid version format: %s", version);
this.version = version;
this.parts = parseVersion(version);
}
private static int[] parseVersion(String version) {
String[] parts = version.split("\\.");
int[] partsNumber = new int[parts.length];
for (int i = 0; i < parts.length; i++) {
partsNumber[i] = Integer.parseInt(parts[i]);
}
return partsNumber;
}
public final String get() {
return this.version;
}
@Override
public int compareTo(Version that) {
if (that == null) {
return 1;
}
int[] thisParts = this.parts;
int[] thatParts = that.parts;
int length = Math.max(thisParts.length, thatParts.length);
for (int i = 0; i < length; i++) {
int thisPart = i < thisParts.length ? thisParts[i] : 0;
int thatPart = i < thatParts.length ? thatParts[i] : 0;
if (thisPart < thatPart) {
return -1;
}
if (thisPart > thatPart) {
return 1;
}
}
return 0;
}
@Override
public boolean equals(Object that) {
if (this == that) {
return true;
}
if (that == null) {
return false;
}
if (this.getClass() != that.getClass()) {
return false;
}
return this.compareTo((Version) that) == 0;
}
@Override
public int hashCode() {
int hash = 0;
for (int i = this.parts.length - 1; i >= 0; i--) {
int part = this.parts[i];
if (part == 0 && hash == 0) {
continue;
}
hash = 31 * hash + Integer.hashCode(part);
}
return hash;
}
@Override
public String toString() {
return this.version;
}
}
}

View File

@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.version;
import org.apache.hugegraph.util.VersionUtil.Version;
public class CommonVersion {
public static final String NAME = "hugegraph-common";
// The second parameter of Version.of() is for all-in-one JAR
public static final Version VERSION = Version.of(CommonVersion.class, "1.5.0");
}

View File

@ -0,0 +1,444 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.testutil;
import org.apache.hugegraph.unit.BaseUnitTest;
import org.junit.Test;
public class AssertTest extends BaseUnitTest {
@Test
public void testAssertEquals() {
Assert.assertEquals((byte) 1, Byte.valueOf("1"));
Assert.assertEquals((short) 1, Short.valueOf("1"));
Assert.assertEquals('1', Character.valueOf('1'));
Assert.assertEquals(1, Integer.valueOf("1"));
Assert.assertEquals(1L, Long.valueOf("1"));
Assert.assertEquals(1f, Float.valueOf("1"));
Assert.assertEquals(1d, Double.valueOf("1"));
}
@Test
public void testAssertEqualsWithError() {
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals((byte) 1, "1");
}, e -> {
Assert.assertContains("expected: java.lang.Byte",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals((short) 1, "1");
}, e -> {
Assert.assertContains("expected: java.lang.Short",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals('1', "1");
}, e -> {
Assert.assertContains("expected: java.lang.Character",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, "1");
}, e -> {
Assert.assertContains("expected: java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1L, "1");
}, e -> {
Assert.assertContains("expected: java.lang.Long",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1f, "1.0");
}, e -> {
Assert.assertContains("expected: java.lang.Float",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1d, "1.0");
}, e -> {
Assert.assertContains("expected: java.lang.Double",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1f, "1");
}, e -> {
Assert.assertContains("expected:<1.0> but was:<1>",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1d, "1");
}, e -> {
Assert.assertContains("expected:<1.0> but was:<1>",
e.getMessage());
});
}
@Test
public void testAssertEqualsOfIntWithError() {
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, (Byte) (byte) 1);
}, e -> {
Assert.assertContains("expected: java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, (Short) (short) 1);
}, e -> {
Assert.assertContains("expected: java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, (Character) '1');
}, e -> {
Assert.assertContains("expected: java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, (Long) 1L);
}, e -> {
Assert.assertContains("expected: java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, (Float) 1f);
}, e -> {
Assert.assertContains("expected:<1> but was:<1.0>",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, (Double) 1d);
}, e -> {
Assert.assertContains("expected:<1> but was:<1.0>",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, "1.0");
}, e -> {
Assert.assertContains("expected:<1> but was:<1.0>",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, (Byte) (byte) 2);
}, e -> {
Assert.assertContains("expected:<1> but was:<2>",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertEquals(1, null);
}, e -> {
Assert.assertContains("expected:<1> but was:<null>",
e.getMessage());
});
}
@Test
public void testAssertThrows() {
Assert.assertThrows(NullPointerException.class, () -> {
throw new NullPointerException();
});
Assert.assertThrows(RuntimeException.class, () -> {
throw new RuntimeException();
});
Throwable exception = Assert.assertThrows(RuntimeException.class, () -> {
throw new RuntimeException("fake-error");
});
Assert.assertInstanceOf(RuntimeException.class, exception);
Assert.assertEquals("fake-error", exception.getMessage());
Assert.assertThrows(RuntimeException.class, () -> {
throw new RuntimeException("fake-error");
}, e -> {
Assert.assertEquals("fake-error", e.getMessage());
});
}
@Test
public void testAssertThrowsWithTypeError() {
try {
Assert.assertThrows(NullPointerException.class, () -> {
// pass
});
Assert.fail("Expect error");
} catch (AssertionError e) {
Assert.assertContains("java.lang.NullPointerException", e.getMessage());
}
try {
Assert.assertThrows(NullPointerException.class, () -> {
throw new RuntimeException();
});
Assert.fail("Expect error");
} catch (AssertionError e) {
Assert.assertContains("java.lang.NullPointerException", e.getMessage());
Assert.assertContains("java.lang.RuntimeException", e.getMessage());
}
}
@Test
public void testAssertThrowsWithMessageError() {
try {
Assert.assertThrows(RuntimeException.class, () -> {
throw new RuntimeException("fake-error");
}, e -> {
Assert.assertEquals("fake-error-typo", e.getMessage());
});
Assert.fail("Expect error");
} catch (AssertionError e) {
Assert.assertContains("expected:<fake-error[-typo]> but was:<fake-error[]>",
e.getMessage());
}
}
@Test
public void testAssertGt() {
Assert.assertGt((byte) 1, Byte.valueOf("2"));
Assert.assertGt((short) 1, Short.valueOf("2"));
Assert.assertGt(1, Integer.valueOf("2"));
Assert.assertGt(1L, Long.valueOf("2"));
Assert.assertGt(1f, Float.valueOf("1.01"));
Assert.assertGt(1d, Double.valueOf("1.01"));
Assert.assertGt((byte) 1, (byte) 2);
Assert.assertGt((short) 1, (short) 2);
Assert.assertGt(1, 2);
Assert.assertGt(1L, 2L);
Assert.assertGt(1f, 1.01f);
Assert.assertGt(1d, 1.01d);
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(1, 0);
}, e -> {
Assert.assertContains("Expected: a number > 1", e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(1, null);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(1, (byte) 2);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(1, 1.1);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(1, '2');
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(0.9, 1);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Double",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(0.9d, 0.98f);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Double",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(0.9f, 0.98d);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Float",
e.getMessage());
});
}
@Test
public void testAssertGte() {
Assert.assertGte((byte) 1, Byte.valueOf("2"));
Assert.assertGte((short) 1, Short.valueOf("2"));
Assert.assertGte(1, Integer.valueOf("2"));
Assert.assertGte(1L, Long.valueOf("2"));
Assert.assertGte(1f, Float.valueOf("1.01"));
Assert.assertGte(1d, Double.valueOf("1.01"));
Assert.assertGte((byte) 1, Byte.valueOf("1"));
Assert.assertGte((short) 1, Short.valueOf("1"));
Assert.assertGte(1, Integer.valueOf("1"));
Assert.assertGte(1L, Long.valueOf("1"));
Assert.assertGte(1f, Float.valueOf("1"));
Assert.assertGte(1d, Double.valueOf("1"));
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGte(1, 0);
}, e -> {
Assert.assertContains("Expected: a number >= 1", e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGte(1, 1.1);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGte(1, '2');
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
}
@Test
public void testAssertLt() {
Assert.assertLt((byte) 1, Byte.valueOf("0"));
Assert.assertLt((short) 1, Short.valueOf("0"));
Assert.assertLt(1, Integer.valueOf("0"));
Assert.assertLt(1L, Long.valueOf("0"));
Assert.assertLt(1f, Float.valueOf("0.99"));
Assert.assertLt(1d, Double.valueOf("0.99"));
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertLt(1, 2);
}, e -> {
Assert.assertContains("Expected: a number < 1", e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(1, 0.9);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertGt(1, '0');
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
}
@Test
public void testAssertLte() {
Assert.assertLte((byte) 1, Byte.valueOf("0"));
Assert.assertLte((short) 1, Short.valueOf("0"));
Assert.assertLte(1, Integer.valueOf("0"));
Assert.assertLte(1L, Long.valueOf("0"));
Assert.assertLte(1f, Float.valueOf("0.99"));
Assert.assertLte(1d, Double.valueOf("0.99"));
Assert.assertLte((byte) 1, Byte.valueOf("1"));
Assert.assertLte((short) 1, Short.valueOf("1"));
Assert.assertLte(1, Integer.valueOf("1"));
Assert.assertLte(1L, Long.valueOf("1"));
Assert.assertLte(1f, Float.valueOf("1"));
Assert.assertLte(1d, Double.valueOf("1"));
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertLte(1, 2);
}, e -> {
Assert.assertContains("Expected: a number <= 1", e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertLte(1, 0.9);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertLte(1, '0');
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Integer",
e.getMessage());
});
}
@Test
public void testAssertContains() {
Assert.assertContains("test", "test");
Assert.assertContains("test", "hellotest");
Assert.assertContains("test", "test123");
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertContains("test123", "test");
}, e -> {
Assert.assertContains("Expected: a string containing",
e.getMessage());
});
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertContains("null", null);
}, e -> {
Assert.assertContains("Expected: a string containing",
e.getMessage());
});
Assert.assertThrows(NullPointerException.class, () -> {
Assert.assertContains(null, "null");
}, e -> {
Assert.assertNull(e.getMessage());
});
}
@Test
public void testAssertInstanceOf() {
Assert.assertInstanceOf(Integer.class, 1);
Assert.assertInstanceOf(Double.class, 1.0);
Assert.assertInstanceOf(String.class, "1.0");
Assert.assertInstanceOf(BaseUnitTest.class, this);
Assert.assertThrows(AssertionError.class, () -> {
Assert.assertInstanceOf(Float.class, 1);
}, e -> {
Assert.assertContains("Expected: an instance of java.lang.Float",
e.getMessage());
});
}
}

View File

@ -0,0 +1,258 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.testutil;
import org.junit.Test;
public class WhiteboxTest {
@Test
public void testGetStaticInternalState() {
Assert.assertEquals(1, Whitebox.getInternalState(Test1.class,
"staticValue"));
Test1 test1 = newTest();
Assert.assertEquals(1, Whitebox.getInternalState(test1, "staticValue"));
Assert.assertEquals(2, Whitebox.getInternalState(test1,
"test2.staticValue"));
}
@Test
public void testSetStaticInternalState() {
try {
Whitebox.setInternalState(Test1.class, "staticValue", 11);
Assert.assertEquals(11, Test1.staticValue);
Test1 test1 = newTest();
Whitebox.setInternalState(test1, "staticValue", 111);
Assert.assertEquals(111, Test1.staticValue);
Whitebox.setInternalState(test1, "test2.staticValue", 22);
Assert.assertEquals(22, Test2.staticValue);
} finally {
Whitebox.setInternalState(Test1.class, "staticValue", 1);
Whitebox.setInternalState(Test2.class, "staticValue", 2);
}
}
@Test
public void testGetInternalState() {
Test1 test1 = newTest();
Assert.assertEquals(1, Whitebox.getInternalState(test1, "ivalue"));
Assert.assertEquals(2f, Whitebox.getInternalState(test1,
"test2.finalValue"));
Assert.assertEquals("3", Whitebox.getInternalState(test1,
"test2.test3.str"));
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.getInternalState(test1, "ivalue2");
});
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.getInternalState(test1, "test2.valueNotExist");
});
}
@Test
public void testSetInternalState() {
Test1 test1 = newTest();
Whitebox.setInternalState(test1, "ivalue", 11);
Assert.assertEquals(11, Whitebox.getInternalState(test1, "ivalue"));
Assert.assertEquals(11, test1.ivalue);
Whitebox.setInternalState(test1, "test2.finalValue", 22f);
Assert.assertEquals(22f, Whitebox.getInternalState(test1,
"test2.finalValue"));
Whitebox.setInternalState(test1, "test2.test3.str", "33");
Assert.assertEquals("33", Whitebox.getInternalState(test1,
"test2.test3.str"));
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.setInternalState(test1, "ivalue2", 11);
});
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.setInternalState(test1, "test2.valueNotExist", 22f);
});
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.setInternalState(test1, "test2.finalValue", 22d);
});
Assert.assertThrows(RuntimeException.class, () -> {
test1.test2 = null;
Whitebox.setInternalState(test1, "test2.finalValue", 22f);
}, e -> {
Assert.assertContains("Can't set value on null field",
e.getMessage());
});
}
@Test
public void testSetInternalFinalState() {
Test1 test1 = newTest();
Assert.assertEquals(1, test1.finalValue);
Whitebox.setInternalState(test1, "finalValue", 2);
Assert.assertEquals(2, Whitebox.getInternalState(test1, "finalValue"));
Whitebox.setInternalState(test1, "finalValue", 3);
Assert.assertEquals(3, Whitebox.getInternalState(test1, "finalValue"));
Whitebox.setInternalState(test1, "test2.finalValue", 22f);
Assert.assertEquals(22f, Whitebox.getInternalState(test1,
"test2.finalValue"));
// FIXME: seems don't take effect!!!
Assert.assertEquals(1, test1.finalValue);
Assert.assertEquals(2f, test1.test2.finalValue, 0f);
}
@Test
public void testInvokeStatic() {
Assert.assertEquals(1, Whitebox.invokeStatic(Test1.class, "svalue"));
Assert.assertEquals(2, Whitebox.invokeStatic(Test1.class, "svalue", 2));
Assert.assertEquals(2, Whitebox.invokeStatic(Test1.class, "svalue",
new Integer(2)));
Assert.assertEquals(2d, Whitebox.invokeStatic(Test1.class,
new Class[]{Object.class},
"svalue", 2d));
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.invokeStatic(Test1.class, "svalue2");
});
Assert.assertThrows(IllegalArgumentException.class, () -> {
Whitebox.invokeStatic(Test1.class, "throwfunc1");
});
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.invokeStatic(Test1.class, "throwfunc2");
});
}
@Test
public void testInvoke() {
Test1 test1 = newTest();
Assert.assertEquals(1, Whitebox.invoke(test1.getClass(),
"value", test1));
Assert.assertEquals(3, Whitebox.invoke(test1.getClass(),
"addValue", test1, 2));
Assert.assertEquals(2f, Whitebox.invoke(test1, "test2", "value"));
Assert.assertEquals(2, Whitebox.invoke(test1, "test2",
new Class[]{Object.class},
"value", 2));
Assert.assertEquals(3, Whitebox.invoke(test1, "test4", "addValue", 2));
Assert.assertEquals(4, Whitebox.invoke(test1, "test4", "value"));
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.invoke(test1.getClass(), "value2", test1);
});
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.invoke(test1, "test22", "value");
});
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.invoke(test1, "test2", "value", 2);
});
Assert.assertThrows(RuntimeException.class, () -> {
Whitebox.invoke(test1.getClass(), "addValue", test1, 2.0);
});
}
private static Test1 newTest() {
Test1 test1 = new Test1();
test1.test2 = new Test2();
test1.test2.test3 = new Test3();
test1.test4 = new TestSubClass();
return test1;
}
@SuppressWarnings("unused")
private static class Test1 {
private static int staticValue = 1;
private int ivalue = 1;
private final int finalValue = 1;
private Test2 test2;
private TestSubClass test4;
private int value() {
return this.ivalue;
}
private int addValue(int i) {
return this.ivalue + i;
}
private static int svalue() {
return 1;
}
private static int svalue(int i) {
return i;
}
private static <T> T svalue(T o) {
return o;
}
private static int throwfunc1() {
throw new IllegalArgumentException("fake runtime exception");
}
private static int throwfunc2() throws Exception {
throw new Exception("fake exception");
}
}
@SuppressWarnings("unused")
private static class Test2 {
private static int staticValue = 2;
private final float finalValue = 2f;
private Test3 test3;
private float value() {
return this.finalValue;
}
private <T> T value(T o) {
return o;
}
}
@SuppressWarnings("unused")
private static class Test3 {
private String str = "3";
private String value() {
return this.str;
}
}
@SuppressWarnings("unused")
private static class TestSubClass extends Test1 {
private int value() {
return 4;
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.unit;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.commons.io.FileUtils;
import org.apache.hugegraph.util.ExceptionUtil;
import org.apache.hugegraph.util.TimeUtil;
import org.junit.AfterClass;
import org.junit.BeforeClass;
public class BaseUnitTest {
@BeforeClass
public static void init() {
// pass
}
@AfterClass
public static void clear() throws Exception {
// pass
}
protected static void runWithThreads(int threads, Runnable task) {
ExecutorService executor = Executors.newFixedThreadPool(threads);
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < threads; i++) {
futures.add(executor.submit(task));
}
for (Future<?> future : futures) {
ExceptionUtil.futureGet(future);
}
}
protected static void waitTillNext(long seconds) {
TimeUtil.tillNextMillis(TimeUtil.timeGen() + seconds * 1000);
}
public static void downloadFileByUrl(String url, String destPath) {
int connectTimeout = 5000;
int readTimeout = 5000;
try {
FileUtils.copyURLToFile(new URL(url), new File(destPath), connectTimeout, readTimeout);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,127 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.unit;
import org.apache.hugegraph.testutil.AssertTest;
import org.apache.hugegraph.testutil.WhiteboxTest;
import org.apache.hugegraph.unit.config.HugeConfigTest;
import org.apache.hugegraph.unit.config.OptionSpaceTest;
import org.apache.hugegraph.unit.event.EventHubTest;
import org.apache.hugegraph.unit.rest.AbstractRestClientTest;
import org.apache.hugegraph.unit.version.VersionTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.apache.hugegraph.unit.concurrent.AtomicLockTest;
import org.apache.hugegraph.unit.concurrent.BarrierEventTest;
import org.apache.hugegraph.unit.concurrent.KeyLockTest;
import org.apache.hugegraph.unit.concurrent.LockGroupTest;
import org.apache.hugegraph.unit.concurrent.LockManagerTest;
import org.apache.hugegraph.unit.concurrent.PausableScheduledThreadPoolTest;
import org.apache.hugegraph.unit.concurrent.RowLockTest;
import org.apache.hugegraph.unit.date.SafeDateFormatTest;
import org.apache.hugegraph.unit.iterator.BatchMapperIteratorTest;
import org.apache.hugegraph.unit.iterator.ExtendableIteratorTest;
import org.apache.hugegraph.unit.iterator.FilterIteratorTest;
import org.apache.hugegraph.unit.iterator.FlatMapperFilterIteratorTest;
import org.apache.hugegraph.unit.iterator.FlatMapperIteratorTest;
import org.apache.hugegraph.unit.iterator.LimitIteratorTest;
import org.apache.hugegraph.unit.iterator.ListIteratorTest;
import org.apache.hugegraph.unit.iterator.MapperIteratorTest;
import org.apache.hugegraph.unit.license.LicenseExtraParamTest;
import org.apache.hugegraph.unit.license.LicenseCreateParamTest;
import org.apache.hugegraph.unit.license.LicenseInstallParamTest;
import org.apache.hugegraph.unit.license.LicenseParamsTest;
import org.apache.hugegraph.unit.license.MachineInfoTest;
import org.apache.hugegraph.unit.perf.PerfUtilTest;
import org.apache.hugegraph.unit.perf.StopwatchTest;
import org.apache.hugegraph.unit.rest.RestClientTest;
import org.apache.hugegraph.unit.rest.RestResultTest;
import org.apache.hugegraph.unit.util.BytesTest;
import org.apache.hugegraph.unit.util.CollectionUtilTest;
import org.apache.hugegraph.unit.util.DateUtilTest;
import org.apache.hugegraph.unit.util.EcheckTest;
import org.apache.hugegraph.unit.util.HashUtilTest;
import org.apache.hugegraph.unit.util.InsertionOrderUtilTest;
import org.apache.hugegraph.unit.util.LogTest;
import org.apache.hugegraph.unit.util.LongEncodingTest;
import org.apache.hugegraph.unit.util.NumericUtilTest;
import org.apache.hugegraph.unit.util.OrderLimitMapTest;
import org.apache.hugegraph.unit.util.ReflectionUtilTest;
import org.apache.hugegraph.unit.util.StringUtilTest;
import org.apache.hugegraph.unit.util.TimeUtilTest;
import org.apache.hugegraph.unit.util.UnitUtilTest;
import org.apache.hugegraph.unit.util.VersionUtilTest;
@RunWith(Suite.class)
@Suite.SuiteClasses({
LockManagerTest.class,
LockGroupTest.class,
AtomicLockTest.class,
KeyLockTest.class,
RowLockTest.class,
PausableScheduledThreadPoolTest.class,
HugeConfigTest.class,
OptionSpaceTest.class,
SafeDateFormatTest.class,
BarrierEventTest.class,
EventHubTest.class,
PerfUtilTest.class,
StopwatchTest.class,
AbstractRestClientTest.class,
RestClientTest.class,
RestResultTest.class,
VersionTest.class,
ExtendableIteratorTest.class,
FilterIteratorTest.class,
LimitIteratorTest.class,
MapperIteratorTest.class,
FlatMapperIteratorTest.class,
FlatMapperFilterIteratorTest.class,
ListIteratorTest.class,
BatchMapperIteratorTest.class,
BytesTest.class,
CollectionUtilTest.class,
EcheckTest.class,
HashUtilTest.class,
InsertionOrderUtilTest.class,
LogTest.class,
NumericUtilTest.class,
ReflectionUtilTest.class,
StringUtilTest.class,
TimeUtilTest.class,
VersionUtilTest.class,
LongEncodingTest.class,
OrderLimitMapTest.class,
DateUtilTest.class,
UnitUtilTest.class,
LicenseExtraParamTest.class,
LicenseCreateParamTest.class,
LicenseInstallParamTest.class,
LicenseParamsTest.class,
MachineInfoTest.class,
AssertTest.class,
WhiteboxTest.class
})
public class UnitTestSuite {
}

View File

@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.unit.concurrent;
import org.junit.Test;
import org.apache.hugegraph.concurrent.AtomicLock;
import org.apache.hugegraph.testutil.Assert;
import org.apache.hugegraph.unit.BaseUnitTest;
public class AtomicLockTest extends BaseUnitTest {
@Test
public void testLockUnlock() {
AtomicLock lock = new AtomicLock("lock");
Assert.assertEquals("lock", lock.name());
Assert.assertTrue(lock.lock(0));
try {
Assert.assertFalse(lock.lock(1));
// lock in other threads
runWithThreads(2, () -> {
Assert.assertFalse(lock.tryLock());
});
lock.unlock();
} finally {
lock.unlock();
// unlock multi times is OK
lock.unlock();
lock.unlock();
}
Assert.assertThrows(RuntimeException.class, () -> {
lock.lock(-1);
}, e -> {
Assert.assertContains("Locking retry times should be in [0, 10], " +
"but got -1", e.getMessage());
});
Assert.assertThrows(RuntimeException.class, () -> {
lock.lock(11);
}, e -> {
Assert.assertContains("Locking retry times should be in [0, 10], " +
"but got 11", e.getMessage());
});
}
}

View File

@ -0,0 +1,288 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.unit.concurrent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
import org.apache.hugegraph.concurrent.BarrierEvent;
import org.apache.hugegraph.testutil.Assert;
public class BarrierEventTest {
private static final int WAIT_THREADS_COUNT = 10;
@Test(timeout = 5000)
public void testAWait() throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
AtomicInteger result = new AtomicInteger(0);
CountDownLatch latch = new CountDownLatch(2);
Thread awaitThread = new Thread(() -> {
try {
barrierEvent.await();
result.incrementAndGet();
} catch (InterruptedException e) {
// Do nothing.
} finally {
latch.countDown();
}
});
awaitThread.start();
Thread signalThread = new Thread(() -> {
barrierEvent.signalAll();
latch.countDown();
});
signalThread.start();
latch.await();
Assert.assertEquals(1, result.get());
}
@Test
public void testAWaitWithTimeout() throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
boolean signaled = barrierEvent.await(1L);
Assert.assertFalse(signaled);
}
@Test
public void testReset() throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
boolean signaled = barrierEvent.await(1L);
Assert.assertFalse(signaled);
barrierEvent.signal();
signaled = barrierEvent.await(1L);
Assert.assertTrue(signaled);
barrierEvent.reset();
signaled = barrierEvent.await(1L);
Assert.assertFalse(signaled);
}
@Test
public void testSignal() throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
boolean signaled = barrierEvent.await(1L);
Assert.assertFalse(signaled);
barrierEvent.signal();
signaled = barrierEvent.await(1L);
Assert.assertTrue(signaled);
}
@Test
public void testSignalByMultiThreadWithSignalFirst()
throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
AtomicInteger eventCount = new AtomicInteger(0);
AtomicInteger waitThreadInterruptedCount = new AtomicInteger(0);
ExecutorService executorService =
Executors.newFixedThreadPool(WAIT_THREADS_COUNT + 1);
CountDownLatch waitLatch = new CountDownLatch(WAIT_THREADS_COUNT);
CountDownLatch signalLatch = new CountDownLatch(1);
for (int i = 0; i < WAIT_THREADS_COUNT; i++) {
executorService.submit(() -> {
try {
signalLatch.await();
barrierEvent.await();
eventCount.incrementAndGet();
} catch (InterruptedException e) {
waitThreadInterruptedCount.incrementAndGet();
} finally {
waitLatch.countDown();
}
});
}
executorService.submit(() -> {
barrierEvent.signal();
signalLatch.countDown();
});
executorService.shutdown();
executorService.awaitTermination(2L, TimeUnit.SECONDS);
waitLatch.await();
Assert.assertEquals(10, eventCount.get());
Assert.assertEquals(0, waitThreadInterruptedCount.get());
}
@Test
public void testSignalByMultiThreadWithSignalLast()
throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
AtomicInteger eventCount = new AtomicInteger(0);
AtomicInteger waitThreadInterruptedCount = new AtomicInteger(0);
AtomicInteger signalThreadInterruptedCount = new AtomicInteger(0);
ExecutorService executorService =
Executors.newFixedThreadPool(WAIT_THREADS_COUNT + 1);
CountDownLatch waitLatch = new CountDownLatch(WAIT_THREADS_COUNT);
CountDownLatch signalLatch = new CountDownLatch(1);
for (int i = 0; i < WAIT_THREADS_COUNT; i++) {
executorService.submit(() -> {
try {
waitLatch.countDown();
barrierEvent.await();
eventCount.incrementAndGet();
} catch (InterruptedException e) {
waitThreadInterruptedCount.incrementAndGet();
}
});
}
executorService.submit(() -> {
try {
waitLatch.await();
} catch (InterruptedException e) {
signalThreadInterruptedCount.incrementAndGet();
}
barrierEvent.signal();
signalLatch.countDown();
});
signalLatch.await();
executorService.shutdownNow();
executorService.awaitTermination(1L, TimeUnit.SECONDS);
Assert.assertEquals(1, eventCount.get());
Assert.assertEquals(WAIT_THREADS_COUNT - 1,
waitThreadInterruptedCount.get());
Assert.assertEquals(0, signalThreadInterruptedCount.get());
}
@Test
public void testSignalAll() throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
boolean signaled = barrierEvent.await(1L);
Assert.assertFalse(signaled);
barrierEvent.signalAll();
signaled = barrierEvent.await(1L);
Assert.assertTrue(signaled);
}
@Test
public void testSignalAllByMultiThreadWithSignalFirst()
throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
AtomicInteger eventCount = new AtomicInteger(0);
AtomicInteger waitThreadInterruptedCount = new AtomicInteger(0);
ExecutorService executorService =
Executors.newFixedThreadPool(WAIT_THREADS_COUNT + 1);
CountDownLatch waitLatch = new CountDownLatch(WAIT_THREADS_COUNT);
CountDownLatch signalLatch = new CountDownLatch(1);
for (int i = 0; i < WAIT_THREADS_COUNT; i++) {
executorService.submit(() -> {
try {
signalLatch.await();
waitLatch.countDown();
barrierEvent.await();
eventCount.incrementAndGet();
} catch (InterruptedException e) {
waitThreadInterruptedCount.incrementAndGet();
}
});
}
executorService.submit(() -> {
barrierEvent.signalAll();
signalLatch.countDown();
});
executorService.shutdown();
executorService.awaitTermination(1L, TimeUnit.SECONDS);
Assert.assertEquals(10, eventCount.get());
Assert.assertEquals(0, waitThreadInterruptedCount.get());
}
@Test
public void testSignalAllByMultiThreadWithSignalLast()
throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
AtomicInteger eventCount = new AtomicInteger(0);
AtomicInteger waitThreadInterruptedCount = new AtomicInteger(0);
AtomicInteger signalThreadInterruptedCount = new AtomicInteger(0);
ExecutorService executorService =
Executors.newFixedThreadPool(WAIT_THREADS_COUNT + 1);
CountDownLatch waitLatch = new CountDownLatch(WAIT_THREADS_COUNT);
CountDownLatch signalLatch = new CountDownLatch(1);
for (int i = 0; i < WAIT_THREADS_COUNT; i++) {
executorService.submit(() -> {
try {
waitLatch.countDown();
barrierEvent.await();
eventCount.incrementAndGet();
} catch (InterruptedException e) {
waitThreadInterruptedCount.incrementAndGet();
}
});
}
executorService.submit(() -> {
try {
waitLatch.await();
} catch (InterruptedException e) {
signalThreadInterruptedCount.incrementAndGet();
}
barrierEvent.signalAll();
signalLatch.countDown();
});
signalLatch.await();
executorService.shutdown();
executorService.awaitTermination(1L, TimeUnit.SECONDS);
Assert.assertEquals(WAIT_THREADS_COUNT, eventCount.get());
Assert.assertEquals(0, waitThreadInterruptedCount.get());
Assert.assertEquals(0, signalThreadInterruptedCount.get());
}
@Test
public void testSignalAllByMultiThreadWithSignalAwaitConcurrent()
throws InterruptedException {
BarrierEvent barrierEvent = new BarrierEvent();
AtomicInteger eventCount = new AtomicInteger(0);
AtomicInteger waitThreadInterruptedCount = new AtomicInteger(0);
AtomicInteger signalThreadInterruptedCount = new AtomicInteger(0);
ExecutorService executorService =
Executors.newFixedThreadPool(WAIT_THREADS_COUNT + 1);
CountDownLatch syncLatch = new CountDownLatch(1);
for (int i = 0; i < WAIT_THREADS_COUNT; i++) {
executorService.submit(() -> {
try {
syncLatch.await();
barrierEvent.await();
eventCount.incrementAndGet();
} catch (InterruptedException e) {
waitThreadInterruptedCount.incrementAndGet();
}
});
}
executorService.submit(() -> {
try {
syncLatch.await();
} catch (InterruptedException e) {
signalThreadInterruptedCount.incrementAndGet();
}
barrierEvent.signalAll();
});
syncLatch.countDown();
executorService.shutdown();
executorService.awaitTermination(1L, TimeUnit.SECONDS);
Assert.assertEquals(WAIT_THREADS_COUNT, eventCount.get());
Assert.assertEquals(0, waitThreadInterruptedCount.get());
Assert.assertEquals(0, signalThreadInterruptedCount.get());
}
}

View File

@ -0,0 +1,124 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.unit.concurrent;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.Lock;
import org.junit.Test;
import org.apache.hugegraph.concurrent.KeyLock;
import org.apache.hugegraph.testutil.Assert;
import org.apache.hugegraph.unit.BaseUnitTest;
public class KeyLockTest extends BaseUnitTest {
@Test
public void testLockUnlock() {
KeyLock locks = new KeyLock();
locks.lock("1");
try {
// lock again is OK
locks.lock("1");
// lock in other threads
runWithThreads(1, () -> {
locks.lock("2");
});
locks.unlock("1");
} finally {
locks.unlock("1");
}
Assert.assertThrows(IllegalMonitorStateException.class, () -> {
locks.unlock("2");
});
Assert.assertThrows(IllegalMonitorStateException.class, () -> {
locks.unlock("3");
});
Assert.assertThrows(IllegalArgumentException.class, () -> {
locks.lock(null);
}, e -> {
Assert.assertContains("Lock key can't be null", e.getMessage());
});
Assert.assertThrows(IllegalArgumentException.class, () -> {
locks.unlock(null);
}, e -> {
Assert.assertContains("Unlock key can't be null", e.getMessage());
});
}
@Test
public void testLockUnlockAll() {
KeyLock locks = new KeyLock();
List<Lock> ls = locks.lockAll("1", 2);
locks.unlockAll(ls);
runWithThreads(1, () -> {
List<Lock> ls2 = locks.lockAll("1", 3);
locks.unlockAll(ls2);
});
List<Lock> ls3 = locks.lockAll("1", 2, 3);
locks.unlockAll(ls3);
Assert.assertThrows(IllegalArgumentException.class, () -> {
locks.lockAll("1", null);
}, e -> {
Assert.assertContains("Lock key can't be null", e.getMessage());
});
Assert.assertThrows(IllegalArgumentException.class, () -> {
locks.lockAll(null, "1");
}, e -> {
Assert.assertContains("Lock key can't be null", e.getMessage());
});
Assert.assertThrows(IllegalArgumentException.class, () -> {
locks.lockAll(Arrays.asList("1", null, 2).toArray());
}, e -> {
Assert.assertContains("Lock key can't be null", e.getMessage());
});
Assert.assertThrows(IllegalArgumentException.class, () -> {
locks.lockAll(Collections.emptyList().toArray());
}, e -> {
Assert.assertContains("Lock keys can't be null or empty",
e.getMessage());
});
Assert.assertThrows(IllegalArgumentException.class, () -> {
locks.lockAll((Object[]) null);
}, e -> {
Assert.assertContains("Lock keys can't be null or empty",
e.getMessage());
});
Assert.assertThrows(IllegalArgumentException.class, () -> {
locks.unlockAll(null);
}, e -> {
Assert.assertContains("Unlock locks can't be null", e.getMessage());
});
}
}

View File

@ -0,0 +1,106 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.unit.concurrent;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.junit.Test;
import org.apache.hugegraph.concurrent.AtomicLock;
import org.apache.hugegraph.concurrent.KeyLock;
import org.apache.hugegraph.concurrent.LockGroup;
import org.apache.hugegraph.concurrent.RowLock;
import org.apache.hugegraph.testutil.Assert;
import org.apache.hugegraph.unit.BaseUnitTest;
public class LockGroupTest extends BaseUnitTest {
private static final String GROUP = "LockGroupTest-test-group";
private final LockGroup group = new LockGroup(GROUP);
@Test
public void testLock() {
Lock lock = this.group.lock("lock");
Assert.assertTrue(lock instanceof ReentrantLock);
Lock lock1 = this.group.lock("lock");
Assert.assertSame(lock, lock1);
lock1.lock();
try {
// lock again is OK
lock1.lock();
// lock in other threads
runWithThreads(2, () -> {
Assert.assertFalse(lock1.tryLock());
});
lock1.unlock();
} finally {
lock1.unlock();
}
}
@Test
public void testAtomicLock() {
AtomicLock lock = this.group.atomicLock("lock");
Assert.assertNotNull(lock);
AtomicLock lock1 = this.group.atomicLock("lock");
Assert.assertSame(lock, lock1);
Assert.assertEquals("lock", lock1.name());
}
@Test
public void testReadWriteLock() {
ReadWriteLock lock = this.group.readWriteLock("lock");
Assert.assertTrue(lock instanceof ReentrantReadWriteLock);
ReadWriteLock lock1 = this.group.readWriteLock("lock");
Assert.assertSame(lock, lock1);
}
@Test
public void testKeyLock() {
KeyLock lock = this.group.keyLock("lock");
Assert.assertNotNull(lock);
KeyLock lock1 = this.group.keyLock("lock");
Assert.assertSame(lock, lock1);
}
@Test
public void testKeyLockWithSize() {
KeyLock lock = this.group.keyLock("lock", 10);
Assert.assertNotNull(lock);
KeyLock lock1 = this.group.keyLock("lock");
Assert.assertSame(lock, lock1);
}
@Test
public void testRowLock() {
RowLock<?> lock = this.group.rowLock("lock");
Assert.assertNotNull(lock);
RowLock<?> lock1 = this.group.rowLock("lock");
Assert.assertSame(lock, lock1);
}
@Test
public void testName() {
Assert.assertEquals(GROUP, this.group.name());
}
}

View File

@ -0,0 +1,125 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You 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 org.apache.hugegraph.unit.concurrent;
import org.junit.After;
import org.junit.Test;
import org.apache.hugegraph.concurrent.LockGroup;
import org.apache.hugegraph.concurrent.LockManager;
import org.apache.hugegraph.testutil.Assert;
import org.apache.hugegraph.unit.BaseUnitTest;
public class LockManagerTest extends BaseUnitTest {
private static final String GROUP = "LockManagerTest-test-group";
private static final String GROUP2 = GROUP + 2;
@After
public void teardown() {
LockManager manager = LockManager.instance();
if (manager.exists(GROUP)) {
manager.destroy(GROUP);
}
if (manager.exists(GROUP2)) {
manager.destroy(GROUP2);
}
}
@Test
public void testCreate() {
LockManager manager = LockManager.instance();
LockGroup lockGroup = manager.create(GROUP);
Assert.assertNotNull(lockGroup);
Assert.assertEquals(GROUP, lockGroup.name());
Assert.assertTrue(manager.exists(GROUP));
Assert.assertFalse(manager.exists(GROUP2));
LockGroup lockGroup2 = manager.create(GROUP2);
Assert.assertNotNull(lockGroup2);
Assert.assertEquals(GROUP2, lockGroup2.name());
Assert.assertTrue(manager.exists(GROUP2));
Assert.assertThrows(RuntimeException.class, () -> {
manager.create(GROUP);
}, e -> {
Assert.assertContains("LockGroup 'LockManagerTest-test-group' " +
"already exists", e.getMessage());
});
}
@Test
public void testGet() {
LockManager manager = LockManager.instance();
LockGroup lockGroup = manager.create(GROUP);
LockGroup lockGroup2 = manager.create(GROUP2);
Assert.assertSame(lockGroup, manager.get(GROUP));
Assert.assertSame(lockGroup2, manager.get(GROUP2));
Assert.assertSame(lockGroup, manager.get(GROUP));
Assert.assertSame(lockGroup2, manager.get(GROUP2));
Assert.assertThrows(RuntimeException.class, () -> {
manager.get("fake-lock-group");
}, e -> {
Assert.assertContains("LockGroup 'fake-lock-group' " +
"does not exists", e.getMessage());
});
}
@Test
public void testDestroy() {
LockManager manager = LockManager.instance();
LockGroup lockGroup = manager.create(GROUP);
LockGroup lockGroup2 = manager.create(GROUP2);
Assert.assertTrue(manager.exists(GROUP));
Assert.assertTrue(manager.exists(GROUP2));
Assert.assertSame(lockGroup, manager.get(GROUP));
Assert.assertSame(lockGroup2, manager.get(GROUP2));
manager.destroy(GROUP);
Assert.assertFalse(manager.exists(GROUP));
Assert.assertTrue(manager.exists(GROUP2));
Assert.assertThrows(RuntimeException.class, () -> {
manager.get(GROUP);
}, e -> {
Assert.assertContains("does not exists", e.getMessage());
});
Assert.assertSame(lockGroup2, manager.get(GROUP2));
manager.destroy(GROUP2);
Assert.assertFalse(manager.exists(GROUP));
Assert.assertFalse(manager.exists(GROUP2));
Assert.assertThrows(RuntimeException.class, () -> {
manager.get(GROUP);
}, e -> {
Assert.assertContains("does not exists", e.getMessage());
});
Assert.assertThrows(RuntimeException.class, () -> {
manager.get(GROUP2);
}, e -> {
Assert.assertContains("does not exists", e.getMessage());
});
}
}

Some files were not shown because too many files have changed in this diff Show More