Compare commits

...
491 Commits
Author SHA1 Message Date
Chris Lu fa7c65bd4b 2.69 2021-09-19 21:44:06 -07:00
Chris Lu 84fdda85e7 go fmt 2021-09-19 12:06:15 -07:00
Chris Lu ad5099e570 refactor 2021-09-19 12:02:23 -07:00
Chris Lu 5abdc0be77 s3: avoid overwriting object with ACL/LegalHold/Retension/LockConfiguration requests 2021-09-19 03:24:47 -07:00
Chris Lu ede7a65a50 update log 2021-09-19 01:33:50 -07:00
Chris Lu c1255d30ad add cache error log 2021-09-19 01:33:26 -07:00
Chris Lu eab7cf4bd3 restore dev binaries building 2021-09-19 00:41:45 -07:00
Chris Lu 59dd271734 more glog 2021-09-19 00:29:51 -07:00
Chris Lu 4cbba2b1c6 add more glog to s3 2021-09-19 00:28:22 -07:00
Chris Lu 71175461ef add glog for s3 handlers 2021-09-19 00:18:59 -07:00
Chris Lu 49d971e602 filer: redis store needs to clean up batch deleted sub folders 2021-09-18 14:05:16 -07:00
Chris Lu 94a01fcfcb filer.remote.gateway: add options to include or exclude new bucket names to mirror 2021-09-15 23:04:16 -07:00
Chris Lu b5f4910412 adjust help messages 2021-09-15 22:53:10 -07:00
Chris Lu f0907eb83c add command filre.remote.gateway 2021-09-15 22:48:04 -07:00
Chris Lu 63da4bbb54 separate filer.remote.gateway command to avoid confusion 2021-09-15 22:47:17 -07:00
Chris LuandGitHub 0c099c1bea Update README.md 2021-09-14 12:09:04 -07:00
Chris LuandGitHub 7a135b7735 Update README.md 2021-09-14 12:07:57 -07:00
Chris Lu 2789d10342 go fmt 2021-09-14 10:37:06 -07:00
Chris Lu 119d5908dd shell: do not need to lock to see volume -h 2021-09-13 22:13:34 -07:00
Chris Lu 7504be58f9 Avoid xattr printed out as HTTP headers
fix https://github.com/chrislusf/seaweedfs/issues/2336
2021-09-13 04:00:57 -07:00
Chris Lu 96514f0f00 fix tests 2021-09-13 02:19:48 -07:00
Chris Lu 20ac710ceb 2.68 2021-09-13 02:16:09 -07:00
Chris Lu 6cd1ce8b74 erasure coding: add cleanup step if anything goes wrong 2021-09-13 01:55:49 -07:00
Chris Lu f74b29416a better etag matching 2021-09-13 00:31:46 -07:00
Chris Lu e9760f261e minor 2021-09-13 00:31:06 -07:00
Chris Lu e5fc35ed0c change server address from string to a type 2021-09-12 22:47:52 -07:00
Chris Lu 2c9d4c8f43 custom grpc port: filer 2021-09-12 02:28:37 -07:00
Chris Lu e690a2be16 custom grpc port: volume server 2021-09-12 02:25:15 -07:00
Chris Lu 232ad2fe65 custom grpc port: master follower 2021-09-12 02:25:00 -07:00
Chris Lu bd1f800efe custom grpc port: master 2021-09-12 02:19:10 -07:00
Chris Lu 7591336a22 log format 2021-09-11 14:27:57 -07:00
Chris Lu 8c6ff55226 add volume not found error type, to reduce error log 2021-09-11 14:26:41 -07:00
Chris Lu 7e600bff5f adjust log level 2021-09-11 12:59:15 -07:00
Chris Lu 67949e25e9 add optional delay 2021-09-11 02:21:55 -07:00
Chris Lu a243d7e047 EC: clean up if failed in the middle 2021-09-11 02:07:14 -07:00
Chris Lu f7f01ac209 return if error 2021-09-11 02:06:43 -07:00
Chris Lu 59cb6146a3 refactor 2021-09-11 02:06:30 -07:00
Chris Lu 5496d68f6a increase counter only if not early terminated 2021-09-11 02:05:55 -07:00
Chris Lu 2b8ab1534a mysql table DDL: minor, not necessary, but a little more strict
the directory is already hashed into dirhash. So this change is not strictly required.
2021-09-08 23:55:18 -07:00
Chris LuandGitHub ac574d5572 Merge pull request #2327 from joshuafc/patch-2 2021-09-08 19:52:19 -07:00
joshuafc 5654d0d60d CompactionTableSizeMultiplier of leveldb use default value. #2325
To improve performance of leveldb find key in condition of large directory(millions of files) which use uuid as filename.
2021-09-09 10:42:34 +08:00
Chris Lu 0b4269b6a8 remember commands even if failed 2021-09-08 15:55:19 -07:00
Chris Lu 0207f5fe9b replicated remote.cache 2021-09-08 15:54:55 -07:00
Chris Lu 00edcf71fc fix compilation 2021-09-08 07:27:03 -07:00
Chris Lu 574485ec69 better IP v6 support 2021-09-07 19:29:42 -07:00
Chris Lu 0128239c0f handle ipv6 addresses 2021-09-07 16:43:54 -07:00
Chris LuandGitHub 35c8ea495f Merge pull request #2321 from joshuafc/patch-1
add bloom filter to leveldb_store to improve fuse performance.
2021-09-07 10:32:06 -07:00
zhoub 6a7ed1bd0e add bloom filter to leveldb_store to improve fuse performance. 2021-09-07 21:09:10 +08:00
Chris Lu a0a6aa36fa adjust name 2021-09-07 02:34:49 -07:00
Chris Lu 9fdf02bcda remove detecting ipv6
Got this error on my local:

transport: Error while dialing dial tcp [fe80::1]:19333: connect: no route to host

related to https://github.com/chrislusf/seaweedfs/pull/2310
2021-09-07 02:31:34 -07:00
Chris Lu 889a39a24f ipv6 2021-09-07 02:30:25 -07:00
Chris Lu 85a2046411 move out latest container building 2021-09-07 02:12:07 -07:00
Chris Lu 9ca7c322b4 reduce resource usage 2021-09-07 01:44:52 -07:00
Chris Lu 8c6d706328 2.67 2021-09-07 00:08:03 -07:00
Chris Lu 2954bd71f8 testing different binary name 2021-09-06 23:44:08 -07:00
Chris Lu ce9e606eb2 fix waiting, binary name. 2021-09-06 23:11:59 -07:00
Chris Lu ee143f9ae0 github action adds dependencies 2021-09-06 22:54:29 -07:00
Chris Lu 5035b0a109 build binaries on release 2021-09-06 21:48:24 -07:00
Chris Lu a443e39def add back delays 2021-09-06 20:29:48 -07:00
Chris Lu 64971b0d7e merge into one action 2021-09-06 18:39:29 -07:00
Chris Lu 68b23114b9 adjust actions 2021-09-06 18:37:57 -07:00
Chris Lu 0c47437ece Revert "action: delete previous assets"
This reverts commit 9ec151fa0d.
2021-09-06 18:37:20 -07:00
Chris Lu 9ec151fa0d action: delete previous assets 2021-09-06 18:35:19 -07:00
Chris Lu 2b1feb732c remote.cache supports replication 2021-09-06 18:30:44 -07:00
Chris Lu 3adc3da291 refactor 2021-09-06 16:35:55 -07:00
Chris Lu 6923af7280 refactoring 2021-09-06 16:20:49 -07:00
Chris Lu 64f6532fbe update help message 2021-09-06 16:16:22 -07:00
Chris Lu 308d4b2dae filer.remote.sync: createBucketWithRandomSuffix defaults to true 2021-09-06 15:14:26 -07:00
Chris Lu 8e4b43a017 minor 2021-09-06 15:13:38 -07:00
Chris Lu c218ef20c7 filer.remote.sync: automatically detect the primary remote storage 2021-09-06 15:10:55 -07:00
Chris Lu 1702ce5395 remove unused code 2021-09-06 12:01:44 -07:00
Chris Lu fe4794fe92 minor 2021-09-06 11:40:51 -07:00
Chris Lu 728ed21a80 just in case 2021-09-06 11:39:10 -07:00
Chris Lu 9fb278c92c Hadoop: avoid case insensitive on windows 2021-09-06 11:33:56 -07:00
Chris Lu 0cda61d539 return error if not found 2021-09-05 23:43:44 -07:00
Chris Lu f62df7f695 fix wrong srcPath checking 2021-09-05 23:37:40 -07:00
Chris Lu e93d4935e3 add other replica locations when assigning volumes 2021-09-05 23:32:25 -07:00
Chris Lu 7a13816e94 refactor 2021-09-05 23:17:15 -07:00
Chris Lu d5c7dbac4a docker: build dev containers 2021-09-05 23:09:13 -07:00
Chris Lu d869a07cd2 clean up 2021-09-05 23:08:34 -07:00
Chris Lu 705285ec60 rename file 2021-09-05 17:02:50 -07:00
Chris Lu f2de7910fc move latest image build to after binary released 2021-09-05 17:02:22 -07:00
Chris Lu ae98a085d3 automated latest image build 2021-09-05 16:56:12 -07:00
Chris Lu 6022db6d6a 2.66 2021-09-05 16:21:14 -07:00
Chris Lu 006c01a519 fix format 2021-09-05 16:18:50 -07:00
Chris Lu 65af3cf4df master: disconnect only the phantom volume server
fix https://github.com/chrislusf/seaweedfs/issues/2311
2021-09-05 15:20:03 -07:00
Chris Lu 57a95887d2 remote.cache remote.uncache supports all mounted directories 2021-09-05 14:47:06 -07:00
Chris Lu 28f45f8fa6 re-org 2021-09-05 14:38:31 -07:00
Chris Lu c735608685 obfuscate secret keys on display 2021-09-05 14:23:49 -07:00
Chris Lu 32e94de86a default auto trimming suffix to true 2021-09-05 13:27:35 -07:00
Chris Lu 60573fd3e2 option to map remote bucket to trimmed bucket name 2021-09-05 11:55:52 -07:00
Chris LuandGitHub 2348e8d8da Merge pull request #2310 from nivekuil/ipv6
Detect ipv6 addresses
2021-09-05 10:56:44 -07:00
nivekuil 0fe9d2997b Detect ipv6 addresses 2021-09-05 06:21:40 -07:00
Chris Lu bdefdee4e6 filer.remote.sync: add option to add randomized suffix to buckets to avoid conflicts 2021-09-04 22:46:28 -07:00
Chris Lu d57d4c5f8f shell: add remote.mount.buckets 2021-09-04 21:37:25 -07:00
Chris Lu 98c68d7a79 filer.remote.sync fix upload logic 2021-09-04 18:46:28 -07:00
Chris Lu d983aa4c7d correct filtering 2021-09-04 13:58:14 -07:00
Chris Lu c5ee03d6af format 2021-09-04 13:57:55 -07:00
Chris Lu cc278a5928 Update Makefile 2021-09-04 13:46:49 -07:00
Chris Lu 16a342eb8a re-ordering 2021-09-04 13:46:44 -07:00
Chris Lu 796b2eb929 remember sync time 2021-09-04 13:46:22 -07:00
Chris Lu 53b9b521c9 adjust error message 2021-09-04 13:46:06 -07:00
Chris Lu 49952ba905 fix cache/uncache filters 2021-09-04 13:45:39 -07:00
Chris Lu 99d4594ee8 update remote storage mount mapping 2021-09-04 05:22:34 -07:00
Chris Lu df29281536 rename 2021-09-04 05:11:06 -07:00
Chris Lu c3db389e42 refactor 2021-09-04 05:09:38 -07:00
Chris Lu e9ce099453 rename 2021-09-04 05:03:51 -07:00
Chris Lu 8707ef00a6 refactor 2021-09-04 05:02:20 -07:00
Chris Lu 13cc2ef723 when creating bucket, use remote storage client for default storage 2021-09-04 04:54:55 -07:00
Chris Lu 63c84584bb refactor 2021-09-04 04:53:36 -07:00
Chris Lu 4b28c5f6c3 filer.remote.sync: split into buckets mode and single directory mode 2021-09-04 04:35:46 -07:00
Chris Lu da49d25950 auto list of storage types 2021-09-04 00:18:21 -07:00
Chris Lu 38f73c8324 add gcs project id 2021-09-03 23:38:33 -07:00
Chris Lu 43d6678d6d remove dep 2021-09-03 23:36:37 -07:00
Chris Lu 8ec357b3d3 go mod 2021-09-03 23:25:33 -07:00
Chris Lu bbc77f7af4 fix compilation 2021-09-03 22:56:59 -07:00
Chris Lu cc36f5b01f go get -u github.com/Azure/azure-storage-blob-go/azblob 2021-09-03 22:31:29 -07:00
Chris Lu 0652805236 cloud drive: add createBucket() deleteBucket() 2021-09-03 22:30:55 -07:00
Chris Lu 03a31587ce go fmt 2021-09-03 20:42:28 -07:00
Chris Lu 83cd0fc739 cloud drive: add list buckets 2021-09-03 20:42:02 -07:00
Chris Lu fbfc90fd1e adjust formatting remote location 2021-09-03 18:52:37 -07:00
Chris Lu 491f7636f8 s3: CopyObject return http Status 400 Bad Request for non-existing source
fix https://github.com/chrislusf/seaweedfs/issues/2306
2021-09-03 17:38:39 -07:00
Chris Lu bca4a9de78 simplify 2021-09-02 23:09:24 -07:00
Chris Lu 958125bd02 conforming to http user agent common practice 2021-09-02 22:55:35 -07:00
Chris Lu 11a496404b reset wait time 2021-09-02 19:55:01 -07:00
Chris Lu 7f2a8246a9 minor 2021-09-02 12:32:59 -07:00
Chris Lu 1b942dfa3c add error message 2021-09-02 12:32:46 -07:00
Chris Lu 9a73b0e3c9 refactor 2021-09-02 07:07:16 -07:00
Chris Lu e281f0fa82 refactor 2021-09-02 06:53:21 -07:00
Chris Lu 24fda6f47f remove QR code for mobile upload 2021-09-01 16:59:37 -07:00
Chris Lu 7ce97b59d8 go fmt 2021-09-01 02:45:42 -07:00
Chris Lu d1a4e19a3f volume: copy file also copies modification time
to ensure ttl can work well
2021-09-01 02:42:57 -07:00
Chris Lu 3bd48c4f29 filer.remote.sync: exit when directory is unmounted
this will not propagate the deletions back to the cloud
2021-09-01 01:29:22 -07:00
Chris Lu 3faaa6e360 ensure cached client with updated storage conf 2021-09-01 01:27:45 -07:00
Chris Lu 8e125339d5 line wrap 2021-08-31 23:30:28 -07:00
Chris Lu 68ea99190f add additionalPathPrefixes 2021-08-31 23:26:26 -07:00
Chris Lu 43fd11278e support follow additional path prefixes 2021-08-31 23:23:08 -07:00
Chris Lu cca588429b shell: fs.meta.save skip saving system logs 2021-08-31 23:05:56 -07:00
Chris Lu 0ee208c1a4 adjust example 2021-08-31 02:04:32 -07:00
Chris Lu 97b7948cd9 adjust error message 2021-08-31 01:07:34 -07:00
Chris Lu c9205458a1 cloud drive: create mount directory if not exists 2021-08-31 01:07:19 -07:00
Chris Lu 1dfcdc53b7 cloud drive: add storj, filebase 2021-08-30 17:43:14 -07:00
Chris Lu 701cc133f3 cloud drive: s3 add option for v4 signature 2021-08-30 17:28:33 -07:00
Chris Lu 8ecd609b48 go tidy 2021-08-30 17:28:14 -07:00
Chris Lu f117f7bf54 adjust comment 2021-08-30 15:56:14 -07:00
Chris LuandGitHub 72d4ff6b28 Merge pull request #2280 from blacktear23/filerstore-tikv
Use TiKV as Filerstore
2021-08-30 02:21:14 -07:00
Chris Lu f811fd0903 fix build 2021-08-30 02:03:08 -07:00
yulai.li b17b81529e Add build tags for TiKV filerstore 2021-08-30 15:59:25 +08:00
Rain LiandGitHub e5f9ff983d Merge branch 'master' into filerstore-tikv 2021-08-30 15:52:54 +08:00
Chris Lu 44d0ac95f6 add cluster id if already set 2021-08-29 22:19:46 -07:00
Chris Lu 18bf556d93 fix comments 2021-08-29 22:19:25 -07:00
Chris Lu 21f37a0a75 remove unused code 2021-08-29 22:19:11 -07:00
Chris Lu 5adfdd7982 change to a new bloom filter library 2021-08-29 21:26:38 -07:00
Chris Lu 05f32376eb add cluster id in filer configuration response 2021-08-29 21:02:10 -07:00
Chris Lu 268de45aa5 reset volume id cache if not found 2021-08-29 20:27:11 -07:00
Chris Lu eacaa44dc2 refactor 2021-08-29 19:13:48 -07:00
Chris Lu 6deee4c0b9 import hdfs 2021-08-29 18:49:43 -07:00
Chris Lu a31f2907f0 cloud drive: filer.remote.sync supports remove folder 2021-08-29 18:46:28 -07:00
Chris Lu 001a472057 cloud mount: remote storage support hdfs 2021-08-29 18:41:29 -07:00
Chris Lu 05d2774117 refactoring 2021-08-28 22:49:38 -07:00
Chris Lu 975fbc9ee3 add wasabi example 2021-08-28 22:49:38 -07:00
Chris LuandGitHub cd838b1197 Merge pull request #2292 from logband/master
fix(ci): update latest to only run once
2021-08-28 20:33:16 -07:00
Chris LuandGitHub b7ec879d32 Merge pull request #2293 from logband/change-ci-naming
fix(ci): use cleaner naming for jobs
2021-08-28 20:32:51 -07:00
Alexander aeda4be42c fix(ci): use cleaner naming for jobs 2021-08-29 12:12:30 +09:00
Alexander 7cfaa1a365 fix(ci): further testing of CI logic 2021-08-29 12:06:10 +09:00
Alexander bfb66b88b1 fix(ci): do not run on mainline branch 2021-08-29 12:02:58 +09:00
Alexander 16f0cdc1bf fix(ci): never try to push on test pull request 2021-08-29 11:57:08 +09:00
Alexander 1587ce779d Merge branch 'master' of https://github.com/logband/seaweedfs 2021-08-29 11:54:57 +09:00
Alexander b686e8c45b fix(ci): update latest to only run once 2021-08-29 11:54:49 +09:00
Chris LuandGitHub e2aaa3e2f3 Merge pull request #2291 from logband/master
fix(ci): upload all arches to Docker Hub in one job
2021-08-28 19:51:48 -07:00
AlexanderandGitHub ab0ebe1d3b Merge branch 'chrislusf:master' into master 2021-08-29 11:47:35 +09:00
Alexander 4128c1126a fix(ci): upload all arches to Docker Hub once 2021-08-29 11:47:19 +09:00
Chris LuandGitHub 8b7063634f Merge pull request #2290 from nivekuil/grafana
grafana dashboard updates
2021-08-28 17:57:44 -07:00
nivekuil a7383a8a1c grafana dashboard updates 2021-08-28 16:50:09 -07:00
Chris Lu bec3f63298 2.65 2021-08-28 05:27:33 -07:00
Chris Lu 223c1b3571 adjust invalidation logic 2021-08-28 05:21:01 -07:00
Chris LuandGitHub ccc44059e8 Merge pull request #2289 from nivekuil/mountfix
mount: fix consistency issue, invalidate mount meta cache more aggressively
2021-08-28 05:18:44 -07:00
nivekuil 8c523d50ad Invalidate mount meta cache more aggressively 2021-08-28 04:26:37 -07:00
Chris Lu 65a29ad42a add warning on unmount a folder 2021-08-28 02:25:48 -07:00
Chris Lu a22f37b01c remove tencent region 2021-08-28 02:23:03 -07:00
Chris Lu a9b41900d8 handle cases when mounted directory does not exist 2021-08-28 01:56:56 -07:00
Chris Lu 0d8936f6cd add aliyun example 2021-08-28 01:09:48 -07:00
Chris Lu ff70ba51ac build with latest go version 2021-08-28 00:41:34 -07:00
Chris Lu dc481c081c remove unused function 2021-08-27 22:18:54 -07:00
Chris LuandGitHub ca80199ccd Merge pull request #2288 from logband/master
feature(cross-platform): add multi-arch support to release
2021-08-27 20:00:14 -07:00
Alexander 7b56a6400d fix(ci): use matrix for all container runs 2021-08-28 11:36:32 +09:00
Alexander b1331ba3fe feature(ci): use matrix for container build 2021-08-28 11:33:08 +09:00
Alexander 6850252e7c revert(ci): remove continue-on-error 2021-08-28 11:23:49 +09:00
Alexander 5a10f27c8d fix(ci): remove ppc64le and s390x support 2021-08-28 11:23:20 +09:00
Alexander 46e78e9b3e fix(ci): allow test job to continue on error 2021-08-28 11:19:33 +09:00
Alexander b4de7c09e7 feature(ci): simplify go binary test build 2021-08-28 11:17:03 +09:00
Alexander b68e76bbac fix(ci): only cancel previous in-progress workflow of the same group 2021-08-28 11:10:15 +09:00
Alexander 7107ded3cd fix(ci): only cancel previous in-progress workflow of the same group 2021-08-28 11:01:09 +09:00
Alexander e73044f1f0 feature(ci): cancel previous runs if in-progress 2021-08-28 10:57:13 +09:00
Alexander 9ac962888c fix(ci): use distinct test job name 2021-08-28 10:54:44 +09:00
Alexander ee52f29c33 feature(ci): recognise more arches and add build tests 2021-08-28 10:53:24 +09:00
Alexander ba45852ca5 revert(ci): re-add platforms since builds were added 2021-08-28 10:35:02 +09:00
Alexander 4f452b71c9 feature(ci): add additional platforms to release 2021-08-28 10:32:35 +09:00
Alexander 3fddbefdb5 fix(ci): seaweedfs does not build for ppc or z-kernel systems 2021-08-28 09:59:23 +09:00
Chris LuandGitHub dded814a62 Merge pull request #2287 from logband/chore-ci-update
chore(ci): move to using newer metadata action
2021-08-27 17:10:33 -07:00
Alexander 059e88d5df chore(ci): move to using newer metadata action
The crazy-max/ghaction-docker-meta@v2 action was moved to docker/metadata-action@v3.
2021-08-28 08:29:32 +09:00
Chris LuandGitHub 9cbb8a14b2 Merge pull request #2286 from logband/add-dev-container-build
feature(ci): add container build testing
2021-08-27 16:12:33 -07:00
Alexander 1d4e412f93 feature(ci): trigger on pull request 2021-08-28 08:11:37 +09:00
Chris LuandGitHub 27cf03d031 Merge pull request #2285 from logband/master
fix(ci): remove linux/riscv64
2021-08-27 16:10:08 -07:00
Alexander 0f85bcaba8 feature(ci): add container build testing 2021-08-28 08:08:54 +09:00
Alexander d0990651ce fix(ci): remove linux/riscv64 2021-08-28 07:59:02 +09:00
Chris LuandGitHub 7be3ab4dc7 Merge pull request #2284 from logband/master
fix(ci): remove mips since alpine does not support it
2021-08-27 15:54:50 -07:00
Alexander e2a7399f69 fix(ci): remove mips since alpine does not support it 2021-08-28 07:52:28 +09:00
Chris LuandGitHub 6ed2e2a21d Merge pull request #2283 from logband/master
fix(ci): add multi-arch image builds
2021-08-27 15:45:21 -07:00
Alexander 72ea1a9a21 fix(ci): add obscure platforms 2021-08-28 07:25:17 +09:00
Alexander 29bc6cb9a2 fix(ci): add multi-arch image builds
Fixes !2282.
2021-08-28 07:05:08 +09:00
Chris Lu dc936921aa ensure the following logic are executed 2021-08-26 18:20:14 -07:00
Chris Lu 9242f3aaeb fix build 2021-08-26 17:33:57 -07:00
Chris Lu 49a8dfb976 adjust default concurrent level 2021-08-26 17:05:56 -07:00
Chris Lu 6a0bb7106b cloud drive: parallelize remote storage downloading 2021-08-26 16:16:26 -07:00
Chris Lu 05a648bb96 refactor: separating out remote.proto 2021-08-26 15:18:34 -07:00
yulai.li c1dc5ab4ac Add deleterange_concurrency to filer configuration file 2021-08-26 18:25:08 +08:00
yulai.li 318757ef8c Change DeleteFolderChildren to DeleteRange api 2021-08-26 17:49:56 +08:00
yulai.li de8ef28460 Update filer.toml scaffold to support tikv store 2021-08-26 16:26:27 +08:00
yulai.li 546efeba8f Fix build bug 2021-08-26 16:20:35 +08:00
yulai.li 2088f28424 init post 2021-08-26 15:20:18 +08:00
Chris Lu c08ac536ed cloud drive: add support for Wasabi
* disable md5, sha256 checking to avoid reading one chunk twice
* single threaded upload to avoid chunk swapping (to be enhanced later)
2021-08-25 17:34:29 -07:00
Chris Lu 9bcf94b2b1 ensure multi-threaded correctness 2021-08-25 17:28:50 -07:00
Chris Lu a7a914f120 cloud drive: add support for Baidu BOS 2021-08-24 23:46:33 -07:00
Chris Lu 2d805beed4 add help mesages 2021-08-24 23:28:35 -07:00
Chris Lu c6c97bd83d add default env variables 2021-08-24 23:25:36 -07:00
Chris Lu a19c728034 cloud drive: add support for Tencent COS 2021-08-24 23:19:45 -07:00
Chris Lu 19a81d25af cloud drive: add support for Aliyun OSS 2021-08-24 23:14:24 -07:00
Chris Lu 47d775cf68 cloud drive: add support for BackBlaze 2021-08-24 22:30:06 -07:00
Chris Lu 6bab20d862 cat entry content 2021-08-24 02:38:32 -07:00
Chris Lu e9ebe24f2e cloud drive: add support for Azure 2021-08-24 01:18:30 -07:00
Chris Lu 7c39a18ba5 update azure library 2021-08-24 00:32:35 -07:00
Chris Lu a78d0227cd adjust package name 2021-08-23 23:19:31 -07:00
Chris Lu 12631a3f5b cloud drive: gcs simplify a little bit 2021-08-23 14:43:01 -07:00
Chris Lu 95a6e0226d move readme 2021-08-23 13:37:40 -07:00
Chris Lu 7eeff1d8a1 rename directory 2021-08-23 13:37:09 -07:00
Chris Lu 93741a6752 remove unused travis related files
fix https://github.com/chrislusf/seaweedfs/issues/2277
2021-08-23 13:33:33 -07:00
Chris LuandGitHub 949ff6475e Update release.yml 2021-08-23 12:52:18 -07:00
Chris LuandGitHub 76422cbe35 Update release.yml 2021-08-23 12:45:44 -07:00
Chris LuandGitHub 68157f3630 Update release.yml 2021-08-23 12:38:58 -07:00
Chris Lu 2ead7adaff Java: FilerProto.Entry can read size via attributes 2021-08-23 12:19:02 -07:00
Chris Lu 00c4e06caa cloud drive: s3 configurable force path style 2021-08-23 03:30:41 -07:00
Chris Lu f0cc130849 do not force path style for better compatibility 2021-08-23 03:09:41 -07:00
Chris Lu 2836a58d87 cloud drive: S3 supports storage class 2021-08-23 02:18:59 -07:00
Chris LuandGitHub 188ecc079d Update README.md 2021-08-23 01:01:29 -07:00
Chris Lu 95e2b83ca5 fix format 2021-08-23 00:49:59 -07:00
Chris Lu ff7dc3b44c 2.64 2021-08-23 00:39:15 -07:00
Chris Lu ca35a77e85 adjust help message 2021-08-23 00:37:55 -07:00
Chris Lu 258063de26 cloud drive: add google cloud storage 2021-08-23 00:29:27 -07:00
Chris Lu 3b2c39f1be mount: set name when mount path equals mount folder
fix https://github.com/chrislusf/seaweedfs/issues/2275#issuecomment-903255876
2021-08-22 04:59:09 -07:00
Chris Lu 2158d4fe4d adjust help message 2021-08-21 02:17:10 -07:00
Chris LuandGitHub 69442d220b Update README.md 2021-08-21 01:39:42 -07:00
Chris LuandGitHub 69c7b7d2a8 Update README.md 2021-08-21 01:36:17 -07:00
Chris LuandGitHub 1b1ab331f6 Merge pull request #2274 from qieqieplus/gzip-pool 2021-08-20 04:22:41 -07:00
qieqieplus 7720533f84 reduce gzip allocation 2021-08-20 18:38:18 +08:00
Chris Lu 05fc7db755 filer.copy: large files pack file ids into chunks 2021-08-18 23:46:54 -07:00
Chris LuandGitHub 02e8f00138 Merge pull request #2271 from mauroparente/master
Fix image resize
2021-08-18 14:33:54 -07:00
mauroparenteandGitHub c63713774b Fix image resize
https://github.com/chrislusf/seaweedfs/issues/2262
2021-08-18 23:15:35 +02:00
Chris Lu 570d2eccec skip body if not allowed by http status 2021-08-18 00:56:35 -07:00
Chris LuandGitHub 605c39ced7 Update README.md 2021-08-17 12:59:26 -07:00
Chris Lu ccb3df41f8 elide secret key 2021-08-17 11:27:08 -07:00
Chris Lu e64339e8c0 update go mod to go 1.17 2021-08-17 11:20:50 -07:00
Chris Lu 223b344c79 update fuse version 2021-08-17 11:18:22 -07:00
Chris LuandGitHub 0e9276b947 Merge pull request #2270 from kmlebedev/gccgo_build
gccgo build
2021-08-17 09:54:06 -07:00
Konstantin Lebedev 1f301e4ba4 gccgo build 2021-08-17 20:27:47 +05:00
Chris Lu 1057d3ac53 go mod tidy -compat=1.17 2021-08-17 03:42:19 -07:00
Chris Lu 8461c025ef mount: use pooled goroutine instead of round-robin
fix https://github.com/chrislusf/seaweedfs/issues/2263
2021-08-17 03:37:06 -07:00
Chris LuandGitHub d2c8f01671 Merge pull request #2267 from kmlebedev/IEEEoptimizations
The IEEE assembler optimizations has been submitted and will be part …
2021-08-17 01:32:52 -07:00
Konstantin Lebedev 865b06b7fe The IEEE assembler optimizations has been submitted and will be part of the Go 1.6 standard library.
https://github.com/klauspost/crc32
2021-08-17 13:06:48 +05:00
Chris Lu d24ad92513 fix building latest docker image 2021-08-16 18:47:46 -07:00
Chris Lu 7bf65c1e99 use go 1.17 for docker 2021-08-16 18:47:46 -07:00
Chris LuandGitHub 5315fcb820 Update README.md 2021-08-16 17:24:16 -07:00
Chris Lu f316de3b5c disable travis 2021-08-16 17:17:24 -07:00
Chris Lu 1023bce6f0 update go version 2021-08-16 17:14:32 -07:00
Chris Lu 8109594c6e Update README.md 2021-08-16 02:57:21 -07:00
Chris LuandGitHub 6f9107862f Update release.yml 2021-08-16 00:29:25 -07:00
Chris LuandGitHub 48f88f9768 Update release_binaries.yml 2021-08-16 00:14:06 -07:00
Chris LuandGitHub d81b20dabb Create release_binaries.yml 2021-08-16 00:11:13 -07:00
Chris Lu e2aa3cf63b fix go test 2021-08-15 23:20:46 -07:00
Chris Lu 1f35d32be0 2.63 2021-08-15 23:14:59 -07:00
Chris Lu 40dc283b2d fix locating data chunks 2021-08-15 23:07:58 -07:00
Chris Lu 72eb6d5b9d ensure no writes to remote storage if content is not changed 2021-08-15 20:23:41 -07:00
Chris Lu 5a7c40510f format output 2021-08-15 20:07:13 -07:00
Chris Lu bb94930196 add some delays if error 2021-08-15 20:06:47 -07:00
Chris Lu 5d5a21ba2d adjust log format 2021-08-15 19:46:45 -07:00
Chris Lu c45c12aedc metadata updates 2021-08-15 19:27:30 -07:00
Chris Lu 507411bdf0 fix https://github.com/chrislusf/seaweedfs/issues/2260
fix https://github.com/chrislusf/seaweedfs/issues/2260
2021-08-15 19:16:00 -07:00
Chris Lu c3ffd457ef fix compilation error 2021-08-15 12:40:22 -07:00
Chris Lu 49b5e47bd1 retry forever with filer.remote.sync, and some refactoring 2021-08-15 12:38:26 -07:00
Chris Lu fda2fc47b1 add RetryForever 2021-08-15 12:37:35 -07:00
Chris Lu a539d64896 refactor 2021-08-15 12:09:54 -07:00
Chris Lu 8f7d2d317f readerAt need to use the right offset
fix https://github.com/chrislusf/seaweedfs/issues/2259
2021-08-15 11:55:58 -07:00
Chris Lu 0b2a92d371 skip if http.StatusNoContent 2021-08-15 11:27:49 -07:00
Chris Lu ec989b0377 remove println 2021-08-15 02:10:27 -07:00
Chris Lu 9462f5129a shell: add "remote.meta.sync" 2021-08-15 01:53:46 -07:00
Chris Lu 3ada61c875 rename 2021-08-14 21:50:35 -07:00
Chris Lu c34747c79d rename, fix wrong logic. 2021-08-14 21:46:34 -07:00
Chris Lu cb53802752 adjust help message 2021-08-14 15:55:53 -07:00
Chris Lu 889b143fa7 adjust modification detection logic 2021-08-14 15:44:47 -07:00
Chris Lu f365af81c2 parallelize remote content fetching 2021-08-14 15:41:37 -07:00
Chris Lu 00ffbb4c9a Update SeaweedFS_RemoteMount.png 2021-08-14 15:18:38 -07:00
Chris Lu 53e66980b2 add comments 2021-08-14 15:16:10 -07:00
Chris Lu 9921801e0c Revert "use default or path-specific setting for cache replication level"
This reverts commit ba6923b223.
2021-08-14 15:14:26 -07:00
Chris Lu ba6923b223 use default or path-specific setting for cache replication level 2021-08-14 15:14:01 -07:00
Chris Lu 708debca14 remote.cache and uncache: more flexible options to select files to cache or uncache 2021-08-14 15:11:55 -07:00
Chris Lu 0c671885bf Update SeaweedFS_RemoteMount.png 2021-08-14 11:47:10 -07:00
Chris LuandGitHub e2115bfbd2 Update README.md 2021-08-14 11:37:53 -07:00
Chris LuandGitHub 0e9c04417d Update README.md 2021-08-14 11:35:44 -07:00
Chris Lu 2c38f8738f Update SeaweedFS_RemoteMount.png 2021-08-14 08:04:55 -07:00
Chris Lu e0c45c24f5 Update SeaweedFS_RemoteMount.png 2021-08-14 07:28:56 -07:00
Chris Lu c587acf3ee Delete SeaweedFS_LogicalStructure.png 2021-08-14 07:24:04 -07:00
Chris Lu 561bea954d Update SeaweedFS_RemoteMount.png 2021-08-14 07:23:23 -07:00
Chris Lu 8ea9a2434d Added SeaweedFS_RemoteMount.png 2021-08-14 06:20:02 -07:00
Chris Lu 68b1667272 Added SeaweedFS_LogicalStructure.png 2021-08-14 06:18:23 -07:00
Chris Lu 08258a819d fix mistake 2021-08-14 05:10:30 -07:00
Chris Lu 4909bd9684 gRpc connection error on filer when no volume left #2243
fix https://github.com/chrislusf/seaweedfs/issues/2243

grpc do not cache connections only when connection problem happens.
Normal error results should not close the shared grpc connection.
2021-08-14 05:06:44 -07:00
Chris Lu 8126ab4b5d rename 2021-08-14 05:03:45 -07:00
Chris Lu 0db2517994 go fmt 2021-08-14 02:55:44 -07:00
Chris Lu 7937db52e1 Filer locationPrefix configure does not exec replication #2257
fix https://github.com/chrislusf/seaweedfs/issues/2257
2021-08-14 02:54:13 -07:00
Chris Lu 0c66b173a4 fix 2021-08-13 11:31:43 -07:00
Chris Lu e02a317d3d adjust retry logic in case some data is partially written 2021-08-13 11:30:38 -07:00
Chris Lu 2d519c6cb6 adjust the retry logic 2021-08-13 11:13:30 -07:00
Chris Lu b961fcd338 filer: stream read from volume server, reduce memory usage 2021-08-13 11:00:11 -07:00
Chris Lu f4decf02df volume copying: clean up stale volume data files
fix https://github.com/chrislusf/seaweedfs/issues/2250
2021-08-13 03:24:21 -07:00
Chris Lu 0f7d4556d8 shell: volume.tier.move makes up changes if volume move failed 2021-08-13 03:09:28 -07:00
Chris Lu 333cdce485 add verbose message 2021-08-13 02:57:14 -07:00
Chris Lu 78e8ddf910 Only when tailing volume, the zero-ed cookie should skip checking.
This only happens when checkCookie == false and fsync == false.
2021-08-13 02:09:35 -07:00
Chris Lu a8617c1a39 tail volume: fix zero cookie problem from batch deletion 2021-08-13 01:54:35 -07:00
Chris Lu 5a0f92423e use grpc and jwt 2021-08-12 21:40:33 -07:00
Chris Lu 6238644c35 remove gateway command 2021-08-12 20:52:04 -07:00
Chris Lu d1d1fc772c move some volume lookup operations to grpc
jwt related lookup will come in next commit
2021-08-12 20:33:00 -07:00
Chris Lu 5571f4f70a master: add master.follower to handle read file id lookup requests 2021-08-12 18:10:59 -07:00
Chris Lu 5469019852 adjust data type 2021-08-12 17:54:34 -07:00
Chris Lu 7667d26ebf gocql update
related to https://github.com/chrislusf/seaweedfs/issues/2246
2021-08-12 00:20:11 -07:00
Chris Lu bfac55e6c0 avoid integer overflow
fix https://github.com/chrislusf/seaweedfs/issues/2254
2021-08-11 22:22:49 -07:00
Chris LuandGitHub 5516fa8e80 Merge pull request #2251 from kmlebedev/rertyUpdateIamIdentity
Retry save and update IAM identity
2021-08-11 09:21:03 -07:00
Chris LuandGitHub a51447ffcb Merge pull request #2252 from combineads/sync_isOpen
Synchronize number of open files
2021-08-11 09:10:25 -07:00
Konstantin Lebedev f0afd35eec Retry save and update IAM identity
https://github.com/chrislusf/seaweedfs/issues/2242
2021-08-11 19:29:04 +05:00
byunghwa.yun 775dfbae85 Synchronize number of open files 2021-08-11 23:14:56 +09:00
Konstantin Lebedev ec09966fd3 Retry save and update IAM identity
https://github.com/chrislusf/seaweedfs/issues/2242
2021-08-11 17:53:48 +05:00
Chris LuandGitHub 5df38d610d Update README.md 2021-08-10 15:43:21 -07:00
Chris Lu f2cd753bf9 fix avoid lock error
fix https://github.com/chrislusf/seaweedfs/issues/2247
2021-08-10 14:34:13 -07:00
Chris Lu 01336d71eb minor 2021-08-10 13:04:33 -07:00
Chris Lu 1154e23e2d add logs for volume creation 2021-08-10 13:04:25 -07:00
Chris Lu 057ef429ac format 2021-08-10 12:33:29 -07:00
Chris Lu b63b042afc dedup keeps the largest replica 2021-08-10 12:30:41 -07:00
Chris Lu 0526db12e2 do not treat read only volumes differently 2021-08-10 11:37:12 -07:00
Chris Lu e50a5b8e28 minor: print disk type 2021-08-10 11:10:09 -07:00
Chris Lu db6275a0c8 print out balance ratio 2021-08-10 10:43:42 -07:00
Chris Lu 9d85569c55 ensure using local quorum consistency 2021-08-10 05:10:57 -07:00
Chris Lu 85832d02c0 wait for goroutines 2021-08-10 04:13:12 -07:00
Chris LuandGitHub 1098ed0d78 Merge pull request #2245 from Bl1tz23/master
Simple healthcheck for S3 API Server
2021-08-10 04:00:15 -07:00
Bl1tz23 095f66cd64 returned deps target call to build Makefile target 2021-08-10 13:51:04 +03:00
Bl1tz23 1c94b3d013 merge master, resolve conflicts 2021-08-10 13:45:24 +03:00
Bl1tz23 e6e57db530 Add liveness\readiness probe for s3 api handler on /status path 2021-08-10 13:42:46 +03:00
Chris LuandGitHub f9cf9b93d3 Update release.yml 2021-08-10 03:30:18 -07:00
Chris Lu 8ff6c9a0c6 output format 2021-08-10 03:25:18 -07:00
Chris Lu 48f448ee09 parallelize tier move 2021-08-10 03:08:29 -07:00
Chris Lu 69a6da7969 avoid fail on tail error 2021-08-10 02:50:28 -07:00
Chris Lu 18228f3044 fix help message 2021-08-10 02:48:41 -07:00
Chris Lu e9128e75d0 Java: 1.6.7 Support Mounted Remote Storage 2021-08-09 22:46:12 -07:00
Chris Lu 69655ba8e5 mount: cache on reading remote storage 2021-08-09 22:11:57 -07:00
Chris Lu a7012d9729 fix 2021-08-09 16:03:03 -07:00
Chris Lu 02f728cb54 fix bug with remote.uncache 2021-08-09 15:24:21 -07:00
Chris Lu 8d3e275735 remote: filer cache remote content on read 2021-08-09 15:16:45 -07:00
Chris Lu 9096f6f4f7 cache: set upper limit of chunk size 2021-08-09 15:08:53 -07:00
Chris Lu 402315f117 go fmt 2021-08-09 14:37:34 -07:00
Chris Lu a6be2520c9 fix 2021-08-09 14:37:25 -07:00
Chris Lu 713c035a6e shell: remote.cache remote.uncache 2021-08-09 14:35:18 -07:00
Chris Lu 8cfd487608 2.62 2021-08-08 23:33:12 -07:00
Chris Lu 734c980040 volume: support concurrent download data size limit 2021-08-08 23:25:16 -07:00
Chris Lu 96ce85f5ae rename 2021-08-08 22:33:31 -07:00
Chris Lu c5f38c365d go fmt 2021-08-08 22:30:36 -07:00
Chris Lu df85f7a1eb adjust help message 2021-08-08 22:30:12 -07:00
Chris Lu c0b12da4ef shell: add filer.remote.unmount 2021-08-08 22:26:37 -07:00
Chris LuandGitHub 52fcce81c6 Merge pull request #2241 from chrislusf/add_remote_storage
WIP: remote storage
2021-08-08 18:55:53 -07:00
Chris Lu 882a93dacd fix tests 2021-08-08 17:56:26 -07:00
Chris Lu 7412ccdf88 write back remote entry to local entry after uploading to remote 2021-08-08 17:55:03 -07:00
Chris Lu dcf614a8c3 skip if the remote entry update is because of internal managerial operations 2021-08-08 15:58:10 -07:00
Chris Lu eed26af266 Merge branch 'master' into add_remote_storage 2021-08-08 15:48:04 -07:00
Chris Lu 4370a4db63 use int64 for volume count in case of negative overflow 2021-08-08 15:19:39 -07:00
Chris Lu 26c222f596 shell: volume.tier.move avoid moving all volumes to one destination 2021-08-08 15:12:39 -07:00
Chris Lu 13e45e1605 filer.remote.sync can work now 2021-08-08 01:21:42 -07:00
Chris Lu 8f5170c138 remove imports 2021-08-07 16:20:17 -07:00
Chris Lu 46b0cb8c86 Merge branch 'master' into add_remote_storage 2021-08-07 15:41:27 -07:00
Chris Lu de730b079d ChunkStreamReader implenents io.ReaderAt 2021-08-07 15:41:07 -07:00
Chris Lu 59732a0529 refactoring 2021-08-07 15:35:27 -07:00
Chris Lu d2b3416d1c java: use empty value as replication default 2021-08-07 14:54:00 -07:00
Chris Lu ecb234f75a refactor 2021-08-07 14:46:23 -07:00
Chris Lu 270770d7d7 refactor 2021-08-07 14:18:53 -07:00
Chris Lu 679f800caa Merge branch 'master' into add_remote_storage 2021-08-06 20:27:12 -07:00
Chris Lu 0c0f77e2ae skip not found error on deletion 2021-08-06 19:35:47 -07:00
Chris Lu 8828f485c0 print volume deletion error 2021-08-06 19:30:22 -07:00
Chris LuandGitHub d2b23f3d38 Merge pull request #2238 from combineads/change_default_mode
Change default permissions
2021-08-05 21:28:06 -07:00
Chris LuandGitHub e23ca3845b Merge pull request #2237 from combineads/add_mtime
Add crtime and mtime
2021-08-05 21:27:13 -07:00
Chris Lu 286e5dd375 Merge branch 'master' into add_remote_storage 2021-08-05 21:07:04 -07:00
Chris Lu 1e22166939 adjust error message 2021-08-05 21:06:55 -07:00
byunghwa.yun f3dc909b21 Change default permissions 2021-08-06 12:24:35 +09:00
byunghwa.yun e84fad9acf Add crtime and mtime 2021-08-06 12:13:37 +09:00
Chris Lu 1a5d29520c add tests 2021-08-05 14:49:24 -07:00
Chris Lu 6b743dbbf9 refactor client subscribe metadata 2021-08-04 16:25:46 -07:00
Chris Lu b9ecf1e3a8 refacotring 2021-08-04 14:56:13 -07:00
Chris Lu d84c311699 refactoring 2021-08-04 12:30:18 -07:00
Chris Lu f6a9ad8001 fix tests 2021-08-04 00:31:06 -07:00
Chris Lu 42969c9c62 Merge branch 'master' into add_remote_storage 2021-08-03 21:20:05 -07:00
Chris Lu 8cf0c515bf shell: volume.fix.replication retries even when there is no error #2235
fix https://github.com/chrislusf/seaweedfs/issues/2235
2021-08-03 09:32:55 -07:00
Chris Lu d2ddf1dbdb typo 2021-08-03 09:32:31 -07:00
Chris Lu 3afbf04007 add TLS grpc support for filer meta clients 2021-08-03 01:30:35 -07:00
Chris Lu fe60c6ef9a minor changes 2021-08-02 11:49:40 -07:00
Chris LuandGitHub 0ca641f33c Merge pull request #2232 from combineads/master
Add autocomplete
2021-08-02 11:46:48 -07:00
byunghwa.yun bdc7730fdb Add autocomplete 2021-08-03 02:56:52 +09:00
Chris Lu 2ae9705442 adjust text 2021-08-01 22:55:19 -07:00
Chris Lu 3739717092 Revert "adds a test"
This reverts commit f690643b47.
2021-08-01 22:54:45 -07:00
Chris Lu f690643b47 adds a test 2021-08-01 22:53:50 -07:00
Chris Lu 6de786185d volume.balance: balance read only volumes first 2021-08-01 22:32:50 -07:00
Chris Lu 3bb640b786 add -force option following #2228 2021-08-01 20:03:05 -07:00
Chris LuandGitHub 02fd913b51 Merge pull request #2228 from combineads/master 2021-08-01 19:46:00 -07:00
byunghwa.yun 9e839cb5cc Add force option in volume.deleteEmpty command 2021-08-02 11:37:20 +09:00
Chris Lu 56ee1d5ef1 2.61 2021-08-01 15:50:19 -07:00
Chris Lu 81b255df8b Merge branch 'master' into add_remote_storage 2021-08-01 15:44:21 -07:00
Chris Lu 58bc3ecf47 add default quietFor value 2021-08-01 15:36:06 -07:00
Chris Lu 2ca1839d77 shell: add volume.deleteEmpty command 2021-08-01 15:33:45 -07:00
Chris Lu 89933c46d2 s3: skip hidden directories in /buckets folder 2021-08-01 12:28:08 -07:00
Chris Lu 1c7e404abe remove buckets folder option
the related code still works for old deployments
2021-08-01 12:23:16 -07:00
Chris Lu cb1dbd3135 refactor 2021-08-01 11:53:46 -07:00
Chris Lu 1161c70dab Merge branch 'master' into add_remote_storage 2021-08-01 01:10:13 -07:00
Chris Lu 9cc84a910f volume: deletion can skip volume size checking
fix https://github.com/chrislusf/seaweedfs/issues/2225
2021-08-01 00:32:51 -07:00
Chris Lu 767edd3c08 rename 2021-07-31 23:52:09 -07:00
Chris Lu 9df7d16791 read <- remote_storage 2021-07-31 22:39:38 -07:00
Chris Lu f5a69a0e44 Merge branch 'master' into add_remote_storage 2021-07-31 09:39:48 -07:00
Chris Lu 6ba65c3382 customizable debug port 2021-07-31 09:18:41 -07:00
Chris LuandGitHub 10c11b9fd1 Merge pull request #2226 from combineads/master 2021-07-31 07:23:07 -07:00
byunghwa.yun 5d4438a72f Fix typo 2021-07-31 22:23:52 +09:00
Chris Lu 1ff8285d82 debug from any server 2021-07-31 02:13:21 -07:00
Chris Lu 0d6f45cb46 add debug option to generate full goroutine stack dump 2021-07-31 02:00:01 -07:00
Chris Lu a3290faf17 shell command to calculate size / number of volumes in a collection
fix https://github.com/chrislusf/seaweedfs/issues/2224
2021-07-30 15:49:46 -07:00
Chris Lu c6f992b2a3 remove dead code 2021-07-30 15:18:01 -07:00
Chris Lu 899963ac20 remote storage location changed to struct 2021-07-29 02:08:55 -07:00
Chris LuandGitHub c16e366fb2 Merge pull request #2223 from combineads/see_meta_detail
Add the additional meta log
2021-07-29 02:08:19 -07:00
byunghwa.yun 285fdd2dd5 Add the additional meta log 2021-07-29 17:43:17 +09:00
Chris Lu c090d6bb25 add ReadRemote(), add read remote setup when filer starts 2021-07-28 22:43:12 -07:00
Chris Lu 4deac06da0 log fix 2021-07-28 22:25:04 -07:00
Chris LuandGitHub ddff849ea6 Merge pull request #2221 from divanikus/master
shell: ability to use wildcards for collections, all collections if ommited
2021-07-27 14:31:13 -07:00
divanikus 5c6270a93a shell: ability to use wildcards for collections, all collections if ommited 2021-07-27 23:53:01 +03:00
Chris Lu 035b0bae29 refactor 2021-07-27 03:32:24 -07:00
Chris Lu 1752eeb538 remote.mount saves the mapping 2021-07-27 03:26:35 -07:00
Chris Lu 4b94b03d90 directory to remote storage mapping 2021-07-27 01:16:28 -07:00
Chris Lu 99b599aa8a remote.mount 2021-07-26 22:53:44 -07:00
Chris Lu 5dede5d38d 2.60 2021-07-25 22:09:09 -07:00
Chris Lu 35f70c51b0 refactor 2021-07-25 03:37:37 -07:00
Chris Lu 72eec84167 shell: add fs.mkdir 2021-07-25 02:37:39 -07:00
Chris LuandGitHub 8dccefbba6 Merge pull request #2218 from combineads/fix_sql_for_batch_delete
Fix mysql sql for batch delete
2021-07-24 21:05:50 -07:00
byunghwa.yun 2b28a818f1 Fix mysql sql for batch delete 2021-07-25 11:06:14 +09:00
Chris LuandGitHub 10464f47d0 Merge pull request #2217 from combineads/add_webp_format 2021-07-24 09:42:41 -07:00
byunghwa.yun 7374b5b473 Add webp extension for resizing 2021-07-24 14:32:31 +09:00
byunghwa.yun 2595f269d1 Add the webp image type 2021-07-24 14:26:40 +09:00
Chris Lu ac28611817 snowflake sequencer need an unique id
fix https://github.com/chrislusf/seaweedfs/issues/2213
2021-07-23 20:54:03 -07:00
Chris Lu 5c14da0f1e filer.copy: fail early if assign request failed
fix https://github.com/chrislusf/seaweedfs/issues/2216
2021-07-23 20:01:43 -07:00
Chris Lu 4cc2165061 weed -h subcommand list is not sorted, makes discovery difficult
fix https://github.com/chrislusf/seaweedfs/issues/2214
2021-07-23 18:44:53 -07:00
Chris Lu 10fc478557 scaffold -config= should output to stdout
fix https://github.com/chrislusf/seaweedfs/issues/2212
2021-07-23 18:41:25 -07:00
Chris Lu 092932af8f shell: faster bucket delete
avoid waiting for large object metadata
2021-07-23 11:25:46 -07:00
Chris LuandGitHub bdb632fa62 Merge pull request #2211 from qieqieplus/filer-bloom-filter
add bloom filter for filer leveldb/rocksdb
2021-07-22 23:35:54 -07:00
qieqieplus 2b46df13f8 add bloom filter for filer leveldb/rocksdb 2021-07-23 14:05:59 -06:00
Chris Lu 60f5c0a2f5 fix security alert on github.com/dgrijalva/jwt-go
resolve https://github.com/chrislusf/seaweedfs/security/dependabot/go.mod/github.com%2Fdgrijalva%2Fjwt-go/open
2021-07-22 10:22:09 -07:00
Chris Lu f3746d350f resolve gjson security alert
resolve https://github.com/chrislusf/seaweedfs/security/dependabot/go.mod/github.com%2Ftidwall%2Fgjson/open
2021-07-22 09:57:49 -07:00
Chris Lu a70e772a03 update mongodb lib due to security warning 2021-07-22 09:49:40 -07:00
Chris Lu 182288f860 filer: fix mysql, postgres batch delete error 2021-07-22 08:23:20 -07:00
Chris Lu 84d91f143f mount: hide /etc folder also from mount 2021-07-22 00:40:16 -07:00
Chris Lu 7359193e97 go fmt 2021-07-21 14:38:12 -07:00
Chris LuandGitHub cc32436d63 Merge pull request #2209 from combineads/fuse_option
Fix error handling
2021-07-21 12:37:20 -07:00
Chris LuandGitHub 67537ff05b Merge pull request #2208 from combineads/add_rm_options 2021-07-21 11:08:43 -07:00
byunghwa.yun e0c7708b03 Fix error handling 2021-07-21 22:48:04 +09:00
byunghwa.yun 41d559f54e Add fs rm options 2021-07-21 21:10:36 +09:00
Chris Lu 70effac0d3 configure and store remote configurations 2021-07-21 02:24:34 -07:00
Chris LuandGitHub 3138805b33 Merge pull request #2200 from combineads/add_fs_rm
weed shell: fs.rm remove file or directory
2021-07-21 00:35:54 -07:00
Chris LuandGitHub a125c8fbe2 Merge pull request #2204 from nivekuil/tokenpolicy
cassandra: use LocalQuorum for all queries
2021-07-20 15:37:31 -07:00
nivekuil b9a67d46c5 cassandra: use LocalQuorum for all queries
This changes this filer store from eventual to strong consistency at the cost
of read performance.
2021-07-20 14:47:39 -07:00
Chris Lu 54c8bc8673 Merge branch 'remote_overlay' 2021-07-19 23:18:35 -07:00
Chris Lu 7ab389e7ec optimization: improve random range query for large files 2021-07-19 23:07:22 -07:00
Chris LuandGitHub 93c37cfded Update filechunk_manifest.go 2021-07-19 18:41:41 -07:00
byunghwa.yun b23b307e08 Add fs rm 2021-07-20 08:49:28 +09:00
Chris Lu b938df97a2 remove unused parameter 2021-07-19 02:59:12 -07:00
Chris Lu 450222dd64 add remote to filer.Entry and filer_pb entry, add RemoteConf 2021-07-19 02:47:27 -07:00
Chris Lu 8dc5def435 proto: add remote 2021-07-19 01:12:31 -07:00
Chris Lu 99155e4880 add -retry option for volume.fix.replication
fix https://github.com/chrislusf/seaweedfs/issues/2191
2021-07-16 12:13:46 -07:00
Chris Lu 2f209675ab Added -retry option for volumeServer.evacuate
related to https://github.com/chrislusf/seaweedfs/issues/2191
2021-07-16 12:08:21 -07:00
Chris Lu fb7a1be1c4 refactor 2021-07-16 11:47:37 -07:00
Chris LuandGitHub 3f31c4091a Merge pull request #2198 from nivekuil/tokenpolicy 2021-07-16 08:55:55 -07:00
nivekuil 2faf96f002 cassandra: Use LocalOne instead of One consistency 2021-07-16 04:29:46 -07:00
Chris Lu 4be5b4ff5c [volume.check.disk] skip errors and check next volumes
fix https://github.com/chrislusf/seaweedfs/issues/2129
2021-07-16 02:03:32 -07:00
Chris Lu e95166d739 S 2021-07-15 17:43:38 -07:00
380 changed files with 15507 additions and 6757 deletions
@@ -1,4 +1,4 @@
name: Release
name: "go: build dev binaries"
on:
push:
@@ -6,36 +6,48 @@ on:
jobs:
build:
name: Build
cleanup:
runs-on: ubuntu-latest
steps:
- name: Delete old release assets
uses: mknejp/delete-release-assets@v1
with:
token: ${{ github.token }}
tag: dev
fail-if-no-assets: false
assets: |
weed-*
build_dev:
needs: cleanup
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux, windows, darwin, freebsd ]
goarch: [amd64, arm]
goos: [linux, windows, darwin, freebsd]
goarch: [amd64, arm, arm64]
exclude:
- goarch: arm
goos: darwin
- goarch: 386
goos: darwin
- goarch: arm
goos: windows
- goarch: arm64
goos: windows
steps:
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Wait for the deletion
uses: jakejarvis/wait-action@master
with:
time: '30s'
- name: Set BUILD_TIME env
run: echo BUILD_TIME=$(date -u +%Y-%m-%d-%H-%M) >> ${GITHUB_ENV}
run: echo BUILD_TIME=$(date -u +%Y%m%d-%H%M) >> ${GITHUB_ENV}
- name: Go Release Binaries
uses: wangyoucao577/go-release-action@v1.17
- name: Go Release Binaries Large Disk
uses: wangyoucao577/go-release-action@v1.20
with:
goversion: 1.16
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
@@ -49,10 +61,9 @@ jobs:
binary_name: weed-large-disk
asset_name: "weed-large-disk-${{ env.BUILD_TIME }}-${{ matrix.goos }}-${{ matrix.goarch }}"
- name: Go Release Binaries
uses: wangyoucao577/go-release-action@v1.17
- name: Go Release Binaries Normal Volume Size
uses: wangyoucao577/go-release-action@v1.20
with:
goversion: 1.16
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
@@ -62,5 +73,5 @@ jobs:
ldflags: -extldflags -static -X github.com/chrislusf/seaweedfs/weed/util.COMMIT=${{github.sha}}
# Where to run `go build .`
project_path: weed
binary_name: weed
binary_name: weed-normal-disk
asset_name: "weed-${{ env.BUILD_TIME }}-${{ matrix.goos }}-${{ matrix.goarch }}"
+63
View File
@@ -0,0 +1,63 @@
# This is a basic workflow to help you get started with Actions
name: "go: build versioned binaries"
on:
push:
tags:
- '*'
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build-release-binaries:
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux, windows, darwin, freebsd]
goarch: [amd64, arm, arm64]
exclude:
- goarch: arm
goos: darwin
- goarch: 386
goos: darwin
- goarch: arm
goos: windows
- goarch: arm64
goos: windows
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Go Release Binaries Normal Volume Size
uses: wangyoucao577/go-release-action@v1.20
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
overwrite: true
pre_command: export CGO_ENABLED=0
# build_flags: -tags 5BytesOffset # optional, default is
ldflags: -extldflags -static -X github.com/chrislusf/seaweedfs/weed/util.COMMIT=${{github.sha}}
# Where to run `go build .`
project_path: weed
binary_name: weed
asset_name: "${{ matrix.goos }}_${{ matrix.goarch }}"
- name: Go Release Large Disk Binaries
uses: wangyoucao577/go-release-action@v1.20
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
overwrite: true
pre_command: export CGO_ENABLED=0
build_flags: -tags 5BytesOffset # optional, default is
ldflags: -extldflags -static -X github.com/chrislusf/seaweedfs/weed/util.COMMIT=${{github.sha}}
# Where to run `go build .`
project_path: weed
binary_name: weed
asset_name: "${{ matrix.goos }}_${{ matrix.goarch }}_large_disk"
-22
View File
@@ -1,22 +0,0 @@
name: Cleanup
on:
push:
branches: [ master ]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Delete old release assets
uses: mknejp/delete-release-assets@v1
with:
token: ${{ github.token }}
tag: dev
fail-if-no-assets: false
assets: |
weed-*
+63
View File
@@ -0,0 +1,63 @@
name: "docker: build dev containers"
on:
push:
branches: [ master ]
workflow_dispatch: []
jobs:
build-dev-containers:
runs-on: [ubuntu-latest]
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Docker meta
id: docker_meta
uses: docker/metadata-action@v3
with:
images: |
chrislusf/seaweedfs
ghcr.io/chrislusf/seaweedfs
tags: |
type=raw,value=dev
labels: |
org.opencontainers.image.title=seaweedfs
org.opencontainers.image.description=SeaweedFS is a distributed storage system for blobs, objects, files, and data lake, to store and serve billions of files fast!
org.opencontainers.image.vendor=Chris Lu
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
with:
buildkitd-flags: "--debug"
-
name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
-
name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME }}
password: ${{ secrets.GHCR_TOKEN }}
-
name: Build
uses: docker/build-push-action@v2
with:
context: ./docker
push: ${{ github.event_name != 'pull_request' }}
file: ./docker/Dockerfile.go_build
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
+7 -58
View File
@@ -1,66 +1,15 @@
name: Build Latest Containers
name: "docker: build latest container"
on:
push:
branches:
- master
branches: [ master ]
workflow_dispatch: []
jobs:
build-latest:
runs-on: [ubuntu-latest]
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Docker meta
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v2
with:
images: |
chrislusf/seaweedfs
ghcr.io/chrislusf/seaweedfs
tags: |
type=raw,value=latest
labels: |
org.opencontainers.image.title=seaweedfs
org.opencontainers.image.vendor=Chris Lu
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
with:
buildkitd-flags: "--debug"
-
name: Login to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
-
name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME }}
password: ${{ secrets.GHCR_TOKEN }}
-
name: Build
uses: docker/build-push-action@v2
with:
context: ./docker
push: ${{ github.event_name != 'pull_request' }}
file: ./docker/Dockerfile
platforms: linux/amd64
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
build-dev:
build-latest-container:
runs-on: [ubuntu-latest]
steps:
-
name: Checkout
@@ -68,7 +17,7 @@ jobs:
-
name: Docker meta
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v2
uses: docker/metadata-action@v3
with:
images: |
chrislusf/seaweedfs
@@ -109,6 +58,6 @@ jobs:
context: ./docker
push: ${{ github.event_name != 'pull_request' }}
file: ./docker/Dockerfile.go_build
platforms: linux/amd64
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
+10 -7
View File
@@ -1,4 +1,5 @@
name: Build Release Containers
name: "docker: build release containers"
on:
push:
tags:
@@ -6,8 +7,9 @@ on:
workflow_dispatch: []
jobs:
build-default:
build-default-release-container:
runs-on: [ubuntu-latest]
steps:
-
name: Checkout
@@ -15,7 +17,7 @@ jobs:
-
name: Docker meta
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v2
uses: docker/metadata-action@v3
with:
images: |
chrislusf/seaweedfs
@@ -58,11 +60,12 @@ jobs:
context: ./docker
push: ${{ github.event_name != 'pull_request' }}
file: ./docker/Dockerfile.go_build
platforms: linux/amd64
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
build-large:
build-large-release-container:
runs-on: [ubuntu-latest]
steps:
-
name: Checkout
@@ -70,7 +73,7 @@ jobs:
-
name: Docker meta
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v2
uses: docker/metadata-action@v3
with:
images: |
chrislusf/seaweedfs
@@ -113,6 +116,6 @@ jobs:
context: ./docker
push: ${{ github.event_name != 'pull_request' }}
file: ./docker/Dockerfile.go_build_large
platforms: linux/amd64
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta.outputs.tags }}
labels: ${{ steps.docker_meta.outputs.labels }}
+5 -1
View File
@@ -1,4 +1,4 @@
name: Go
name: "go: build binary"
on:
push:
@@ -6,6 +6,10 @@ on:
pull_request:
branches: [ master ]
concurrency:
group: ${{ github.head_ref }}/go
cancel-in-progress: true
jobs:
build:
-46
View File
@@ -1,46 +0,0 @@
sudo: false
language: go
go:
- 1.16.x
before_install:
- export PATH=/home/travis/gopath/bin:$PATH
install:
- export CGO_ENABLED="0"
- go env
script:
- env GO111MODULE=on go test ./weed/...
before_deploy:
- make release
deploy:
provider: releases
skip_cleanup: true
api_key:
secure: ERL986+ncQ8lwAJUYDrQ8s2/FxF/cyNIwJIFCqspnWxQgGNNyokET9HapmlPSxjpFRF0q6L2WCg9OY3mSVRq4oI6hg1igOQ12KlLyN71XSJ3c8w0Ay5ho48TQ9l3f3Iu97mntBCe9l0R9pnT8wj1VI8YJxloXwUMG2yeTjA9aBI=
file:
- build/linux_arm.tar.gz
- build/linux_arm64.tar.gz
- build/linux_386.tar.gz
- build/linux_amd64.tar.gz
- build/linux_amd64_large_disk.tar.gz
- build/darwin_amd64.tar.gz
- build/darwin_amd64_large_disk.tar.gz
- build/windows_386.zip
- build/windows_amd64.zip
- build/windows_amd64_large_disk.zip
- build/freebsd_arm.tar.gz
- build/freebsd_amd64.tar.gz
- build/freebsd_386.tar.gz
- build/netbsd_arm.tar.gz
- build/netbsd_amd64.tar.gz
- build/netbsd_386.tar.gz
- build/openbsd_arm.tar.gz
- build/openbsd_amd64.tar.gz
- build/openbsd_386.tar.gz
on:
tags: true
repo: chrislusf/seaweedfs
go: 1.16.x
-144
View File
@@ -1,144 +0,0 @@
BINARY = weed/weed
package = github.com/chrislusf/seaweedfs/weed
GO_FLAGS = #-v
SOURCE_DIR = ./weed/
appname := weed
sources := $(wildcard *.go)
COMMIT ?= $(shell git rev-parse --short HEAD)
LDFLAGS ?= -X github.com/chrislusf/seaweedfs/weed/util.COMMIT=${COMMIT}
build = CGO_ENABLED=0 GOOS=$(1) GOARCH=$(2) go build -ldflags "-extldflags -static $(LDFLAGS)" -o build/$(appname)$(3) $(SOURCE_DIR)
tar = cd build && tar -cvzf $(1)_$(2).tar.gz $(appname)$(3) && rm $(appname)$(3)
zip = cd build && zip $(1)_$(2).zip $(appname)$(3) && rm $(appname)$(3)
build_large = CGO_ENABLED=0 GOOS=$(1) GOARCH=$(2) go build -tags 5BytesOffset -ldflags "-extldflags -static $(LDFLAGS)" -o build/$(appname)$(3) $(SOURCE_DIR)
tar_large = cd build && tar -cvzf $(1)_$(2)_large_disk.tar.gz $(appname)$(3) && rm $(appname)$(3)
zip_large = cd build && zip $(1)_$(2)_large_disk.zip $(appname)$(3) && rm $(appname)$(3)
all: build
.PHONY : clean deps build linux release windows_build darwin_build linux_build bsd_build clean
clean:
go clean -i $(GO_FLAGS) $(SOURCE_DIR)
rm -f $(BINARY)
rm -rf build/
deps:
go get $(GO_FLAGS) -d $(SOURCE_DIR)
rm -rf /home/travis/gopath/src/github.com/coreos/etcd/vendor/golang.org/x/net/trace
rm -rf /home/travis/gopath/src/go.etcd.io/etcd/vendor/golang.org/x/net/trace
build: deps
go build $(GO_FLAGS) -ldflags "$(LDFLAGS)" -o $(BINARY) $(SOURCE_DIR)
install: deps
go install $(GO_FLAGS) -ldflags "$(LDFLAGS)" $(SOURCE_DIR)
linux: deps
mkdir -p linux
GOOS=linux GOARCH=amd64 go build $(GO_FLAGS) -ldflags "$(LDFLAGS)" -o linux/$(BINARY) $(SOURCE_DIR)
release: deps windows_build darwin_build linux_build bsd_build 5_byte_linux_build 5_byte_arm64_build 5_byte_darwin_build 5_byte_windows_build
##### LINUX BUILDS #####
5_byte_linux_build:
$(call build_large,linux,amd64,)
$(call tar_large,linux,amd64)
5_byte_darwin_build:
$(call build_large,darwin,amd64,)
$(call tar_large,darwin,amd64)
5_byte_windows_build:
$(call build_large,windows,amd64,.exe)
$(call zip_large,windows,amd64,.exe)
5_byte_arm_build: $(sources)
$(call build_large,linux,arm,)
$(call tar_large,linux,arm)
5_byte_arm64_build: $(sources)
$(call build_large,linux,arm64,)
$(call tar_large,linux,arm64)
linux_build: build/linux_arm.tar.gz build/linux_arm64.tar.gz build/linux_386.tar.gz build/linux_amd64.tar.gz
build/linux_386.tar.gz: $(sources)
$(call build,linux,386,)
$(call tar,linux,386)
build/linux_amd64.tar.gz: $(sources)
$(call build,linux,amd64,)
$(call tar,linux,amd64)
build/linux_arm.tar.gz: $(sources)
$(call build,linux,arm,)
$(call tar,linux,arm)
build/linux_arm64.tar.gz: $(sources)
$(call build,linux,arm64,)
$(call tar,linux,arm64)
##### DARWIN (MAC) BUILDS #####
darwin_build: build/darwin_amd64.tar.gz
build/darwin_amd64.tar.gz: $(sources)
$(call build,darwin,amd64,)
$(call tar,darwin,amd64)
##### WINDOWS BUILDS #####
windows_build: build/windows_386.zip build/windows_amd64.zip
build/windows_386.zip: $(sources)
$(call build,windows,386,.exe)
$(call zip,windows,386,.exe)
build/windows_amd64.zip: $(sources)
$(call build,windows,amd64,.exe)
$(call zip,windows,amd64,.exe)
##### BSD BUILDS #####
bsd_build: build/freebsd_arm.tar.gz build/freebsd_386.tar.gz build/freebsd_amd64.tar.gz \
build/netbsd_arm.tar.gz build/netbsd_386.tar.gz build/netbsd_amd64.tar.gz \
build/openbsd_arm.tar.gz build/openbsd_386.tar.gz build/openbsd_amd64.tar.gz
build/freebsd_386.tar.gz: $(sources)
$(call build,freebsd,386,)
$(call tar,freebsd,386)
build/freebsd_amd64.tar.gz: $(sources)
$(call build,freebsd,amd64,)
$(call tar,freebsd,amd64)
build/freebsd_arm.tar.gz: $(sources)
$(call build,freebsd,arm,)
$(call tar,freebsd,arm)
build/netbsd_386.tar.gz: $(sources)
$(call build,netbsd,386,)
$(call tar,netbsd,386)
build/netbsd_amd64.tar.gz: $(sources)
$(call build,netbsd,amd64,)
$(call tar,netbsd,amd64)
build/netbsd_arm.tar.gz: $(sources)
$(call build,netbsd,arm,)
$(call tar,netbsd,arm)
build/openbsd_386.tar.gz: $(sources)
$(call build,openbsd,386,)
$(call tar,openbsd,386)
build/openbsd_amd64.tar.gz: $(sources)
$(call build,openbsd,amd64,)
$(call tar,openbsd,amd64)
build/openbsd_arm.tar.gz: $(sources)
$(call build,openbsd,arm,)
$(call tar,openbsd,arm)
+14 -8
View File
@@ -3,7 +3,7 @@
[![Slack](https://img.shields.io/badge/slack-purple)](https://join.slack.com/t/seaweedfs/shared_invite/enQtMzI4MTMwMjU2MzA3LTEyYzZmZWYzOGQ3MDJlZWMzYmI0OTE4OTJiZjJjODBmMzUxNmYwODg0YjY3MTNlMjBmZDQ1NzQ5NDJhZWI2ZmY)
[![Twitter](https://img.shields.io/twitter/follow/seaweedfs.svg?style=social&label=Follow)](https://twitter.com/intent/follow?screen_name=seaweedfs)
[![Build Status](https://travis-ci.com/chrislusf/seaweedfs.svg?branch=master)](https://travis-ci.com/chrislusf/seaweedfs)
[![Build Status](https://img.shields.io/github/workflow/status/chrislusf/seaweedfs/Go)](https://github.com/chrislusf/seaweedfs/actions/workflows/go.yml)
[![GoDoc](https://godoc.org/github.com/chrislusf/seaweedfs/weed?status.svg)](https://godoc.org/github.com/chrislusf/seaweedfs/weed)
[![Wiki](https://img.shields.io/badge/docs-wiki-blue.svg)](https://github.com/chrislusf/seaweedfs/wiki)
[![Docker Pulls](https://img.shields.io/docker/pulls/chrislusf/seaweedfs?maxAge=4800)](https://hub.docker.com/r/chrislusf/seaweedfs/)
@@ -69,16 +69,16 @@ Table of Contents
* [License](#license)
## Quick Start for S3 API on Docker ##
`docker run -p 8333:8333 chrislusf/seaweedfs server -s3`
## Quick Start with single binary ##
* Download the latest binary from https://github.com/chrislusf/seaweedfs/releases and unzip a single binary file `weed` or `weed.exe`
* Run `weed server -dir=/some/data/dir -s3` to start one master, one volume server, one filer, and one S3 gateway.
Also, to increase capacity, just add more volume servers by running `weed volume -dir="/some/data/dir2" -mserver="<master_host>:9333" -port=8081` locally, or on a different machine, or on thousands of machines. That is it!
## Quick Start for S3 API on Docker ##
`docker run -p 8333:8333 chrislusf/seaweedfs server -s3`
## Introduction ##
SeaweedFS is a simple and highly scalable distributed file system. There are two objectives:
@@ -146,6 +146,8 @@ Faster and Cheaper than direct cloud storage!
* [WebDAV] accesses as a mapped drive on Mac and Windows, or from mobile devices.
* [AES256-GCM Encrypted Storage][FilerDataEncryption] safely stores the encrypted data.
* [Super Large Files][SuperLargeFiles] stores large or super large files in tens of TB.
* [Cloud Drive][CloudDrive] mounts cloud storage to local cluster, cached for fast read and write with asynchronous write back.
* [Gateway to Remote Object Store][GatewayToRemoteObjectStore] mirrors bucket operations to remote object storage, in addition to [Cloud Drive][CloudDrive]
## Kubernetes ##
* [Kubernetes CSI Driver][SeaweedFsCsiDriver] A Container Storage Interface (CSI) Driver. [![Docker Pulls](https://img.shields.io/docker/pulls/chrislusf/seaweedfs-csi-driver.svg?maxAge=4800)](https://hub.docker.com/r/chrislusf/seaweedfs-csi-driver/)
@@ -168,6 +170,9 @@ Faster and Cheaper than direct cloud storage!
[ActiveActiveAsyncReplication]: https://github.com/chrislusf/seaweedfs/wiki/Filer-Active-Active-cross-cluster-continuous-synchronization
[FilerStoreReplication]: https://github.com/chrislusf/seaweedfs/wiki/Filer-Store-Replication
[KeyLargeValueStore]: https://github.com/chrislusf/seaweedfs/wiki/Filer-as-a-Key-Large-Value-Store
[CloudDrive]: https://github.com/chrislusf/seaweedfs/wiki/Cloud-Drive-Architecture
[GatewayToRemoteObjectStore]: https://github.com/chrislusf/seaweedfs/wiki/Gateway-to-Remote-Object-Storage
[Back to TOC](#table-of-contents)
@@ -321,7 +326,7 @@ When requesting a file key, an optional "dataCenter" parameter can limit the ass
[Back to TOC](#table-of-contents)
## Architecture ##
## Object Store Architecture ##
Usually distributed file systems split each file into chunks, a central master keeps a mapping of filenames, chunk indices to chunk handles, and also which chunks each chunk server has.
@@ -587,6 +592,7 @@ The text of this page is available for modification and reuse under the terms of
[Back to TOC](#table-of-contents)
## Stargazers over time ##
## Stargazers over time
[![Stargazers over time](https://starchart.cc/chrislusf/seaweedfs.svg)](https://starchart.cc/chrislusf/seaweedfs)
[![Stargazers over time](https://starcharts.herokuapp.com/chrislusf/seaweedfs.svg)](https://starcharts.herokuapp.com/chrislusf/seaweedfs)
+4 -2
View File
@@ -8,7 +8,9 @@ RUN \
elif [ $(uname -m) == "x86_64" ] && [ $(getconf LONG_BIT) == "32" ]; then echo "386"; \
elif [ $(uname -m) == "aarch64" ]; then echo "arm64"; \
elif [ $(uname -m) == "armv7l" ]; then echo "arm"; \
elif [ $(uname -m) == "armv6l" ]; then echo "arm"; fi;) && \
elif [ $(uname -m) == "armv6l" ]; then echo "arm"; \
elif [ $(uname -m) == "s390x" ]; then echo "s390x"; \
elif [ $(uname -m) == "ppc64le" ]; then echo "ppc64le"; fi;) && \
echo "Building for $ARCH" 1>&2 && \
SUPERCRONIC_SHA1SUM=$(echo $ARCH | sed 's/386/e0126b0102b9f388ecd55714358e3ad60d0cebdb/g' | sed 's/amd64/5ddf8ea26b56d4a7ff6faecdd8966610d5cb9d85/g' | sed 's/arm64/e2714c43e7781bf1579c85aa61259245f56dbba1/g' | sed 's/arm/47481c3341bc3a1ae91a728e0cc63c8e6d3791ad/g') && \
SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.1.9/supercronic-linux-$ARCH && \
@@ -16,7 +18,7 @@ RUN \
# Install SeaweedFS and Supercronic ( for cron job mode )
apk add --no-cache --virtual build-dependencies --update wget curl ca-certificates && \
apk add fuse && \
wget -P /tmp https://github.com/$(curl -s -L https://github.com/chrislusf/seaweedfs/releases/${RELEASE} | egrep -o "chrislusf/seaweedfs/releases/download/.*/linux_$ARCH.tar.gz") && \
wget -P /tmp https://github.com/$(curl -s -L https://github.com/chrislusf/seaweedfs/releases/${RELEASE} | egrep -o "chrislusf/seaweedfs/releases/download/.*/linux_$ARCH.tar.gz" | head -n 1) && \
tar -C /usr/bin/ -xzvf /tmp/linux_$ARCH.tar.gz && \
curl -fsSLO "$SUPERCRONIC_URL" && \
echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - && \
+43
View File
@@ -0,0 +1,43 @@
FROM gcc:11 as builder
RUN mkdir -p /go/src/github.com/chrislusf/
RUN git clone https://github.com/chrislusf/seaweedfs /go/src/github.com/chrislusf/seaweedfs
ARG BRANCH=${BRANCH:-master}
RUN cd /go/src/github.com/chrislusf/seaweedfs && git checkout $BRANCH
RUN cd /go/src/github.com/chrislusf/seaweedfs/weed \
&& apt-get update \
&& apt-get install -y golang-src \
&& export LDFLAGS="-X github.com/chrislusf/seaweedfs/weed/util.COMMIT=$(git rev-parse --short HEAD)" \
&& CGO_ENABLED=0 go install -ldflags "-extldflags -static ${LDFLAGS}" -compiler=gccgo -tags gccgo,noasm
FROM alpine AS final
LABEL author="Chris Lu"
COPY --from=builder /go/bin/weed /usr/bin/
RUN mkdir -p /etc/seaweedfs
COPY --from=builder /go/src/github.com/chrislusf/seaweedfs/docker/filer.toml /etc/seaweedfs/filer.toml
COPY --from=builder /go/src/github.com/chrislusf/seaweedfs/docker/entrypoint.sh /entrypoint.sh
RUN apk add fuse # for weed mount
# volume server gprc port
EXPOSE 18080
# volume server http port
EXPOSE 8080
# filer server gprc port
EXPOSE 18888
# filer server http port
EXPOSE 8888
# master server shared gprc port
EXPOSE 19333
# master server shared http port
EXPOSE 9333
# s3 server http port
EXPOSE 8333
# webdav server http port
EXPOSE 7333
RUN mkdir -p /data/filerldb2
VOLUME /data
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
+1 -1
View File
@@ -1,4 +1,4 @@
FROM amd64/golang:1.16-alpine as builder
FROM amd64/golang:1.17-alpine as builder
RUN apk add git g++ fuse
RUN mkdir -p /go/src/github.com/chrislusf/
RUN git clone https://github.com/chrislusf/seaweedfs /go/src/github.com/chrislusf/seaweedfs
+1 -1
View File
@@ -1,4 +1,4 @@
FROM amd64/golang:1.16-alpine as builder
FROM amd64/golang:1.17-alpine as builder
RUN apk add git g++ fuse
RUN mkdir -p /go/src/github.com/chrislusf/
RUN git clone https://github.com/chrislusf/seaweedfs /go/src/github.com/chrislusf/seaweedfs
+137 -33
View File
@@ -1,23 +1,34 @@
module github.com/chrislusf/seaweedfs
go 1.16
go 1.17
require (
cloud.google.com/go v0.94.1 // indirect
cloud.google.com/go/pubsub v1.3.1
cloud.google.com/go/storage v1.9.0
github.com/Azure/azure-storage-blob-go v0.9.0
cloud.google.com/go/storage v1.16.1
github.com/Azure/azure-pipeline-go v0.2.3
github.com/Azure/azure-storage-blob-go v0.14.0
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798 // indirect
github.com/OneOfOne/xxhash v1.2.2
github.com/Shopify/sarama v1.23.1
github.com/aws/aws-sdk-go v1.34.30
github.com/aws/aws-sdk-go v1.35.3
github.com/beorn7/perks v1.0.1 // indirect
github.com/buraksezer/consistent v0.0.0-20191006190839-693edf70fd72
github.com/bwmarrin/snowflake v0.3.0
github.com/cespare/xxhash v1.1.0
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/chrislusf/raft v1.0.7
github.com/colinmarc/hdfs/v2 v2.2.0
github.com/coreos/go-semver v0.3.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/disintegration/imaging v1.6.2
github.com/dustin/go-humanize v1.0.0
github.com/eapache/go-resiliency v1.2.0 // indirect
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 // indirect
github.com/eapache/queue v1.1.0 // indirect
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c // indirect
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
@@ -25,74 +36,167 @@ require (
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 // indirect
github.com/fclairamb/ftpserverlib v0.8.0
github.com/frankban/quicktest v1.7.2 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-errors/errors v1.1.1 // indirect
github.com/go-redis/redis/v8 v8.4.4
github.com/go-sql-driver/mysql v1.5.0
github.com/gocql/gocql v0.0.0-20190829130954-e163eff7a8c6
github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48 // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e
github.com/golang/protobuf v1.4.3
github.com/go-stack/stack v1.8.0 // indirect
github.com/go-zookeeper/zk v1.0.2 // indirect
github.com/gocql/gocql v0.0.0-20210707082121-9a3953d1826d
github.com/golang-jwt/jwt v3.2.1+incompatible
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
github.com/golang/protobuf v1.5.2
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.0.0
github.com/google/uuid v1.1.1
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/uuid v1.3.0
github.com/google/wire v0.4.0 // indirect
github.com/googleapis/gax-go v2.0.2+incompatible // indirect
github.com/googleapis/gax-go/v2 v2.1.0 // indirect
github.com/gorilla/mux v1.7.4
github.com/gorilla/websocket v1.4.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4
github.com/grpc-ecosystem/grpc-gateway v1.11.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
github.com/hashicorp/errwrap v1.0.0 // indirect
github.com/hashicorp/go-multierror v1.0.0 // indirect
github.com/hashicorp/go-uuid v1.0.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/jcmturner/gofork v1.0.0 // indirect
github.com/jcmturner/gokrb5/v8 v8.4.1
github.com/jinzhu/copier v0.2.8
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/json-iterator/go v1.1.11
github.com/karlseguin/ccache/v2 v2.0.7
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/klauspost/compress v1.10.9 // indirect
github.com/klauspost/cpuid v1.2.1 // indirect
github.com/klauspost/crc32 v1.2.0
github.com/klauspost/reedsolomon v1.9.2
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/kurin/blazer v0.5.3
github.com/lib/pq v1.10.0
github.com/magiconair/properties v1.8.1 // indirect
github.com/mattn/go-runewidth v0.0.4 // indirect
github.com/mailru/easyjson v0.7.1 // indirect
github.com/mattn/go-ieproxy v0.0.1 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/nats-io/jwt v1.0.1 // indirect
github.com/nats-io/nats.go v1.10.0 // indirect
github.com/nats-io/nkeys v0.2.0 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/olivere/elastic/v7 v7.0.19
github.com/pelletier/go-toml v1.7.0 // indirect
github.com/peterh/liner v1.1.0
github.com/pierrec/lz4 v2.2.7+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/posener/complete v1.2.3
github.com/pquerna/cachecontrol v0.1.0
github.com/prometheus/client_golang v1.11.0
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.26.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563 // indirect
github.com/seaweedfs/fuse v1.1.8
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/seaweedfs/fuse v1.2.0
github.com/seaweedfs/goexif v1.0.2
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/cast v1.3.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/viper v1.4.0
github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71
github.com/stretchr/testify v1.6.1
github.com/syndtr/goleveldb v1.0.0
github.com/stretchr/testify v1.7.0
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c
github.com/tidwall/gjson v1.3.2
github.com/tidwall/match v1.0.1
github.com/tidwall/gjson v1.8.1
github.com/tidwall/match v1.0.3
github.com/tidwall/pretty v1.1.0 // indirect
github.com/tikv/client-go/v2 v2.0.0-alpha.0.20210824090536-16d902a3c7e5
github.com/tsuna/gohbase v0.0.0-20201125011725-348991136365
github.com/tylertreat/BoomFilters v0.0.0-20210315201527-1a82519a3e43
github.com/valyala/bytebufferpool v1.0.0
github.com/viant/assertly v0.5.4 // indirect
github.com/viant/ptrie v0.3.0
github.com/viant/toolbox v0.33.2 // indirect
github.com/willf/bitset v1.1.10 // indirect
github.com/willf/bloom v2.0.3+incompatible
go.etcd.io/etcd v3.3.15+incompatible
go.mongodb.org/mongo-driver v1.3.2
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2 // indirect
github.com/xdg-go/stringprep v1.0.2 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
go.etcd.io/etcd v3.3.25+incompatible
go.mongodb.org/mongo-driver v1.7.0
go.opencensus.io v0.23.0 // indirect
go.opentelemetry.io/otel v0.15.0 // indirect
gocloud.dev v0.20.0
gocloud.dev/pubsub/natspubsub v0.20.0
gocloud.dev/pubsub/rabbitpubsub v0.20.0
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78
google.golang.org/api v0.26.0
google.golang.org/grpc v1.29.1
google.golang.org/protobuf v1.26.0-rc.1
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 // indirect
golang.org/x/image v0.0.0-20200119044424-58c23975cae1
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf
golang.org/x/text v0.3.6 // indirect
golang.org/x/tools v0.1.5
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/api v0.56.0
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83 // indirect
google.golang.org/grpc v1.40.0
google.golang.org/protobuf v1.27.1
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect
gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect
gopkg.in/jcmturner/goidentity.v3 v3.0.0 // indirect
gopkg.in/jcmturner/gokrb5.v7 v7.3.0 // indirect
gopkg.in/jcmturner/rpc.v1 v1.1.0 // indirect
modernc.org/b v1.0.0 // indirect
modernc.org/cc/v3 v3.33.5 // indirect
modernc.org/ccgo/v3 v3.9.4 // indirect
modernc.org/libc v1.9.5 // indirect
modernc.org/mathutil v1.2.2 // indirect
modernc.org/memory v1.0.4 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/sqlite v1.10.7
modernc.org/strutil v1.1.0 // indirect
modernc.org/token v1.0.0 // indirect
)
require (
github.com/coreos/etcd v3.3.10+incompatible // indirect
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
github.com/d4l3k/messagediff v1.2.1 // indirect
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/jcmturner/aescts/v2 v2.0.0 // indirect
github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
github.com/jcmturner/rpc/v2 v2.0.2 // indirect
github.com/mattn/go-runewidth v0.0.7 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pingcap/errors v0.11.5-0.20201126102027-b0a155152ca3 // indirect
github.com/pingcap/failpoint v0.0.0-20210316064728-7acb0f0a3dfd // indirect
github.com/pingcap/kvproto v0.0.0-20210806074406-317f69fb54b4 // indirect
github.com/pingcap/log v0.0.0-20210317133921-96f4fcab92a4 // indirect
github.com/pingcap/parser v0.0.0-20210525032559-c37778aff307 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/tikv/pd v1.1.0-beta.0.20210323121136-78679e5e209d // indirect
github.com/twmb/murmur3 v1.1.3 // indirect
go.etcd.io/etcd/api/v3 v3.5.0 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.0 // indirect
go.etcd.io/etcd/client/v3 v3.5.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.17.0 // indirect
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
// replace github.com/seaweedfs/fuse => /Users/chris/go/src/github.com/seaweedfs/fuse
// replace github.com/chrislusf/raft => /Users/chris/go/src/github.com/chrislusf/raft
replace go.etcd.io/etcd => go.etcd.io/etcd v0.5.0-alpha.5.0.20200425165423-262c93980547
+593 -68
View File
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,5 @@
apiVersion: v1
description: SeaweedFS
name: seaweedfs
appVersion: "2.59"
version: "2.59"
appVersion: "2.69"
version: "2.69"
@@ -4,7 +4,6 @@ global:
registry: ""
repository: ""
imageName: chrislusf/seaweedfs
# imageTag: "2.59" - started using {.Chart.appVersion}
imagePullPolicy: IfNotPresent
imagePullSecrets: imagepullsecret
restartPolicy: Always
Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

+2 -2
View File
@@ -5,7 +5,7 @@
<groupId>com.github.chrislusf</groupId>
<artifactId>seaweedfs-client</artifactId>
<version>1.6.6</version>
<version>1.6.8</version>
<parent>
<groupId>org.sonatype.oss</groupId>
@@ -135,7 +135,7 @@
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
+2 -2
View File
@@ -5,7 +5,7 @@
<groupId>com.github.chrislusf</groupId>
<artifactId>seaweedfs-client</artifactId>
<version>1.6.6</version>
<version>1.6.8</version>
<parent>
<groupId>org.sonatype.oss</groupId>
@@ -130,7 +130,7 @@
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
+1 -1
View File
@@ -5,7 +5,7 @@
<groupId>com.github.chrislusf</groupId>
<artifactId>seaweedfs-client</artifactId>
<version>1.6.6</version>
<version>1.6.8</version>
<parent>
<groupId>org.sonatype.oss</groupId>
@@ -4,7 +4,6 @@ import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
@@ -15,7 +14,11 @@ public class FilerClient extends FilerGrpcClient {
private static final Logger LOG = LoggerFactory.getLogger(FilerClient.class);
public FilerClient(String host, int grpcPort) {
super(host, grpcPort);
super(host, grpcPort-10000, grpcPort);
}
public FilerClient(String host, int port, int grpcPort) {
super(host, port, grpcPort);
}
public static String toFileId(FilerProto.FileId fid) {
@@ -59,24 +62,39 @@ public class FilerClient extends FilerGrpcClient {
public static FilerProto.Entry afterEntryDeserialization(FilerProto.Entry entry) {
if (entry.getChunksList().size() <= 0) {
return entry;
}
String fileId = entry.getChunks(0).getFileId();
if (fileId != null && fileId.length() != 0) {
return entry;
}
FilerProto.Entry.Builder entryBuilder = entry.toBuilder();
entryBuilder.clearChunks();
for (FilerProto.FileChunk chunk : entry.getChunksList()) {
FilerProto.FileChunk.Builder chunkBuilder = chunk.toBuilder();
chunkBuilder.setFileId(toFileId(chunk.getFid()));
String sourceFileId = toFileId(chunk.getSourceFid());
if (sourceFileId != null) {
chunkBuilder.setSourceFileId(sourceFileId);
if (entry.getContent().isEmpty()) {
return entry;
} else {
if (entry.getAttributes().getFileSize() <= 0) {
FilerProto.Entry.Builder entryBuilder = entry.toBuilder();
FilerProto.FuseAttributes.Builder attrBuilder = entry.getAttributes().toBuilder();
attrBuilder.setFileSize(entry.getContent().size());
entryBuilder.setAttributes(attrBuilder);
return entryBuilder.build();
}
}
entryBuilder.addChunks(chunkBuilder);
return entry;
} else {
FilerProto.Entry.Builder entryBuilder = entry.toBuilder();
entryBuilder.clearChunks();
long fileSize = 0;
for (FilerProto.FileChunk chunk : entry.getChunksList()) {
fileSize = Math.max(fileSize, chunk.getOffset()+chunk.getSize());
FilerProto.FileChunk.Builder chunkBuilder = chunk.toBuilder();
chunkBuilder.setFileId(toFileId(chunk.getFid()));
String sourceFileId = toFileId(chunk.getSourceFid());
if (sourceFileId != null) {
chunkBuilder.setSourceFileId(sourceFileId);
}
entryBuilder.addChunks(chunkBuilder);
}
if (entry.getAttributes().getFileSize() <= 0) {
FilerProto.FuseAttributes.Builder attrBuilder = entry.getAttributes().toBuilder();
attrBuilder.setFileSize(fileSize);
entryBuilder.setAttributes(attrBuilder);
}
return entryBuilder.build();
}
return entryBuilder.build();
}
public boolean mkdirs(String path, int mode) {
@@ -93,9 +111,9 @@ public class FilerClient extends FilerGrpcClient {
if ("/".equals(path)) {
return true;
}
File pathFile = new File(path);
String parent = pathFile.getParent().replace('\\','/');
String name = pathFile.getName();
String[] dirAndName = SeaweedUtil.toDirAndName(path);
String parent = dirAndName[0];
String name = dirAndName[1];
mkdirs(parent, mode, uid, gid, userName, groupNames);
@@ -114,35 +132,32 @@ public class FilerClient extends FilerGrpcClient {
public boolean mv(String oldPath, String newPath) {
File oldPathFile = new File(oldPath);
String oldParent = oldPathFile.getParent().replace('\\','/');
String oldName = oldPathFile.getName();
String[] oldDirAndName = SeaweedUtil.toDirAndName(oldPath);
String oldParent = oldDirAndName[0];
String oldName = oldDirAndName[1];
File newPathFile = new File(newPath);
String newParent = newPathFile.getParent().replace('\\','/');
String newName = newPathFile.getName();
String[] newDirAndName = SeaweedUtil.toDirAndName(newPath);
String newParent = newDirAndName[0];
String newName = newDirAndName[1];
return atomicRenameEntry(oldParent, oldName, newParent, newName);
}
public boolean exists(String path){
File pathFile = new File(path);
String parent = pathFile.getParent();
String entryName = pathFile.getName();
if(parent == null) {
parent = path;
entryName ="";
}
return lookupEntry(parent, entryName) != null;
String[] dirAndName = SeaweedUtil.toDirAndName(path);
String parent = dirAndName[0];
String entryName = dirAndName[1];
return lookupEntry(parent, entryName) != null;
}
public boolean rm(String path, boolean isRecursive, boolean ignoreRecusiveError) {
File pathFile = new File(path);
String parent = pathFile.getParent().replace('\\','/');
String name = pathFile.getName();
String[] dirAndName = SeaweedUtil.toDirAndName(path);
String parent = dirAndName[0];
String name = dirAndName[1];
return deleteEntry(
parent,
@@ -153,17 +168,19 @@ public class FilerClient extends FilerGrpcClient {
}
public boolean touch(String path, int mode) {
String currentUser = System.getProperty("user.name");
long now = System.currentTimeMillis() / 1000L;
return touch(path, now, mode, 0, 0, currentUser, new String[]{});
}
public boolean touch(String path, long modifiedTimeSecond, int mode, int uid, int gid, String userName, String[] groupNames) {
File pathFile = new File(path);
String parent = pathFile.getParent().replace('\\','/');
String name = pathFile.getName();
String[] dirAndName = SeaweedUtil.toDirAndName(path);
String parent = dirAndName[0];
String name = dirAndName[1];
FilerProto.Entry entry = lookupEntry(parent, name);
if (entry == null) {
@@ -40,11 +40,11 @@ public class FilerGrpcClient {
private int volumeServerAccess = VOLUME_SERVER_ACCESS_DIRECT;
private String filerAddress;
public FilerGrpcClient(String host, int grpcPort) {
this(host, grpcPort, sslContext);
public FilerGrpcClient(String host, int port, int grpcPort) {
this(host, port, grpcPort, sslContext);
}
public FilerGrpcClient(String host, int grpcPort, SslContext sslContext) {
public FilerGrpcClient(String host, int port, int grpcPort, SslContext sslContext) {
this(sslContext == null ?
ManagedChannelBuilder.forAddress(host, grpcPort).usePlaintext()
@@ -54,7 +54,7 @@ public class FilerGrpcClient {
.negotiationType(NegotiationType.TLS)
.sslContext(sslContext));
filerAddress = String.format("%s:%d", host, grpcPort - 10000);
filerAddress = SeaweedUtil.joinHostPort(host, port);
FilerProto.GetFilerConfigurationResponse filerConfigurationResponse =
this.getBlockingStub().getFilerConfiguration(
@@ -0,0 +1,23 @@
package seaweedfs.client;
import java.io.IOException;
public class RemoteUtil {
public static boolean isInRemoteOnly(FilerProto.Entry entry) {
if (entry.getChunksList() == null || entry.getChunksList().isEmpty()) {
return entry.getRemoteEntry() != null && entry.getRemoteEntry().getRemoteSize() > 0;
}
return false;
}
public static FilerProto.Entry downloadRemoteEntry(FilerClient filerClient, String fullpath, FilerProto.Entry entry) throws IOException {
String dir = SeaweedOutputStream.getParentDirectory(fullpath);
String name = SeaweedOutputStream.getFileName(fullpath);
final FilerProto.DownloadToLocalResponse downloadToLocalResponse = filerClient.getBlockingStub()
.downloadToLocal(FilerProto.DownloadToLocalRequest.newBuilder()
.setDirectory(dir).setName(name).build());
return downloadToLocalResponse.getEntry();
}
}
@@ -19,9 +19,9 @@ public class SeaweedInputStream extends InputStream {
private final FilerClient filerClient;
private final String path;
private final FilerProto.Entry entry;
private final List<SeaweedRead.VisibleInterval> visibleIntervalList;
private final long contentLength;
private FilerProto.Entry entry;
private long position = 0; // cursor of the file
@@ -35,10 +35,14 @@ public class SeaweedInputStream extends InputStream {
this.entry = filerClient.lookupEntry(
SeaweedOutputStream.getParentDirectory(fullpath),
SeaweedOutputStream.getFileName(fullpath));
if(entry == null){
if (entry == null) {
throw new FileNotFoundException();
}
if (RemoteUtil.isInRemoteOnly(entry)) {
entry = RemoteUtil.downloadRemoteEntry(filerClient, fullpath, entry);
}
this.contentLength = SeaweedRead.fileSize(entry);
this.visibleIntervalList = SeaweedRead.nonOverlappingVisibleIntervals(filerClient, entry.getChunksList());
@@ -54,6 +58,11 @@ public class SeaweedInputStream extends InputStream {
this.filerClient = filerClient;
this.path = path;
this.entry = entry;
if (RemoteUtil.isInRemoteOnly(entry)) {
this.entry = RemoteUtil.downloadRemoteEntry(filerClient, path, entry);
}
this.contentLength = SeaweedRead.fileSize(entry);
this.visibleIntervalList = SeaweedRead.nonOverlappingVisibleIntervals(filerClient, entry.getChunksList());
@@ -111,8 +120,8 @@ public class SeaweedInputStream extends InputStream {
long bytesRead = 0;
int len = buf.remaining();
int start = (int) this.position;
if (start+len <= entry.getContent().size()) {
entry.getContent().substring(start, start+len).copyTo(buf);
if (start + len <= entry.getContent().size()) {
entry.getContent().substring(start, start + len).copyTo(buf);
} else {
bytesRead = SeaweedRead.read(this.filerClient, this.visibleIntervalList, this.position, buf, SeaweedRead.fileSize(entry));
}
@@ -32,10 +32,10 @@ public class SeaweedOutputStream extends OutputStream {
private long lastTotalAppendOffset = 0;
private ByteBuffer buffer;
private long outputIndex;
private String replication = "000";
private String replication = "";
public SeaweedOutputStream(FilerClient filerClient, final String fullpath) {
this(filerClient, fullpath, "000");
this(filerClient, fullpath, "");
}
public SeaweedOutputStream(FilerClient filerClient, final String fullpath, final String replication) {
@@ -64,10 +64,11 @@ public class SeaweedRead {
startOffset += gap;
}
FilerProto.Locations locations = knownLocations.get(parseVolumeId(chunkView.fileId));
String volumeId = parseVolumeId(chunkView.fileId);
FilerProto.Locations locations = knownLocations.get(volumeId);
if (locations == null || locations.getLocationsCount() == 0) {
LOG.error("failed to locate {}", chunkView.fileId);
// log here!
volumeIdCache.clearLocations(volumeId);
return 0;
}
@@ -27,4 +27,30 @@ public class SeaweedUtil {
public static CloseableHttpClient getClosableHttpClient() {
return httpClient;
}
public static String[] toDirAndName(String fullpath) {
if (fullpath == null) {
return new String[]{"/", ""};
}
if (fullpath.endsWith("/")) {
fullpath = fullpath.substring(0, fullpath.length() - 1);
}
if (fullpath.length() == 0) {
return new String[]{"/", ""};
}
int sep = fullpath.lastIndexOf("/");
String parent = sep == 0 ? "/" : fullpath.substring(0, sep);
String name = fullpath.substring(sep + 1);
return new String[]{parent, name};
}
public static String joinHostPort(String host, int port) {
if (host.startsWith("[") && host.endsWith("]")) {
return host + ":" + port;
}
if (host.indexOf(':')>=0) {
return "[" + host + "]:" + port;
}
return host + ":" + port;
}
}
@@ -59,7 +59,7 @@ public class SeaweedWrite {
String fileId = response.getFileId();
String auth = response.getAuth();
String targetUrl = filerClient.getChunkUrl(fileId, response.getUrl(), response.getPublicUrl());
String targetUrl = filerClient.getChunkUrl(fileId, response.getLocation().getUrl(), response.getLocation().getPublicUrl());
ByteString cipherKeyString = com.google.protobuf.ByteString.EMPTY;
byte[] cipherKey = null;
@@ -26,6 +26,13 @@ public class VolumeIdCache {
return this.cache.getIfPresent(volumeId);
}
public void clearLocations(String volumeId) {
if (this.cache == null) {
return;
}
this.cache.invalidate(volumeId);
}
public void setLocations(String volumeId, FilerProto.Locations locations) {
if (this.cache == null) {
return;
+31 -2
View File
@@ -67,6 +67,8 @@ service SeaweedFiler {
rpc KvPut (KvPutRequest) returns (KvPutResponse) {
}
rpc DownloadToLocal (DownloadToLocalRequest) returns (DownloadToLocalResponse) {
}
}
//////////////////////////////////////////////////
@@ -92,6 +94,13 @@ message ListEntriesResponse {
Entry entry = 1;
}
message RemoteEntry {
string storage_name = 1;
int64 last_local_sync_ts_ns = 2;
string remote_e_tag = 3;
int64 remote_mtime = 4;
int64 remote_size = 5;
}
message Entry {
string name = 1;
bool is_directory = 2;
@@ -101,6 +110,8 @@ message Entry {
bytes hard_link_id = 7;
int32 hard_link_counter = 8; // only exists in hard link meta data
bytes content = 9; // if not empty, the file content
RemoteEntry remote_entry = 10;
}
message FullEntry {
@@ -227,13 +238,12 @@ message AssignVolumeRequest {
message AssignVolumeResponse {
string file_id = 1;
string url = 2;
string public_url = 3;
int32 count = 4;
string auth = 5;
string collection = 6;
string replication = 7;
string error = 8;
Location location = 9;
}
message LookupVolumeRequest {
@@ -247,6 +257,7 @@ message Locations {
message Location {
string url = 1;
string public_url = 2;
uint32 grpc_port = 3;
}
message LookupVolumeResponse {
map<string, Locations> locations_map = 1;
@@ -294,6 +305,7 @@ message GetFilerConfigurationResponse {
string metrics_address = 9;
int32 metrics_interval_sec = 10;
string version = 11;
string cluster_id = 12;
}
message SubscribeMetadataRequest {
@@ -301,6 +313,7 @@ message SubscribeMetadataRequest {
string path_prefix = 2;
int64 since_ns = 3;
int32 signature = 4;
repeated string path_prefixes = 6;
}
message SubscribeMetadataResponse {
string directory = 1;
@@ -325,6 +338,7 @@ message KeepConnectedResponse {
message LocateBrokerRequest {
string resource = 1;
}
message LocateBrokerResponse {
bool found = 1;
// if found, send the exact address
@@ -336,7 +350,9 @@ message LocateBrokerResponse {
repeated Resource resources = 2;
}
/////////////////////////
// Key-Value operations
/////////////////////////
message KvGetRequest {
bytes key = 1;
}
@@ -352,7 +368,9 @@ message KvPutResponse {
string error = 1;
}
/////////////////////////
// path-based configurations
/////////////////////////
message FilerConf {
int32 version = 1;
message PathConf {
@@ -367,3 +385,14 @@ message FilerConf {
}
repeated PathConf locations = 2;
}
/////////////////////////
// Remote Storage related
/////////////////////////
message DownloadToLocalRequest {
string directory = 1;
string name = 2;
}
message DownloadToLocalResponse {
Entry entry = 1;
}
+2 -2
View File
@@ -11,13 +11,13 @@
<dependency>
<groupId>com.github.chrislusf</groupId>
<artifactId>seaweedfs-client</artifactId>
<version>1.6.6</version>
<version>1.6.8</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.chrislusf</groupId>
<artifactId>seaweedfs-hadoop2-client</artifactId>
<version>1.6.6</version>
<version>1.6.8</version>
<scope>compile</scope>
</dependency>
<dependency>
+2 -2
View File
@@ -86,7 +86,7 @@
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
@@ -301,7 +301,7 @@
</snapshotRepository>
</distributionManagement>
<properties>
<seaweedfs.client.version>1.6.6</seaweedfs.client.version>
<seaweedfs.client.version>1.6.8</seaweedfs.client.version>
<hadoop.version>2.9.2</hadoop.version>
</properties>
</project>
+2 -2
View File
@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<seaweedfs.client.version>1.6.6</seaweedfs.client.version>
<seaweedfs.client.version>1.6.8</seaweedfs.client.version>
<hadoop.version>2.9.2</hadoop.version>
</properties>
@@ -105,7 +105,7 @@
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
@@ -23,6 +23,7 @@ public class SeaweedFileSystem extends FileSystem {
public static final String FS_SEAWEED_FILER_HOST = "fs.seaweed.filer.host";
public static final String FS_SEAWEED_FILER_PORT = "fs.seaweed.filer.port";
public static final String FS_SEAWEED_FILER_PORT_GRPC = "fs.seaweed.filer.port.grpc";
public static final int FS_SEAWEED_DEFAULT_PORT = 8888;
public static final String FS_SEAWEED_BUFFER_SIZE = "fs.seaweed.buffer.size";
public static final String FS_SEAWEED_REPLICATION = "fs.seaweed.replication";
@@ -50,9 +51,6 @@ public class SeaweedFileSystem extends FileSystem {
// get host information from uri (overrides info in conf)
String host = uri.getHost();
host = (host == null) ? conf.get(FS_SEAWEED_FILER_HOST, "localhost") : host;
if (host == null) {
throw new IOException("Invalid host specified");
}
conf.set(FS_SEAWEED_FILER_HOST, host);
// get port information from uri, (overrides info in conf)
@@ -60,10 +58,12 @@ public class SeaweedFileSystem extends FileSystem {
port = (port == -1) ? FS_SEAWEED_DEFAULT_PORT : port;
conf.setInt(FS_SEAWEED_FILER_PORT, port);
int grpcPort = conf.getInt(FS_SEAWEED_FILER_PORT_GRPC, port+10000);
setConf(conf);
this.uri = uri;
seaweedFileSystemStore = new SeaweedFileSystemStore(host, port, conf);
seaweedFileSystemStore = new SeaweedFileSystemStore(host, port, grpcPort, conf);
}
@@ -27,9 +27,8 @@ public class SeaweedFileSystemStore {
private FilerClient filerClient;
private Configuration conf;
public SeaweedFileSystemStore(String host, int port, Configuration conf) {
int grpcPort = 10000 + port;
filerClient = new FilerClient(host, grpcPort);
public SeaweedFileSystemStore(String host, int port, int grpcPort, Configuration conf) {
filerClient = new FilerClient(host, port, grpcPort);
this.conf = conf;
String volumeServerAccessMode = this.conf.get(FS_SEAWEED_VOLUME_SERVER_ACCESS, "direct");
if (volumeServerAccessMode.equals("publicUrl")) {
+2 -2
View File
@@ -86,7 +86,7 @@
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
@@ -309,7 +309,7 @@
</snapshotRepository>
</distributionManagement>
<properties>
<seaweedfs.client.version>1.6.6</seaweedfs.client.version>
<seaweedfs.client.version>1.6.8</seaweedfs.client.version>
<hadoop.version>3.1.1</hadoop.version>
</properties>
</project>
+2 -2
View File
@@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<seaweedfs.client.version>1.6.6</seaweedfs.client.version>
<seaweedfs.client.version>1.6.8</seaweedfs.client.version>
<hadoop.version>3.1.1</hadoop.version>
</properties>
@@ -105,7 +105,7 @@
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.7</version>
<version>1.6.8</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
@@ -23,6 +23,7 @@ public class SeaweedFileSystem extends FileSystem {
public static final String FS_SEAWEED_FILER_HOST = "fs.seaweed.filer.host";
public static final String FS_SEAWEED_FILER_PORT = "fs.seaweed.filer.port";
public static final String FS_SEAWEED_FILER_PORT_GRPC = "fs.seaweed.filer.port.grpc";
public static final int FS_SEAWEED_DEFAULT_PORT = 8888;
public static final String FS_SEAWEED_BUFFER_SIZE = "fs.seaweed.buffer.size";
public static final String FS_SEAWEED_REPLICATION = "fs.seaweed.replication";
@@ -50,9 +51,6 @@ public class SeaweedFileSystem extends FileSystem {
// get host information from uri (overrides info in conf)
String host = uri.getHost();
host = (host == null) ? conf.get(FS_SEAWEED_FILER_HOST, "localhost") : host;
if (host == null) {
throw new IOException("Invalid host specified");
}
conf.set(FS_SEAWEED_FILER_HOST, host);
// get port information from uri, (overrides info in conf)
@@ -60,10 +58,12 @@ public class SeaweedFileSystem extends FileSystem {
port = (port == -1) ? FS_SEAWEED_DEFAULT_PORT : port;
conf.setInt(FS_SEAWEED_FILER_PORT, port);
int grpcPort = conf.getInt(FS_SEAWEED_FILER_PORT_GRPC, port+10000);
setConf(conf);
this.uri = uri;
seaweedFileSystemStore = new SeaweedFileSystemStore(host, port, conf);
seaweedFileSystemStore = new SeaweedFileSystemStore(host, port, grpcPort, conf);
}
@@ -27,9 +27,8 @@ public class SeaweedFileSystemStore {
private FilerClient filerClient;
private Configuration conf;
public SeaweedFileSystemStore(String host, int port, Configuration conf) {
int grpcPort = 10000 + port;
filerClient = new FilerClient(host, grpcPort);
public SeaweedFileSystemStore(String host, int port, int grpcPort, Configuration conf) {
filerClient = new FilerClient(host, port, grpcPort);
this.conf = conf;
String volumeServerAccessMode = this.conf.get(FS_SEAWEED_VOLUME_SERVER_ACCESS, "direct");
if (volumeServerAccessMode.equals("publicUrl")) {
File diff suppressed because it is too large Load Diff
@@ -6,13 +6,9 @@ import (
"errors"
"flag"
"fmt"
"io"
"math"
"os"
"strings"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/operation"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
"github.com/chrislusf/seaweedfs/weed/security"
"github.com/chrislusf/seaweedfs/weed/storage/idx"
@@ -20,6 +16,9 @@ import (
"github.com/chrislusf/seaweedfs/weed/storage/types"
"github.com/chrislusf/seaweedfs/weed/util"
"google.golang.org/grpc"
"io"
"math"
"os"
)
var (
@@ -45,13 +44,13 @@ func main() {
grpcDialOption = security.LoadClientTLS(util.GetViper(), "grpc.client")
vid := uint32(*volumeId)
servers := strings.Split(*serversStr, ",")
servers := pb.ServerAddresses(*serversStr).ToAddresses()
if len(servers) < 2 {
glog.Fatalf("You must specify more than 1 server\n")
}
var referenceServer string
var referenceServer pb.ServerAddress
var maxOffset int64
allFiles := map[string]map[types.NeedleId]needleState{}
allFiles := map[pb.ServerAddress]map[types.NeedleId]needleState{}
for _, addr := range servers {
files, offset, err := getVolumeFiles(vid, addr)
if err != nil {
@@ -121,7 +120,7 @@ type needleState struct {
size types.Size
}
func getVolumeFiles(v uint32, addr string) (map[types.NeedleId]needleState, int64, error) {
func getVolumeFiles(v uint32, addr pb.ServerAddress) (map[types.NeedleId]needleState, int64, error) {
var idxFile *bytes.Reader
err := operation.WithVolumeServerClient(addr, grpcDialOption, func(vs volume_server_pb.VolumeServerClient) error {
ctx, cancel := context.WithCancel(context.Background())
@@ -179,7 +178,7 @@ func getVolumeFiles(v uint32, addr string) (map[types.NeedleId]needleState, int6
return files, maxOffset, nil
}
func getNeedleFileId(v uint32, nid types.NeedleId, addr string) (string, error) {
func getNeedleFileId(v uint32, nid types.NeedleId, addr pb.ServerAddress) (string, error) {
var id string
err := operation.WithVolumeServerClient(addr, grpcDialOption, func(vs volume_server_pb.VolumeServerClient) error {
resp, err := vs.VolumeNeedleStatus(context.Background(), &volume_server_pb.VolumeNeedleStatusRequest{
@@ -1,23 +1,22 @@
package main
import (
"context"
"flag"
"fmt"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
"google.golang.org/grpc"
"io"
"strconv"
"time"
)
var (
dir = flag.String("dir", "/tmp", "directory to create files")
n = flag.Int("n", 100, "the number of metadata")
tailFiler = flag.String("filer", "localhost:8888", "the filer address")
isWrite = flag.Bool("write", false, "only write")
dir = flag.String("dir", "/tmp", "directory to create files")
n = flag.Int("n", 100, "the number of metadata")
tailFiler = flag.String("filer", "localhost:8888", "the filer address")
isWrite = flag.Bool("write", false, "only write")
writeInterval = flag.Duration("writeInterval", 0, "write interval, e.g., 1s")
)
func main() {
@@ -52,10 +51,11 @@ func main() {
}
func startGenerateMetadata() {
pb.WithFilerClient(*tailFiler, grpc.WithInsecure(), func(client filer_pb.SeaweedFilerClient) error {
pb.WithFilerClient(pb.ServerAddress(*tailFiler), grpc.WithInsecure(), func(client filer_pb.SeaweedFilerClient) error {
for i := 0; i < *n; i++ {
name := fmt.Sprintf("file%d", i)
glog.V(0).Infof("write %s/%s", *dir, name)
if err := filer_pb.CreateEntry(client, &filer_pb.CreateEntryRequest{
Directory: *dir,
Entry: &filer_pb.Entry{
@@ -65,6 +65,9 @@ func startGenerateMetadata() {
fmt.Printf("create entry %s: %v\n", name, err)
return err
}
if *writeInterval > 0 {
time.Sleep(*writeInterval)
}
}
return nil
@@ -74,38 +77,8 @@ func startGenerateMetadata() {
func startSubscribeMetadata(eachEntryFunc func(event *filer_pb.SubscribeMetadataResponse) error) {
lastTsNs := int64(0)
tailErr := pb.FollowMetadata(pb.ServerAddress(*tailFiler), grpc.WithInsecure(), "tail", *dir, nil, 0, 0, eachEntryFunc, false)
tailErr := pb.WithFilerClient(*tailFiler, grpc.WithInsecure(), func(client filer_pb.SeaweedFilerClient) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
stream, err := client.SubscribeMetadata(ctx, &filer_pb.SubscribeMetadataRequest{
ClientName: "tail",
PathPrefix: *dir,
SinceNs: lastTsNs,
})
if err != nil {
return fmt.Errorf("listen: %v", err)
}
for {
resp, listenErr := stream.Recv()
if listenErr == io.EOF {
return nil
}
if listenErr != nil {
return listenErr
}
if err = eachEntryFunc(resp); err != nil {
glog.V(0).Infof("tail last record:%+v", time.Unix(0, lastTsNs))
return err
}
lastTsNs = resp.TsNs
}
})
if tailErr != nil {
fmt.Printf("tail %s: %v\n", *tailFiler, tailErr)
}
@@ -3,6 +3,7 @@ package main
import (
"flag"
"fmt"
"github.com/chrislusf/seaweedfs/weed/pb"
"log"
"math/rand"
"time"
@@ -32,7 +33,7 @@ func main() {
go func() {
for {
println("vacuum threshold", *garbageThreshold)
_, _, err := util.Get(fmt.Sprintf("http://%s/vol/vacuum?garbageThreshold=%f", *master, *garbageThreshold))
_, _, err := util.Get(fmt.Sprintf("http://%s/vol/vacuum?garbageThreshold=%f", pb.ServerAddress(*master).ToHttpAddress(), *garbageThreshold))
if err != nil {
log.Fatalf("vacuum: %v", err)
}
@@ -52,7 +53,7 @@ func main() {
}
func genFile(grpcDialOption grpc.DialOption, i int) (*operation.AssignResult, string) {
assignResult, err := operation.Assign(func() string { return *master }, grpcDialOption, &operation.VolumeAssignRequest{
assignResult, err := operation.Assign(func() pb.ServerAddress { return pb.ServerAddress(*master) }, grpcDialOption, &operation.VolumeAssignRequest{
Count: 1,
Replication: *replication,
})
@@ -65,7 +66,16 @@ func genFile(grpcDialOption grpc.DialOption, i int) (*operation.AssignResult, st
targetUrl := fmt.Sprintf("http://%s/%s", assignResult.Url, assignResult.Fid)
_, err = operation.UploadData(targetUrl, fmt.Sprintf("test%d", i), false, data, false, "bench/test", nil, assignResult.Auth)
uploadOption := &operation.UploadOption{
UploadUrl: targetUrl,
Filename: fmt.Sprintf("test%d", i),
Cipher: false,
IsInputCompressed: true,
MimeType: "bench/test",
PairMap: nil,
Jwt: assignResult.Auth,
}
_, err = operation.UploadData(data, uploadOption)
if err != nil {
log.Fatalf("upload: %v", err)
}
+1 -1
View File
@@ -60,7 +60,7 @@ func walkMetaFile(dst *os.File) error {
fmt.Fprintf(os.Stdout, "file %s %v\n", util.FullPath(fullEntry.Dir).Child(fullEntry.Entry.Name), fullEntry.Entry.Attributes.String())
for i, chunk := range fullEntry.Entry.Chunks {
fmt.Fprintf(os.Stdout, " chunk %d %v\n", i+1, chunk.String())
fmt.Fprintf(os.Stdout, " chunk: %d %v %d,%x%08x\n", i+1, chunk, chunk.Fid.VolumeId, chunk.Fid.FileKey, chunk.Fid.Cookie)
}
}
+2 -1
View File
@@ -2,6 +2,7 @@ package main
import (
"flag"
"github.com/chrislusf/seaweedfs/weed/pb"
"log"
"time"
@@ -37,7 +38,7 @@ func main() {
sinceTimeNs = time.Now().Add(-*rewindDuration).UnixNano()
}
err := operation.TailVolume(func()string{return *master}, grpcDialOption, vid, uint64(sinceTimeNs), *timeoutSeconds, func(n *needle.Needle) (err error) {
err := operation.TailVolume(func()pb.ServerAddress{return pb.ServerAddress(*master)}, grpcDialOption, vid, uint64(sinceTimeNs), *timeoutSeconds, func(n *needle.Needle) (err error) {
if n.Size == 0 {
println("-", n.String())
return nil
+13
View File
@@ -37,3 +37,16 @@ debug_s3:
debug_filer_copy:
go build -gcflags="all=-N -l"
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec weed -- -v=4 filer.backup -filer=localhost:8888 -filerProxy -timeAgo=10h
debug_filer_remote_sync_dir:
go build -gcflags="all=-N -l"
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec weed -- -v=4 filer.remote.sync -filer="localhost:8888" -dir=/buckets/b2 -timeAgo=1h
debug_filer_remote_sync_buckets:
go build -gcflags="all=-N -l"
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec weed -- -v=4 filer.remote.sync -filer="localhost:8888" -createBucketAt=cloud1 -timeAgo=1h
debug_master_follower:
go build -gcflags="all=-N -l"
dlv --listen=:2345 --headless=true --api-version=2 --accept-multiclient exec weed -- -v=4 master.follower
+109
View File
@@ -0,0 +1,109 @@
package command
import (
"fmt"
flag "github.com/chrislusf/seaweedfs/weed/util/fla9"
"github.com/posener/complete"
completeinstall "github.com/posener/complete/cmd/install"
"runtime"
)
func AutocompleteMain(commands []*Command) bool {
subCommands := make(map[string]complete.Command)
helpSubCommands := make(map[string]complete.Command)
for _, cmd := range commands {
flags := make(map[string]complete.Predictor)
cmd.Flag.VisitAll(func(flag *flag.Flag) {
flags["-"+flag.Name] = complete.PredictAnything
})
subCommands[cmd.Name()] = complete.Command{
Flags: flags,
}
helpSubCommands[cmd.Name()] = complete.Command{}
}
subCommands["help"] = complete.Command{Sub: helpSubCommands}
globalFlags := make(map[string]complete.Predictor)
flag.VisitAll(func(flag *flag.Flag) {
globalFlags["-"+flag.Name] = complete.PredictAnything
})
weedCmd := complete.Command{
Sub: subCommands,
Flags: globalFlags,
GlobalFlags: complete.Flags{"-h": complete.PredictNothing},
}
cmp := complete.New("weed", weedCmd)
return cmp.Complete()
}
func installAutoCompletion() bool {
if runtime.GOOS == "windows" {
fmt.Println("windows is not supported")
return false
}
err := completeinstall.Install("weed")
if err != nil {
fmt.Printf("install failed! %s\n", err)
return false
}
fmt.Printf("autocompletion is enabled. Please restart your shell.\n")
return true
}
func uninstallAutoCompletion() bool {
if runtime.GOOS == "windows" {
fmt.Println("windows is not supported")
return false
}
err := completeinstall.Uninstall("weed")
if err != nil {
fmt.Printf("uninstall failed! %s\n", err)
return false
}
fmt.Printf("autocompletion is disable. Please restart your shell.\n")
return true
}
var cmdAutocomplete = &Command{
Run: runAutocomplete,
UsageLine: "autocomplete",
Short: "install autocomplete",
Long: `weed autocomplete is installed in the shell.
Supported shells are bash, zsh, and fish.
Windows is not supported.
`,
}
func runAutocomplete(cmd *Command, args []string) bool {
if len(args) != 0 {
cmd.Usage()
}
return installAutoCompletion()
}
var cmdUnautocomplete = &Command{
Run: runUnautocomplete,
UsageLine: "autocomplete.uninstall",
Short: "uninstall autocomplete",
Long: `weed autocomplete is uninstalled in the shell.
Windows is not supported.
`,
}
func runUnautocomplete(cmd *Command, args []string) bool {
if len(args) != 0 {
cmd.Usage()
}
return uninstallAutoCompletion()
}
+3 -2
View File
@@ -2,6 +2,7 @@ package command
import (
"fmt"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/security"
"github.com/chrislusf/seaweedfs/weed/storage/needle"
@@ -72,12 +73,12 @@ func runBackup(cmd *Command, args []string) bool {
vid := needle.VolumeId(*s.volumeId)
// find volume location, replication, ttl info
lookup, err := operation.Lookup(func() string { return *s.master }, vid.String())
lookup, err := operation.LookupVolumeId(func() pb.ServerAddress { return pb.ServerAddress(*s.master) }, grpcDialOption, vid.String())
if err != nil {
fmt.Printf("Error looking up volume %d: %v\n", vid, err)
return true
}
volumeServer := lookup.Locations[0].Url
volumeServer := lookup.Locations[0].ServerAddress()
stats, err := operation.GetVolumeSyncStatus(volumeServer, grpcDialOption, uint32(vid))
if err != nil {
+3 -3
View File
@@ -3,6 +3,7 @@ package command
import (
"bufio"
"fmt"
"github.com/chrislusf/seaweedfs/weed/pb"
"io"
"math"
"math/rand"
@@ -10,7 +11,6 @@ import (
"runtime"
"runtime/pprof"
"sort"
"strings"
"sync"
"time"
@@ -129,7 +129,7 @@ func runBenchmark(cmd *Command, args []string) bool {
defer pprof.StopCPUProfile()
}
b.masterClient = wdclient.NewMasterClient(b.grpcDialOption, "client", "", 0, "", strings.Split(*b.masters, ","))
b.masterClient = wdclient.NewMasterClient(b.grpcDialOption, "client", "", "", pb.ServerAddresses(*b.masters).ToAddresses())
go b.masterClient.KeepConnectedToMaster()
b.masterClient.WaitUntilConnected()
@@ -212,7 +212,7 @@ func writeFiles(idChan chan int, fileIdLineChan chan string, s *stat) {
}
var jwtAuthorization security.EncodedJwt
if isSecure {
jwtAuthorization = operation.LookupJwt(b.masterClient.GetMaster(), df.fp.Fid)
jwtAuthorization = operation.LookupJwt(b.masterClient.GetMaster(), b.grpcDialOption, df.fp.Fid)
}
if e := util.Delete(fmt.Sprintf("http://%s/%s", df.fp.Server, df.fp.Fid), string(jwtAuthorization)); e == nil {
s.completed++
+7 -3
View File
@@ -8,23 +8,27 @@ import (
)
var Commands = []*Command{
cmdBenchmark,
cmdAutocomplete,
cmdUnautocomplete,
cmdBackup,
cmdBenchmark,
cmdCompact,
cmdCopy,
cmdDownload,
cmdExport,
cmdFiler,
cmdFilerBackup,
cmdFilerCat,
cmdFilerCopy,
cmdFilerMetaBackup,
cmdFilerMetaTail,
cmdFilerRemoteGateway,
cmdFilerRemoteSynchronize,
cmdFilerReplicate,
cmdFilerSynchronize,
cmdFix,
cmdFuse,
cmdGateway,
cmdMaster,
cmdMasterFollower,
cmdMount,
cmdS3,
cmdIam,
+14 -8
View File
@@ -2,6 +2,9 @@ package command
import (
"fmt"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/security"
"google.golang.org/grpc"
"io"
"io/ioutil"
"net/http"
@@ -43,20 +46,23 @@ var cmdDownload = &Command{
}
func runDownload(cmd *Command, args []string) bool {
util.LoadConfiguration("security", false)
grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client")
for _, fid := range args {
if e := downloadToFile(func() string { return *d.server }, fid, util.ResolvePath(*d.dir)); e != nil {
if e := downloadToFile(func() pb.ServerAddress { return pb.ServerAddress(*d.server) }, grpcDialOption, fid, util.ResolvePath(*d.dir)); e != nil {
fmt.Println("Download Error: ", fid, e)
}
}
return true
}
func downloadToFile(masterFn operation.GetMasterFn, fileId, saveDir string) error {
fileUrl, lookupError := operation.LookupFileId(masterFn, fileId)
func downloadToFile(masterFn operation.GetMasterFn, grpcDialOption grpc.DialOption, fileId, saveDir string) error {
fileUrl, jwt, lookupError := operation.LookupFileId(masterFn, grpcDialOption, fileId)
if lookupError != nil {
return lookupError
}
filename, _, rc, err := util.DownloadFile(fileUrl)
filename, _, rc, err := util.DownloadFile(fileUrl, jwt)
if err != nil {
return err
}
@@ -83,7 +89,7 @@ func downloadToFile(masterFn operation.GetMasterFn, fileId, saveDir string) erro
fids := strings.Split(string(content), "\n")
for _, partId := range fids {
var n int
_, part, err := fetchContent(masterFn, partId)
_, part, err := fetchContent(masterFn, grpcDialOption, partId)
if err == nil {
n, err = f.Write(part)
}
@@ -103,13 +109,13 @@ func downloadToFile(masterFn operation.GetMasterFn, fileId, saveDir string) erro
return nil
}
func fetchContent(masterFn operation.GetMasterFn, fileId string) (filename string, content []byte, e error) {
fileUrl, lookupError := operation.LookupFileId(masterFn, fileId)
func fetchContent(masterFn operation.GetMasterFn, grpcDialOption grpc.DialOption, fileId string) (filename string, content []byte, e error) {
fileUrl, jwt, lookupError := operation.LookupFileId(masterFn, grpcDialOption, fileId)
if lookupError != nil {
return "", nil, lookupError
}
var rc *http.Response
if filename, _, rc, e = util.DownloadFile(fileUrl); e != nil {
if filename, _, rc, e = util.DownloadFile(fileUrl, jwt); e != nil {
return "", nil, e
}
defer util.CloseResponse(rc)
+25 -13
View File
@@ -4,7 +4,6 @@ import (
"fmt"
"net/http"
"os"
"strconv"
"strings"
"time"
@@ -30,10 +29,12 @@ var (
)
type FilerOptions struct {
masters *string
masters []pb.ServerAddress
mastersString *string
ip *string
bindIp *string
port *int
portGrpc *int
publicPort *int
collection *string
defaultReplicaPlacement *string
@@ -50,15 +51,18 @@ type FilerOptions struct {
saveToFilerLimit *int
defaultLevelDbDirectory *string
concurrentUploadLimitMB *int
debug *bool
debugPort *int
}
func init() {
cmdFiler.Run = runFiler // break init cycle
f.masters = cmdFiler.Flag.String("master", "localhost:9333", "comma-separated master servers")
f.mastersString = cmdFiler.Flag.String("master", "localhost:9333", "comma-separated master servers")
f.collection = cmdFiler.Flag.String("collection", "", "all data will be stored in this default collection")
f.ip = cmdFiler.Flag.String("ip", util.DetectedHostAddress(), "filer server http listen ip address")
f.bindIp = cmdFiler.Flag.String("ip.bind", "", "ip address to bind to")
f.port = cmdFiler.Flag.Int("port", 8888, "filer server http listen port")
f.portGrpc = cmdFiler.Flag.Int("port.grpc", 18888, "filer server grpc listen port")
f.publicPort = cmdFiler.Flag.Int("port.readonly", 0, "readonly port opened to public")
f.defaultReplicaPlacement = cmdFiler.Flag.String("defaultReplicaPlacement", "", "default replication type. If not specified, use master setting.")
f.disableDirListing = cmdFiler.Flag.Bool("disableDirListing", false, "turn off directory listing")
@@ -73,6 +77,8 @@ func init() {
f.saveToFilerLimit = cmdFiler.Flag.Int("saveToFilerLimit", 0, "files smaller than this limit will be saved in filer store")
f.defaultLevelDbDirectory = cmdFiler.Flag.String("defaultStoreDir", ".", "if filer.toml is empty, use an embedded filer store in the directory")
f.concurrentUploadLimitMB = cmdFiler.Flag.Int("concurrentUploadLimitMB", 128, "limit total concurrent upload size")
f.debug = cmdFiler.Flag.Bool("debug", false, "serves runtime profiling data, e.g., http://localhost:<debug.port>/debug/pprof/goroutine?debug=2")
f.debugPort = cmdFiler.Flag.Int("debug.port", 6060, "http port for debugging")
// start s3 on filer
filerStartS3 = cmdFiler.Flag.Bool("s3", false, "whether to start S3 gateway")
@@ -122,12 +128,15 @@ var cmdFiler = &Command{
}
func runFiler(cmd *Command, args []string) bool {
if *f.debug {
go http.ListenAndServe(fmt.Sprintf(":%d", *f.debugPort), nil)
}
util.LoadConfiguration("security", false)
go stats_collect.StartMetricsServer(*f.metricsHttpPort)
filerAddress := fmt.Sprintf("%s:%d", *f.ip, *f.port)
filerAddress := util.JoinHostPort(*f.ip, *f.port)
startDelay := time.Duration(2)
if *filerStartS3 {
filerS3Options.filer = &filerAddress
@@ -149,13 +158,15 @@ func runFiler(cmd *Command, args []string) bool {
if *filerStartIam {
filerIamOptions.filer = &filerAddress
filerIamOptions.masters = f.masters
filerIamOptions.masters = f.mastersString
go func() {
time.Sleep(startDelay * time.Second)
filerIamOptions.startIamServer()
}()
}
f.masters = pb.ServerAddresses(*f.mastersString).ToAddresses()
f.startFiler()
return true
@@ -177,8 +188,10 @@ func (fo *FilerOptions) startFiler() {
peers = strings.Split(*fo.peers, ",")
}
filerAddress := pb.NewServerAddress(*fo.ip, *fo.port, *fo.portGrpc)
fs, nfs_err := weed_server.NewFilerServer(defaultMux, publicVolumeMux, &weed_server.FilerOption{
Masters: strings.Split(*fo.masters, ","),
Masters: fo.masters,
Collection: *fo.collection,
DefaultReplication: *fo.defaultReplicaPlacement,
DisableDirListing: *fo.disableDirListing,
@@ -188,11 +201,10 @@ func (fo *FilerOptions) startFiler() {
Rack: *fo.rack,
DefaultLevelDbDir: defaultLevelDbDirectory,
DisableHttp: *fo.disableHttp,
Host: *fo.ip,
Port: uint32(*fo.port),
Host: filerAddress,
Cipher: *fo.cipher,
SaveToFilerLimit: int64(*fo.saveToFilerLimit),
Filers: peers,
Filers: pb.FromAddressStrings(peers),
ConcurrentUploadLimit: int64(*fo.concurrentUploadLimitMB) * 1024 * 1024,
})
if nfs_err != nil {
@@ -200,7 +212,7 @@ func (fo *FilerOptions) startFiler() {
}
if *fo.publicPort != 0 {
publicListeningAddress := *fo.bindIp + ":" + strconv.Itoa(*fo.publicPort)
publicListeningAddress := util.JoinHostPort(*fo.bindIp, *fo.publicPort)
glog.V(0).Infoln("Start Seaweed filer server", util.Version(), "public at", publicListeningAddress)
publicListener, e := util.NewListener(publicListeningAddress, 0)
if e != nil {
@@ -215,7 +227,7 @@ func (fo *FilerOptions) startFiler() {
glog.V(0).Infof("Start Seaweed Filer %s at %s:%d", util.Version(), *fo.ip, *fo.port)
filerListener, e := util.NewListener(
*fo.bindIp+":"+strconv.Itoa(*fo.port),
util.JoinHostPort(*fo.bindIp, *fo.port),
time.Duration(10)*time.Second,
)
if e != nil {
@@ -223,8 +235,8 @@ func (fo *FilerOptions) startFiler() {
}
// starting grpc server
grpcPort := *fo.port + 10000
grpcL, err := util.NewListener(*fo.bindIp+":"+strconv.Itoa(grpcPort), 0)
grpcPort := *fo.portGrpc
grpcL, err := util.NewListener(util.JoinHostPort(*fo.bindIp, grpcPort), 0)
if err != nil {
glog.Fatalf("failed to listen on grpc port %d: %v", grpcPort, err)
}
+10 -49
View File
@@ -1,16 +1,13 @@
package command
import (
"context"
"fmt"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
"github.com/chrislusf/seaweedfs/weed/replication/source"
"github.com/chrislusf/seaweedfs/weed/security"
"github.com/chrislusf/seaweedfs/weed/util"
"google.golang.org/grpc"
"io"
"time"
)
@@ -52,11 +49,11 @@ var cmdFilerBackup = &Command{
func runFilerBackup(cmd *Command, args []string) bool {
grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client")
util.LoadConfiguration("security", false)
util.LoadConfiguration("replication", true)
grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client")
for {
err := doFilerBackup(grpcDialOption, &filerBackupOptions)
if err != nil {
@@ -81,7 +78,7 @@ func doFilerBackup(grpcDialOption grpc.DialOption, backupOption *FilerBackupOpti
return fmt.Errorf("no data sink configured in replication.toml")
}
sourceFiler := *backupOption.filer
sourceFiler := pb.ServerAddress(*backupOption.filer)
sourcePath := *backupOption.path
timeAgo := *backupOption.timeAgo
targetPath := dataSink.GetSinkToDirectory()
@@ -105,53 +102,17 @@ func doFilerBackup(grpcDialOption grpc.DialOption, backupOption *FilerBackupOpti
// create filer sink
filerSource := &source.FilerSource{}
filerSource.DoInitialize(sourceFiler, pb.ServerToGrpcAddress(sourceFiler), sourcePath, *backupOption.proxyByFiler)
filerSource.DoInitialize(sourceFiler.ToHttpAddress(), sourceFiler.ToGrpcAddress(), sourcePath, *backupOption.proxyByFiler)
dataSink.SetSourceFiler(filerSource)
processEventFn := genProcessFunction(sourcePath, targetPath, dataSink, debug)
return pb.WithFilerClient(sourceFiler, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
stream, err := client.SubscribeMetadata(ctx, &filer_pb.SubscribeMetadataRequest{
ClientName: "backup_" + dataSink.GetName(),
PathPrefix: sourcePath,
SinceNs: startFrom.UnixNano(),
})
if err != nil {
return fmt.Errorf("listen: %v", err)
}
var counter int64
var lastWriteTime time.Time
for {
resp, listenErr := stream.Recv()
if listenErr == io.EOF {
return nil
}
if listenErr != nil {
return listenErr
}
if err := processEventFn(resp); err != nil {
return fmt.Errorf("processEventFn: %v", err)
}
counter++
if lastWriteTime.Add(3 * time.Second).Before(time.Now()) {
glog.V(0).Infof("backup %s progressed to %v %0.2f/sec", sourceFiler, time.Unix(0, resp.TsNs), float64(counter)/float64(3))
counter = 0
lastWriteTime = time.Now()
if err := setOffset(grpcDialOption, sourceFiler, BackupKeyPrefix, int32(sinkId), resp.TsNs); err != nil {
return fmt.Errorf("setOffset: %v", err)
}
}
}
processEventFnWithOffset := pb.AddOffsetFunc(processEventFn, 3*time.Second, func(counter int64, lastTsNs int64) error {
glog.V(0).Infof("backup %s progressed to %v %0.2f/sec", sourceFiler, time.Unix(0, lastTsNs), float64(counter)/float64(3))
return setOffset(grpcDialOption, sourceFiler, BackupKeyPrefix, int32(sinkId), lastTsNs)
})
return pb.FollowMetadata(sourceFiler, grpcDialOption, "backup_"+dataSink.GetName(),
sourcePath, nil, startFrom.UnixNano(), 0, processEventFnWithOffset, false)
}
+7 -2
View File
@@ -23,7 +23,7 @@ var (
type FilerCatOptions struct {
grpcDialOption grpc.DialOption
filerAddress string
filerAddress pb.ServerAddress
filerClient filer_pb.SeaweedFilerClient
output *string
}
@@ -78,7 +78,7 @@ func runFilerCat(cmd *Command, args []string) bool {
return false
}
filerCat.filerAddress = filerUrl.Host
filerCat.filerAddress = pb.ServerAddress(filerUrl.Host)
filerCat.grpcDialOption = security.LoadClientTLS(util.GetViper(), "grpc.client")
dir, name := util.FullPath(urlPath).DirAndName()
@@ -108,6 +108,11 @@ func runFilerCat(cmd *Command, args []string) bool {
return err
}
if len(respLookupEntry.Entry.Content) > 0 {
_, err = writer.Write(respLookupEntry.Entry.Content)
return err
}
filerCat.filerClient = client
return filer.StreamContent(&filerCat, writer, respLookupEntry.Entry.Chunks, 0, math.MaxInt64)
+124 -56
View File
@@ -7,7 +7,6 @@ import (
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
@@ -52,21 +51,21 @@ type CopyOptions struct {
}
func init() {
cmdCopy.Run = runCopy // break init cycle
cmdCopy.IsDebug = cmdCopy.Flag.Bool("debug", false, "verbose debug information")
copy.include = cmdCopy.Flag.String("include", "", "pattens of files to copy, e.g., *.pdf, *.html, ab?d.txt, works together with -dir")
copy.replication = cmdCopy.Flag.String("replication", "", "replication type")
copy.collection = cmdCopy.Flag.String("collection", "", "optional collection name")
copy.ttl = cmdCopy.Flag.String("ttl", "", "time to live, e.g.: 1m, 1h, 1d, 1M, 1y")
copy.diskType = cmdCopy.Flag.String("disk", "", "[hdd|ssd|<tag>] hard drive or solid state drive or any tag")
copy.maxMB = cmdCopy.Flag.Int("maxMB", 4, "split files larger than the limit")
copy.concurrenctFiles = cmdCopy.Flag.Int("c", 8, "concurrent file copy goroutines")
copy.concurrenctChunks = cmdCopy.Flag.Int("concurrentChunks", 8, "concurrent chunk copy goroutines for each file")
copy.checkSize = cmdCopy.Flag.Bool("check.size", false, "copy when the target file size is different from the source file")
copy.verbose = cmdCopy.Flag.Bool("verbose", false, "print out details during copying")
cmdFilerCopy.Run = runCopy // break init cycle
cmdFilerCopy.IsDebug = cmdFilerCopy.Flag.Bool("debug", false, "verbose debug information")
copy.include = cmdFilerCopy.Flag.String("include", "", "pattens of files to copy, e.g., *.pdf, *.html, ab?d.txt, works together with -dir")
copy.replication = cmdFilerCopy.Flag.String("replication", "", "replication type")
copy.collection = cmdFilerCopy.Flag.String("collection", "", "optional collection name")
copy.ttl = cmdFilerCopy.Flag.String("ttl", "", "time to live, e.g.: 1m, 1h, 1d, 1M, 1y")
copy.diskType = cmdFilerCopy.Flag.String("disk", "", "[hdd|ssd|<tag>] hard drive or solid state drive or any tag")
copy.maxMB = cmdFilerCopy.Flag.Int("maxMB", 4, "split files larger than the limit")
copy.concurrenctFiles = cmdFilerCopy.Flag.Int("c", 8, "concurrent file copy goroutines")
copy.concurrenctChunks = cmdFilerCopy.Flag.Int("concurrentChunks", 8, "concurrent chunk copy goroutines for each file")
copy.checkSize = cmdFilerCopy.Flag.Bool("check.size", false, "copy when the target file size is different from the source file")
copy.verbose = cmdFilerCopy.Flag.Bool("verbose", false, "print out details during copying")
}
var cmdCopy = &Command{
var cmdFilerCopy = &Command{
UsageLine: "filer.copy file_or_dir1 [file_or_dir2 file_or_dir3] http://localhost:8888/path/to/a/folder/",
Short: "copy one or a list of files to a filer folder",
Long: `copy one or a list of files, or batch copy one whole folder recursively, to a filer folder
@@ -92,35 +91,21 @@ func runCopy(cmd *Command, args []string) bool {
filerDestination := args[len(args)-1]
fileOrDirs := args[0 : len(args)-1]
filerUrl, err := url.Parse(filerDestination)
filerAddress, urlPath, err := pb.ParseUrl(filerDestination)
if err != nil {
fmt.Printf("The last argument should be a URL on filer: %v\n", err)
return false
}
urlPath := filerUrl.Path
if !strings.HasSuffix(urlPath, "/") {
fmt.Printf("The last argument should be a folder and end with \"/\"\n")
return false
}
if filerUrl.Port() == "" {
fmt.Printf("The filer port should be specified.\n")
return false
}
filerPort, parseErr := strconv.ParseUint(filerUrl.Port(), 10, 64)
if parseErr != nil {
fmt.Printf("The filer port parse error: %v\n", parseErr)
return false
}
filerGrpcPort := filerPort + 10000
filerGrpcAddress := fmt.Sprintf("%s:%d", filerUrl.Hostname(), filerGrpcPort)
copy.grpcDialOption = security.LoadClientTLS(util.GetViper(), "grpc.client")
masters, collection, replication, dirBuckets, maxMB, cipher, err := readFilerConfiguration(copy.grpcDialOption, filerGrpcAddress)
masters, collection, replication, dirBuckets, maxMB, cipher, err := readFilerConfiguration(copy.grpcDialOption, filerAddress)
if err != nil {
fmt.Printf("read from filer %s: %v\n", filerGrpcAddress, err)
fmt.Printf("read from filer %s: %v\n", filerAddress, err)
return false
}
if strings.HasPrefix(urlPath, dirBuckets+"/") {
@@ -154,7 +139,7 @@ func runCopy(cmd *Command, args []string) bool {
}
copy.ttlSec = int32(ttl.Minutes()) * 60
if *cmdCopy.IsDebug {
if *cmdFilerCopy.IsDebug {
grace.SetupProfiling("filer.copy.cpu.pprof", "filer.copy.mem.pprof")
}
@@ -174,9 +159,8 @@ func runCopy(cmd *Command, args []string) bool {
go func() {
defer waitGroup.Done()
worker := FileCopyWorker{
options: &copy,
filerHost: filerUrl.Host,
filerGrpcAddress: filerGrpcAddress,
options: &copy,
filerAddress: filerAddress,
}
if err := worker.copyFiles(fileCopyTaskChan); err != nil {
fmt.Fprintf(os.Stderr, "copy file error: %v\n", err)
@@ -189,7 +173,7 @@ func runCopy(cmd *Command, args []string) bool {
return true
}
func readFilerConfiguration(grpcDialOption grpc.DialOption, filerGrpcAddress string) (masters []string, collection, replication string, dirBuckets string, maxMB uint32, cipher bool, err error) {
func readFilerConfiguration(grpcDialOption grpc.DialOption, filerGrpcAddress pb.ServerAddress) (masters []string, collection, replication string, dirBuckets string, maxMB uint32, cipher bool, err error) {
err = pb.WithGrpcFilerClient(filerGrpcAddress, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
resp, err := client.GetFilerConfiguration(context.Background(), &filer_pb.GetFilerConfigurationRequest{})
if err != nil {
@@ -241,9 +225,8 @@ func genFileCopyTask(fileOrDir string, destPath string, fileCopyTaskChan chan Fi
}
type FileCopyWorker struct {
options *CopyOptions
filerHost string
filerGrpcAddress string
options *CopyOptions
filerAddress pb.ServerAddress
}
func (worker *FileCopyWorker) copyFiles(fileCopyTaskChan chan FileCopyTask) error {
@@ -321,7 +304,7 @@ func (worker *FileCopyWorker) checkExistingFileFirst(task FileCopyTask, f *os.Fi
return
}
err = pb.WithGrpcFilerClient(worker.filerGrpcAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
err = pb.WithGrpcFilerClient(worker.filerAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.LookupDirectoryEntryRequest{
Directory: task.destinationUrlPath,
@@ -363,7 +346,7 @@ func (worker *FileCopyWorker) uploadFileAsOne(task FileCopyTask, f *os.File) err
// assign a volume
err = util.Retry("assignVolume", func() error {
return pb.WithGrpcFilerClient(worker.filerGrpcAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
return pb.WithGrpcFilerClient(worker.filerAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.AssignVolumeRequest{
Count: 1,
@@ -381,6 +364,9 @@ func (worker *FileCopyWorker) uploadFileAsOne(task FileCopyTask, f *os.File) err
if assignResult.Error != "" {
return fmt.Errorf("assign volume failure %v: %v", request, assignResult.Error)
}
if assignResult.Location.Url == "" {
return fmt.Errorf("assign volume failure %v: %v", request, assignResult)
}
return nil
})
})
@@ -388,9 +374,17 @@ func (worker *FileCopyWorker) uploadFileAsOne(task FileCopyTask, f *os.File) err
return fmt.Errorf("Failed to assign from %v: %v\n", worker.options.masters, err)
}
targetUrl := "http://" + assignResult.Url + "/" + assignResult.FileId
uploadResult, err := operation.UploadData(targetUrl, fileName, worker.options.cipher, data, false, mimeType, nil, security.EncodedJwt(assignResult.Auth))
targetUrl := "http://" + assignResult.Location.Url + "/" + assignResult.FileId
uploadOption := &operation.UploadOption{
UploadUrl: targetUrl,
Filename: fileName,
Cipher: worker.options.cipher,
IsInputCompressed: false,
MimeType: mimeType,
PairMap: nil,
Jwt: security.EncodedJwt(assignResult.Auth),
}
uploadResult, err := operation.UploadData(data, uploadOption)
if err != nil {
return fmt.Errorf("upload data %v to %s: %v\n", fileName, targetUrl, err)
}
@@ -403,10 +397,10 @@ func (worker *FileCopyWorker) uploadFileAsOne(task FileCopyTask, f *os.File) err
chunks = append(chunks, uploadResult.ToPbFileChunk(assignResult.FileId, 0))
fmt.Printf("copied %s => http://%s%s%s\n", f.Name(), worker.filerHost, task.destinationUrlPath, fileName)
fmt.Printf("copied %s => http://%s%s%s\n", f.Name(), worker.filerAddress.ToHttpAddress(), task.destinationUrlPath, fileName)
}
if err := pb.WithGrpcFilerClient(worker.filerGrpcAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
if err := pb.WithGrpcFilerClient(worker.filerAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.CreateEntryRequest{
Directory: task.destinationUrlPath,
Entry: &filer_pb.Entry{
@@ -432,7 +426,7 @@ func (worker *FileCopyWorker) uploadFileAsOne(task FileCopyTask, f *os.File) err
}
return nil
}); err != nil {
return fmt.Errorf("upload data %v to http://%s%s%s: %v\n", fileName, worker.filerHost, task.destinationUrlPath, fileName, err)
return fmt.Errorf("upload data %v to http://%s%s%s: %v\n", fileName, worker.filerAddress.ToHttpAddress(), task.destinationUrlPath, fileName, err)
}
return nil
@@ -463,7 +457,7 @@ func (worker *FileCopyWorker) uploadFileInChunks(task FileCopyTask, f *os.File,
var assignResult *filer_pb.AssignVolumeResponse
var assignError error
err := util.Retry("assignVolume", func() error {
return pb.WithGrpcFilerClient(worker.filerGrpcAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
return pb.WithGrpcFilerClient(worker.filerAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.AssignVolumeRequest{
Count: 1,
Replication: *worker.options.replication,
@@ -487,7 +481,7 @@ func (worker *FileCopyWorker) uploadFileInChunks(task FileCopyTask, f *os.File,
fmt.Printf("Failed to assign from %v: %v\n", worker.options.masters, err)
}
targetUrl := "http://" + assignResult.Url + "/" + assignResult.FileId
targetUrl := "http://" + assignResult.Location.Url + "/" + assignResult.FileId
if collection == "" {
collection = assignResult.Collection
}
@@ -495,7 +489,16 @@ func (worker *FileCopyWorker) uploadFileInChunks(task FileCopyTask, f *os.File,
replication = assignResult.Replication
}
uploadResult, err, _ := operation.Upload(targetUrl, fileName+"-"+strconv.FormatInt(i+1, 10), worker.options.cipher, io.NewSectionReader(f, i*chunkSize, chunkSize), false, "", nil, security.EncodedJwt(assignResult.Auth))
uploadOption := &operation.UploadOption{
UploadUrl: targetUrl,
Filename: fileName + "-" + strconv.FormatInt(i+1, 10),
Cipher: worker.options.cipher,
IsInputCompressed: false,
MimeType: "",
PairMap: nil,
Jwt: security.EncodedJwt(assignResult.Auth),
}
uploadResult, err, _ := operation.Upload(io.NewSectionReader(f, i*chunkSize, chunkSize), uploadOption)
if err != nil {
uploadError = fmt.Errorf("upload data %v to %s: %v\n", fileName, targetUrl, err)
return
@@ -522,13 +525,18 @@ func (worker *FileCopyWorker) uploadFileInChunks(task FileCopyTask, f *os.File,
for _, chunk := range chunks {
fileIds = append(fileIds, chunk.FileId)
}
operation.DeleteFiles(func() string {
return copy.masters[0]
operation.DeleteFiles(func() pb.ServerAddress {
return pb.ServerAddress(copy.masters[0])
}, false, worker.options.grpcDialOption, fileIds)
return uploadError
}
if err := pb.WithGrpcFilerClient(worker.filerGrpcAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
manifestedChunks, manifestErr := filer.MaybeManifestize(worker.saveDataAsChunk, chunks)
if manifestErr != nil {
return fmt.Errorf("create manifest: %v", manifestErr)
}
if err := pb.WithGrpcFilerClient(worker.filerAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
request := &filer_pb.CreateEntryRequest{
Directory: task.destinationUrlPath,
Entry: &filer_pb.Entry{
@@ -545,7 +553,7 @@ func (worker *FileCopyWorker) uploadFileInChunks(task FileCopyTask, f *os.File,
Collection: collection,
TtlSec: worker.options.ttlSec,
},
Chunks: chunks,
Chunks: manifestedChunks,
},
}
@@ -554,10 +562,10 @@ func (worker *FileCopyWorker) uploadFileInChunks(task FileCopyTask, f *os.File,
}
return nil
}); err != nil {
return fmt.Errorf("upload data %v to http://%s%s%s: %v\n", fileName, worker.filerHost, task.destinationUrlPath, fileName, err)
return fmt.Errorf("upload data %v to http://%s%s%s: %v\n", fileName, worker.filerAddress.ToHttpAddress(), task.destinationUrlPath, fileName, err)
}
fmt.Printf("copied %s => http://%s%s%s\n", f.Name(), worker.filerHost, task.destinationUrlPath, fileName)
fmt.Printf("copied %s => http://%s%s%s\n", f.Name(), worker.filerAddress.ToHttpAddress(), task.destinationUrlPath, fileName)
return nil
}
@@ -580,3 +588,63 @@ func detectMimeType(f *os.File) string {
}
return mimeType
}
func (worker *FileCopyWorker) saveDataAsChunk(reader io.Reader, name string, offset int64) (chunk *filer_pb.FileChunk, collection, replication string, err error) {
var fileId, host string
var auth security.EncodedJwt
if flushErr := pb.WithGrpcFilerClient(worker.filerAddress, worker.options.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
ctx := context.Background()
assignErr := util.Retry("assignVolume", func() error {
request := &filer_pb.AssignVolumeRequest{
Count: 1,
Replication: *worker.options.replication,
Collection: *worker.options.collection,
TtlSec: worker.options.ttlSec,
DiskType: *worker.options.diskType,
Path: name,
}
resp, err := client.AssignVolume(ctx, request)
if err != nil {
return fmt.Errorf("assign volume failure %v: %v", request, err)
}
if resp.Error != "" {
return fmt.Errorf("assign volume failure %v: %v", request, resp.Error)
}
fileId, host, auth = resp.FileId, resp.Location.Url, security.EncodedJwt(resp.Auth)
collection, replication = resp.Collection, resp.Replication
return nil
})
if assignErr != nil {
return assignErr
}
return nil
}); flushErr != nil {
return nil, collection, replication, fmt.Errorf("filerGrpcAddress assign volume: %v", flushErr)
}
uploadOption := &operation.UploadOption{
UploadUrl: fmt.Sprintf("http://%s/%s", host, fileId),
Filename: name,
Cipher: worker.options.cipher,
IsInputCompressed: false,
MimeType: "",
PairMap: nil,
Jwt: auth,
}
uploadResult, flushErr, _ := operation.Upload(reader, uploadOption)
if flushErr != nil {
return nil, collection, replication, fmt.Errorf("upload data: %v", flushErr)
}
if uploadResult.Error != "" {
return nil, collection, replication, fmt.Errorf("upload result: %v", uploadResult.Error)
}
return uploadResult.ToPbFileChunk(fileId, offset), collection, replication, nil
}
+10 -43
View File
@@ -7,7 +7,6 @@ import (
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/spf13/viper"
"google.golang.org/grpc"
"io"
"reflect"
"time"
@@ -53,6 +52,7 @@ The backup writes to another filer store specified in a backup_filer.toml.
func runFilerMetaBackup(cmd *Command, args []string) bool {
util.LoadConfiguration("security", false)
metaBackup.grpcDialOption = security.LoadClientTLS(util.GetViper(), "grpc.client")
// load backup_filer.toml
@@ -189,48 +189,15 @@ func (metaBackup *FilerMetaBackupOptions) streamMetadataBackup() error {
return nil
}
tailErr := pb.WithFilerClient(*metaBackup.filerAddress, metaBackup.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
stream, err := client.SubscribeMetadata(ctx, &filer_pb.SubscribeMetadataRequest{
ClientName: "meta_backup",
PathPrefix: *metaBackup.filerDirectory,
SinceNs: startTime.UnixNano(),
})
if err != nil {
return fmt.Errorf("listen: %v", err)
}
var counter int64
var lastWriteTime time.Time
for {
resp, listenErr := stream.Recv()
if listenErr == io.EOF {
return nil
}
if listenErr != nil {
return listenErr
}
if err = eachEntryFunc(resp); err != nil {
return err
}
counter++
if lastWriteTime.Add(3 * time.Second).Before(time.Now()) {
glog.V(0).Infof("meta backup %s progressed to %v %0.2f/sec", *metaBackup.filerAddress, time.Unix(0, resp.TsNs), float64(counter)/float64(3))
counter = 0
lastWriteTime = time.Now()
if err2 := metaBackup.setOffset(lastWriteTime); err2 != nil {
return err2
}
}
}
processEventFnWithOffset := pb.AddOffsetFunc(eachEntryFunc, 3*time.Second, func(counter int64, lastTsNs int64) error {
lastTime := time.Unix(0, lastTsNs)
glog.V(0).Infof("meta backup %s progressed to %v %0.2f/sec", *metaBackup.filerAddress, lastTime, float64(counter)/float64(3))
return metaBackup.setOffset(lastTime)
})
return tailErr
return pb.FollowMetadata(pb.ServerAddress(*metaBackup.filerAddress), metaBackup.grpcDialOption, "meta_backup",
*metaBackup.filerDirectory, nil, startTime.UnixNano(), 0, processEventFnWithOffset, false)
}
func (metaBackup *FilerMetaBackupOptions) getOffset() (lastWriteTime time.Time, err error) {
@@ -257,7 +224,7 @@ var _ = filer_pb.FilerClient(&FilerMetaBackupOptions{})
func (metaBackup *FilerMetaBackupOptions) WithFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
return pb.WithFilerClient(*metaBackup.filerAddress, metaBackup.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
return pb.WithFilerClient(pb.ServerAddress(*metaBackup.filerAddress), metaBackup.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
return fn(client)
})
+9 -28
View File
@@ -3,16 +3,15 @@ package command
import (
"context"
"fmt"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/golang/protobuf/jsonpb"
jsoniter "github.com/json-iterator/go"
"github.com/olivere/elastic/v7"
"io"
"os"
"path/filepath"
"strings"
"time"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
"github.com/chrislusf/seaweedfs/weed/security"
"github.com/chrislusf/seaweedfs/weed/util"
@@ -45,6 +44,7 @@ var (
func runFilerMetaTail(cmd *Command, args []string) bool {
util.LoadConfiguration("security", false)
grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client")
var filterFunc func(dir, fname string) bool
@@ -103,37 +103,18 @@ func runFilerMetaTail(cmd *Command, args []string) bool {
}
}
tailErr := pb.WithFilerClient(*tailFiler, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
stream, err := client.SubscribeMetadata(ctx, &filer_pb.SubscribeMetadataRequest{
ClientName: "tail",
PathPrefix: *tailTarget,
SinceNs: time.Now().Add(-*tailStart).UnixNano(),
})
if err != nil {
return fmt.Errorf("listen: %v", err)
}
for {
resp, listenErr := stream.Recv()
if listenErr == io.EOF {
tailErr := pb.FollowMetadata(pb.ServerAddress(*tailFiler), grpcDialOption, "tail",
*tailTarget, nil, time.Now().Add(-*tailStart).UnixNano(), 0,
func(resp *filer_pb.SubscribeMetadataResponse) error {
if !shouldPrint(resp) {
return nil
}
if listenErr != nil {
return listenErr
}
if !shouldPrint(resp) {
continue
}
if err = eachEntryFunc(resp); err != nil {
if err := eachEntryFunc(resp); err != nil {
return err
}
}
return nil
}, false)
})
if tailErr != nil {
fmt.Printf("tail %s: %v\n", *tailFiler, tailErr)
}
+117
View File
@@ -0,0 +1,117 @@
package command
import (
"context"
"fmt"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
"github.com/chrislusf/seaweedfs/weed/pb/remote_pb"
"github.com/chrislusf/seaweedfs/weed/replication/source"
"github.com/chrislusf/seaweedfs/weed/security"
"github.com/chrislusf/seaweedfs/weed/util"
"google.golang.org/grpc"
"os"
"time"
)
type RemoteGatewayOptions struct {
filerAddress *string
grpcDialOption grpc.DialOption
readChunkFromFiler *bool
timeAgo *time.Duration
createBucketAt *string
createBucketRandomSuffix *bool
include *string
exclude *string
mappings *remote_pb.RemoteStorageMapping
remoteConfs map[string]*remote_pb.RemoteConf
bucketsDir string
}
var _ = filer_pb.FilerClient(&RemoteGatewayOptions{})
func (option *RemoteGatewayOptions) WithFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
return pb.WithFilerClient(pb.ServerAddress(*option.filerAddress), option.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
return fn(client)
})
}
func (option *RemoteGatewayOptions) AdjustedUrl(location *filer_pb.Location) string {
return location.Url
}
var (
remoteGatewayOptions RemoteGatewayOptions
)
func init() {
cmdFilerRemoteGateway.Run = runFilerRemoteGateway // break init cycle
remoteGatewayOptions.filerAddress = cmdFilerRemoteGateway.Flag.String("filer", "localhost:8888", "filer of the SeaweedFS cluster")
remoteGatewayOptions.createBucketAt = cmdFilerRemoteGateway.Flag.String("createBucketAt", "", "one remote storage name to create new buckets in")
remoteGatewayOptions.createBucketRandomSuffix = cmdFilerRemoteGateway.Flag.Bool("createBucketWithRandomSuffix", true, "add randomized suffix to bucket name to avoid conflicts")
remoteGatewayOptions.readChunkFromFiler = cmdFilerRemoteGateway.Flag.Bool("filerProxy", false, "read file chunks from filer instead of volume servers")
remoteGatewayOptions.timeAgo = cmdFilerRemoteGateway.Flag.Duration("timeAgo", 0, "start time before now. \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\"")
remoteGatewayOptions.include = cmdFilerRemoteGateway.Flag.String("include", "", "pattens of new bucket names, e.g., s3*")
remoteGatewayOptions.exclude = cmdFilerRemoteGateway.Flag.String("exclude", "", "pattens of new bucket names, e.g., local*")
}
var cmdFilerRemoteGateway = &Command{
UsageLine: "filer.remote.gateway",
Short: "resumable continuously write back bucket creation, deletion, and other local updates to remote object store",
Long: `resumable continuously write back bucket creation, deletion, and other local updates to remote object store
filer.remote.gateway listens on filer local buckets update events.
If any bucket is created, deleted, or updated, it will mirror the changes to remote object store.
weed filer.remote.sync -createBucketAt=cloud1
`,
}
func runFilerRemoteGateway(cmd *Command, args []string) bool {
util.LoadConfiguration("security", false)
grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client")
remoteGatewayOptions.grpcDialOption = grpcDialOption
filerAddress := pb.ServerAddress(*remoteGatewayOptions.filerAddress)
filerSource := &source.FilerSource{}
filerSource.DoInitialize(
filerAddress.ToHttpAddress(),
filerAddress.ToGrpcAddress(),
"/", // does not matter
*remoteGatewayOptions.readChunkFromFiler,
)
remoteGatewayOptions.bucketsDir = "/buckets"
// check buckets again
remoteGatewayOptions.WithFilerClient(func(filerClient filer_pb.SeaweedFilerClient) error {
resp, err := filerClient.GetFilerConfiguration(context.Background(), &filer_pb.GetFilerConfigurationRequest{})
if err != nil {
return err
}
remoteGatewayOptions.bucketsDir = resp.DirBuckets
return nil
})
// read filer remote storage mount mappings
if detectErr := remoteGatewayOptions.collectRemoteStorageConf(); detectErr != nil {
fmt.Fprintf(os.Stderr, "read mount info: %v\n", detectErr)
return true
}
// synchronize /buckets folder
fmt.Printf("synchronize buckets in %s ...\n", remoteGatewayOptions.bucketsDir)
util.RetryForever("filer.remote.sync buckets", func() error {
return remoteGatewayOptions.followBucketUpdatesAndUploadToRemote(filerSource)
}, func(err error) bool {
if err != nil {
glog.Errorf("synchronize %s: %v", remoteGatewayOptions.bucketsDir, err)
}
return true
})
return true
}
@@ -0,0 +1,398 @@
package command
import (
"fmt"
"github.com/chrislusf/seaweedfs/weed/filer"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
"github.com/chrislusf/seaweedfs/weed/pb/remote_pb"
"github.com/chrislusf/seaweedfs/weed/remote_storage"
"github.com/chrislusf/seaweedfs/weed/replication/source"
"github.com/chrislusf/seaweedfs/weed/util"
"github.com/golang/protobuf/proto"
"math"
"math/rand"
"path/filepath"
"strings"
"time"
)
func (option *RemoteGatewayOptions) followBucketUpdatesAndUploadToRemote(filerSource *source.FilerSource) error {
// read filer remote storage mount mappings
if detectErr := option.collectRemoteStorageConf(); detectErr != nil {
return fmt.Errorf("read mount info: %v", detectErr)
}
eachEntryFunc, err := option.makeBucketedEventProcessor(filerSource)
if err != nil {
return err
}
processEventFnWithOffset := pb.AddOffsetFunc(eachEntryFunc, 3*time.Second, func(counter int64, lastTsNs int64) error {
lastTime := time.Unix(0, lastTsNs)
glog.V(0).Infof("remote sync %s progressed to %v %0.2f/sec", *option.filerAddress, lastTime, float64(counter)/float64(3))
return remote_storage.SetSyncOffset(option.grpcDialOption, pb.ServerAddress(*option.filerAddress), option.bucketsDir, lastTsNs)
})
lastOffsetTs := collectLastSyncOffset(option, option.grpcDialOption, pb.ServerAddress(*option.filerAddress), option.bucketsDir, *option.timeAgo)
return pb.FollowMetadata(pb.ServerAddress(*option.filerAddress), option.grpcDialOption, "filer.remote.sync",
option.bucketsDir, []string{filer.DirectoryEtcRemote}, lastOffsetTs.UnixNano(), 0, processEventFnWithOffset, false)
}
func (option *RemoteGatewayOptions) makeBucketedEventProcessor(filerSource *source.FilerSource) (pb.ProcessMetadataFunc, error) {
handleCreateBucket := func(entry *filer_pb.Entry) error {
if !entry.IsDirectory {
return nil
}
if entry.RemoteEntry != nil {
// this directory is imported from "remote.mount.buckets" or "remote.mount"
return nil
}
if option.mappings.PrimaryBucketStorageName != "" && *option.createBucketAt == "" {
*option.createBucketAt = option.mappings.PrimaryBucketStorageName
glog.V(0).Infof("%s is set as the primary remote storage", *option.createBucketAt)
}
if len(option.mappings.Mappings) == 1 && *option.createBucketAt == "" {
for k := range option.mappings.Mappings {
*option.createBucketAt = k
glog.V(0).Infof("%s is set as the only remote storage", *option.createBucketAt)
}
}
if *option.createBucketAt == "" {
return nil
}
remoteConf, found := option.remoteConfs[*option.createBucketAt]
if !found {
return fmt.Errorf("un-configured remote storage %s", *option.createBucketAt)
}
client, err := remote_storage.GetRemoteStorage(remoteConf)
if err != nil {
return err
}
bucketName := strings.ToLower(entry.Name)
if *option.include != "" {
if ok, _ := filepath.Match(*option.include, entry.Name); !ok {
return nil
}
}
if *option.exclude != "" {
if ok, _ := filepath.Match(*option.exclude, entry.Name); ok {
return nil
}
}
if *option.createBucketRandomSuffix {
// https://docs.aws.amazon.com/AmazonS3/latest/userguide/bucketnamingrules.html
if len(bucketName)+5 > 63 {
bucketName = bucketName[:58]
}
bucketName = fmt.Sprintf("%s-%4d", bucketName, rand.Uint32()%10000)
}
glog.V(0).Infof("create bucket %s", bucketName)
if err := client.CreateBucket(bucketName); err != nil {
return fmt.Errorf("create bucket %s in %s: %v", bucketName, remoteConf.Name, err)
}
bucketPath := util.FullPath(option.bucketsDir).Child(entry.Name)
remoteLocation := &remote_pb.RemoteStorageLocation{
Name: *option.createBucketAt,
Bucket: bucketName,
Path: "/",
}
// need to add new mapping here before getting upates from metadata tailing
option.mappings.Mappings[string(bucketPath)] = remoteLocation
return filer.InsertMountMapping(option, string(bucketPath), remoteLocation)
}
handleDeleteBucket := func(entry *filer_pb.Entry) error {
if !entry.IsDirectory {
return nil
}
client, remoteStorageMountLocation, err := option.findRemoteStorageClient(entry.Name)
if err != nil {
return fmt.Errorf("findRemoteStorageClient %s: %v", entry.Name, err)
}
glog.V(0).Infof("delete remote bucket %s", remoteStorageMountLocation.Bucket)
if err := client.DeleteBucket(remoteStorageMountLocation.Bucket); err != nil {
return fmt.Errorf("delete remote bucket %s: %v", remoteStorageMountLocation.Bucket, err)
}
bucketPath := util.FullPath(option.bucketsDir).Child(entry.Name)
return filer.DeleteMountMapping(option, string(bucketPath))
}
handleEtcRemoteChanges := func(resp *filer_pb.SubscribeMetadataResponse) error {
message := resp.EventNotification
if message.NewEntry != nil {
// update
if message.NewEntry.Name == filer.REMOTE_STORAGE_MOUNT_FILE {
newMappings, readErr := filer.UnmarshalRemoteStorageMappings(message.NewEntry.Content)
if readErr != nil {
return fmt.Errorf("unmarshal mappings: %v", readErr)
}
option.mappings = newMappings
}
if strings.HasSuffix(message.NewEntry.Name, filer.REMOTE_STORAGE_CONF_SUFFIX) {
conf := &remote_pb.RemoteConf{}
if err := proto.Unmarshal(message.NewEntry.Content, conf); err != nil {
return fmt.Errorf("unmarshal %s/%s: %v", filer.DirectoryEtcRemote, message.NewEntry.Name, err)
}
option.remoteConfs[conf.Name] = conf
}
} else if message.OldEntry != nil {
// deletion
if strings.HasSuffix(message.OldEntry.Name, filer.REMOTE_STORAGE_CONF_SUFFIX) {
conf := &remote_pb.RemoteConf{}
if err := proto.Unmarshal(message.OldEntry.Content, conf); err != nil {
return fmt.Errorf("unmarshal %s/%s: %v", filer.DirectoryEtcRemote, message.OldEntry.Name, err)
}
delete(option.remoteConfs, conf.Name)
}
}
return nil
}
eachEntryFunc := func(resp *filer_pb.SubscribeMetadataResponse) error {
message := resp.EventNotification
if strings.HasPrefix(resp.Directory, filer.DirectoryEtcRemote) {
return handleEtcRemoteChanges(resp)
}
if message.OldEntry == nil && message.NewEntry == nil {
return nil
}
if message.OldEntry == nil && message.NewEntry != nil {
if message.NewParentPath == option.bucketsDir {
return handleCreateBucket(message.NewEntry)
}
if !filer.HasData(message.NewEntry) {
return nil
}
bucket, remoteStorageMountLocation, remoteStorage, ok := option.detectBucketInfo(message.NewParentPath)
if !ok {
return nil
}
client, err := remote_storage.GetRemoteStorage(remoteStorage)
if err != nil {
return err
}
glog.V(2).Infof("create: %+v", resp)
if !shouldSendToRemote(message.NewEntry) {
glog.V(2).Infof("skipping creating: %+v", resp)
return nil
}
dest := toRemoteStorageLocation(bucket, util.NewFullPath(message.NewParentPath, message.NewEntry.Name), remoteStorageMountLocation)
if message.NewEntry.IsDirectory {
glog.V(0).Infof("mkdir %s", remote_storage.FormatLocation(dest))
return client.WriteDirectory(dest, message.NewEntry)
}
glog.V(0).Infof("create %s", remote_storage.FormatLocation(dest))
reader := filer.NewFileReader(filerSource, message.NewEntry)
remoteEntry, writeErr := client.WriteFile(dest, message.NewEntry, reader)
if writeErr != nil {
return writeErr
}
return updateLocalEntry(&remoteSyncOptions, message.NewParentPath, message.NewEntry, remoteEntry)
}
if message.OldEntry != nil && message.NewEntry == nil {
if resp.Directory == option.bucketsDir {
return handleDeleteBucket(message.OldEntry)
}
bucket, remoteStorageMountLocation, remoteStorage, ok := option.detectBucketInfo(resp.Directory)
if !ok {
return nil
}
client, err := remote_storage.GetRemoteStorage(remoteStorage)
if err != nil {
return err
}
glog.V(2).Infof("delete: %+v", resp)
dest := toRemoteStorageLocation(bucket, util.NewFullPath(resp.Directory, message.OldEntry.Name), remoteStorageMountLocation)
if message.OldEntry.IsDirectory {
glog.V(0).Infof("rmdir %s", remote_storage.FormatLocation(dest))
return client.RemoveDirectory(dest)
}
glog.V(0).Infof("delete %s", remote_storage.FormatLocation(dest))
return client.DeleteFile(dest)
}
if message.OldEntry != nil && message.NewEntry != nil {
if resp.Directory == option.bucketsDir {
if message.NewParentPath == option.bucketsDir {
if message.OldEntry.Name == message.NewEntry.Name {
return nil
}
if err := handleCreateBucket(message.NewEntry); err != nil {
return err
}
if err := handleDeleteBucket(message.OldEntry); err != nil {
return err
}
}
}
oldBucket, oldRemoteStorageMountLocation, oldRemoteStorage, oldOk := option.detectBucketInfo(resp.Directory)
newBucket, newRemoteStorageMountLocation, newRemoteStorage, newOk := option.detectBucketInfo(message.NewParentPath)
if oldOk && newOk {
if !shouldSendToRemote(message.NewEntry) {
glog.V(2).Infof("skipping updating: %+v", resp)
return nil
}
client, err := remote_storage.GetRemoteStorage(oldRemoteStorage)
if err != nil {
return err
}
if resp.Directory == message.NewParentPath && message.OldEntry.Name == message.NewEntry.Name {
// update the same entry
if message.NewEntry.IsDirectory {
// update directory property
return nil
}
if filer.IsSameData(message.OldEntry, message.NewEntry) {
glog.V(2).Infof("update meta: %+v", resp)
oldDest := toRemoteStorageLocation(oldBucket, util.NewFullPath(resp.Directory, message.OldEntry.Name), oldRemoteStorageMountLocation)
return client.UpdateFileMetadata(oldDest, message.OldEntry, message.NewEntry)
} else {
newDest := toRemoteStorageLocation(newBucket, util.NewFullPath(message.NewParentPath, message.NewEntry.Name), newRemoteStorageMountLocation)
reader := filer.NewFileReader(filerSource, message.NewEntry)
glog.V(0).Infof("create %s", remote_storage.FormatLocation(newDest))
remoteEntry, writeErr := client.WriteFile(newDest, message.NewEntry, reader)
if writeErr != nil {
return writeErr
}
return updateLocalEntry(&remoteSyncOptions, message.NewParentPath, message.NewEntry, remoteEntry)
}
}
}
// the following is entry rename
if oldOk {
client, err := remote_storage.GetRemoteStorage(oldRemoteStorage)
if err != nil {
return err
}
oldDest := toRemoteStorageLocation(oldBucket, util.NewFullPath(resp.Directory, message.OldEntry.Name), oldRemoteStorageMountLocation)
if message.OldEntry.IsDirectory {
return client.RemoveDirectory(oldDest)
}
glog.V(0).Infof("delete %s", remote_storage.FormatLocation(oldDest))
if err := client.DeleteFile(oldDest); err != nil {
return err
}
}
if newOk {
if !shouldSendToRemote(message.NewEntry) {
glog.V(2).Infof("skipping updating: %+v", resp)
return nil
}
client, err := remote_storage.GetRemoteStorage(newRemoteStorage)
if err != nil {
return err
}
newDest := toRemoteStorageLocation(newBucket, util.NewFullPath(message.NewParentPath, message.NewEntry.Name), newRemoteStorageMountLocation)
if message.NewEntry.IsDirectory {
return client.WriteDirectory(newDest, message.NewEntry)
}
reader := filer.NewFileReader(filerSource, message.NewEntry)
glog.V(0).Infof("create %s", remote_storage.FormatLocation(newDest))
remoteEntry, writeErr := client.WriteFile(newDest, message.NewEntry, reader)
if writeErr != nil {
return writeErr
}
return updateLocalEntry(&remoteSyncOptions, message.NewParentPath, message.NewEntry, remoteEntry)
}
}
return nil
}
return eachEntryFunc, nil
}
func (option *RemoteGatewayOptions) findRemoteStorageClient(bucketName string) (client remote_storage.RemoteStorageClient, remoteStorageMountLocation *remote_pb.RemoteStorageLocation, err error) {
bucket := util.FullPath(option.bucketsDir).Child(bucketName)
var isMounted bool
remoteStorageMountLocation, isMounted = option.mappings.Mappings[string(bucket)]
if !isMounted {
return nil, remoteStorageMountLocation, fmt.Errorf("%s is not mounted", bucket)
}
remoteConf, hasClient := option.remoteConfs[remoteStorageMountLocation.Name]
if !hasClient {
return nil, remoteStorageMountLocation, fmt.Errorf("%s mounted to un-configured %+v", bucket, remoteStorageMountLocation)
}
client, err = remote_storage.GetRemoteStorage(remoteConf)
if err != nil {
return nil, remoteStorageMountLocation, err
}
return client, remoteStorageMountLocation, nil
}
func (option *RemoteGatewayOptions) detectBucketInfo(actualDir string) (bucket util.FullPath, remoteStorageMountLocation *remote_pb.RemoteStorageLocation, remoteConf *remote_pb.RemoteConf, ok bool) {
bucket, ok = extractBucketPath(option.bucketsDir, actualDir)
if !ok {
return "", nil, nil, false
}
var isMounted bool
remoteStorageMountLocation, isMounted = option.mappings.Mappings[string(bucket)]
if !isMounted {
glog.Warningf("%s is not mounted", bucket)
return "", nil, nil, false
}
var hasClient bool
remoteConf, hasClient = option.remoteConfs[remoteStorageMountLocation.Name]
if !hasClient {
glog.Warningf("%s mounted to un-configured %+v", bucket, remoteStorageMountLocation)
return "", nil, nil, false
}
return bucket, remoteStorageMountLocation, remoteConf, true
}
func extractBucketPath(bucketsDir, dir string) (util.FullPath, bool) {
if !strings.HasPrefix(dir, bucketsDir+"/") {
return "", false
}
parts := strings.SplitN(dir[len(bucketsDir)+1:], "/", 2)
return util.FullPath(bucketsDir).Child(parts[0]), true
}
func (option *RemoteGatewayOptions) collectRemoteStorageConf() (err error) {
if mappings, err := filer.ReadMountMappings(option.grpcDialOption, pb.ServerAddress(*option.filerAddress)); err != nil {
return err
} else {
option.mappings = mappings
}
option.remoteConfs = make(map[string]*remote_pb.RemoteConf)
var lastConfName string
err = filer_pb.List(option, filer.DirectoryEtcRemote, "", func(entry *filer_pb.Entry, isLast bool) error {
if !strings.HasSuffix(entry.Name, filer.REMOTE_STORAGE_CONF_SUFFIX) {
return nil
}
conf := &remote_pb.RemoteConf{}
if err := proto.Unmarshal(entry.Content, conf); err != nil {
return fmt.Errorf("unmarshal %s/%s: %v", filer.DirectoryEtcRemote, entry.Name, err)
}
option.remoteConfs[conf.Name] = conf
lastConfName = conf.Name
return nil
}, "", false, math.MaxUint32)
if option.mappings.PrimaryBucketStorageName == "" && len(option.remoteConfs) == 1 {
glog.V(0).Infof("%s is set to the default remote storage", lastConfName)
option.mappings.PrimaryBucketStorageName = lastConfName
}
return
}
+92
View File
@@ -0,0 +1,92 @@
package command
import (
"fmt"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
"github.com/chrislusf/seaweedfs/weed/replication/source"
"github.com/chrislusf/seaweedfs/weed/security"
"github.com/chrislusf/seaweedfs/weed/util"
"google.golang.org/grpc"
"time"
)
type RemoteSyncOptions struct {
filerAddress *string
grpcDialOption grpc.DialOption
readChunkFromFiler *bool
timeAgo *time.Duration
dir *string
}
var _ = filer_pb.FilerClient(&RemoteSyncOptions{})
func (option *RemoteSyncOptions) WithFilerClient(fn func(filer_pb.SeaweedFilerClient) error) error {
return pb.WithFilerClient(pb.ServerAddress(*option.filerAddress), option.grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
return fn(client)
})
}
func (option *RemoteSyncOptions) AdjustedUrl(location *filer_pb.Location) string {
return location.Url
}
var (
remoteSyncOptions RemoteSyncOptions
)
func init() {
cmdFilerRemoteSynchronize.Run = runFilerRemoteSynchronize // break init cycle
remoteSyncOptions.filerAddress = cmdFilerRemoteSynchronize.Flag.String("filer", "localhost:8888", "filer of the SeaweedFS cluster")
remoteSyncOptions.dir = cmdFilerRemoteSynchronize.Flag.String("dir", "", "a mounted directory on filer")
remoteSyncOptions.readChunkFromFiler = cmdFilerRemoteSynchronize.Flag.Bool("filerProxy", false, "read file chunks from filer instead of volume servers")
remoteSyncOptions.timeAgo = cmdFilerRemoteSynchronize.Flag.Duration("timeAgo", 0, "start time before now. \"300ms\", \"1.5h\" or \"2h45m\". Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\"")
}
var cmdFilerRemoteSynchronize = &Command{
UsageLine: "filer.remote.sync",
Short: "resumable continuously write back updates to remote storage",
Long: `resumable continuously write back updates to remote storage
filer.remote.sync listens on filer update events.
If any mounted remote file is updated, it will fetch the updated content,
and write to the remote storage.
weed filer.remote.sync -dir=/mount/s3_on_cloud
`,
}
func runFilerRemoteSynchronize(cmd *Command, args []string) bool {
util.LoadConfiguration("security", false)
grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client")
remoteSyncOptions.grpcDialOption = grpcDialOption
dir := *remoteSyncOptions.dir
filerAddress := pb.ServerAddress(*remoteSyncOptions.filerAddress)
filerSource := &source.FilerSource{}
filerSource.DoInitialize(
filerAddress.ToHttpAddress(),
filerAddress.ToGrpcAddress(),
"/", // does not matter
*remoteSyncOptions.readChunkFromFiler,
)
if dir != "" {
fmt.Printf("synchronize %s to remote storage...\n", dir)
util.RetryForever("filer.remote.sync "+dir, func() error {
return followUpdatesAndUploadToRemote(&remoteSyncOptions, filerSource, dir)
}, func(err error) bool {
if err != nil {
glog.Errorf("synchronize %s: %v", dir, err)
}
return true
})
return true
}
return true
}
+222
View File
@@ -0,0 +1,222 @@
package command
import (
"context"
"fmt"
"github.com/chrislusf/seaweedfs/weed/filer"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/pb"
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
"github.com/chrislusf/seaweedfs/weed/pb/remote_pb"
"github.com/chrislusf/seaweedfs/weed/remote_storage"
"github.com/chrislusf/seaweedfs/weed/replication/source"
"github.com/chrislusf/seaweedfs/weed/util"
"github.com/golang/protobuf/proto"
"google.golang.org/grpc"
"os"
"strings"
"time"
)
func followUpdatesAndUploadToRemote(option *RemoteSyncOptions, filerSource *source.FilerSource, mountedDir string) error {
// read filer remote storage mount mappings
_, _, remoteStorageMountLocation, remoteStorage, detectErr := filer.DetectMountInfo(option.grpcDialOption, pb.ServerAddress(*option.filerAddress), mountedDir)
if detectErr != nil {
return fmt.Errorf("read mount info: %v", detectErr)
}
eachEntryFunc, err := makeEventProcessor(remoteStorage, mountedDir, remoteStorageMountLocation, filerSource)
if err != nil {
return err
}
processEventFnWithOffset := pb.AddOffsetFunc(eachEntryFunc, 3*time.Second, func(counter int64, lastTsNs int64) error {
lastTime := time.Unix(0, lastTsNs)
glog.V(0).Infof("remote sync %s progressed to %v %0.2f/sec", *option.filerAddress, lastTime, float64(counter)/float64(3))
return remote_storage.SetSyncOffset(option.grpcDialOption, pb.ServerAddress(*option.filerAddress), mountedDir, lastTsNs)
})
lastOffsetTs := collectLastSyncOffset(option, option.grpcDialOption, pb.ServerAddress(*option.filerAddress), mountedDir, *option.timeAgo)
return pb.FollowMetadata(pb.ServerAddress(*option.filerAddress), option.grpcDialOption, "filer.remote.sync",
mountedDir, []string{filer.DirectoryEtcRemote}, lastOffsetTs.UnixNano(), 0, processEventFnWithOffset, false)
}
func makeEventProcessor(remoteStorage *remote_pb.RemoteConf, mountedDir string, remoteStorageMountLocation *remote_pb.RemoteStorageLocation, filerSource *source.FilerSource) (pb.ProcessMetadataFunc, error) {
client, err := remote_storage.GetRemoteStorage(remoteStorage)
if err != nil {
return nil, err
}
handleEtcRemoteChanges := func(resp *filer_pb.SubscribeMetadataResponse) error {
message := resp.EventNotification
if message.NewEntry == nil {
return nil
}
if message.NewEntry.Name == filer.REMOTE_STORAGE_MOUNT_FILE {
mappings, readErr := filer.UnmarshalRemoteStorageMappings(message.NewEntry.Content)
if readErr != nil {
return fmt.Errorf("unmarshal mappings: %v", readErr)
}
if remoteLoc, found := mappings.Mappings[mountedDir]; found {
if remoteStorageMountLocation.Bucket != remoteLoc.Bucket || remoteStorageMountLocation.Path != remoteLoc.Path {
glog.Fatalf("Unexpected mount changes %+v => %+v", remoteStorageMountLocation, remoteLoc)
}
} else {
glog.V(0).Infof("unmounted %s exiting ...", mountedDir)
os.Exit(0)
}
}
if message.NewEntry.Name == remoteStorage.Name+filer.REMOTE_STORAGE_CONF_SUFFIX {
conf := &remote_pb.RemoteConf{}
if err := proto.Unmarshal(message.NewEntry.Content, conf); err != nil {
return fmt.Errorf("unmarshal %s/%s: %v", filer.DirectoryEtcRemote, message.NewEntry.Name, err)
}
remoteStorage = conf
if newClient, err := remote_storage.GetRemoteStorage(remoteStorage); err == nil {
client = newClient
} else {
return err
}
}
return nil
}
eachEntryFunc := func(resp *filer_pb.SubscribeMetadataResponse) error {
message := resp.EventNotification
if strings.HasPrefix(resp.Directory, filer.DirectoryEtcRemote) {
return handleEtcRemoteChanges(resp)
}
if message.OldEntry == nil && message.NewEntry == nil {
return nil
}
if message.OldEntry == nil && message.NewEntry != nil {
if !filer.HasData(message.NewEntry) {
return nil
}
glog.V(2).Infof("create: %+v", resp)
if !shouldSendToRemote(message.NewEntry) {
glog.V(2).Infof("skipping creating: %+v", resp)
return nil
}
dest := toRemoteStorageLocation(util.FullPath(mountedDir), util.NewFullPath(message.NewParentPath, message.NewEntry.Name), remoteStorageMountLocation)
if message.NewEntry.IsDirectory {
glog.V(0).Infof("mkdir %s", remote_storage.FormatLocation(dest))
return client.WriteDirectory(dest, message.NewEntry)
}
glog.V(0).Infof("create %s", remote_storage.FormatLocation(dest))
reader := filer.NewFileReader(filerSource, message.NewEntry)
remoteEntry, writeErr := client.WriteFile(dest, message.NewEntry, reader)
if writeErr != nil {
return writeErr
}
return updateLocalEntry(&remoteSyncOptions, message.NewParentPath, message.NewEntry, remoteEntry)
}
if message.OldEntry != nil && message.NewEntry == nil {
glog.V(2).Infof("delete: %+v", resp)
dest := toRemoteStorageLocation(util.FullPath(mountedDir), util.NewFullPath(resp.Directory, message.OldEntry.Name), remoteStorageMountLocation)
if message.OldEntry.IsDirectory {
glog.V(0).Infof("rmdir %s", remote_storage.FormatLocation(dest))
return client.RemoveDirectory(dest)
}
glog.V(0).Infof("delete %s", remote_storage.FormatLocation(dest))
return client.DeleteFile(dest)
}
if message.OldEntry != nil && message.NewEntry != nil {
oldDest := toRemoteStorageLocation(util.FullPath(mountedDir), util.NewFullPath(resp.Directory, message.OldEntry.Name), remoteStorageMountLocation)
dest := toRemoteStorageLocation(util.FullPath(mountedDir), util.NewFullPath(message.NewParentPath, message.NewEntry.Name), remoteStorageMountLocation)
if !shouldSendToRemote(message.NewEntry) {
glog.V(2).Infof("skipping updating: %+v", resp)
return nil
}
if message.NewEntry.IsDirectory {
return client.WriteDirectory(dest, message.NewEntry)
}
if resp.Directory == message.NewParentPath && message.OldEntry.Name == message.NewEntry.Name {
if filer.IsSameData(message.OldEntry, message.NewEntry) {
glog.V(2).Infof("update meta: %+v", resp)
return client.UpdateFileMetadata(dest, message.OldEntry, message.NewEntry)
}
}
glog.V(2).Infof("update: %+v", resp)
glog.V(0).Infof("delete %s", remote_storage.FormatLocation(oldDest))
if err := client.DeleteFile(oldDest); err != nil {
return err
}
reader := filer.NewFileReader(filerSource, message.NewEntry)
glog.V(0).Infof("create %s", remote_storage.FormatLocation(dest))
remoteEntry, writeErr := client.WriteFile(dest, message.NewEntry, reader)
if writeErr != nil {
return writeErr
}
return updateLocalEntry(&remoteSyncOptions, message.NewParentPath, message.NewEntry, remoteEntry)
}
return nil
}
return eachEntryFunc, nil
}
func collectLastSyncOffset(filerClient filer_pb.FilerClient, grpcDialOption grpc.DialOption, filerAddress pb.ServerAddress, mountedDir string, timeAgo time.Duration) time.Time {
// 1. specified by timeAgo
// 2. last offset timestamp for this directory
// 3. directory creation time
var lastOffsetTs time.Time
if timeAgo == 0 {
mountedDirEntry, err := filer_pb.GetEntry(filerClient, util.FullPath(mountedDir))
if err != nil {
glog.V(0).Infof("get mounted directory %s: %v", mountedDir, err)
return time.Now()
}
lastOffsetTsNs, err := remote_storage.GetSyncOffset(grpcDialOption, filerAddress, mountedDir)
if mountedDirEntry != nil {
if err == nil && mountedDirEntry.Attributes.Crtime < lastOffsetTsNs/1000000 {
lastOffsetTs = time.Unix(0, lastOffsetTsNs)
glog.V(0).Infof("resume from %v", lastOffsetTs)
} else {
lastOffsetTs = time.Unix(mountedDirEntry.Attributes.Crtime, 0)
}
} else {
lastOffsetTs = time.Now()
}
} else {
lastOffsetTs = time.Now().Add(-timeAgo)
}
return lastOffsetTs
}
func toRemoteStorageLocation(mountDir, sourcePath util.FullPath, remoteMountLocation *remote_pb.RemoteStorageLocation) *remote_pb.RemoteStorageLocation {
source := string(sourcePath[len(mountDir):])
dest := util.FullPath(remoteMountLocation.Path).Child(source)
return &remote_pb.RemoteStorageLocation{
Name: remoteMountLocation.Name,
Bucket: remoteMountLocation.Bucket,
Path: string(dest),
}
}
func shouldSendToRemote(entry *filer_pb.Entry) bool {
if entry.RemoteEntry == nil {
return true
}
if entry.RemoteEntry.RemoteMtime < entry.Attributes.Mtime {
return true
}
return false
}
func updateLocalEntry(filerClient filer_pb.FilerClient, dir string, entry *filer_pb.Entry, remoteEntry *filer_pb.RemoteEntry) error {
remoteEntry.LastLocalSyncTsNs = time.Now().UnixNano()
entry.RemoteEntry = remoteEntry
return filerClient.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
_, err := client.UpdateEntry(context.Background(), &filer_pb.UpdateEntryRequest{
Directory: dir,
Entry: entry,
})
return err
})
}
-6
View File
@@ -7,12 +7,6 @@ import (
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/replication"
"github.com/chrislusf/seaweedfs/weed/replication/sink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/azuresink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/b2sink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/filersink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/gcssink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/localsink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/s3sink"
"github.com/chrislusf/seaweedfs/weed/replication/sub"
"github.com/chrislusf/seaweedfs/weed/util"
)
+18 -52
View File
@@ -15,7 +15,6 @@ import (
"github.com/chrislusf/seaweedfs/weed/util"
"github.com/chrislusf/seaweedfs/weed/util/grace"
"google.golang.org/grpc"
"io"
"strings"
"time"
)
@@ -71,8 +70,8 @@ func init() {
var cmdFilerSynchronize = &Command{
UsageLine: "filer.sync -a=<oneFilerHost>:<oneFilerPort> -b=<otherFilerHost>:<otherFilerPort>",
Short: "resumeable continuous synchronization between two active-active or active-passive SeaweedFS clusters",
Long: `resumeable continuous synchronization for file changes between two active-active or active-passive filers
Short: "resumable continuous synchronization between two active-active or active-passive SeaweedFS clusters",
Long: `resumable continuous synchronization for file changes between two active-active or active-passive filers
filer.sync listens on filer notifications. If any file is updated, it will fetch the updated content,
and write to the other destination. Different from filer.replicate:
@@ -89,13 +88,16 @@ var cmdFilerSynchronize = &Command{
func runFilerSynchronize(cmd *Command, args []string) bool {
util.LoadConfiguration("security", false)
grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client")
grace.SetupProfiling(*syncCpuProfile, *syncMemProfile)
filerA := pb.ServerAddress(*syncOptions.filerA)
filerB := pb.ServerAddress(*syncOptions.filerB)
go func() {
for {
err := doSubscribeFilerMetaChanges(grpcDialOption, *syncOptions.filerA, *syncOptions.aPath, *syncOptions.aProxyByFiler, *syncOptions.filerB,
err := doSubscribeFilerMetaChanges(grpcDialOption, filerA, *syncOptions.aPath, *syncOptions.aProxyByFiler, filerB,
*syncOptions.bPath, *syncOptions.bReplication, *syncOptions.bCollection, *syncOptions.bTtlSec, *syncOptions.bProxyByFiler, *syncOptions.bDiskType, *syncOptions.bDebug)
if err != nil {
glog.Errorf("sync from %s to %s: %v", *syncOptions.filerA, *syncOptions.filerB, err)
@@ -107,7 +109,7 @@ func runFilerSynchronize(cmd *Command, args []string) bool {
if !*syncOptions.isActivePassive {
go func() {
for {
err := doSubscribeFilerMetaChanges(grpcDialOption, *syncOptions.filerB, *syncOptions.bPath, *syncOptions.bProxyByFiler, *syncOptions.filerA,
err := doSubscribeFilerMetaChanges(grpcDialOption, filerB, *syncOptions.bPath, *syncOptions.bProxyByFiler, filerA,
*syncOptions.aPath, *syncOptions.aReplication, *syncOptions.aCollection, *syncOptions.aTtlSec, *syncOptions.aProxyByFiler, *syncOptions.aDiskType, *syncOptions.aDebug)
if err != nil {
glog.Errorf("sync from %s to %s: %v", *syncOptions.filerB, *syncOptions.filerA, err)
@@ -122,7 +124,7 @@ func runFilerSynchronize(cmd *Command, args []string) bool {
return true
}
func doSubscribeFilerMetaChanges(grpcDialOption grpc.DialOption, sourceFiler, sourcePath string, sourceReadChunkFromFiler bool, targetFiler, targetPath string,
func doSubscribeFilerMetaChanges(grpcDialOption grpc.DialOption, sourceFiler pb.ServerAddress, sourcePath string, sourceReadChunkFromFiler bool, targetFiler pb.ServerAddress, targetPath string,
replicationStr, collection string, ttlSec int, sinkWriteChunkByFiler bool, diskType string, debug bool) error {
// read source filer signature
@@ -147,9 +149,9 @@ func doSubscribeFilerMetaChanges(grpcDialOption grpc.DialOption, sourceFiler, so
// create filer sink
filerSource := &source.FilerSource{}
filerSource.DoInitialize(sourceFiler, pb.ServerToGrpcAddress(sourceFiler), sourcePath, sourceReadChunkFromFiler)
filerSource.DoInitialize(sourceFiler.ToHttpAddress(), sourceFiler.ToGrpcAddress(), sourcePath, sourceReadChunkFromFiler)
filerSink := &filersink.FilerSink{}
filerSink.DoInitialize(targetFiler, pb.ServerToGrpcAddress(targetFiler), targetPath, replicationStr, collection, ttlSec, diskType, grpcDialOption, sinkWriteChunkByFiler)
filerSink.DoInitialize(targetFiler.ToHttpAddress(), targetFiler.ToGrpcAddress(), targetPath, replicationStr, collection, ttlSec, diskType, grpcDialOption, sinkWriteChunkByFiler)
filerSink.SetSourceFiler(filerSource)
persistEventFn := genProcessFunction(sourcePath, targetPath, filerSink, debug)
@@ -165,57 +167,21 @@ func doSubscribeFilerMetaChanges(grpcDialOption grpc.DialOption, sourceFiler, so
return persistEventFn(resp)
}
return pb.WithFilerClient(sourceFiler, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
stream, err := client.SubscribeMetadata(ctx, &filer_pb.SubscribeMetadataRequest{
ClientName: "syncTo_" + targetFiler,
PathPrefix: sourcePath,
SinceNs: sourceFilerOffsetTsNs,
Signature: targetFilerSignature,
})
if err != nil {
return fmt.Errorf("listen: %v", err)
}
var counter int64
var lastWriteTime time.Time
for {
resp, listenErr := stream.Recv()
if listenErr == io.EOF {
return nil
}
if listenErr != nil {
return listenErr
}
if err := processEventFn(resp); err != nil {
return err
}
counter++
if lastWriteTime.Add(3 * time.Second).Before(time.Now()) {
glog.V(0).Infof("sync %s to %s progressed to %v %0.2f/sec", sourceFiler, targetFiler, time.Unix(0, resp.TsNs), float64(counter)/float64(3))
counter = 0
lastWriteTime = time.Now()
if err := setOffset(grpcDialOption, targetFiler, SyncKeyPrefix, sourceFilerSignature, resp.TsNs); err != nil {
return err
}
}
}
processEventFnWithOffset := pb.AddOffsetFunc(processEventFn, 3*time.Second, func(counter int64, lastTsNs int64) error {
glog.V(0).Infof("sync %s to %s progressed to %v %0.2f/sec", sourceFiler, targetFiler, time.Unix(0, lastTsNs), float64(counter)/float64(3))
return setOffset(grpcDialOption, targetFiler, SyncKeyPrefix, sourceFilerSignature, lastTsNs)
})
return pb.FollowMetadata(sourceFiler, grpcDialOption, "syncTo_"+string(targetFiler),
sourcePath, nil, sourceFilerOffsetTsNs, targetFilerSignature, processEventFnWithOffset, false)
}
const (
SyncKeyPrefix = "sync."
)
func getOffset(grpcDialOption grpc.DialOption, filer string, signaturePrefix string, signature int32) (lastOffsetTsNs int64, readErr error) {
func getOffset(grpcDialOption grpc.DialOption, filer pb.ServerAddress, signaturePrefix string, signature int32) (lastOffsetTsNs int64, readErr error) {
readErr = pb.WithFilerClient(filer, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
syncKey := []byte(signaturePrefix + "____")
@@ -242,7 +208,7 @@ func getOffset(grpcDialOption grpc.DialOption, filer string, signaturePrefix str
}
func setOffset(grpcDialOption grpc.DialOption, filer string, signaturePrefix string, signature int32, offsetTsNs int64) error {
func setOffset(grpcDialOption grpc.DialOption, filer pb.ServerAddress, signaturePrefix string, signature int32, offsetTsNs int64) error {
return pb.WithFilerClient(filer, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
syncKey := []byte(signaturePrefix + "____")
+1
View File
@@ -1,3 +1,4 @@
//go:build !windows
// +build !windows
package command
+10 -10
View File
@@ -62,7 +62,7 @@ func runFuse(cmd *Command, args []string) bool {
option.WriteByte(rawArgs[i])
}
// single quote separator read option until next single quote
// single quote separator read option until next single quote
} else if rawArgs[i] == '\'' {
for i++; i < rawArgsLen && rawArgs[i] != '\''; i++ {
option.WriteByte(rawArgs[i])
@@ -109,7 +109,7 @@ func runFuse(cmd *Command, args []string) bool {
case "filer.path":
mountOptions.filerMountRootPath = &parameter.value
case "dirAutoCreate":
if parsed, err := strconv.ParseBool(parameter.value); err != nil {
if parsed, err := strconv.ParseBool(parameter.value); err == nil {
mountOptions.dirAutoCreate = &parsed
} else {
panic(fmt.Errorf("dirAutoCreate: %s", err))
@@ -121,14 +121,14 @@ func runFuse(cmd *Command, args []string) bool {
case "disk":
mountOptions.diskType = &parameter.value
case "ttl":
if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err == nil {
intValue := int(parsed)
mountOptions.ttlSec = &intValue
} else {
panic(fmt.Errorf("ttl: %s", err))
}
case "chunkSizeLimitMB":
if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err == nil {
intValue := int(parsed)
mountOptions.chunkSizeLimitMB = &intValue
} else {
@@ -136,7 +136,7 @@ func runFuse(cmd *Command, args []string) bool {
}
case "concurrentWriters":
i++
if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err != nil {
if parsed, err := strconv.ParseInt(parameter.value, 0, 32); err == nil {
intValue := int(parsed)
mountOptions.concurrentWriters = &intValue
} else {
@@ -145,7 +145,7 @@ func runFuse(cmd *Command, args []string) bool {
case "cacheDir":
mountOptions.cacheDir = &parameter.value
case "cacheCapacityMB":
if parsed, err := strconv.ParseInt(parameter.value, 0, 64); err != nil {
if parsed, err := strconv.ParseInt(parameter.value, 0, 64); err == nil {
mountOptions.cacheSizeMB = &parsed
} else {
panic(fmt.Errorf("cacheCapacityMB: %s", err))
@@ -153,7 +153,7 @@ func runFuse(cmd *Command, args []string) bool {
case "dataCenter":
mountOptions.dataCenter = &parameter.value
case "allowOthers":
if parsed, err := strconv.ParseBool(parameter.value); err != nil {
if parsed, err := strconv.ParseBool(parameter.value); err == nil {
mountOptions.allowOthers = &parsed
} else {
panic(fmt.Errorf("allowOthers: %s", err))
@@ -161,7 +161,7 @@ func runFuse(cmd *Command, args []string) bool {
case "umask":
mountOptions.umaskString = &parameter.value
case "nonempty":
if parsed, err := strconv.ParseBool(parameter.value); err != nil {
if parsed, err := strconv.ParseBool(parameter.value); err == nil {
mountOptions.nonempty = &parsed
} else {
panic(fmt.Errorf("nonempty: %s", err))
@@ -173,7 +173,7 @@ func runFuse(cmd *Command, args []string) bool {
case "map.gid":
mountOptions.gidMap = &parameter.value
case "readOnly":
if parsed, err := strconv.ParseBool(parameter.value); err != nil {
if parsed, err := strconv.ParseBool(parameter.value); err == nil {
mountOptions.readOnly = &parsed
} else {
panic(fmt.Errorf("readOnly: %s", err))
@@ -183,7 +183,7 @@ func runFuse(cmd *Command, args []string) bool {
case "memprofile":
mountMemProfile = &parameter.value
case "readRetryTime":
if parsed, err := time.ParseDuration(parameter.value); err != nil {
if parsed, err := time.ParseDuration(parameter.value); err == nil {
mountReadRetryTime = &parsed
} else {
panic(fmt.Errorf("readRetryTime: %s", err))
-93
View File
@@ -1,93 +0,0 @@
package command
import (
"net/http"
"strconv"
"strings"
"time"
"github.com/chrislusf/seaweedfs/weed/glog"
"github.com/chrislusf/seaweedfs/weed/server"
"github.com/chrislusf/seaweedfs/weed/util"
)
var (
gatewayOptions GatewayOptions
)
type GatewayOptions struct {
masters *string
filers *string
bindIp *string
port *int
maxMB *int
}
func init() {
cmdGateway.Run = runGateway // break init cycle
gatewayOptions.masters = cmdGateway.Flag.String("master", "localhost:9333", "comma-separated master servers")
gatewayOptions.filers = cmdGateway.Flag.String("filer", "localhost:8888", "comma-separated filer servers")
gatewayOptions.bindIp = cmdGateway.Flag.String("ip.bind", "localhost", "ip address to bind to")
gatewayOptions.port = cmdGateway.Flag.Int("port", 5647, "gateway http listen port")
gatewayOptions.maxMB = cmdGateway.Flag.Int("maxMB", 4, "split files larger than the limit")
}
var cmdGateway = &Command{
UsageLine: "gateway -port=8888 -master=<ip:port>[,<ip:port>]* -filer=<ip:port>[,<ip:port>]*",
Short: "start a gateway server that points to a list of master servers or a list of filers",
Long: `start a gateway server which accepts REST operation to write any blobs, files, or topic messages.
POST /blobs/
upload the blob and return a chunk id
DELETE /blobs/<chunk_id>
delete a chunk id
/*
POST /files/path/to/a/file
save /path/to/a/file on filer
DELETE /files/path/to/a/file
delete /path/to/a/file on filer
POST /topics/topicName
save on filer to /topics/topicName/<ds>/ts.json
*/
`,
}
func runGateway(cmd *Command, args []string) bool {
util.LoadConfiguration("security", false)
gatewayOptions.startGateway()
return true
}
func (gw *GatewayOptions) startGateway() {
defaultMux := http.NewServeMux()
_, gws_err := weed_server.NewGatewayServer(defaultMux, &weed_server.GatewayOption{
Masters: strings.Split(*gw.masters, ","),
Filers: strings.Split(*gw.filers, ","),
MaxMB: *gw.maxMB,
})
if gws_err != nil {
glog.Fatalf("Gateway startup error: %v", gws_err)
}
glog.V(0).Infof("Start Seaweed Gateway %s at %s:%d", util.Version(), *gw.bindIp, *gw.port)
gatewayListener, e := util.NewListener(
*gw.bindIp+":"+strconv.Itoa(*gw.port),
time.Duration(10)*time.Second,
)
if e != nil {
glog.Fatalf("Filer listener error: %v", e)
}
httpS := &http.Server{Handler: defaultMux}
if err := httpS.Serve(gatewayListener); err != nil {
glog.Fatalf("Gateway Fail to serve: %v", e)
}
}
+11 -13
View File
@@ -43,37 +43,35 @@ func runIam(cmd *Command, args []string) bool {
}
func (iamopt *IamOptions) startIamServer() bool {
filerGrpcAddress, err := pb.ParseServerToGrpcAddress(*iamopt.filer)
if err != nil {
glog.Fatal(err)
return false
}
filerAddress := pb.ServerAddress(*iamopt.filer)
util.LoadConfiguration("security", false)
grpcDialOption := security.LoadClientTLS(util.GetViper(), "grpc.client")
for {
err = pb.WithGrpcFilerClient(filerGrpcAddress, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
err := pb.WithGrpcFilerClient(filerAddress, grpcDialOption, func(client filer_pb.SeaweedFilerClient) error {
resp, err := client.GetFilerConfiguration(context.Background(), &filer_pb.GetFilerConfigurationRequest{})
if err != nil {
return fmt.Errorf("get filer %s configuration: %v", filerGrpcAddress, err)
return fmt.Errorf("get filer %s configuration: %v", filerAddress, err)
}
glog.V(0).Infof("IAM read filer configuration: %s", resp)
return nil
})
if err != nil {
glog.V(0).Infof("wait to connect to filer %s grpc address %s", *iamopt.filer, filerGrpcAddress)
glog.V(0).Infof("wait to connect to filer %s grpc address %s", *iamopt.filer, filerAddress.ToGrpcAddress())
time.Sleep(time.Second)
} else {
glog.V(0).Infof("connected to filer %s grpc address %s", *iamopt.filer, filerGrpcAddress)
glog.V(0).Infof("connected to filer %s grpc address %s", *iamopt.filer, filerAddress.ToGrpcAddress())
break
}
}
masters := pb.ServerAddresses(*iamopt.masters).ToAddresses()
router := mux.NewRouter().SkipClean(true)
_, iamApiServer_err := iamapi.NewIamApiServer(router, &iamapi.IamServerOption{
Filer: *iamopt.filer,
Port: *iamopt.port,
FilerGrpcAddress: filerGrpcAddress,
GrpcDialOption: grpcDialOption,
Masters: masters,
Filer: filerAddress,
Port: *iamopt.port,
GrpcDialOption: grpcDialOption,
})
glog.V(0).Info("NewIamApiServer created")
if iamApiServer_err != nil {
+34
View File
@@ -0,0 +1,34 @@
package command
import (
_ "net/http/pprof"
_ "github.com/chrislusf/seaweedfs/weed/remote_storage/azure"
_ "github.com/chrislusf/seaweedfs/weed/remote_storage/gcs"
_ "github.com/chrislusf/seaweedfs/weed/remote_storage/hdfs"
_ "github.com/chrislusf/seaweedfs/weed/remote_storage/s3"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/azuresink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/b2sink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/filersink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/gcssink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/localsink"
_ "github.com/chrislusf/seaweedfs/weed/replication/sink/s3sink"
_ "github.com/chrislusf/seaweedfs/weed/filer/cassandra"
_ "github.com/chrislusf/seaweedfs/weed/filer/elastic/v7"
_ "github.com/chrislusf/seaweedfs/weed/filer/etcd"
_ "github.com/chrislusf/seaweedfs/weed/filer/hbase"
_ "github.com/chrislusf/seaweedfs/weed/filer/leveldb"
_ "github.com/chrislusf/seaweedfs/weed/filer/leveldb2"
_ "github.com/chrislusf/seaweedfs/weed/filer/leveldb3"
_ "github.com/chrislusf/seaweedfs/weed/filer/mongodb"
_ "github.com/chrislusf/seaweedfs/weed/filer/mysql"
_ "github.com/chrislusf/seaweedfs/weed/filer/mysql2"
_ "github.com/chrislusf/seaweedfs/weed/filer/postgres"
_ "github.com/chrislusf/seaweedfs/weed/filer/postgres2"
_ "github.com/chrislusf/seaweedfs/weed/filer/redis"
_ "github.com/chrislusf/seaweedfs/weed/filer/redis2"
_ "github.com/chrislusf/seaweedfs/weed/filer/sqlite"
_ "github.com/chrislusf/seaweedfs/weed/filer/tikv"
)
+19 -18
View File
@@ -7,7 +7,6 @@ import (
"net/http"
"os"
"sort"
"strconv"
"strings"
"time"
@@ -28,6 +27,7 @@ var (
type MasterOptions struct {
port *int
portGrpc *int
ip *string
ipBind *string
metaFolder *string
@@ -47,6 +47,7 @@ type MasterOptions struct {
func init() {
cmdMaster.Run = runMaster // break init cycle
m.port = cmdMaster.Flag.Int("port", 9333, "http listen port")
m.portGrpc = cmdMaster.Flag.Int("port.grpc", 19333, "grpc listen port")
m.ip = cmdMaster.Flag.String("ip", util.DetectedHostAddress(), "master <ip>|<server> address, also used as identifier")
m.ipBind = cmdMaster.Flag.String("ip.bind", "", "ip address to bind to")
m.metaFolder = cmdMaster.Flag.String("mdir", os.TempDir(), "data directory to store meta data")
@@ -54,7 +55,7 @@ func init() {
m.volumeSizeLimitMB = cmdMaster.Flag.Uint("volumeSizeLimitMB", 30*1000, "Master stops directing writes to oversized volumes.")
m.volumePreallocate = cmdMaster.Flag.Bool("volumePreallocate", false, "Preallocate disk space for volumes.")
// m.pulseSeconds = cmdMaster.Flag.Int("pulseSeconds", 5, "number of seconds between heartbeats")
m.defaultReplication = cmdMaster.Flag.String("defaultReplication", "000", "Default replication type if not specified.")
m.defaultReplication = cmdMaster.Flag.String("defaultReplication", "", "Default replication type if not specified.")
m.garbageThreshold = cmdMaster.Flag.Float64("garbageThreshold", 0.3, "threshold to vacuum and reclaim spaces")
m.whiteList = cmdMaster.Flag.String("whiteList", "", "comma separated Ip addresses having write permission. No limit if empty.")
m.disableHttp = cmdMaster.Flag.Bool("disableHttp", false, "disable http requests, only gRPC operations are allowed.")
@@ -112,11 +113,11 @@ func startMaster(masterOption MasterOptions, masterWhiteList []string) {
backend.LoadConfiguration(util.GetViper())
myMasterAddress, peers := checkPeers(*masterOption.ip, *masterOption.port, *masterOption.peers)
myMasterAddress, peers := checkPeers(*masterOption.ip, *masterOption.port, *masterOption.portGrpc, *masterOption.peers)
r := mux.NewRouter()
ms := weed_server.NewMasterServer(r, masterOption.toMasterOption(masterWhiteList), peers)
listeningAddress := *masterOption.ipBind + ":" + strconv.Itoa(*masterOption.port)
listeningAddress := util.JoinHostPort(*masterOption.ipBind, *masterOption.port)
glog.V(0).Infof("Start Seaweed Master %s at %s", util.Version(), listeningAddress)
masterListener, e := util.NewListener(listeningAddress, 0)
if e != nil {
@@ -131,8 +132,8 @@ func startMaster(masterOption MasterOptions, masterWhiteList []string) {
ms.SetRaftServer(raftServer)
r.HandleFunc("/cluster/status", raftServer.StatusHandler).Methods("GET")
// starting grpc server
grpcPort := *masterOption.port + 10000
grpcL, err := util.NewListener(*masterOption.ipBind+":"+strconv.Itoa(grpcPort), 0)
grpcPort := *masterOption.portGrpc
grpcL, err := util.NewListener(util.JoinHostPort(*masterOption.ipBind, grpcPort), 0)
if err != nil {
glog.Fatalf("master failed to listen on grpc port %d: %v", grpcPort, err)
}
@@ -161,16 +162,14 @@ func startMaster(masterOption MasterOptions, masterWhiteList []string) {
select {}
}
func checkPeers(masterIp string, masterPort int, peers string) (masterAddress string, cleanedPeers []string) {
func checkPeers(masterIp string, masterPort int, masterGrpcPort int, peers string) (masterAddress pb.ServerAddress, cleanedPeers []pb.ServerAddress) {
glog.V(0).Infof("current: %s:%d peers:%s", masterIp, masterPort, peers)
masterAddress = masterIp + ":" + strconv.Itoa(masterPort)
if peers != "" {
cleanedPeers = strings.Split(peers, ",")
}
masterAddress = pb.NewServerAddress(masterIp, masterPort, masterGrpcPort)
cleanedPeers = pb.ServerAddresses(peers).ToAddresses()
hasSelf := false
for _, peer := range cleanedPeers {
if peer == masterAddress {
if peer.ToHttpAddress() == masterAddress.ToHttpAddress() {
hasSelf = true
break
}
@@ -180,13 +179,15 @@ func checkPeers(masterIp string, masterPort int, peers string) (masterAddress st
cleanedPeers = append(cleanedPeers, masterAddress)
}
if len(cleanedPeers)%2 == 0 {
glog.Fatalf("Only odd number of masters are supported!")
glog.Fatalf("Only odd number of masters are supported: %+v", cleanedPeers)
}
return
}
func isTheFirstOne(self string, peers []string) bool {
sort.Strings(peers)
func isTheFirstOne(self pb.ServerAddress, peers []pb.ServerAddress) bool {
sort.Slice(peers, func(i, j int) bool {
return strings.Compare(string(peers[i]), string(peers[j])) < 0
})
if len(peers) <= 0 {
return true
}
@@ -194,11 +195,11 @@ func isTheFirstOne(self string, peers []string) bool {
}
func (m *MasterOptions) toMasterOption(whiteList []string) *weed_server.MasterOption {
masterAddress := pb.NewServerAddress(*m.ip, *m.port, *m.portGrpc)
return &weed_server.MasterOption{
Host: *m.ip,
Port: *m.port,
Master: masterAddress,
MetaFolder: *m.metaFolder,
VolumeSizeLimitMB: *m.volumeSizeLimitMB,
VolumeSizeLimitMB: uint32(*m.volumeSizeLimitMB),
VolumePreallocate: *m.volumePreallocate,
// PulseSeconds: *m.pulseSeconds,
DefaultReplicaPlacement: *m.defaultReplication,

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