Compare commits

..

2453 commits

Author SHA1 Message Date
Stephanie Yang
4baffff847
Merge pull request #1630 from molecula/feature/syang/querybuilder-types
CLOUD-77: Allow all field types for query builder
2021-06-07 20:19:26 -05:00
Stephanie Yang
90d795cc69 update stringifyRowData tests 2021-06-07 17:23:42 -05:00
Stephanie Yang
cc624a9c18 add support for non-keyed set, time, mutex and decimals 2021-06-07 17:23:42 -05:00
Travis Turner
22d46a8afa
Merge pull request #1623 from molecula/feature/syang/querybuilder-like
CLOUD-76: Allow `like` for query builder queries
2021-06-07 17:18:34 -05:00
Stephanie Yang
732040dc80 update like to wrap between % if no wildcard is given 2021-06-07 16:30:39 -05:00
Stephanie Yang
af83e61101 add tests 2021-06-07 16:30:39 -05:00
Stephanie Yang
64c0542c3e implement 'like' for query builder queries 2021-06-07 16:30:39 -05:00
Nia
e6644d25d2
Merge pull request #1626 from niaow/fix-keys
[CORE-579] Standardize key translation on the find and create methods
2021-06-07 16:17:41 -04:00
Kuba Podgórski
118961b911
Merge branch 'master' into fix-keys 2021-06-07 21:21:31 +02:00
Kuba Podgórski
c2a0bba99c
Merge pull request #1629 from kuba--/core-531
[CORE-531]: Additional logging for LookupDB connection
2021-06-07 21:16:49 +02:00
Nia Weiss
c2f58f7af0
fix column key translation test
It previously checked hardcoded values.
This does not work due to shard width differences.
2021-06-07 14:52:04 -04:00
Nia Weiss
39337fa41b
fix shadowing of require in client internal tests
The `require` tool was being shadowed with the outer test's T, causing the testing package to explode sometimes.
2021-06-07 14:52:04 -04:00
Nia Weiss
c0ef297b11
standardize key translation on the find and create methods
This migrates existing code from the old TranslateKey(s) endpoints to the newer CreateKeys and FindKeys endpoints.
The CreateKeys and FindKeys endpoints were created previously as the TranslateKeys endpoint had no way to behave sanely when the looked-up key did not exist (the parallel-arrays representation did not have a good way to represent a missing key).
This change also removes the old TranslateKey(s) functions from the translation stores.
It leaves a wrapper emulating the TranslateKey(s) endpoints so that old idk still works for now.
2021-06-07 14:47:52 -04:00
Kuba Podgórski
46fbde4f0b Update holder.go 2021-06-07 18:41:13 +02:00
Samir Patel
b886d1e571
Merge pull request #1622 from 54mir/lattice-fix
CORE-557 UI/Usage Cache with Lattice Fix
2021-06-04 12:12:34 -05:00
Samir Patel
5ef218977f
Merge branch 'master' into lattice-fix 2021-06-04 10:16:46 -05:00
nagamocha3000
3b6ba01111
Merge pull request #1628 from nagamocha3000/delete-id-allocs
Delete ids allocated for index if any present
2021-06-04 16:51:32 +03:00
tgruben
6f06a6cba3
Merge branch 'master' into lattice-fix 2021-06-04 07:36:24 -05:00
nagamocha3000
a904d9e68e Delete ids allocated for index if any present 2021-06-04 14:34:48 +03:00
Stephanie Yang
e1394c2bdb
Merge pull request #1612 from molecula/feature/syang/groupby-filter
CLOUD-59: Updates saved query list for GroupBy filter
2021-06-03 16:57:22 -05:00
Stephanie Yang
3801d4b072 add gitignore to lattice folder 2021-06-03 16:40:10 -05:00
Stephanie Yang
c1915ff361 filter out saved queries without rowCalls 2021-06-03 16:40:10 -05:00
nagamocha3000
29002b3f62
Merge pull request #1624 from nagamocha3000/fix-percentile-overflow
Fix percentile overflow error
2021-06-04 00:24:19 +03:00
nagamocha3000
b1d18a1ba3 Make percentile checker in test-case match executor implementation 2021-06-03 22:14:05 +03:00
nagamocha3000
af83205032 Fix percentile overflow error 2021-06-02 21:28:07 +03:00
Samir Patel
883fa9ac0b replace sleep with after in select 2021-06-01 21:24:08 -05:00
Samir Patel
15ef157779 remove comment 2021-06-01 20:50:55 -05:00
Samir Patel
2e08b15620 remove lastupdate log to console 2021-06-01 20:48:44 -05:00
Samir Patel
9608c0c2cb move trigger to inside refresh fn 2021-06-01 20:48:12 -05:00
Samir Patel
81f1606242 poll places in indexDetails to check for closing 2021-06-01 20:47:53 -05:00
Samir Patel
041ae01da1 poll places in usage calculation to check for closing 2021-06-01 20:46:44 -05:00
Samir Patel
a9079815b2 remove prints 2021-06-01 14:45:52 -05:00
Samir Patel
6a8bf3acd6 stops calculation on server close 2021-06-01 14:34:51 -05:00
Samir Patel
edf71c1bf7 update comment and remote print 2021-06-01 10:47:10 -05:00
Samir Patel
5437a11216 remove prints 2021-06-01 10:47:10 -05:00
Samir Patel
660c6d10ca rename locks and remove prints 2021-06-01 10:47:10 -05:00
Samir Patel
017d012d51 change lock order 2021-06-01 10:47:10 -05:00
Samir Patel
20b721ad9d add wait group 2021-06-01 10:47:10 -05:00
Samir Patel
81413c4f0a Remove recalculation on new index 2021-06-01 10:47:10 -05:00
Samir Patel
4ac7f6e154 check error from ResetCache 2021-06-01 10:47:10 -05:00
Samir Patel
a5ae6c15fc add locks 2021-06-01 10:47:10 -05:00
Samir Patel
5f46635094 add channel to Refresh goroutine 2021-06-01 10:47:10 -05:00
Samir Patel
0810273ea1 reset cache before test and add test conditions 2021-06-01 10:47:10 -05:00
Samir Patel
fcdefe8bb6 add ability to reset cache 2021-06-01 10:47:10 -05:00
Samir Patel
468a288b72 remove print 2021-06-01 10:47:10 -05:00
Samir Patel
a7620012fa adjust locking 2021-06-01 10:47:10 -05:00
Samir Patel
4b7e0e9194 move where cache updates lastUpdated val 2021-06-01 10:47:10 -05:00
Samir Patel
abcd90b60a remove print statements 2021-06-01 10:47:10 -05:00
Samir Patel
4e2727c255 revert txfactory to original 2021-06-01 10:47:10 -05:00
Samir Patel
3e81406ab0 clean test case and add comments 2021-06-01 10:47:10 -05:00
Samir Patel
eff3b25b97 change test case to reflect cache loading before test 2021-06-01 10:47:10 -05:00
Samir Patel
fe0bb20658 remove intentional failure 2021-06-01 10:47:10 -05:00
Samir Patel
53b0e98bb1 add while loop to wait for holder to populate 2021-06-01 10:47:09 -05:00
Samir Patel
5cbf828588 adjust timing 2021-06-01 10:47:09 -05:00
Samir Patel
8824dddc3a add debug statements 2021-06-01 10:47:09 -05:00
Samir Patel
a0ba9327f7 play with timing 2021-06-01 10:47:09 -05:00
Samir Patel
dbdd3c4998 see if this is the only test failing 2021-06-01 10:47:09 -05:00
Samir Patel
fd58fe1a7d test stuff 2021-06-01 10:47:09 -05:00
Samir Patel
63300db1bd try test with usage always blocking on calc 2021-06-01 10:47:09 -05:00
Samir Patel
108da005b7 test stuff 2021-06-01 10:47:09 -05:00
Samir Patel
f946528053 comment out debug statements 2021-06-01 10:47:09 -05:00
Samir Patel
7799d7c680 Add sleep to wait for holder to load 2021-06-01 10:47:09 -05:00
Samir Patel
f6d7d1af39 move requestNodes() out of refresh loop 2021-06-01 10:47:09 -05:00
Samir Patel
0b083da126 debugging test 2021-06-01 10:47:09 -05:00
Samir Patel
1e5df36fb7 change to not calculate node usage periodically 2021-06-01 10:47:09 -05:00
Samir Patel
1385cf61eb attempt to address missing node uri issue 2021-06-01 10:47:09 -05:00
Samir Patel
79f04f31cb see if this gets test passing 2021-06-01 10:47:09 -05:00
Samir Patel
21e5cda7e0 Add lock to node usage 2021-06-01 10:47:09 -05:00
Samir Patel
14533d88a1 add read lock 2021-06-01 10:47:09 -05:00
Samir Patel
7d56414557 change err response to info messages 2021-06-01 10:47:09 -05:00
Samir Patel
4096c8cb8e go mod tidy 2021-06-01 10:47:09 -05:00
Samir Patel
e7f1c8b66a Reverted directoryUsage back to using old Readdir() 2021-06-01 10:47:09 -05:00
Samir Patel
ae6687e71b change flag name to usage-interval 2021-06-01 10:47:09 -05:00
Samir Patel
42067237f7 simplify if statement in calcUsage() 2021-06-01 10:47:09 -05:00
Samir Patel
e8b9fa0482 update comments and rename nodeUsage() 2021-06-01 10:47:09 -05:00
Samir Patel
f5cc179893 change flag from interval to duration 2021-06-01 10:47:09 -05:00
Samir Patel
0ef16ce634 fix calculation for nodes 2021-06-01 10:47:09 -05:00
Samir Patel
ff6b3fed97 remove initCache 2021-06-01 10:47:09 -05:00
Samir Patel
431db4c1a3 add 'lastUpdated' in http response 2021-06-01 10:47:09 -05:00
Samir Patel
8ce17f405b rename flag to disk-usage-interval 2021-06-01 10:47:09 -05:00
Samir Patel
9beb3f0b3a rename flag and add default value for flag 2021-06-01 10:47:09 -05:00
Samir Patel
827b125c3c rename and set default 2021-06-01 10:47:09 -05:00
Samir Patel
03e0df389d use flag value as refresh value 2021-06-01 10:47:09 -05:00
Samir Patel
cd47a381f2 use flag value as refresh value 2021-06-01 10:47:09 -05:00
Samir Patel
b02188fd15 update usage cache periodically 2021-06-01 10:47:09 -05:00
Samir Patel
52418df4ba start periodic cache recalculation at startup 2021-06-01 10:47:08 -05:00
Samir Patel
835c63011a add server flag 2021-06-01 10:47:08 -05:00
Samir Patel
be10927ca7 set lastUpdated after cache calculation 2021-06-01 10:47:08 -05:00
Samir Patel
20f8479f41 add time based cache 2021-06-01 10:47:08 -05:00
Samir Patel
11d1859830 undo changes to IndexUsageDetails 2021-06-01 10:47:08 -05:00
Samir Patel
4842d93850 adds logic to remove old items from cache 2021-06-01 10:47:08 -05:00
Samir Patel
d71da09db2 add cache update on time 2021-06-01 10:47:08 -05:00
Samir Patel
713ffb723b replace ReadDir 2021-06-01 10:47:08 -05:00
Samir Patel
155003122b replace ReadDir syscall with new one from 1.16 2021-06-01 10:47:08 -05:00
Samir Patel
c812cca58e add cache 2021-06-01 10:47:08 -05:00
tgruben
3c399bc533
Merge pull request #1621 from tgruben/cluster-restore
[CORE-529] Multi-node restore
2021-05-28 11:36:04 -05:00
Todd Gruben
c16a7a06a0 applied bens suggestions mainly using errgroup 2021-05-28 11:02:31 -05:00
Todd Gruben
35672c53ce added node partition endpoint;cluster aware key restore 2021-05-28 09:27:42 -05:00
Nia
9c7ca2380f
Merge pull request #1620 from niaow/fix-like
[CORE-577] Execute like queries on the primary's key translation database
2021-05-28 07:18:11 -04:00
Nia
a77be9dd61
Merge branch 'master' into fix-like 2021-05-28 06:40:57 -04:00
Alan Bernstein
9ca33abadd
Merge pull request #1610 from molecula/remove-oss-readme
Remove readme content that only applies to the open-source fork
2021-05-27 18:29:45 -05:00
Nia Weiss
a8f7ec4a12
execute like queries on the primary's key translation database
This works around an issue where unreplicated keys will not be matched everywhere.
This also avoids the cost of creating millions of bolt read transactions and allocating strings.
2021-05-27 14:45:10 -04:00
Alan Bernstein
052956daaf Remove readme content that only applies to the open-source fork 2021-05-26 17:13:05 -05:00
Stephanie Yang
bfef27205b
Merge pull request #1618 from molecula/chore/syang/remove-prodpad
CLOUD-75: Remove ProdPad integration
2021-05-26 15:43:23 -05:00
Stephanie Yang
d047c45045
Merge branch 'master' into chore/syang/remove-prodpad 2021-05-26 15:11:05 -05:00
Nia
97fee3b7a8
Merge pull request #1619 from niaow/postgres-delete
[CORE-573] Add an option to open a postgres transaction in lookup
2021-05-26 14:54:06 -04:00
Nia Weiss
a72f6425af
add an option to open a postgres transaction in lookup so it isnt actually a lookup 2021-05-26 14:07:52 -04:00
Alan Bernstein
a94dc50b1c
Merge pull request #1617 from molecula/update-circleci-logic
CLOUD-65 Avoid early exit in 'bash -eo pipefail' script
2021-05-26 12:18:48 -05:00
Stephanie Yang
291a9c1329 remove prodpad integration 2021-05-26 12:09:56 -05:00
Alan Bernstein
daed890f8c Avoid early exit in 'bash -eo pipefail' script 2021-05-26 11:55:44 -05:00
Alan Bernstein
10af6d588f
Merge pull request #1616 from molecula/update-circleci-logic
CLOUD-65 Default output to 'true' in CircleCI job skipping steps
2021-05-26 11:31:20 -05:00
Alan Bernstein
529a325880 Default output to 'true' in CircleCI job skipping steps 2021-05-26 11:00:48 -05:00
Alan Bernstein
90e2d15cf0
Merge pull request #1609 from molecula/more-merge-lattice-stuff
CLOUD-65 Finalize UI merge
2021-05-26 10:43:52 -05:00
Alan Bernstein
58f0f42c1e Add /querybuilder path to statik lattice handler 2021-05-26 10:04:46 -05:00
Alan Bernstein
45dd6dd6bc Remove leftovers from lattice submodule 2021-05-26 10:04:46 -05:00
Alan Bernstein
f51bb0ea43 Update and verbosify job-skipping CI steps 2021-05-26 10:04:46 -05:00
Kuba Podgórski
894f599310
Merge pull request #1613 from kuba--/missed-return
Add return to handleCommitIDs
2021-05-26 16:36:41 +02:00
Kuba Podgórski
1ffafd70eb Add return to handleCommitIDs 2021-05-26 15:43:21 +02:00
Stephanie Yang
17a58f1020
Merge pull request #1608 from molecula/feature/syang/groupby-filter
CLOUD-59: Allow filter parameter query builder GroupBy
2021-05-24 23:06:10 -05:00
Stephanie Yang
3edac67c0c update helper text 2021-05-24 21:44:48 -05:00
Stephanie Yang
2966bb5d66 add helper text for using GroupBy filter 2021-05-24 20:27:58 -05:00
Stephanie Yang
4367f58081 oops 2021-05-24 18:30:09 -05:00
Stephanie Yang
2a4c6d3503 cleanup unused code 2021-05-24 17:06:34 -05:00
Stephanie Yang
fc121f40b2 allow optional filter parameter from saved queries for group by 2021-05-24 16:51:44 -05:00
Mahesh Arumugam
aed8727aea
Merge pull request #1597 from ma-molecula/ma/darwin-arm64
CLOUD-69 add darwin-arm64 support
2021-05-24 12:56:20 -07:00
Mahesh Arumugam
9dc750df97 add .idea to .gitignore 2021-05-24 12:18:56 -07:00
Mahesh Arumugam
f57abbf7fc go version set to 1.16.3 in makefile 2021-05-24 12:17:19 -07:00
Mahesh Arumugam
2679fa6cfd restore import syscall, accidentally removed in previous commit 2021-05-24 12:17:00 -07:00
Mahesh Arumugam
277eba9895 update comment 2021-05-24 12:17:00 -07:00
Mahesh Arumugam
ce2b07b650 move to go 1.16.4 2021-05-24 12:16:57 -07:00
Mahesh Arumugam
b6098f05e6 fixing the build for linux,arm 2021-05-24 12:16:30 -07:00
Mahesh Arumugam
25ddc2d3a0 fixing the build tags 2021-05-24 12:16:28 -07:00
Mahesh Arumugam
0523088fed add darwin-arm64 support 2021-05-24 12:15:48 -07:00
Nia
a0f2623b04
Merge pull request #1607 from niaow/fix-get-translate
Correct handling of field translate data fetch in get translate data endpoint
2021-05-24 13:07:42 -04:00
Kuba Podgórski
ba8d4c4ca1
Merge branch 'master' into fix-get-translate 2021-05-24 18:52:41 +02:00
Kuba Podgórski
01c4b11efb
Merge pull request #1605 from kuba--/fix-file-backup
Fix backup to a file
2021-05-24 18:52:23 +02:00
Kuba Podgórski
a1e7755fe7
Merge branch 'master' into fix-file-backup 2021-05-24 18:29:44 +02:00
Nia Weiss
bfe2383f65
correct handling of field translate data fetch in get translate data endpoint
After retrieving field translation, this attempted to fetch index translation which didn't work because this is not an index translation request.
2021-05-24 12:24:00 -04:00
tgruben
576c2d9efc
Merge pull request #1606 from tgruben/restore-fix
Restore arg handling bug
2021-05-24 11:19:33 -05:00
Todd Gruben
94e66b74b5 tls config bug and arge handling 2021-05-24 11:00:37 -05:00
Kuba Podgórski
be06340869
Merge branch 'master' into fix-file-backup 2021-05-24 16:21:56 +02:00
tgruben
89bf845192
Merge pull request #1600 from tgruben/restore
[ CORE-525] Restore
2021-05-24 09:15:10 -05:00
tgruben
5be61772f0
Merge branch 'master' into restore 2021-05-24 08:51:32 -05:00
Ben Johnson
9cb7c2be6c
Merge pull request #1603 from molecula/fix-bench-filename
Fix benchmark file naming
2021-05-24 07:50:53 -06:00
Todd Gruben
69fda13ff4 cleanup arg processing 2021-05-24 08:48:32 -05:00
Ben Johnson
34bd5c9fa2
Merge branch 'master' into fix-bench-filename 2021-05-24 07:11:17 -06:00
Kuba Podgórski
935edba1db Fix backup to a file 2021-05-24 10:36:58 +02:00
tgruben
b5613a6c33
Merge branch 'master' into restore 2021-05-23 21:18:34 -05:00
Todd Gruben
ff86f82ef2 applied ben's suggestions 2021-05-23 10:27:50 -05:00
Alan Bernstein
9992cb886a
Merge pull request #1599 from alanbernstein/merge-lattice-take2
CLOUD-65 Merge lattice take2
2021-05-21 21:04:54 -05:00
Ben Johnson
69e15525d8 Fix benchmark file naming 2021-05-21 14:51:08 -06:00
Alan Bernstein
e4a8293c0e Update lattice makefile to reflect new structure 2021-05-21 14:56:55 -05:00
Alan Bernstein
4aaf3e2fc2 Copy lattice repo @8c29787 into subdirectory lattice/ 2021-05-21 14:56:55 -05:00
Alan Bernstein
4a00bd9d6e Remove lattice submodule steps from pilosa makefile 2021-05-21 14:56:55 -05:00
Alan Bernstein
89891174b6 Add job skipping step to CI jobs 2021-05-21 14:56:55 -05:00
Alan Bernstein
9ea12803a2 Remove lattice submodule 2021-05-21 14:56:55 -05:00
Todd Gruben
05fea53f73 linter 2021-05-21 09:27:53 -05:00
Todd Gruben
3d577d762a cleanup 2021-05-21 09:27:08 -05:00
Todd Gruben
35f4c33de9 first cache rebuild was ineffective 2021-05-21 09:27:08 -05:00
Todd Gruben
7520e0ef28 rebuild rank caches on restore 2021-05-21 09:27:08 -05:00
Todd Gruben
b25ad81e67 restore without restart 2021-05-21 09:27:08 -05:00
Todd Gruben
cc0c1b829a restore idalloc 2021-05-21 09:27:08 -05:00
Todd Gruben
a1a9103f62 restore column translate keys 2021-05-21 09:27:08 -05:00
Todd Gruben
329f86033d restore field translate keys 2021-05-21 09:27:08 -05:00
Todd Gruben
69245ee209 shard import 2021-05-21 09:27:08 -05:00
Todd Gruben
42b465b80c load schema 2021-05-21 09:27:08 -05:00
Todd Gruben
9d24fb07b7 wired in restore command 2021-05-21 09:27:08 -05:00
Todd Gruben
169dc30d62 api compiles 2021-05-21 09:27:08 -05:00
Todd Gruben
7c6423587a skeleton restore 2021-05-21 09:27:08 -05:00
seebs
b784dd88d9
Merge pull request #1602 from seebs/addgo116
add go 1.16.3 to circleci
2021-05-20 18:43:04 -05:00
Seebs
ac5964480b add go 1.16.3 to circleci
Since we're starting to use this more, add it to the matrix. We should
probably make it our default later, but for now let's just start testing
it.
2021-05-20 17:25:07 -05:00
seebs
2f95bd2de8
Merge pull request #1593 from seebs/getTx
write operations can cause deadlocks in GetTx
2021-05-20 17:09:08 -05:00
Seebs
1c7a6da37b write operations can cause deadlocks in GetTx
The GetTx logic is deeply broken, this DOES NOT fix the underlying
bug.

When any call anywhere in a given set of calls has a top-level write,
we perform all transactions as write transactions, and we do not cache or
share those transactions. This means that anything which causes a
second GetTx for the same index/shard deadlocks against itself.

The two easy to find cases by casual inspection are time quantums
and Not queries, so this addresses those, but this should NOT be
considered a general fix.
2021-05-20 16:41:38 -05:00
seebs
479d668045
Merge pull request #1601 from seebs/noTxBitmap
drop unused TxBitmap
2021-05-20 16:41:18 -05:00
Seebs
7cf0ea452a drop unused TxBitmap
TxBitmap was a workaround for performance problems with doing
individual-bit operations directly on RBF, used only in the
large-writes path of importValue. With importValue no longer
using that path, ever, there are zero remaining users of TxBitmap,
and the test for it no longer exercises it.

Solution: Remove it.
2021-05-20 16:28:19 -05:00
seebs
a46e14ef22
Merge pull request #1598 from seebs/importSpeedups
improve performance of importValue in most cases, switching to consistently use importPositions.
2021-05-20 16:26:38 -05:00
seebs
45255d050f
Merge branch 'master' into importSpeedups 2021-05-20 15:42:11 -05:00
Ben Johnson
4ea655a707
Merge pull request #1596 from molecula/cluster-backup
[CORE-501] Add support for clustered backups
2021-05-20 14:32:23 -06:00
Ben Johnson
94d45a36ed
Merge branch 'master' into cluster-backup 2021-05-20 14:10:27 -06:00
Seebs
4bad5defb6 sort import values stably without using sort.Stable
sort.Stable has horrible runtime -- O(n*logn*logn) -- but if we
don't use sort.Stable, our logic for ensuring that we apply the
"last" value for a given column is actually completely wrong in
the first place.
2021-05-20 12:39:27 -05:00
Seebs
7572acb450 drop "another shard" test as it's probably not valid
We've got a fairly consistent thing of the API splitting data up
into shards before sending it to a field, which it has to do because
of clustering, so we don't intend to support the case where you
have data from another shard in a data set.

Also drop the identical but mislabeled test from TestIntField's
corresponding case.
2021-05-20 12:39:27 -05:00
Seebs
aa4a23b2d9 generate sorted positions from bulkImportStandard
Ensure that positions are sorted, and that we don't generate the same
position more than once.
2021-05-20 12:39:27 -05:00
Seebs
7c4b91eef0 simplify field ImportValue
There's only ever one view in importValue, but there's also only ever
one shard, because importValue is only called by things called from
the API after it has split everything up by shard.
2021-05-20 12:39:27 -05:00
Seebs
d2b925d296 make importValueSmallWrite faster and also the only path
Since we don't always have "snapshots" anymore, the arguable benefit of
avoiding the snapshot is reduced, and the primary expense of
importPositions has been dramatically reduced as well, so let's
just use that all the time, and simplify life.

We also want to make it faster. We don't know how many bits there
are to set or clear in the input set, but we do know exactly how
many bits there are to set AND clear. We can subdivide these into
batches by rows, then process each batch by storing sets at the
bottom and clears at the top. We can also do batches by columns,
reducing the memory overhead of unpacking all the bits at once.

(For extra credit, we could alternate set/clear settings, and
thus do batches of "the clears from row 0, followed by the clears
from row 1" and "the sets from row 1, followed by the sets from
row 2", and so on, but this is too fancy.)

Every caller of importValue is in fact already providing values
with column IDs sorted. As such, we don't need a map for checking
the previously-set columns; we just need to check against the
previous value.
2021-05-20 12:39:27 -05:00
Maxton Huff
741dd2d1ca
Merge pull request #1590 from Maxtonian/longmessage
[CORE-279] Bad query parameters gives error with super long list of shards
2021-05-20 10:40:12 -05:00
Maxton Huff
d9d360aa4d
Merge branch 'master' into longmessage 2021-05-20 10:17:04 -05:00
Maxton Huff
e646d7ac79 wrap mapper error with shards by node 2021-05-20 09:55:42 -05:00
Seebs
bb40d6589f change addOrRemove to not sort inputs
We also implement, but disable for now, a check for sortedness of
inputs. This check was useful in development but it's expensive (about
5% of CPU time for large inputs!) and once we've verified that we
can make it through tests without triggering it, we're probably fine.
2021-05-19 17:36:57 -05:00
Seebs
671a0cf5c6 tweak ImportValue benchmark
With timestamps, we probably want to at least check larger BSI fields,
so we add that. Also, tweak the interpretation of b.N (making each
N count for 10,000 bits) so we can see allocation load at all. But we
also reduce the sparse set to be about one bit per 19 bits, because
if we do one per 70,000, and are doing field-at-a-time imports, we're
getting hundreds of imports to try to match a target of, say, around
a million values.

We also sort the inputs, because ImportValue is about to start requiring
that, since the API does it anyway.

Also, extend this to be available on Fields, because field.ImportValue
is ALSO doing things which could be inefficient or expensive.
2021-05-19 16:40:34 -05:00
Ben Johnson
a4f282c8e8 Allow backup to stdout 2021-05-19 15:04:36 -06:00
Maxton Huff
04bf214f81 remove shard list from mapper error message to avoid duplicate output 2021-05-19 12:20:39 -05:00
Ben Johnson
eb79c35cbd Add support for clustered backups 2021-05-18 15:17:28 -06:00
Nia
ed5359468d
Merge pull request #1592 from niaow/remove-attr
[CORE-421] Remove attributes
2021-05-14 12:34:04 -04:00
Nia Weiss
7fe37a83f4
update license header check exceptions
When moving the protobuf files around, the paths to the generated protobuf files were not updated.
This change updates the paths.
2021-05-14 10:45:46 -04:00
Nia Weiss
f4ba34247f
remove attributes
Attributes are unmaintained and unused.
They have become more of a liability than a benefit.
This change eliminates them from the codebase.
The only user-visible change (assuming that attrs are not used) is that the attrs field will no longer appear in row JSON.
2021-05-14 10:28:08 -04:00
Maxton Huff
53da35eb00 add missing String() calls in error messages 2021-05-13 12:01:12 -05:00
Maxton Huff
63196e7981 add String() to shard slices to reduce error length 2021-05-13 11:39:23 -05:00
Kuba Podgórski
e4be3583d7
Merge pull request #1585 from kuba--/available-shards
[CORE-493] Write remote available shards to etcd, instead of local file.
2021-05-12 18:32:08 +02:00
Kuba Podgórski
79eaae7881
Update field_internal_test.go 2021-05-12 17:02:36 +02:00
Kuba Podgórski
1e6b8434eb
Merge branch 'master' into available-shards 2021-05-11 11:53:35 +02:00
Matthew Jaffee
649ce77dd6
Merge pull request #1589 from jaffee/update-lattice
Update to latest UI including Lookup functionality
2021-05-10 19:46:40 -05:00
Matthew Jaffee
c83099bc8a update lattice submodule, should include all the lookup/postgres changes 2021-05-10 17:29:42 -05:00
seebs
e49192af69
Merge pull request #1580 from seebs/mutexOverwrite
[CORE-533] Improve performance on mutex fields with sparse writes
2021-05-10 15:07:54 -05:00
seebs
82bb067d8e
Merge branch 'master' into mutexOverwrite 2021-05-10 14:48:56 -05:00
Maxton Huff
2467431caf
Merge pull request #1588 from Maxtonian/inspect2
[CORE-459] Investigate- Panic accessing "/inspect" in Molecula 4.1.1
2021-05-10 14:46:39 -05:00
Maxton Huff
e21382fab8 remove handleInspect and inspect validator 2021-05-10 13:14:50 -05:00
Kuba Podgórski
606f664fcc remove unused 2021-05-10 20:02:13 +02:00
Kuba Podgórski
17f89f1bf6 flush bytes instead of roaring 2021-05-10 19:20:34 +02:00
Seebs
130b17b621 don't force immediate recalculate of cache on every update
When writing things that cause additions to the cache, mark it dirty and
flag it for recomputing, but only sometimes actually do the recalculation,
currently implying a 10-second window. We still mark the cache dirty,
so if a request comes in, we'll get fresh data, but the query will be
slowed down because the recomputation will happen then. But that's better
than doing thousands of recalculations which are never used...
2021-05-10 11:58:18 -05:00
Seebs
1e00b50953 gratuitously fancy logic for array/array callbacks
When searching for a small array in a large array, scanning ahead
is productive. The switch from counting indexes to reslicing the
slice appears to improve performance in this case. The fairly arbitrary
value `na << 2` is like `nb / 4 > na` except that it computes faster,
and lets us avoid the expensive overhead unless we have reason to
expect that there's significantly more items in b than in a.

Improvements: Not huge in some cases, but sometimes quite noticeable,
especially as the frequency of overlap increases, which is also
the expensive case in other ways.

name                                              old time/op  new time/op  delta
ImportMutexSampleData/64K/2Kr/40/none/write-0-8    501ms ± 4%   486ms ± 2%     ~     (p=0.052 n=6+5)
ImportMutexSampleData/64K/2Kr/40/none/write-1-8    756ms ± 5%   698ms ± 5%   -7.62%  (p=0.002 n=6+6)
ImportMutexSampleData/64K/2Kr/80/none/write-0-8    292ms ± 3%   276ms ± 4%   -5.46%  (p=0.002 n=6+6)
ImportMutexSampleData/64K/2Kr/80/none/write-1-8    511ms ± 6%   482ms ± 4%   -5.72%  (p=0.015 n=6+6)
ImportMutexSampleData/64K/2Kr/240/none/write-0-8   153ms ± 3%   132ms ± 5%  -13.91%  (p=0.008 n=5+5)
ImportMutexSampleData/64K/2Kr/240/none/write-1-8   354ms ± 2%   215ms ± 6%  -39.41%  (p=0.004 n=5+6)
ImportMutexSampleData/1K/2Kr/40/none/write-0-8     565ms ± 3%   543ms ± 3%   -3.89%  (p=0.015 n=6+6)
ImportMutexSampleData/1K/2Kr/40/none/write-1-8     807ms ± 6%   778ms ± 3%     ~     (p=0.180 n=6+6)
ImportMutexSampleData/1K/2Kr/80/none/write-0-8     317ms ± 3%   300ms ± 1%   -5.40%  (p=0.002 n=6+6)
ImportMutexSampleData/1K/2Kr/80/none/write-1-8     462ms ± 3%   437ms ± 4%   -5.31%  (p=0.009 n=6+6)
ImportMutexSampleData/1K/2Kr/240/none/write-0-8    141ms ± 1%   119ms ± 2%  -15.85%  (p=0.004 n=5+6)
ImportMutexSampleData/1K/2Kr/240/none/write-1-8    213ms ± 3%   171ms ± 3%  -19.70%  (p=0.002 n=6+6)
2021-05-10 11:58:18 -05:00
Seebs
54f5cc799c performance hackery: add intersectCallback for use in running callbacks
In BitmapBitmapFilter.ConsiderData, we intersect things solely in order
to perform callbacks on them. Creating these intermediate arrays is
actually somewhat expensive, and all we're going to do with them is
make callbacks anyway.

So, we add a new `intersectCallback`, which behaves similarly to
`intersectionCount`, but which dramatically reduces the amount of memory
allocation associated with doing the callbacks; in some test cases
on mutex data, this code was >90% of all memory allocations, and
getting rid of that helps a lot.

At that point, we no longer need the separate intersectAny check,
because it doesn't save us any time anymore.
2021-05-10 11:58:18 -05:00
Seebs
ffb796448c make mutex tests smarter
The mutex tests had weird and un-idiomatic definitions for b.N, and
in particular would report ludicrously low times for high values of
b.N because they'd still only do a small amount of importing, then
get counted as having done a much larger number of iterations. Also,
the computation of the number of values to create was pretty noticably
wrong so the secondary data set was unduly tiny.

Do tests with ranked cache and larger row counts because we have
reason to suspect that the cache behavior is mattering. We adjust the
range of tests performed to reflect real world data a bit. We also
drop the "don't do large mutex tests" thing because the insanely
bad performance on larger mutex data should be fixed now, we hope.
2021-05-10 11:58:18 -05:00
Kuba Podgórski
252fadf6a0 Merge branch 'available-shards' of github.com:kuba--/molecula-pilosa into available-shards 2021-05-10 18:50:24 +02:00
Kuba Podgórski
6bdca67882 replace roaring.Bitmap by [][]byte 2021-05-10 18:45:23 +02:00
Nia
26b49cca21
fix remote available shard races (#3) 2021-05-10 18:36:40 +02:00
Maxton Huff
882327b0a6 remove inspect router 2021-05-10 10:36:24 -05:00
Kuba Podgórski
046b98bdf9
Merge branch 'master' into available-shards 2021-05-10 13:54:43 +02:00
Kuba Podgórski
b36de3146a write shards per node 2021-05-10 13:54:18 +02:00
Ben Johnson
03d258a3db
Merge pull request #1579 from molecula/backup-poc
[CORE-485] Backup CLI
2021-05-07 13:41:07 -06:00
Ben Johnson
e044a489fa
Merge branch 'master' into backup-poc 2021-05-07 13:09:54 -06:00
seebs
a302071b7f
Merge pull request #1587 from seebs/translateKeys
improve key creation/translation performance for large batches, especially on field keys
2021-05-07 14:09:36 -05:00
seebs
c473ff9925
Merge branch 'master' into translateKeys 2021-05-07 13:56:51 -05:00
tgruben
0fe0ae2b66
Merge branch 'master' into backup-poc 2021-05-07 13:37:11 -05:00
Ben Johnson
97cdc2405d
Merge pull request #1586 from molecula/rbf-rr-cache
Fix RBF root record cache build
2021-05-07 12:35:52 -06:00
Seebs
9e6ec3b17a break boltDB operations into chunks
boltDB's bucket.Put() is quadratic on "new keys put into a bucket during
this transaction", which is why BoltDB has warnings not to use it with over
100k new keys at a time. The translation store logic wasn't actually using
that. The actual value picked is smaller, based on some half-baked benchmarking.

We also avoid heap-allocating separate 16-byte (not 8-byte, of course,
because make(...) is *helping*) chunks twice for each key we insert, instead
allocating a single buffer which we reuse for each new transaction.

Also fixed a check against the nilness of the wrong pointer and generally
made CreateKeys and TranslateKeys a little more similar.
2021-05-07 13:19:15 -05:00
Ben Johnson
21c6203438 Fix linter 2021-05-07 11:15:13 -06:00
Ben Johnson
8a161bc423 Fix RBF root record cache build
This commit fixes an issue where the root record cache is only
built when a write transaction successfully commits. However, if
no write transactions are occurring then the the cache is never
built and saved so it is recomputed on every read tx.
2021-05-07 11:10:47 -06:00
Ben Johnson
7e804d7d08 Fix id alloc backup invocation 2021-05-07 10:59:01 -06:00
Ben Johnson
7284c4dd10 Add id alloc, col attrs, & row attrs backup 2021-05-07 10:59:01 -06:00
Todd Gruben
963bb3ec59 enable apiFieldTranslateData apiTranslateData 2021-05-07 10:59:01 -06:00
Ben Johnson
776b43a3cd Backup CLI 2021-05-07 10:59:01 -06:00
Kuba Podgórski
2517ee1bde remove unused 2021-05-07 15:45:30 +02:00
Kuba Podgórski
a79a36232f Write remote available shards to etcd, instead of local file. 2021-05-07 15:33:18 +02:00
Matthew Jaffee
1af85a818b
Merge pull request #1581 from jaffee/portmapper-npe
avoid nil pointer exception when failing to get listener
2021-05-05 14:18:22 -05:00
Matthew Jaffee
8274a8cfee avoid nil pointer exception when failing to get listener
instead of an opaque NPE on the next line, panic with explicit error
telling you what went wrong (in my case it was too many open files)
2021-05-04 15:17:41 -05:00
Alan Bernstein
7d1f9e33b8
Merge pull request #1577 from alanbernstein/core-478-query-history-nanoseconds
CORE-478 Add 'Nanoseconds' units to query-history 'runtime' json key
2021-04-22 20:23:28 -05:00
Alan Bernstein
7ffc103777 Add 'ns' units to query history runtime json 2021-04-22 15:26:15 -05:00
seebs
8c28a5f8ca
Merge pull request #1576 from seebs/ulimit
centralize attempts to set/check limits [CORE-426]
2021-04-21 15:05:23 -05:00
Seebs
1a5696fe23 centralize attempts to set/check limits
We check mmap limits, and try to set/increase our open file limits,
and we check the mmap limit when we start the server, and try to set
the open file limit every time we open a holder.

It's useless to do these things more than once, though. We migrate
these things to be run through a sync.Once, which runs all of them
the first time a server starts up, and then thereafter just returns
the error code from that first run. This should make test startup
ever so slightly cheaper, saving us potentially several microseconds,
but also reducing the spamminess of the message.

I've taken out the `sudo ulimit` advice since it's wrong, and the
documentation link is updated to point to our (now private!)
customer documentation.
2021-04-21 13:56:42 -05:00
seebs
0adc10d2c1
Merge pull request #1578 from seebs/bitmaaaapMaster
roaring ops log and TxBitmap fixes
2021-04-21 12:16:47 -05:00
Seebs
5a7c0971ca additional fragment tests: bitmap file growth, TxBitmap data loss
Checking issues encountered while tracking down an unexpected disk
usage increase.
2021-04-20 12:03:49 -05:00
Seebs
014a94c9c7 TxBitmap: track seen container keys
We can't assume that a container we've seen stays present in our bitmap
after possible remove operations. Solution: Track keys seen.
2021-04-20 12:03:44 -05:00
Seebs
5ffa4ba803 drop "batched" flag from Add operation
The "batched" flag creates a complexity which is that the return value of Add
might or might not be meaningful, but it doesn't really buy us very much.

If we are concerned about the ops log size of writing single ops as 21-byte
arrays of 1 op rather than as 13-byte ops, we can make the AddN code smarter
about how it writes ops. And probably should.

Along with this, change Remove to use the batched operation form, which
writes a more meaningful ops log, and return a meaningful value for changes
made. Otherwise, it ends up writing potentially thousands of ops to the
ops log without reporting any OpN, because the number of ops written isn't
the same as the number of changes those ops made. This could result in
files growing by megabytes without OpN changing.

There was a comment here about a test failing with RemoveN. I can't prove
it, but I strongly suspect that this was actually a result of that test
case hitting a particular bug that we eventually fixed, and which we might
have fixed sooner if we'd realized why using RemoveN made that test
fail.
2021-04-20 12:03:25 -05:00
Seebs
e93d2fe06c bitmap unmarshalling and testing bug fixes
When unmarshalling ops, we weren't adding a meaningful OpN to them,
resulting in misleading reports from `pilosa inspect`. Also, we were
mistakenly reporting things as "mapped" when they were actually
using their internal storage (as with small array containers).

Add the "sanity check" to `pilosa inspect` so that errors like the
above get noticed more easily and corrected. Also, to make that work,
have roaring.InspectBinary actually put containers in the bitmap
it creates rather than just creating info entries for them.
2021-04-20 12:01:21 -05:00
Seebs
ca216a14c5 fix bitmap.BitwiseEqual bugs
bitmap.BitwiseEqual had a couple of subtle bugs, and the net result
is that if the bitmap you were comparing to had an empty container after
the original bitmap ran out of containers, we'd spuriously report
the container as existing and being... the last container in the original,
actually.

Issues are both that we were grabbing the value from the wrong iterator,
and also that we were iterating twice per loop, and thus could also
have missed a non-empty container immediately following an empty one.
2021-04-20 12:01:13 -05:00
Kuba Podgórski
358e4b860e
Merge pull request #1574 from kuba--/public-name-validator
Make validateName function public,
2021-04-16 17:37:39 +02:00
Kuba Podgórski
74c1c8a86c
Merge branch 'master' into public-name-validator 2021-04-14 22:17:07 +02:00
Ben Johnson
3eca5944d4
Merge pull request #1571 from molecula/timestamp-epoch
Switch timestamp field to use epoch instead of min/max
2021-04-14 12:34:35 -06:00
tgruben
69e50b04d8
Merge pull request #1575 from tgruben/timestamp-client
Timestamp client
2021-04-14 12:58:33 -05:00
tgruben
813687d522
Merge branch 'timestamp-epoch' into timestamp-client 2021-04-14 11:37:40 -05:00
Todd Gruben
5737381d23 clientside timestamp support 2021-04-14 11:28:06 -05:00
Ben Johnson
bc4ad866c6
Merge branch 'master' into timestamp-epoch 2021-04-14 09:56:25 -06:00
seebs
8d1b1f24f9
Merge pull request #1551 from seebs/heartbeat
etcd: overhaul interactions to use heartbeats and cache things only until something changes.
2021-04-14 10:49:57 -05:00
Kuba Podgórski
29fe5cabaa
Merge branch 'master' into heartbeat 2021-04-14 17:10:20 +02:00
seebs
ee629bfd6a
Merge pull request #1569 from ajnavarro/improvement/reduce-executor-test-execution-time
[CORE-438] Reduce executor tests execution time from 2:30 to 30s reusing clusters.
2021-04-14 09:58:59 -05:00
Ben Johnson
ea01f7e37c Switch timestamp field to use epoch instead of min/max 2021-04-14 08:46:37 -06:00
Kuba Podgórski
ca1cbadb45 Make validateName function public, so other packages and projects (like IDK, Ingester) can re-use it 2021-04-14 13:33:26 +02:00
Antonio Navarro Perez
43c230039f Reduce executor tests execution time from 2:30 to 30s reusing clusters.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-04-14 11:30:02 +02:00
Seebs
7497d5fbe2 artificially increase heartbeat TTL for tests only
CI systems sometimes hiccup for five seconds, which causes heartbeat leases
to fail and breaks all sorts of things. As a workaround, update heartbeat
TTL for tests only. This might in turn cause different failures to do
with leader elections, but in theory those should be handled now?
2021-04-13 12:37:07 -05:00
Seebs
0638101d2a cluster state checking cleanups and fixes
A while back we started just polling the reported cluster state of one node
when starting a cluster for tests. This works fine if we're doing fresh
new etcd queries for every single operation -- but that's insanely
expensive, it turns out.

When we use the watcher, some nodes will report stale data for "a
while", where "a while" appears to be easily a couple dozen milliseconds.
This is probably irrelevant in most real-world cases, because the common
case (detecting a node going down) means that we have at least five
seconds after a node goes down before etcd notices the lease expiring,
and a few milliseconds more or less won't matter.

But we have tests that assume either that node 0 is always the
coordinator (wrong) or that waiting for node 0 to think the cluster
is up means that every node in the cluster thinks the cluster is up,
or at least that it means that the coordinator thinks the cluster is
up. We retried later operations but not the initial ones against
the coordinator.

In fact, we probably want to wait for the entire cluster to think
it's up before we start trying things on clusters.

We also replace the "CheckClusterState" function with the existing
AwaitState call, or a new AssertState which errors out since that's
the way we usually use AwaitState anyway.

In the AwaitPrimaryState function, which used to be
AwaitCoordinatorState in a different long-lost revision, we have
to delay until a primary node is available, or fail if one does
not become available, to avoid a panic. This probably shouldn't
happen anymore, because of the last change:

Also, rovide dummy topology.Node entries before metadata is read.

During initial startup, we want to be able to do things like determine
which node is the primary, even before we've read metadata from them.

To do this, we populate the node list with dummy entries that just have
the ID (the only part we need to sort our list), and a node state of
UNKNOWN.

This breaks the fancy logic for determining whether or not to update
the node data, because the initial status of UNKNOWN matches what we
get from SetMetadata giving us new data so we end up not realizing
that this was actually a meaningful change. But actually, that's
a pretty niche optimization; we usually only get state changes when
there's an actual change in state. The updates here are cheap
and only happen after a write (or on the first query) so it's not
worth making the logic a lot fancier to make it work, when we can
just do the simple thing and update any time the dirty flag is set.

We also standardize on a 50ms delay, because 1ms delays were
really expensive when each check was hitting etcd multiple times,
and 50ms is Usually Long Enough.
2021-04-13 12:37:07 -05:00
Seebs
d1752a7af7 switch to using a watcher to watch etcd changes
This is a significant overhaul! Quite a lot of things changed here.

Basically: Prior to this, every request for data from etcd implies
requesting the current live data from etcd, and then unpacking it or
extracting it in some way. This is expensive, which is why we have
a cache in front of it.

We don't need to do that! We can use a Watch, which notifies us
of changes as changes happen. However, there's some challenges and
difficulties along the way, and there's a couple of other changes
which are included here because it's a pain to try to separate them
out.

1. We require a logger to be provided to create our internal Etcd
wrapper. We then use that logger, instead of `fmt.Printf`. This makes
debugging messages work better, and also diagnostics, and so on.

2. The internal client that we are reusing can enter a failed state
after a leader election, in which case we have to recreate the client
to have a working client. We add a new internal-use method,
`retryClient`, which wraps a function which takes an etcd client
and returns an error, and checks for leader-election type errors
and retries creating the client when they happen. That last bit
has not been successfully tested because it's actually really hard
to trigger this now. (Because it was related in part to the
amount of etcd traffic we were producing, which is reduced.)

3. The general swap over from looking things up to unpacking things
as they come in, then returning those already-unpacked things when
we get requests.

With this change, *many tests will fail*. That is addressed by
a separate commit which addresses the secondary problem, which is
that some of our test harness code was relying on the assumption
that if any node in a cluster thinks the cluster is up, every node
will. That was usually true when we were doing everything as
expensive fully-synchronized cluster checks, but becomes significantly
less reliably true in real-world cases where nodes are also
going down sometimes, or nodes are going up and down unexpectedly.
2021-04-13 12:37:07 -05:00
Seebs
fd8a19278c add TestMain wrapper in ctl
The TestMain wrapper gets us the fancy testhook stuff tracking whether we're
deallocating things as expected, and we probably want that.
2021-04-13 12:37:07 -05:00
Seebs
6b1cd1e43b drop etcd-with-cache option
The new etcd implementation has internal caching-like behavior which is
much more reliable (it doesn't use a TTL, it just updates when there's updates
to process) so we don't need this cache.
2021-04-13 12:37:07 -05:00
Ben Johnson
6616b0d6f0
Merge pull request #1570 from molecula/extract-timestamp
Fix timestamp Extract()
2021-04-13 11:18:19 -06:00
Ben Johnson
7863a97add
Merge branch 'master' into extract-timestamp 2021-04-13 10:36:31 -06:00
Alan Bernstein
a0992e0393
Merge pull request #1573 from alanbernstein/logger-prefixes-again
CORE-72 Add log prefix levels
2021-04-12 22:57:42 -05:00
Alan Bernstein
ce4ed1d81d Apply review suggestion
typo fix

Co-authored-by: Travis Turner <travis@pilosa.com>
2021-04-12 22:25:26 -05:00
Alan Bernstein
54ff05c266 Apply review suggestion
typo fix

Co-authored-by: Travis Turner <travis@pilosa.com>
2021-04-12 22:25:26 -05:00
Alan Bernstein
177c27dc31 Switch to new logger in client code (go-pilosa) 2021-04-12 22:25:13 -05:00
Alan Bernstein
285d0a0af8 Add log prefix levels 2021-04-12 20:33:39 -05:00
tgruben
ebbb196a23
Merge pull request #1560 from tgruben/delete
[CORE-245] added pql delete function
2021-04-12 16:47:40 -05:00
tgruben
83eb82f271
Merge pull request #5 from seebs/delete
Delete hackery
2021-04-12 16:22:26 -05:00
Seebs
2833365aae reuse the findExisting filter between fields, drop separate hack for existence
The existence field wasn't working because runs were broken for filters in
RBF. Fixing that allows us to simplify the logic. Also, we reuse the
findExisting filter because the filter's cached collection of containers
can be reused between things, allowing us to reduce allocations when
there's a lot of views.
2021-04-12 16:14:45 -05:00
Seebs
269837414e rbf/intoContainer: ensure correct N, avoid recounting
The remake container logic (used to avoid allocating extra containers while
applying filters) relied on roaring recomputing N, which it did for bitmaps
but didn't do for runs. Fix this both ways; it would now do that for runs,
but also we add "with explicit N" variants and use those since we have a
correct count already, and don't need it. This means fewer popcounts on
bitmaps, and working at all on runs.
2021-04-12 16:13:16 -05:00
Ben Johnson
2864a851ab Fix timestamp Extract() 2021-04-12 13:58:46 -06:00
Ben Johnson
0b76fd5179 Switch timestamp field to use epoch instead of min/max 2021-04-12 13:55:54 -06:00
tgruben
84c269bfc0
Update delete_test.go 2021-04-12 13:38:58 -05:00
tgruben
2d85918f43
Merge branch 'master' into delete 2021-04-09 14:31:40 -05:00
Samir Patel
da749cc757
Merge pull request #1563 from 54mir/timestamp-in-orm
Replicate timefield functionality in pilosaclient
2021-04-09 13:36:39 -05:00
tgruben
b6c80969a1
Merge branch 'master' into timestamp-in-orm 2021-04-09 12:51:36 -05:00
tgruben
f6632bcaca
Merge branch 'master' into delete 2021-04-09 12:51:03 -05:00
Ben Johnson
eb119d2d35
Merge pull request #1568 from molecula/fix-int-fk
Remove integer fk error check
2021-04-09 11:50:41 -06:00
tgruben
3bc4309a96
Merge branch 'master' into delete 2021-04-09 12:41:31 -05:00
tgruben
12748d75d3
Merge branch 'master' into timestamp-in-orm 2021-04-09 12:41:12 -05:00
Ben Johnson
fbd713d435
Merge branch 'master' into fix-int-fk 2021-04-09 11:28:07 -06:00
Ben Johnson
84f9fde25a
Merge pull request #1567 from molecula/import-timestamp-values
Fix timestamp value import
2021-04-09 11:28:01 -06:00
Ben Johnson
e1909661d5 Remove integer fk error check 2021-04-09 11:01:28 -06:00
Ben Johnson
5defbe3ef2 Fix timestamp value import 2021-04-09 10:56:25 -06:00
tgruben
a60c70b2a5
Merge branch 'master' into delete 2021-04-09 10:26:30 -05:00
tgruben
4b484f41f2
Merge branch 'master' into timestamp-in-orm 2021-04-09 10:20:46 -05:00
Ben Johnson
8802856120
Merge pull request #1564 from molecula/timestamp-fixes
Fix timestamp field issues
2021-04-09 09:01:30 -06:00
Ben Johnson
485c1c888b
Merge branch 'master' into timestamp-fixes 2021-04-09 08:31:55 -06:00
Nia
95dd262bb3
Merge pull request #1559 from niaow/id-alloc-desync-structured-error
[CORE-386] Change ID allocation to return a structured error on offset desync
2021-04-09 10:28:26 -04:00
Ben Johnson
d70eb737cb Fix timestamp field issues 2021-04-09 08:26:12 -06:00
Nia
6140fc9d4c
Merge branch 'master' into id-alloc-desync-structured-error 2021-04-09 09:16:25 -04:00
Todd Gruben
ac7a8c3dd5 validate existence 2021-04-09 07:24:43 -05:00
Kuba Podgórski
6caae41432
Merge pull request #1565 from kuba--/fix-panic
Fix panic on field not found on /import
2021-04-09 14:01:07 +02:00
Kuba Podgórski
c021b873d5 Fix panic on field not found on /import 2021-04-09 13:38:39 +02:00
Samir Patel
b1d1ac0cae
Merge branch 'master' into timestamp-in-orm 2021-04-08 13:40:14 -05:00
Samir
83932041a5 Replicate timefield functionality in pilosaclient 2021-04-08 13:21:49 -05:00
tgruben
784c78e313
Merge branch 'master' into delete 2021-04-08 10:05:31 -05:00
Nia
dbf9b14963
Merge pull request #1562 from niaow/update-before-install
Update the package database before installing dependencies in CI
2021-04-08 10:46:47 -04:00
Todd Gruben
dcd6c649e8 skip blue-green on delete test 2021-04-08 09:37:34 -05:00
Nia Weiss
c127f0a959
update the package database before installing dependencies in CI 2021-04-08 10:20:16 -04:00
Todd Gruben
918644820b added pql delete function 2021-04-07 13:57:43 -05:00
Ben Johnson
7e369aeac4
Merge pull request #1558 from molecula/timestamp
CORE-372: Add timestamp field type support
2021-04-06 11:28:10 -06:00
Ben Johnson
cfc725e799 Add timestamp field type support 2021-04-06 10:50:10 -06:00
Alan Bernstein
f75e46c2f6
Merge pull request #1544 from alanbernstein/clarify-longquerytime-log
Add some context to the longquerytime log message
2021-04-06 11:18:07 -05:00
Nia Weiss
7734bcd53c
change ID allocation to return a structured error on offset desync
This is used to handle a possible case where a kafka partition is moved to another ingester while a previous ingester is still processing it, causing 2 ingesters to process it at the same time.
This allows a duplicate ingester to skip past messages which have already been ingested.
2021-04-06 10:39:22 -04:00
Alan Bernstein
2e93b2eea2 Add some context the longquerytime log message 2021-04-05 17:02:58 -05:00
Antonio Navarro Perez
6664e86222
Merge pull request #1556 from ajnavarro/tests/review-skipped-tests 2021-03-31 16:29:02 +02:00
Kuba Podgórski
ddf7ff7b70
Merge branch 'master' into tests/review-skipped-tests 2021-03-31 15:38:36 +02:00
Nia
aa212cb83b
Merge pull request #1547 from niaow/external-lookup
[CORE-388] Add ExternalLookup query
2021-03-31 08:35:54 -04:00
Nia
d5da6e229c
Merge branch 'master' into external-lookup 2021-03-31 08:12:18 -04:00
Antonio Navarro Perez
ebe3afcb96
Merge branch 'master' into tests/review-skipped-tests 2021-03-31 14:03:35 +02:00
Matthew Jaffee
4856c68760
Merge pull request #1542 from Maxtonian/percentile
CORE-412 change percentile value ranges from 0-1 to 0-100
2021-03-30 09:23:12 -05:00
Maxton Huff
ff82447647
Merge branch 'master' into percentile 2021-03-30 08:20:45 -05:00
Maxton Huff
8c20d9a51c remove redundant error message 2021-03-30 08:13:36 -05:00
Antonio Navarro Perez
03659d8d39 Review skipped tests, and try to execute them again.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-30 13:37:33 +02:00
Nia
71b2cb80f7
Merge pull request #1555 from niaow/test-tx-commit-rollback-single-writer-race
Fix DB-close race condition in TestTx_CommitRollback/SingleWriter
2021-03-29 18:13:37 -04:00
Maxton Huff
13ec97abf5 add new test cases for limits and clarify error messages 2021-03-29 16:55:50 -05:00
Nia
1fa3947f8d
Merge branch 'master' into test-tx-commit-rollback-single-writer-race 2021-03-29 17:51:54 -04:00
Maxton Huff
4c8dc8d54f address variable declaration warning 2021-03-29 16:24:56 -05:00
Maxton Huff
377c3f3654 rework checks and reword incorrect type error message 2021-03-29 15:59:30 -05:00
Nia Weiss
c931a3e63f
fix DB-close race condition in TestTx_CommitRollback/SingleWriter
Due to lack of synchronization, this test would sometimes close the DB before terminating a transaction:
=== RUN   TestTx_CommitRollback/SingleWriter
    tx_test.go:132: db still has 1 active transactions; must closed before closing db

The test now waits for the goroutines to terminate before closing the DB.
2021-03-29 15:06:07 -04:00
Kuba Podgórski
6185abacc1
Merge pull request #1552 from kuba--/test-pilosa/client
[CORE-458] Integration tests client against cluster
2021-03-29 19:07:53 +02:00
Nia Weiss
9bc1b23b7e
change "External" DB to "Lookup" DB 2021-03-29 12:54:29 -04:00
Kuba Podgórski
c23bc901e8 Integration tests client against cluster 2021-03-29 18:31:45 +02:00
Kuba Podgórski
b835221ded
Merge pull request #1553 from kuba--/wth-is-vprint
[CORE-452] Move `vprint` to separate package
2021-03-29 18:10:18 +02:00
Kuba Podgórski
9a02004a4f Move vprint to separate pakage 2021-03-29 14:29:19 +02:00
Nia Weiss
c4aad290ed
address ExternalLookup review comments 2021-03-29 08:22:41 -04:00
Kuba Podgórski
8948c4531a
Merge pull request #1550 from ajnavarro/fix/use-at-least-3-nodes-on-cluster-tests
[CORE-432] Add at least 3 nodes on test clusters.
2021-03-27 17:07:17 +01:00
Maxton Huff
4ce71eeddf change nth value limit message and number of test int64 nth values 2021-03-26 16:54:44 -05:00
Maxton Huff
f06c13abcd alter incorrect type error message 2021-03-26 16:11:16 -05:00
Maxton Huff
6c94bfdb5e improve error responses and change switch statement to allow int64 2021-03-26 13:56:22 -05:00
Maxton Huff
87412068f1 add new test to account for int64 nth values 2021-03-26 13:01:31 -05:00
Antonio Navarro Perez
79c6493d9a Fix executor test.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-26 13:21:56 +01:00
Antonio Navarro Perez
0483553b16 Fix two more tests
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-26 13:04:15 +01:00
Antonio Navarro Perez
7ec85a1c0f Add at least 3 nodes on test clusters.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-26 10:16:41 +01:00
Maxton Huff
8746444cdb add error message for invalid type 2021-03-25 16:57:08 -05:00
Maxton Huff
61beef7e5a add Int64() function and include case of int64 2021-03-25 16:27:55 -05:00
Kuba Podgórski
878f7fd4e7
Merge pull request #1546 from kuba--/fix-pb-endpoints
Update internal endpoints
2021-03-25 18:25:38 +01:00
Nia Weiss
e9b92e1cd4
add ExternalLookup query 2021-03-25 13:21:28 -04:00
Kuba Podgórski
65cb2cdf73 Update internal endpoints 2021-03-25 18:00:56 +01:00
Kuba Podgórski
0649ba3f8d
Merge pull request #1545 from kuba--/fix-endpoint
Fix internal endpoint
2021-03-25 17:18:37 +01:00
Kuba Podgórski
761190ec32 Fix internal endpoint 2021-03-25 16:44:05 +01:00
Kuba Podgórski
989a01db33
Merge pull request #1539 from kuba--/core-230/go-pilosa
[CORE-230] Combine go-pilosa and pilosa into one repo
2021-03-25 15:31:32 +01:00
Kuba Podgórski
40337cff09
Merge branch 'master' into core-230/go-pilosa 2021-03-24 21:23:04 +01:00
tgruben
76b676a256
Merge pull request #1537 from tgruben/tds
[CORE-311] etcd tls configuration support
2021-03-24 12:30:50 -05:00
Kuba Podgórski
000f708c40 Address PR comments
+ some docs
2021-03-24 18:09:01 +01:00
Maxton Huff
d3438e8a80 correct k calculation and change test nth values 2021-03-24 10:58:47 -05:00
Kuba Podgórski
d6129517db
Update handler.go
Co-authored-by: Travis Turner <travis@pilosa.com>
2021-03-24 16:49:32 +01:00
Todd Gruben
e46a41638f Merge branch 'tds' of github.com:tgruben/privilosa into tds 2021-03-24 10:44:31 -05:00
Todd Gruben
6bafa989e0 adjust etcd config comments 2021-03-24 10:43:28 -05:00
tgruben
160e64fbf3
Merge branch 'master' into tds 2021-03-24 10:07:50 -05:00
Kuba Podgórski
913c909ef7
Merge branch 'master' into core-230/go-pilosa 2021-03-24 15:19:44 +01:00
Kuba Podgórski
03386392ea Fix typos, replace panics by error 2021-03-24 15:15:50 +01:00
Antonio Navarro Perez
7cf4233fdb
Merge pull request #1541 from ajnavarro/fix/call-cancel-if-any 2021-03-24 11:35:41 +01:00
Antonio Navarro Perez
ffcaa1b500
Merge branch 'master' into fix/call-cancel-if-any 2021-03-24 10:30:39 +01:00
Maxton Huff
40e3acc3e4 change percentile value ranges from 0-1 to 0-100 2021-03-23 16:57:37 -05:00
tgruben
9e6855b315
Merge branch 'master' into tds 2021-03-23 16:40:48 -05:00
Ben Johnson
1228c6e188
Merge pull request #1532 from molecula/fix-delete-field-panic
CORE-334: Fix panic on field deletion
2021-03-23 09:03:46 -06:00
Antonio Navarro Perez
6e6eb962ee Call cancel when we try to renew the lease after an error.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-23 14:20:14 +01:00
Todd Gruben
8c4d7e09ff re-use pilosa tls settings 2021-03-22 16:48:09 -05:00
Kuba Podgórski
1e5388dbe9 Move internals proto files into separate package (pb) 2021-03-22 20:28:00 +01:00
Kuba Podgórski
8131e807bf Add client package with go-pilosa implementation 2021-03-22 20:22:38 +01:00
Ben Johnson
5d2f957404
Merge branch 'master' into fix-delete-field-panic 2021-03-22 08:32:34 -06:00
Todd Gruben
f52b88a962 etcd tls configuration support 2021-03-22 09:10:32 -05:00
Nia
b6810f3ce7
Merge pull request #1535 from niaow/fix-unkeyed-panic
CORE-382 Handle translation errors when using keys against an unkeyed index
2021-03-17 17:16:55 -04:00
Nia Weiss
6f421dad69
handle translation errors when using keys against an unkeyed index
This also adds tests for our error outputs.
2021-03-17 12:02:29 -04:00
Kuba Podgórski
16245b1742
Merge pull request #1534 from kuba--/call-agg/335
CORE-335 Consistency with aggregate functions
2021-03-16 19:54:12 +01:00
Kuba Podgórski
d370452449 Add helper function FirstStringArg 2021-03-16 16:32:35 +01:00
Kuba Podgórski
1dac4c7622 Consistency with aggregate functions 2021-03-16 15:02:40 +01:00
Ben Johnson
195050e20c CORE-334: Fix panic on field deletion 2021-03-15 12:19:43 -06:00
Matthew Jaffee
c6ea56bbad
Merge pull request #1529 from travisturner/cache-bitdepth
[Core-370] Cache BitDepth on bsiGroup during index.Open
2021-03-15 07:38:05 -05:00
Travis
314cf3461d
Cache BitDepth on bsiGroup during index.Open.
Before this change, we were only caching the BitDepth on the
field.options. This was ok as long as applyOptions() was called after
that. But unfortunately, during startup, applyOptions() was called prior
to that being set. So with this commit, we explicitly set the value in
bsiGroup.BitDepth as well.
2021-03-14 22:51:24 -05:00
Matthew Jaffee
9b3cce619a
Merge pull request #1530 from jaffee/revert-custom-json
Revert "Basic pilosa changes for oracle support"
2021-03-14 22:50:37 -05:00
Matt Jaffee
11288c2ae8
Revert "Basic pilosa changes for oracle support"
This reverts commit 47e74f2603.
2021-03-14 22:17:26 -05:00
Nia
c694189648
Merge pull request #1523 from niaow/idalloc-fix
CORE-361 Fix ID allocation API after disco
2021-03-14 16:52:52 -04:00
Nia Weiss
2f4a2bf98f
fix ID allocation API after disco
The ID allocation API was broken because the operations were removed from the list allowed in the NORMAL cluster state.
Additionally the operations were set to only run on non-primaries (where they were actually only supposed to run on the primary).
2021-03-13 07:41:00 -06:00
Nia
ec899bcc64
Merge pull request #1519 from niaow/rbf-typos
fix a typo in the RBF spec
2021-03-13 00:25:12 -05:00
Ben Johnson
ddb8c95737
Merge branch 'master' into rbf-typos 2021-03-12 20:16:17 -07:00
tgruben
29b8501aff
Merge pull request #1527 from tgruben/core-334-fix
[CORE-334]  more graceful error handling for corrupt containers
2021-03-12 15:16:12 -06:00
Todd Gruben
346a248019 Merge branch 'core-334-fix' of github.com:tgruben/privilosa into core-334-fix 2021-03-12 13:28:11 -06:00
Todd Gruben
2711bf321f replace error with wrap 2021-03-12 13:27:28 -06:00
tgruben
fd7ea42451
Merge branch 'master' into core-334-fix 2021-03-12 12:11:52 -06:00
Kuba Podgórski
38c2c4ad6f
Merge pull request #1526 from seebs/testLeaks
CORE-358 Test leaks
2021-03-12 19:10:02 +01:00
Todd Gruben
94d7b295ea added more graceful error handling for corrupt containers 2021-03-12 10:37:40 -06:00
seebs
78ed9a2d57
Merge branch 'master' into testLeaks 2021-03-12 10:02:11 -06:00
Kuba Podgórski
1b486ac812
Merge pull request #1522 from kuba--/core-344
CORE-344: Fix deprecation plan for "github.com/golang/protobuf/protoc-gen-go/generator" package
2021-03-12 15:29:54 +01:00
Kuba Podgórski
61585b251e
Merge branch 'master' into testLeaks 2021-03-12 14:14:03 +01:00
Kuba Podgórski
4043f22db2
Merge branch 'master' into core-344 2021-03-12 14:08:03 +01:00
Travis Turner
81c47b778e
Merge pull request #1525 from travisturner/startup-log-dir
[CORE-362] Create the data directory during "log startup" if it doesn't already exist
2021-03-12 06:47:45 -06:00
Kuba Podgórski
1ba52dbca9 Update go.sum 2021-03-12 13:06:23 +01:00
Kuba Podgórski
a12a130420
Merge branch 'master' into core-344 2021-03-12 12:51:58 +01:00
Kuba Podgórski
ddc924de0c go mod tidy 2021-03-12 12:48:53 +01:00
Seebs
ef8dd91077 report errors more clearly when trying to recreate leases
There's some loose ends here because really we probably want to be
using the top-level server logger, and we should fix that, but in the
mean time, let's not swallow the errors as much, because the last
line printed doesn't actually show what the error was, but it could.

To do this, we distinguish between the current error (which might
be a wrapper around DeadlineExceeded) and a previous error which
we might prefer to return, if one exists, since it's more likely
the "real" cause.
2021-03-11 19:42:10 -06:00
Seebs
1045268f01 use testhook to ensure temporary files and directories are cleaned up
In nearly all cases, we can just switch ioutil.TempDir->testhook.TempDir
and similarly for TempFile. There's one case where we can't because we
need files to be removed before tests are over.

Also in the process give identifiable names to a lot of temporary files
and make sure they're being cleaned up, and don't use "/tmp/foo" as a
file name in a test that could be running in more than one test process
at once. :)
2021-03-11 19:42:10 -06:00
Travis
9e0ea9709a
Create the data directory during "log startup" if it doesn't already exist.
Prior to using etcd for node membership, the data director was created
during the cluster topology setup. Since that no longer exists, we
weren't actually creating the data directory before getting to
logStartup(). So this change ensure that the data directory exists.
2021-03-11 17:31:46 -06:00
tgruben
9b913ce904
Merge pull request #1489 from tgruben/theoracle
Theoracle
2021-03-11 16:11:38 -06:00
tgruben
391588bd1b
Merge branch 'master' into theoracle 2021-03-11 13:56:34 -06:00
Alan Bernstein
7df5375572
Merge pull request #1524 from alanbernstein/fix-null-schema
Represent zero indexes in /schema response as [] instead of null
2021-03-11 13:23:19 -06:00
tgruben
21910ef321
Update main.go 2021-03-11 11:47:57 -06:00
tgruben
a5dceaae11
Update main.go 2021-03-11 11:26:58 -06:00
Alan Bernstein
8e123b821d Replace null with [] in schema response 2021-03-11 11:23:20 -06:00
Todd Gruben
47e74f2603 Basic pilosa changes for oracle support 2021-03-11 11:16:53 -06:00
Kuba Podgórski
95eaab8ffc
Merge pull request #1514 from seebs/discoSyncer
CORE-299 check for nil translate store while reading translate entries
2021-03-11 13:03:24 +01:00
Nia Weiss
e73d9cb61b
fix a typo in the RBF spec 2021-03-10 14:25:38 -05:00
Kuba Podgórski
3fde2dcac2
Merge branch 'master' into discoSyncer 2021-03-10 12:35:10 +01:00
Kuba Podgórski
5af850c64a
Merge pull request #1518 from kuba--/fix-metadata-noder
Get metadata in Tx. Fix Nodes implementation
2021-03-10 11:24:09 +01:00
Kuba Podgórski
4c787870b2 Get metadata in Tx. Fix Nodes implementation 2021-03-10 00:28:49 +01:00
Seebs
810f840839 combine field and index translation readers
There's no need to have two different translation readers, a single
reader can handle both partitions and fields at the same time, so we
can combine them. This may not actually change things much but was
a useful step in diagnosing a different problem with translate readers,
and I think it is a minor improvement so I'm preserving the patch
just in case.
2021-03-09 13:37:51 -06:00
Seebs
76e4181740 don't reuse sync.Mutex between translate readers
The functional option and returned closure combine to result in
us using the same sync.Mutex object for every TranslateReader on
a given server, which means that if one of them isn't producing anything,
we eventually end up waiting on that with all the others blocked
waiting for the lock. Use separate locks for each, of the same
type as the one initially provided as a template. This does mean
that multiple readers can be operating at once, but in theory
no two readers should ever be writing to the same stores, we
think.
2021-03-08 17:04:52 -06:00
Seebs
51744dc77a check for nil translate store while reading translate entries
If we are using replication, we can be a replica translate store for a
partition, which means we start a translate store reader to replicate
data for it. The translation logic does not admit *stopping* the
translate reader, only "resetting" it (stopping and immediately
restarting), so the translate reader just runs until it hits an error
and terminates, which it does even if perhaps it shouldn't. Oops.

Anyway, one potential failure mode is that if you hit timing just
right, you can end up trying to process translation *while* the
index is being closed, and the index can close its translation stores,
and make them all nil, right before we request a store and try to use
it. Another is a similar error, but during the initial startup of the
translate store readers. Either way, we want to error out of the
process cleanly if this happens.

This could also happen during initial creation, perhaps.

We're aborting translation sync on these errors, because otherwise
we'd continue accepting new keys, and then end up with our highest
known key being higher than some keys we missed; this way the next
restart will restart from the last key we have.
2021-03-08 17:04:52 -06:00
Travis Turner
45577494c3
Merge pull request #1517 from travisturner/datadir-take-3
Remove stutter and suffix from backend files
2021-03-08 11:50:42 -06:00
Travis Turner
2a0765d7f0
Merge branch 'master' into datadir-take-3 2021-03-08 11:21:05 -06:00
Kuba Podgórski
d6e9e88872
Merge pull request #1516 from kuba--/test-close
Close resources in TestLeasedKv
2021-03-08 11:01:40 +01:00
Travis
f78a6508f0
Remove stutter and suffix from backend files 2021-03-07 22:11:51 -06:00
Kuba Podgórski
7b005f69c6 Close resources in TestLeasedKv 2021-03-06 12:03:57 +01:00
Travis Turner
ab50403c35
Merge pull request #1512 from travisturner/datadir-take-2
Core-316 Reorganize Pilosa datadir
2021-03-05 17:15:03 -06:00
Travis
cad78f1d34
remove "Default*" from const names 2021-03-05 16:56:44 -06:00
Travis
5191d0c3f4
remove unnecessary skip check 2021-03-05 16:56:44 -06:00
Travis
4661f3ac08
reorganize the storage backends directory 2021-03-05 16:56:44 -06:00
Travis
4738a818d2
change attributes file ".data" to "column/row-attributes" 2021-03-05 16:56:44 -06:00
Travis
345d076fdf
introduce "fields" directory between index and field 2021-03-05 16:56:44 -06:00
Travis
4e7ec34c6d
change directory ".disco" to "disco" 2021-03-05 16:56:44 -06:00
Travis
7789e24965
introduce "indexes" directory between datadir and index 2021-03-05 16:56:43 -06:00
Matthew Jaffee
863e57d5d1
Merge pull request #1513 from ajnavarro/disco/improve-leased-keys
[CORE-312] Improve leased keys.
2021-03-05 16:47:54 -06:00
Antonio Navarro Perez
542a98548a Breaking code at friday afternoon...
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-05 23:35:53 +01:00
Antonio Navarro Perez
2927943734 Copy paste fix.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-05 23:35:53 +01:00
Antonio Navarro Perez
feea0fa347 Requested changes.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-05 23:35:53 +01:00
Antonio Navarro Perez
85a43c519d Fix problem with context errors.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-05 23:35:53 +01:00
Antonio Navarro Perez
df0064c55f Add godoc.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-05 23:35:53 +01:00
Antonio Navarro Perez
955ab2b5a0 Requested changes
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-05 23:35:53 +01:00
Antonio Navarro Perez
851c41cd45 Implement infinite lease renewal logic.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-05 23:35:53 +01:00
Antonio Navarro Perez
7a1e4cd2d7 Improve leased keys.
Added a leasedKV struct in charge of maintain a lease for a specific
key.

Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-05 23:35:53 +01:00
Matthew Jaffee
6966c3f7c3
Merge pull request #1515 from jaffee/invalid-pilosa-message-fix
CORE-319 Fix issue where restarting a node fails to sync and logs "invalid pilosa.Message"
2021-03-05 15:58:06 -06:00
Matt Jaffee
f97ac4928c
add test for pilosa.Message issue
this doesn't quite work as-is, but I verified that it reproduced/fixed
the issue by adding a panic where the problem log statement
is. There's a follow up ticket to fix the test... it's just a bit open
ended as to the best way to do that.
2021-03-05 14:16:52 -06:00
Matt Jaffee
08d4511e6c
fix issue where restarting a cluster logged "invalid pilosa.Message"
we were sending pilosa.Message objects from a spool, but actually
passing a pointer to them rather than the Message itself. I'm
concerned this wasn't caught in any test, and also curious if that
needed to be a pointer for some reason or if it's a typo.

Definitely need to write a test still.
2021-03-05 12:51:39 -06:00
Travis Turner
fa9e17878f
Merge pull request #1503 from molecula/disco
DisCo
2021-03-04 17:24:42 -06:00
Matt Jaffee
bb713f94a5
Merge branch 'master' into disco 2021-03-04 16:56:35 -06:00
Cody Soyland
bf050a69d2
Merge pull request #1511 from codysoyland/release-on-tag
Run release stage when tags are pushed
2021-03-04 15:22:01 -06:00
Cody Soyland
ba8fb56a4a
Run release stage when tags are pushed 2021-03-04 15:11:57 -06:00
Matthew Jaffee
911c874fa1
Merge pull request #1510 from jaffee/upgrade-lettuce
upgrade UI for final Molecula 3.x/Pilosa 2.x release
2021-03-04 15:05:08 -06:00
Matt Jaffee
e1f2ffe614
upgrade UI for final Molecula 3.x/Pilosa 2.x release 2021-03-04 14:44:38 -06:00
Travis Turner
10a55040e8
Merge pull request #1509 from travisturner/disco-remove-gossip-config
Remove gossip config
2021-03-04 14:19:35 -06:00
Travis
42d69d6c5d
Remove gossip config 2021-03-04 13:51:18 -06:00
Nia
d2b0749c8a
Merge pull request #1507 from niaow/always-build-release
CORE-313 Build release bundles on every merge
2021-03-04 13:29:46 -05:00
Nia Weiss
0fbdbc7ccb
build release bundles on every merge 2021-03-04 12:34:51 -05:00
Kuba Podgórski
da3116a642
Merge pull request #1504 from kuba--/txn-state
Always Put states in Txn
2021-03-04 00:21:40 +01:00
Kuba Podgórski
d311b0cac4 Comment Status function
+ make waitForStatus more generic
2021-03-03 23:47:47 +01:00
Kuba Podgórski
fa293ba6c3 Address PR comments 2021-03-03 16:13:03 +01:00
Kuba Podgórski
a14baf8c15 waitForStatus for cluster test 2021-03-03 14:22:44 +01:00
Kuba Podgórski
6f7d748c8a Always Put states in Txn 2021-03-03 13:37:20 +01:00
Travis
883e687094
fix missing bracket 2021-03-02 22:14:07 -06:00
Travis
ea8b07d380
Merge branch 'master' into disco 2021-03-02 22:11:04 -06:00
Matthew Jaffee
c4c4a49f13
Merge pull request #1483 from jaffee/core-101-disco
CORE-101 Percentiles on disco
2021-03-02 22:02:27 -06:00
Matt Jaffee
f81c0cab6b
move 0.0 check up to right after Min is queried 2021-03-02 21:59:46 -06:00
Matt Jaffee
1e4cc12bd0
handle 0th percentile properly 2021-03-02 21:47:27 -06:00
Matt Jaffee
b1f9e6ad05
turn off parallel for variousQueries 2021-03-02 20:36:54 -06:00
Matt Jaffee
ad88f4fac8
refactor tests to reuse clusters more 2021-03-02 20:36:54 -06:00
Matt Jaffee
88b093db7a
add 60m timeout to topt-race tests to match topt 2021-03-02 20:36:53 -06:00
nagamocha3000
7da218727d
Separate out tests on Percentile to top level 2021-03-02 20:36:53 -06:00
nagamocha3000
832c6f1a71
Restore filter argument 2021-03-02 20:36:53 -06:00
nagamocha3000
66d12f88e2
Remove filter to check if it's cause of leaks 2021-03-02 20:36:53 -06:00
nagamocha3000
abe8e61539
Remove check for basic response 2021-03-02 20:36:53 -06:00
nagamocha3000
4e81fd8101
Limit size of nums to 100 2021-03-02 20:36:53 -06:00
nagamocha3000
4be9ac7554
Remove percentile tests temporarily to see if they are the cause 2021-03-02 20:36:53 -06:00
nagamocha3000
1947325e00
Fix error on index name for Percentile query 2021-03-02 20:36:53 -06:00
nagamocha3000
2de543bc55
Rename index to avoid possible conflict 2021-03-02 20:36:52 -06:00
nagamocha3000
a6c157d5db
Fix errenous estimation that caused infinite loop 2021-03-02 20:36:52 -06:00
nagamocha3000
ef58b66e2c
Add ability to compose filter Row Call with Percentile 2021-03-02 20:36:52 -06:00
nagamocha3000
131d4fd97c
Make tests for median more extensive 2021-03-02 20:36:52 -06:00
nagamocha3000
72af5f37df
Remove redundant assignment to countCall.children since we already have the reference 2021-03-02 20:36:52 -06:00
nagamocha3000
3fb79b4d97
Fix errors on creating pql Call 2021-03-02 20:36:52 -06:00
nagamocha3000
d740a0cda7
Add execution for median 2021-03-02 20:36:52 -06:00
nagamocha3000
26fd199716
Add basic test for Percentile query 2021-03-02 20:36:51 -06:00
nagamocha3000
30a7e0f0da
Add pql syntax for Percentile 2021-03-02 20:36:51 -06:00
Matthew Jaffee
61e84a01dc
Merge pull request #1500 from jaffee/default-rbf
change default backend to RBF, remove separate RBF race target
2021-03-02 20:34:32 -06:00
Matt Jaffee
52a0c90cd6
change default backend to RBF, remove separate RBF race target 2021-03-02 17:50:56 -06:00
Matthew Jaffee
34e742d9c6
Merge pull request #1502 from niaow/fix-more-kv
fix more incorrect uses of KV
2021-03-02 17:50:29 -06:00
Nia Weiss
a698eeaac2
fix more incorrect uses of KV 2021-03-02 18:35:19 -05:00
Matthew Jaffee
b790d2cc5f
Merge pull request #1501 from travisturner/disco-bitdepth-test-fix
fix SaveMeta test; ensure storage backend env is used
2021-03-02 17:26:52 -06:00
Travis
3d10af9d47
fix SaveMeta test; ensure storage backend env is used 2021-03-02 17:19:45 -06:00
Cody Soyland
acc1175c93
Merge pull request #1498 from codysoyland/docker-ci-version
Workaround CI versioning issue
2021-03-02 15:03:52 -06:00
Cody Soyland
0532987d57
Workaround CI versioning issue 2021-03-02 14:39:32 -06:00
Maxton Huff
068325277d
Merge pull request #1465 from Maxtonian/topNfieldequal
Allow "field=" for TopN()
2021-03-02 14:32:25 -06:00
Matthew Jaffee
0568daaa14
Merge pull request #1486 from ajnavarro/disco/remove-unused-code-and-godoc
[DISCO] Add documentation and try to remove code.
2021-03-02 14:07:06 -06:00
Maxton Huff
d61fdc2521
Merge branch 'master' into topNfieldequal 2021-03-02 14:02:58 -06:00
Cody Soyland
d2f391d650
Merge pull request #1496 from codysoyland/docker-build-ci
Docker login prior to building image
2021-03-02 13:59:26 -06:00
Cody Soyland
a94c6cf8a2
Docker login prior to building image 2021-03-02 13:43:27 -06:00
Maxton Huff
d20dc525f5
Merge branch 'master' into topNfieldequal 2021-03-02 13:35:17 -06:00
seebs
2d1d8afdf3
Merge pull request #1490 from seebs/disco1443c
avoid deadlocks or crashes when clients cancel queries
2021-03-02 10:17:24 -06:00
Cody Soyland
0488dbe8d3
Merge pull request #1492 from codysoyland/fix-flags
Fix incorrect build flags
2021-03-02 07:46:07 -06:00
Antonio Navarro Perez
274540ea0b Requested changes
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-02 13:46:37 +01:00
Kuba Podgórski
0cb311f2b3 Fix Heartbeat TTL for disco test 2021-03-02 11:30:25 +01:00
Matthew Jaffee
94ccd514ea
Merge branch 'master' into topNfieldequal 2021-03-01 22:18:36 -06:00
Cody Soyland
bfa9682ba5
Fix incorrect build flags 2021-03-01 17:01:06 -06:00
Seebs
5258532157 bump usage guesstimate again
Same machine, a week later: Got 618k instead of 500k. I'm doomed.
2021-03-01 14:20:18 -06:00
Seebs
35d360c68d fix up executor shard-counting logic a bit better
Ensure that mapReduce always waits on its ErrGroup, even if it wants to return
early due to a failure somewhere. Also check logic a bit more carefully on
the error returns; we don't want a transient failure from one node to result
in the whole query failing, we just want it to retry on the next node, so that
shouldn't cancel the whole ErrGroup.
2021-03-01 14:03:49 -06:00
Antonio Navarro Perez
f67db5035e Add part of cache back.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-01 19:09:31 +01:00
Antonio Navarro Perez
50fd72f980
Apply suggestions from code review
Co-authored-by: Travis Turner <travis@pilosa.com>
2021-03-01 18:41:58 +01:00
Antonio Navarro Perez
6f5770bf65 Fix nil pointer exception
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-01 18:39:04 +01:00
Maxton Huff
15aa7d1ad8 add field to SetRowAttrs and TopK to prototypes in ast.go 2021-03-01 11:18:31 -06:00
Antonio Navarro Perez
ea7643f8bf Add documentation and try to remove code.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-03-01 16:25:32 +01:00
Nia
a906a9036b
Merge pull request #1482 from niaow/force-transactional-etcd-reads
Force transactional etcd reads
2021-02-26 19:03:21 -05:00
Travis Turner
4add6134b8
Merge pull request #1468 from travisturner/disco-clustertests
adjust clustertests to have etcd config
2021-02-26 17:49:20 -06:00
seebs
d455fb3105
Merge pull request #1476 from seebs/disco1443b
mapper/mapReduce/worker: always wait for jobs to be finished
2021-02-26 17:35:02 -06:00
Nia Weiss
4be4097edd
force transactional etcd reads 2021-02-26 18:29:01 -05:00
Maxton Huff
23f44725cb remove var allowUnderField 2021-02-26 16:36:16 -06:00
Cody Soyland
c328a18889
Merge pull request #1440 from codysoyland/cd
Add new Docker build process and continuous delivery
2021-02-26 16:32:46 -06:00
Maxton Huff
3822e38952 remove z arg from Rows tests 2021-02-26 16:15:37 -06:00
Travis
ef40bbb617
renew heartbeat lease if the lease expires while a node is unavailable 2021-02-26 16:15:06 -06:00
Travis
d416b88dda
adjust clustertests to have etcd config 2021-02-26 16:15:06 -06:00
Maxton Huff
441630d804 try fixing tests 2021-02-26 16:13:00 -06:00
Nia
590dc3b226
Merge pull request #1478 from niaow/start-http-after-server-open
Start HTTP after server open
2021-02-26 16:04:34 -05:00
Cody Soyland
dca19f7e94
Add new Docker build process and continuous delivery 2021-02-26 14:34:14 -06:00
Seebs
7d15fc2f26 don't reduce errors with non-errors
if we got an error, we don't have to merge it. so either ctx.Err or
resp.err being non-nil means we shouldn't be reducing, but we still need
to grab the responses to make sure we waited for them all.
2021-02-26 14:26:02 -06:00
Nia Weiss
4340e90396
start HTTP handler after server initialization
This fixes a variety of bugs where API requests would read uninitialized state, causing crashes or race conditions.

Co-authored-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-26 15:23:47 -05:00
Ben Johnson
eff313d181
Merge pull request #1474 from molecula/bench-autogenerate
Add benchmarking of autogenerated ID data
2021-02-26 12:39:36 -07:00
Nia
d205ea5441
Merge pull request #1442 from niaow/fix-foreignindex-race
Fix a race condition when deferring foreign-index initialization
2021-02-26 14:30:18 -05:00
Maxton Huff
8bc8368c57 change test arguments to be appropriate 2021-02-26 12:58:59 -06:00
Seebs
29fddd40f6 mapper/mapReduce/worker: always wait for jobs to be finished
It's not enough to cancel jobs so their goroutines *will* exit; we have
to be certain that they *have exited* before we finish returning from,
e.g., mapReduce(), or a query can "complete" at a time when there are
still running goroutines accessing data that we're about to invalidate
when we terminate the Qcx.

A better solution would integrate this logic and control into the Qcx
and pass it through everything, rather than having the Qcx bypass
the mapper/mapperLocal and be passed into the mapFn/reduceFn via
closures. But a better solution would be a lot larger.
2021-02-26 12:47:02 -06:00
Maxton Huff
6f76767841 add test in executor.go to compare results of query w/without field= 2021-02-26 12:06:25 -06:00
Ben Johnson
90278b206c Add benchmarking of autogenerated ID data 2021-02-26 10:37:15 -07:00
Maxton Huff
d49a8f953e regenerate pql from modified peg file 2021-02-26 11:27:39 -06:00
Nia
65e4496ea7
Merge pull request #1449 from niaow/deferredcreateshard
Defer cluster messages until startup
2021-02-26 08:13:51 -05:00
Maxton Huff
ab41d0492c add more tests for TopK, Rows, and SetRowAttrs 2021-02-25 16:04:31 -06:00
Nia Weiss
3fbf6993d0
defer cluster messages until startup 2021-02-25 16:01:49 -05:00
Nia Weiss
ca918c187d
fix a race condition when deferring foreign-index initialization 2021-02-25 16:00:56 -05:00
Kuba Podgórski
a1d4418236
Merge pull request #1464 from kuba--/etcd-shared-client
One shared etcd client
2021-02-25 19:45:22 +01:00
Kuba Podgórski
50cbb72619 Remove comments/leftovers 2021-02-25 19:00:52 +01:00
Kuba Podgórski
49dc48f057 Switch to server API for KV Get/Range 2021-02-25 18:34:24 +01:00
Kuba Podgórski
aa15e08558 Reduce number of Txn 2021-02-25 18:12:13 +01:00
Maxton Huff
6b75a8b500 Revert "allow 'field=' for TopN()"
This reverts commit db01237904.
2021-02-25 11:01:22 -06:00
Kuba Podgórski
a5f3bce3bf Use hookedClient 2021-02-25 16:56:30 +01:00
Kuba Podgórski
1623007af1 Add waitgroup - don't close the server wait for all keepaliveFunc 2021-02-25 13:41:10 +01:00
Kuba Podgórski
23f901635e Revert "Remove etcd cache"
This reverts commit 0f4b273d3a.
2021-02-25 13:41:10 +01:00
Kuba Podgórski
0f4b273d3a Remove etcd cache 2021-02-25 11:30:09 +01:00
Kuba Podgórski
1fc3d37134
Merge branch 'disco' into etcd-shared-client 2021-02-25 09:42:00 +01:00
Kuba Podgórski
01e0c44069 One shared etcd client 2021-02-25 09:39:44 +01:00
Nia
0cfd4e9780
Merge pull request #1463 from niaow/dontcachestate
Stop caching node state in Etcd
2021-02-24 18:28:03 -05:00
Nia Weiss
8b645e02a2
stop caching node state in Etcd 2021-02-24 17:19:27 -05:00
Maxton Huff
db01237904 allow 'field=' for TopN() 2021-02-24 15:29:10 -06:00
seebs
bffdee1e8e
Merge pull request #1432 from seebs/discoPorts
possible fix for CI deadlocks after port_mapper messages in CI
2021-02-24 12:03:14 -06:00
Seebs
8d6f97604f use testhook to run server tests so we can have post-processing and audits
This gives more consistency with the other tests and allows us to get audit
checks on the server/ tests. The tests on the clients being closed are
temporarily disabled because they tend to think the last test's clients
are "still open" for a few seconds after the test completes.
2021-02-24 11:25:46 -06:00
Seebs
2ee589ae1d reduce goroutine spam during TestVariousQueries
etcd runs a LOT more goroutines during server startup. Fix a
goroutine/for loop bug causing us to run four 7-node clusters
instead of 1/3/4/7-node clusters, also have the test/cluster
code reduce import workers. We can't do much about the spamminess
of the Raft stuff, but this should tone it down some.
2021-02-24 11:25:46 -06:00
Seebs
9333b1b27e leaseKeepAlive: manage context and shut it down cleanly
Every usage of this just ran keepAlive func as a goroutine with a timer, using
a parent context, but the keepAlive func didn't know about that context, so
it couldn't use that context for its own messages or interactions. Change
it to create its own cancelable context from a provided parent, and use
that to control its inner behavior.

Note that we *do* still need to send the revoke at least sometimes -- otherwise
cluster states don't update correctly. But we can time that send out
rather than using context.Background(), because after a TTL's worth of time,
there's no lease to revoke anyway.

Also, add hooks for testhook tracking so we can confirm/deny that things
are getting shut down, which they weren't.
2021-02-24 11:25:46 -06:00
Seebs
c1c0e828cd lock read from bsig.BitDepth, not just write to it 2021-02-24 11:25:46 -06:00
Seebs
8eaa4e592f shut down GRPC client after running QueryGRPC against a cluster
If you don't shut the client down, it leaves two goroutines running forever.
2021-02-24 11:25:46 -06:00
Seebs
66ed216023 bump UI/usage guesstimated limit because my laptop uses about 6% too much 2021-02-24 11:25:46 -06:00
Seebs
4f5f3e30ea remove port_mapper because it can't work with our unrestartable server
Long story short: Once we create a server and start it, we can't start
it again. We can't close it and restart it, and we can't just start
it without closing it.

Unfortunately, if the server's config needs to change, we have a Problem
here.

This ultimately means that the retry logic for GetListeners can't actually
retry successfully; if we fail on the first attempt, we necessarily fail
on any later attempts also, and if we try to fix that, we get panics.

But!

We don't actually NEED to retry. We just need to ensure that we can
open a :0 port, extract the actual port number, and use that in places
where the port number mattered, without having to rebind it.

The only actual place we needed to rebind things was opening gRPC
servers, so we introduce a gRPC Listener that can be used instead of
trying to bind to a specified port.

In a bunch of other cases where we had similar logic to try to allocate
and then use a port, we can switch to just using a provided listener.
For instance, net/http has `Serve(net.Listener, handler)`, not just
ListenAndServe(addr, handler).

This should eliminate the weird CI failures from eaddrinuse.

NOT fixed: server/cluster_test.go/TestClusterResize_AddNode isn't working
right now. The new node isn't actually being added to the existing cluster.
I attempted this but was outsmarted by it, and I think fixing the
rest of this is worth it as a separate thing.
2021-02-24 11:25:46 -06:00
Travis Turner
4200de481d
Merge pull request #1458 from travisturner/disco-remove-coordinator
remove remaining references to "coordinator"
2021-02-24 09:43:04 -06:00
Travis
2bbe1fdde0
remove remaining references to "coordinator" 2021-02-23 17:23:09 -06:00
Ben Johnson
4454df0af0
Merge pull request #1454 from molecula/remove-rbftx-frag
Remove unused RBFTx.frag field
2021-02-23 09:42:50 -07:00
Travis Turner
c16c543274
Merge pull request #1456 from travisturner/disco-remove-docs
remove docs directory
2021-02-23 10:33:12 -06:00
Travis Turner
aa43367f45
Merge pull request #1448 from travisturner/disco-no-metadata-base
Disco no metadata base
2021-02-23 10:15:52 -06:00
Travis
295101ecbd
remove docs directory 2021-02-23 10:13:16 -06:00
Travis
81fbeb61f9
fix logic in fragment.bitDepth() 2021-02-23 10:09:56 -06:00
Travis
912e51790f
remove Field.saveMeta(). get Feild.options.BitDepth from fragment 2021-02-23 10:09:56 -06:00
Travis
8b0f18721e
remove Field.loadMeta() 2021-02-23 10:09:55 -06:00
Travis
dfd49c3648
add a gob-encoding Serializer implementation for tests 2021-02-23 10:09:55 -06:00
Travis
4e857e8de4
remove some calls to Field.saveMeta() 2021-02-23 10:09:55 -06:00
Travis
d639e228ae
remove Index.saveMeta(). remove support for deleing existence field. 2021-02-23 10:09:55 -06:00
Travis
2c112a73fe
remove Index.loadMeta() 2021-02-23 10:09:55 -06:00
Travis
38d5459e25
convert holder decode* methods to functions 2021-02-23 10:09:55 -06:00
Travis
3f0745647b
set timestamp() on field 2021-02-23 10:09:55 -06:00
Travis
ebb340d83e
remove old BSI upgrade code 2021-02-23 10:09:54 -06:00
Travis
114d74af29
pass cfm to openField() 2021-02-23 10:09:54 -06:00
Travis
24c5b654c6
change IndexOptions to reference by value 2021-02-23 10:09:54 -06:00
Ben Johnson
02de222387
Merge branch 'master' into remove-rbftx-frag 2021-02-23 08:56:45 -07:00
Antonio Navarro Perez
5794a4af69
Merge pull request #1452 from ajnavarro/disco/coordinator-err-to-primary
Change coordinator error to primary
2021-02-23 16:44:50 +01:00
Alan Bernstein
2641e57ddb
Merge pull request #1450 from alanbernstein/dont-limit-before-sort
CORE-182 Add ignoreLimit argument to executeGroupByShard
2021-02-23 09:33:07 -06:00
Ben Johnson
5e477e107a Remove unused RBFTx.frag field 2021-02-23 08:32:07 -07:00
Antonio Navarro Perez
f0a5ca5d3a Change coordinator error to primary
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-23 09:58:22 +01:00
Alan Bernstein
f228a35d52 Add ignoreLimit argument to executeGroupByShard 2021-02-22 16:16:11 -06:00
tgruben
0170167bdf
Merge pull request #1447 from tgruben/cleanup
Provide option to update existence field on import roaring request
2021-02-22 15:36:50 -06:00
Todd Gruben
081d86c04b mixed row test 2021-02-22 15:06:45 -06:00
Todd Gruben
d220426686 doc comment 2021-02-22 11:50:01 -06:00
tgruben
18e31a63b6
Update roaring/roaring.go
Co-authored-by: Matthew Jaffee <matthew.jaffee@gmail.com>
2021-02-22 11:42:48 -06:00
Todd Gruben
8e27e55459 Merge branch 'cleanup' of github.com:tgruben/privilosa into cleanup 2021-02-22 11:38:02 -06:00
Todd Gruben
5cbbb7996e jaffee test handling suggestions 2021-02-22 11:37:30 -06:00
tgruben
c2da1d2671
Update api.go
Co-authored-by: Matthew Jaffee <matthew.jaffee@gmail.com>
2021-02-22 11:07:41 -06:00
tgruben
1b87b7148e
Update api.go
Co-authored-by: Matthew Jaffee <matthew.jaffee@gmail.com>
2021-02-22 11:06:55 -06:00
Todd Gruben
155a4b4a31 comment clarification 2021-02-22 10:07:32 -06:00
Todd Gruben
9e186669d8 update go mod to fix cors bug 2021-02-22 08:33:52 -06:00
Travis
9f14415b58
Merge branch 'master' into disco 2021-02-20 10:28:38 -06:00
Todd Gruben
4e3beb0d10 Provide option to update existence on import roaring 2021-02-19 18:08:25 -06:00
Todd Gruben
6219b4ca8b add optional UpdateExistence on importRoaring 2021-02-19 17:47:28 -06:00
Todd Gruben
5b43a84a3b . 2021-02-19 17:09:50 -06:00
Ben Johnson
8647b80adb
Merge pull request #1435 from molecula/fix-node-removal-error
Clarify node removal error when self-removing
2021-02-19 08:23:21 -07:00
Ben Johnson
841208858f Clarify node removal error when self-removing
Currently, if you issue a node removal from the node that is being
removed, then you will see a "node cannot be removed error". It's
not clear why you aren't able to remove the node. The error message
has been updated to clarify why.
2021-02-18 12:55:06 -07:00
Kuba Podgórski
e724ad53f2
Merge pull request #1437 from kuba--/check-state
Check state in shardsByNode once stator is implemented
2021-02-18 12:50:03 +01:00
Kuba Podgórski
484f709621 Add regression test 2021-02-18 12:33:01 +01:00
Kuba Podgórski
bfc24a1745 Check state in shardsByNode once stator is implemented 2021-02-17 16:02:28 +01:00
Kuba Podgórski
b17d2b6d18
Merge pull request #1431 from kuba--/import-412
Avoid precondition failed (412) on ingest
2021-02-17 11:50:44 +01:00
Travis Turner
5c5712dba1
Merge pull request #1434 from travisturner/disco-replica-failover
don't cancel the context if replicas should be attempted
2021-02-16 22:00:02 -06:00
Travis
0d08a68c28
fix test expected error message 2021-02-16 21:59:35 -06:00
Travis
a7d4226326
only cancel() in mapper on a secondary, replica error
There is another case where cancelling here might be useful,
and that's if the query is on a primary node and the replication
factor is 1, meaning there are no secondary nodes to fail over to.
That case is handled here as well.
2021-02-16 16:29:49 -06:00
Travis
d27afc42f1
don't cancel the context if replicas should be attempted 2021-02-16 15:10:24 -06:00
Kuba Podgórski
de17c51293 Avoid precondition failed (412) on ingest 2021-02-16 20:18:14 +01:00
Travis Turner
42b8522e80
Merge pull request #1429 from travisturner/disco-field-createdat
ensure field.CreatedAt is set on loadField
2021-02-15 21:50:28 -06:00
Travis
e54f7d9a0b
ensure field.CreatedAt is set on loadField 2021-02-15 21:28:20 -06:00
Travis Turner
17c0d73fa2
Merge pull request #1427 from travisturner/disco-simplify-view
stop storing a value for views in etcd
2021-02-15 15:41:36 -06:00
nagamocha3000
4dfd713189
Merge pull request #1395 from nagamocha3000/fix-core-78
CORE-78 Add parsing for partial time inputs
2021-02-16 00:18:36 +03:00
Travis
b5d6c632bf
stop storing a value for views in etcd 2021-02-15 14:39:52 -06:00
nagamocha3000
0927240956 Add parsing for partial time inputs 2021-02-15 22:55:35 +03:00
Travis Turner
062851bae5
Merge pull request #1419 from seebs/discoFever
Performance improvements for disco branch
2021-02-15 12:28:10 -06:00
Seebs
82a975fd2a avoid race conditions on nodes
Turns out we sometimes modify returned nodes. Handle this better, but
also fix up some cases where we were generating node lists we didn't really
need to answer simple questions.
2021-02-15 10:20:31 -06:00
Seebs
07a014e952 cache Nodes calls in EtcdWithCache
The Peers() data is cached, but then every call still has to unmarshal JSON
and that's stunningly expensive. Let's not!
2021-02-15 10:19:56 -06:00
Seebs
e2b6912d1c uninvert test for coordinator node / primary field translation node
If we're the primary field translation node, we don't need to set up
translation replication; we only need that if we're *not*. So it
makes sense to test if !IsPrimaryFieldTranslationNode... except that
the test is to determine whether to return early. So it should not
be inverted.
2021-02-15 10:19:03 -06:00
Seebs
0790fbe866 only persist views to etcd when they're not already known
Persisting views to etcd every time we check for them causes
what ends up being about a factor of 60 slowdown. Let's do it a little
less.
2021-02-15 10:19:03 -06:00
Travis
4097ec155b
Merge branch 'master' into disco 2021-02-13 10:00:20 -06:00
Alan Bernstein
06503813c5
Merge pull request #1420 from alanbernstein/fix-schema-null-fields
Represent zero fields in /schema response as [] instead of null
2021-02-13 06:40:36 -06:00
Travis
9fa271a7b8
remove dead code (api.HostStates()) 2021-02-12 21:51:27 -06:00
Travis
d3ffdafdd8
remove some more TXSRCs that slipped in 2021-02-12 21:44:20 -06:00
Travis Turner
b7db27b7a7
Merge pull request #1416 from travisturner/disco-load-schema-on-open
Load schema from etcd on holder open; validate indexes, fields, views
2021-02-12 21:35:13 -06:00
Travis
a2a6e91f6d
remove old, now conflicting test value 2021-02-12 21:21:56 -06:00
Travis
2d17405e94
fix SchemaDetails test 2021-02-12 21:11:45 -06:00
Travis
8f0270acda
adjust openExistenceField() to check on disk first 2021-02-12 20:35:36 -06:00
Kuba Podgórski
40fe280453
Remove not needed holder test 2021-02-12 20:35:36 -06:00
Kuba Podgórski
2f35b51db8
Fix endpoint tests + change BitDepth type to uint64 2021-02-12 20:35:36 -06:00
Travis
a6297dc48e
WIP: load schema from etcd on holder open; validate indexes, fields, views 2021-02-12 20:32:31 -06:00
Travis
b89c699a8e
fix bug from merge 2021-02-12 20:32:12 -06:00
Travis
5b237cae13
Merge branch 'master' into disco 2021-02-12 20:29:41 -06:00
Alan Bernstein
f758a04e18 Represent zero fields in /schema response as [] instead of null 2021-02-12 19:40:42 -06:00
Matthew Jaffee
421848c86a
Merge pull request #1418 from molecula/fix-lattice
update lattice version to correct from accidental downgrade
2021-02-12 16:16:34 -06:00
Matt Jaffee
0e3461e9f4
update lattice version to correct from accidental downgrade 2021-02-12 14:50:10 -06:00
Alan Bernstein
a75c62c90f
Merge pull request #1391 from alanbernstein/field-cardinality
CORE-92 Add /schema/details endpoint, which includes field cardinality
2021-02-12 09:38:42 -06:00
Antonio Navarro Perez
2089e5eeb4
Merge pull request #1417 from ajnavarro/fix-log-web-ui-http-handler 2021-02-12 10:18:51 +01:00
Alan Bernstein
882b14444b Use consistent behavior in test to add queries to transaction 2021-02-11 16:42:30 -06:00
Alan Bernstein
dc6c92771b Fail entire /schema/details request if one field query fails 2021-02-11 16:42:30 -06:00
Alan Bernstein
2773999190 Simplify response structs 2021-02-11 16:42:30 -06:00
Alan Bernstein
12462886a6 Shorten shard lists in error messages 2021-02-11 16:42:30 -06:00
Alan Bernstein
246c345c49 Eliminate omitempty from /schema/details response type 2021-02-11 16:42:30 -06:00
Alan Bernstein
56c940c6a0 Add /schema/details endpoint, which includes field cardinality computed via Count(Distinct()) 2021-02-11 16:42:30 -06:00
Maxton Huff
2e6a8e2030
Merge pull request #1393 from Maxtonian/30trial
CORE-140 add draft trial version of molecula
2021-02-11 16:38:53 -06:00
Maxton Huff
f8fc69670c Merge branch '30trial' of github.com:Maxtonian/pilosa into 30trial 2021-02-11 16:19:09 -06:00
Maxton Huff
b89dae01cc clarify purpose of trialVersion by changing the name to handleTrialDeadline and adding a doc string 2021-02-11 16:13:04 -06:00
Maxton Huff
d5b96ab5ce
Merge branch 'master' into 30trial 2021-02-11 11:02:21 -06:00
Maxton Huff
136a4b8068 change wording 2021-02-11 11:01:16 -06:00
Maxton Huff
dd8d6ebfb1 Respond to code review feedback
change logic in version.go so that the trial related messages only appear on trial versions of molecula
convert Command methods in trial.go to functions and  pass a loggerLogger variable instead since that was the only piece of Command being used
add a function named expireAfter which seperately runs similar functionality to what was previously in daily check with chnages directed at stopping users from changing their internal clock date
change variable names and placement to be more readable and organized
2021-02-11 11:01:16 -06:00
Maxton Huff
ddcf9fe1e8 add licence header 2021-02-11 11:01:16 -06:00
Maxton Huff
c973fae6aa remove remaining release-build-trial 2021-02-11 11:01:16 -06:00
Maxton Huff
c60893a8ee edit and move trial code from server.go to trial.go and combine release build targets 2021-02-11 11:01:16 -06:00
Maxton Huff
7fd3fc775f remove test code 2021-02-11 11:01:16 -06:00
Maxton Huff
d02ba32743 alter error output to satisfy test 2021-02-11 11:01:15 -06:00
Maxton Huff
9840ae67e4 remove error return type 2021-02-11 11:01:15 -06:00
Maxton Huff
1dbab1ff92 add draft trial version of molecula 2021-02-11 11:01:15 -06:00
Maxton Huff
d357447673 change wording 2021-02-11 10:59:32 -06:00
Maxton Huff
0f952bb594 Respond to code review feedback
change logic in version.go so that the trial related messages only appear on trial versions of molecula
convert Command methods in trial.go to functions and  pass a loggerLogger variable instead since that was the only piece of Command being used
add a function named expireAfter which seperately runs similar functionality to what was previously in daily check with chnages directed at stopping users from changing their internal clock date
change variable names and placement to be more readable and organized
2021-02-11 10:36:04 -06:00
Antonio Navarro Perez
e0787ed8a8 Requested changes.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-11 16:37:41 +01:00
Antonio Navarro Perez
5440e177de Use advertised URL
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-11 11:52:42 +01:00
Antonio Navarro Perez
1f234df86e Really fix url on Web UI log
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-11 11:10:38 +01:00
Kuba Podgórski
d491c26b8e
Merge pull request #1413 from kuba--/stop-server
Do not stop etcd server before closing
2021-02-11 10:50:43 +01:00
Matthew Jaffee
a781d472b8
Merge pull request #1415 from molecula/revert-1412-import-roaring-existence
Revert "Update existence field on import-roaring requests"
2021-02-10 18:40:59 -06:00
Kuba Podgórski
5774a8e066 Do not stop etcd server before closing 2021-02-11 00:36:13 +01:00
tgruben
a61ed011fc
Revert "Update existence field on import-roaring requests" 2021-02-10 14:51:11 -06:00
tgruben
a41a65d7bd
Merge pull request #1412 from tgruben/import-roaring-existence
Update existence field on import-roaring requests
2021-02-10 13:03:54 -06:00
Todd Gruben
e7f272f37f updates existence field on importroaring fixes issue (1411) 2021-02-10 12:43:27 -06:00
Maxton Huff
302093035e add licence header 2021-02-10 12:37:13 -06:00
Travis Turner
88f13d5e8b
Merge pull request #1398 from travisturner/disco-schema
Implement Schemator
2021-02-10 12:01:00 -06:00
Travis
7a5192aba6
handle error on LoadSchema() message 2021-02-10 12:00:36 -06:00
Travis
c37424f24f
remove commented code 2021-02-10 11:57:23 -06:00
Travis Turner
5a09b5196e
Merge pull request #23 from travisturner/disco-schema-views
store views in etcd via Schemator
2021-02-10 11:55:58 -06:00
Travis
f3d1572232
update comment 2021-02-10 11:55:34 -06:00
Travis
1c3b0f364d
implement ApplySchema, LoadSchema, and LoadSchemaMessage 2021-02-10 11:51:52 -06:00
Travis
bcb71b023a
fix misplaced _exists check 2021-02-10 11:47:26 -06:00
Travis
8fe1b9a37c
store views in etcd via Schemator 2021-02-10 11:47:26 -06:00
Kuba Podgórski
86f45e9e62 Fix TestClusterResize_AddNode 2021-02-10 16:33:22 +01:00
Kuba Podgórski
ecba5e3636 Fix TestCRUDIndexes 2021-02-10 16:22:34 +01:00
Maxton Huff
4bcdfcc9a2 remove remaining release-build-trial 2021-02-10 08:21:36 -06:00
Kuba Podgórski
2d666f8ee8 Test cleanup 2021-02-10 14:56:48 +01:00
Kuba Podgórski
8c0ece5b7e Merge branch 'disco-schema' of github.com:travisturner/privilosa into pr/travisturner/1398 2021-02-10 14:30:06 +01:00
Kuba Podgórski
9faabd8535 Fix Test_TxFactory_UpdateBlueFromGreen_OnStartup 2021-02-10 14:26:52 +01:00
Kuba Podgórski
1dd9aa866f Fix Test_TxFactory_UpdateBlueFromGreen_OnStartup 2021-02-10 14:09:20 +01:00
Kuba Podgórski
efc598a68b
Merge pull request #1410 from ajnavarro/web-enabled-url-fix
Fix enabled Web UI url log
2021-02-10 13:40:22 +01:00
Antonio Navarro Perez
484abe9cdb Fix enabled Web UI url log
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-10 13:36:19 +01:00
Travis Turner
c85c42c58a
Merge pull request #25 from kuba--/index-exists
Fix TestHandler_PostSchemaCluster
2021-02-09 21:23:55 -06:00
Maxton Huff
7ae1599c12 edit and move trial code from server.go to trial.go and combine release build targets 2021-02-09 15:39:32 -06:00
Cody Soyland
f1f7bd6327
Merge pull request #1406 from codysoyland/upgrade-lattice
Upgrade lattice
2021-02-09 15:19:04 -06:00
Cody Soyland
0227d8306f
Upgrade lattice 2021-02-09 15:00:11 -06:00
Kuba Podgórski
40063a6aa9 Fix TestHandler_PostSchemaCluster 2021-02-09 20:13:38 +01:00
Kuba Podgórski
8591599b4c
Merge pull request #24 from kuba--/delete-views
Fix TestAPI_Import. Delete views when deleting a field.
2021-02-09 16:39:58 +01:00
Kuba Podgórski
d827f63148 Fix ApplySchema API 2021-02-09 16:21:25 +01:00
Kuba Podgórski
5d9fd0906c Fix TestClusterResize_AddNodeConcurrentIndex 2021-02-09 15:51:27 +01:00
Kuba Podgórski
0f97066914 Fix TestAPI_Import. Delete views when deleting a field. 2021-02-09 13:36:53 +01:00
Travis Turner
ccd89bbe2a
Merge pull request #22 from kuba--/index-schemator
Move schemator from API to index. Fix TestExecutor_Execute_SetRow
2021-02-08 15:43:15 -06:00
Kuba Podgórski
37b309be16 Move schemator from API to index. Fix TestExecutor_Execute_SetRow 2021-02-08 21:54:39 +01:00
Kuba Podgórski
2a9423e7f8
Merge pull request #21 from ajnavarro/disco/add-nop-schemator-serializer
Add NopSchemator and NopSerializer
2021-02-08 18:50:49 +01:00
Antonio Navarro Perez
17a5bc51ca Add NopSchemator and NopSerializer
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-08 18:36:53 +01:00
Travis
3542134100
WIP: implement Schemator 2021-02-08 10:42:55 -06:00
Travis
114f6a8751
add withViews argument to api.Schema() method 2021-02-08 10:42:55 -06:00
Travis Turner
ecd8e3fa10
Merge pull request #1397 from travisturner/disco-unify-state
Unify state
2021-02-08 10:00:36 -06:00
Antonio Navarro Perez
b1ff8e55cd
Unify state
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-06 16:53:42 -06:00
Travis Turner
968b1ade50
Merge pull request #1394 from travisturner/disco-clean-topology
Remove pilosa-chk, Topology and ClusterCluster
2021-02-06 16:18:00 -06:00
Kuba Podgórski
218d14df3f
Merge pull request #1396 from kuba--/mod-tidy
cleanup memberlist
2021-02-06 23:16:45 +01:00
Kuba Podgórski
750a684b51 cleanup memberlist 2021-02-06 23:12:08 +01:00
Travis
4bcdbf1bff
go mod tidy 2021-02-05 16:33:35 -06:00
Travis
30d4687a99
remove type Topology 2021-02-05 16:13:43 -06:00
Travis
002aee63e3
remove code related to pilosa-chk 2021-02-05 16:13:43 -06:00
Travis
b7d6db51a3
remove dead code related to pilosa-chk 2021-02-05 16:13:43 -06:00
Travis
4dd6bddf7f
remove pilosa-chk 2021-02-05 16:13:43 -06:00
Travis
b2d666a1d0
remove unused tx function 2021-02-05 16:13:17 -06:00
Travis
d192c1f24f
Merge branch 'master' into disco 2021-02-05 15:58:36 -06:00
Maxton Huff
c967bc96f4 remove test code 2021-02-05 15:40:55 -06:00
Maxton Huff
f37ec5b425 alter error output to satisfy test 2021-02-05 14:25:57 -06:00
Maxton Huff
fb47cb875a remove error return type 2021-02-05 13:40:57 -06:00
Travis Turner
86abf22e6d
Merge pull request #1392 from travisturner/disco-deadcode
remove dead code
2021-02-05 12:22:25 -06:00
Maxton Huff
fec0337630 add draft trial version of molecula 2021-02-05 12:16:08 -06:00
Travis
ec91dad198
remove dead code 2021-02-05 11:31:33 -06:00
Travis Turner
4a408a895a
Merge pull request #1378 from travisturner/disco-config-noder
Disco config noder
2021-02-05 10:37:56 -06:00
Kuba Podgórski
ab3353fb56 Add resize messages for broadcaster 2021-02-05 14:02:28 +01:00
Kuba Podgórski
e4fb58132b
Merge pull request #19 from kuba--/resizer-interface
Apply resizer interface (remove and add node)
2021-02-05 12:48:55 +01:00
Kuba Podgórski
bdbffe8d96 Update cluster_internal_test.go 2021-02-05 12:48:22 +01:00
Kuba Podgórski
35b9d41da1
Merge branch 'disco-config-noder' into resizer-interface 2021-02-05 11:57:51 +01:00
Travis Turner
e48fd9bf88
Merge pull request #18 from travisturner/disco-config-noder-remove-gossip
remove the rest of the gossip code (except config)
2021-02-04 21:35:22 -06:00
Travis
c8c59b649d
remove pilosa-fsck 2021-02-04 21:34:15 -06:00
Kuba Podgórski
ab37bf5c7b Apply resizer interface (remove and add node) 2021-02-04 20:26:41 +01:00
Travis
a4b37273ea
remove the rest of the gossip code (except config) 2021-02-04 13:03:02 -06:00
Travis Turner
3e90a88c34
Merge pull request #17 from ajnavarro/do-not-write-on-degraded
Stop writes on DEGRADED state
2021-02-04 13:01:22 -06:00
Antonio Navarro Perez
87ba73fa16 Stop writes on DEGRADED state
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-04 17:30:14 +01:00
Antonio Navarro Perez
39eacfb9a3
Merge pull request #16 from travisturner/disco-config-noder-primaryid-remove-gossip 2021-02-04 10:45:23 +01:00
Antonio Navarro Perez
add5065144
Merge pull request #13 from travisturner/disco-config-noder-primaryid 2021-02-04 10:38:15 +01:00
Travis
afc53e1163
remove ReceiveEvent 2021-02-03 23:31:38 -06:00
Travis
652014539c
remove temporary Gossiper interface 2021-02-03 23:06:51 -06:00
Travis
6e4ea21ce5
remove gossip listenForJoins 2021-02-03 22:34:45 -06:00
Travis
6a0f67278a
revert a test boolean 2021-02-03 21:44:05 -06:00
Travis
fbdca3c622
refactor the PrimaryNodeID logic 2021-02-03 20:58:25 -06:00
Alan Bernstein
8e637cc34a
Merge pull request #1390 from alanbernstein/memory-usage
CORE-162 Add memory info to /ui/usage response
2021-02-03 16:36:57 -06:00
Travis
da804ee6d5
linter fixes 2021-02-03 15:11:24 -06:00
Travis
f9661b7b81
add PrimaryNodeID() method to Noder interface 2021-02-03 15:11:24 -06:00
Kuba Podgórski
893b5ea6ab
Merge pull request #15 from kuba--/no-mu
No mu
2021-02-03 22:06:39 +01:00
Alan Bernstein
6c139935f7 Add memory info to /ui/usage response 2021-02-03 14:18:29 -06:00
Kuba Podgórski
377ef73fbd
Merge pull request #14 from kuba--/remove-cluster-state
Remove state member from cluster.
2021-02-03 19:40:22 +01:00
Kuba Podgórski
6601835ba1 Remove public mutex from Node 2021-02-03 19:37:54 +01:00
nagamocha3000
52ab7e5a99
Merge pull request #1379 from nagamocha3000/fix-core-26
Close process on fragment.openStorage error
2021-02-03 19:18:58 +03:00
nagamocha3000
92426a9d1b Close process on fragment.openStorage error
When *fragment.openStorage is invoked in both f.importValue and
f.importValueSmallWrite and it returns an error, this means there's
some underlying error with the storage device and at the point of this
commit, the sane thing to do is to close the process, otherwise the
operation of Pilosa might proceed in an inconsistent state thus
precipiatting other silent but hairy errors along the way such as
dereferencing *fragment.gen later on which is set to nil once
openStorage fails.
2021-02-03 18:47:10 +03:00
Kuba Podgórski
6826997852 Remove state member from cluster.
Remove all function SetState like. Stop broadcasting cluster state.
2021-02-03 15:16:59 +01:00
Travis
4c1d94da14
remove some dead code related to coordinator 2021-02-02 15:59:36 -06:00
Antonio Navarro Perez
c45e21640c
Change coordinator to primary
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-02-02 15:56:12 -06:00
Travis
28a19cdff7
Merge branch 'disco-config-noder' of github.com:travisturner/privilosa into disco-config-noder 2021-02-02 15:54:01 -06:00
Travis Turner
71084a0429
Merge pull request #12 from kuba--/apply-stator
Apply stator
2021-02-02 15:53:35 -06:00
Kuba Podgórski
a16a83445b Apply stator 2021-02-02 19:36:34 +01:00
Kuba Podgórski
0e34409ff0 Close etcd client after Revoke 2021-02-02 11:47:06 +01:00
Travis
91c0df29a1
remove disco debugging printlns 2021-02-01 22:28:43 -06:00
Travis
629bfa3ac8
add more AwaitState calls in the tests 2021-02-01 21:21:06 -06:00
Travis
4811958de4
add AwaitState to test which re-opens node 2021-02-01 17:34:12 -06:00
Travis
26176c15eb
fix linter issues (wrap all ClusterStates in string() until we update the type) 2021-02-01 16:57:35 -06:00
Kuba Podgórski
b611480499
disco State 2021-02-01 16:37:04 -06:00
Kuba Podgórski
6058fc22e4
Porting disco.Stator (next step) 2021-02-01 16:35:59 -06:00
Ben Johnson
c75d5553b9
Merge pull request #1373 from molecula/bench
Update keyed/unkeyed benchmarks
2021-02-01 14:39:21 -07:00
Ben Johnson
0900e7b9d2
Merge branch 'master' into bench 2021-02-01 14:10:15 -07:00
Cody Soyland
a057cc9899
Merge pull request #1375 from codysoyland/duration-header
CORE-27 Add duration header to all gRPC query results
2021-02-01 11:55:55 -06:00
Cody Soyland
0e22ed71cc
Fix instances of context.Background that need mocked context 2021-02-01 11:40:45 -06:00
Cody Soyland
c30e3f0c2d
Move duration header to fix error handling 2021-02-01 11:40:45 -06:00
Cody Soyland
e2331372d8
Handle errors 2021-02-01 11:40:45 -06:00
Cody Soyland
367425bba1
Add duration header to all gRPC query results 2021-02-01 11:40:43 -06:00
Alan Bernstein
51e41ee6b2
Merge pull request #1331 from alanbernstein/field-usage
Show disk usage broken down by field and keys
2021-02-01 11:31:29 -06:00
Travis
855e1b35f5
more use of noder; remove c.nodes
disable some of the gossip logic

implement some of the stator logic
2021-01-31 23:42:49 -06:00
Travis
97eaff5c82
use Etcd Noder; actually use EtcdWithCache 2021-01-31 23:42:44 -06:00
Travis
7ed1417893
set node metadata in server.Open() 2021-01-30 09:12:07 -06:00
Travis
457194f6a8
update config to support etcd arguments 2021-01-29 19:43:48 -06:00
Alan Bernstein
e981b162f0 Upgrade lattice 2021-01-29 17:48:24 -06:00
Alan Bernstein
1e7c4d7e8e Include metadata AKA 'other' in response 2021-01-29 17:48:24 -06:00
Alan Bernstein
5beb2664b0 Use simpler test 2021-01-29 17:48:24 -06:00
Alan Bernstein
c81ea88847 Fix total summation 2021-01-29 17:48:24 -06:00
Alan Bernstein
15443b371c Force consistent timestamp width in startup log 2021-01-29 17:48:24 -06:00
Alan Bernstein
5dc00883bd Add more involved diskUsage test 2021-01-29 17:48:24 -06:00
Alan Bernstein
703bd14048 Fix errors in usage check 2021-01-29 17:48:24 -06:00
Alan Bernstein
85fad859e2 Correct some disk usage computations 2021-01-29 17:48:24 -06:00
Ben Johnson
32a35805a4 Add RBF index/field usage stats 2021-01-29 17:48:24 -06:00
Alan Bernstein
e397d35ed5 Include roaring field and key details in usage endpoint 2021-01-29 17:48:24 -06:00
Travis
e459c9a77b
change Config.DisCo to Config.Etcd 2021-01-29 14:11:51 -06:00
Ben Johnson
ea653eb9a4
Merge branch 'master' into bench 2021-01-29 12:46:26 -07:00
Nia
20d55f0805
Merge pull request #1369 from niaow/count-global
CORE-29 Invoke pre-calls directly in count operations (fixes Count(Distinct()) on negative integers)
2021-01-29 11:20:29 -05:00
Nia
2961a69bd2
Merge branch 'master' into count-global 2021-01-29 11:14:02 -05:00
Alan Bernstein
1f87b54e5f
Merge pull request #1361 from alanbernstein/distinct-crash
CORE-32 Handle nil result in signed row translation
2021-01-29 10:13:48 -06:00
Nia
13db91379f
Merge branch 'master' into count-global 2021-01-29 10:57:46 -05:00
Alan Bernstein
c4455acbd8 Use inconsistent JSON schema to reach Distinct translation error condition 2021-01-29 09:39:31 -06:00
Alan Bernstein
4fba6bea82 Prevent nil pointer exception during Distinct key translation 2021-01-29 09:39:01 -06:00
Kuba Podgórski
9a70e15cb3
Merge pull request #1372 from travisturner/disco-groupby-fix
Fix Groupby test which uses RowKey instead of RowID
2021-01-29 11:31:11 +01:00
Travis
58ff92d3d6
Fix Groupby test which uses RowKey instead of RowID
This commit introduces a CheckGroupByOnKey function which acts like the
CheckGroupBy function, but it only ensures equality on RowKey, not
RowID.
2021-01-28 21:12:02 -06:00
Travis
1c0b926eae
Merge master into disco 2021-01-28 18:03:38 -06:00
Ben Johnson
60b6eecc7a Update keyed/unkeyed benchmarks 2021-01-28 16:36:45 -07:00
Travis Turner
92ee314891
Merge pull request #1362 from travisturner/disco-node-id
use etcd for node.ID
2021-01-28 15:26:48 -06:00
Travis Turner
1726aa137e
Merge pull request #11 from kuba--/fix-server_tests
Fix server tests
2021-01-28 14:36:02 -06:00
Kuba Podgórski
cef6925e7b Fix server tests 2021-01-28 17:39:58 +01:00
Maxton Huff
4b33a7fe16
Merge pull request #1368 from Maxtonian/mmap
Mmap limit comparison warning message for Linux
2021-01-27 10:33:43 -06:00
Maxton Huff
7d82c55274
Merge branch 'master' into mmap 2021-01-27 10:15:50 -06:00
Maxton Huff
927db378b4 add linux OS check and the way mmap limit is read 2021-01-27 09:52:13 -06:00
Nia Weiss
0d97ec559b
switch signed count distinct test to use TestVariousQueries 2021-01-27 10:29:40 -05:00
Travis
4380a05bbd
address some coord/node0 test issues 2021-01-26 22:46:37 -06:00
Matthew Jaffee
f84f43ec64
Merge pull request #1370 from travisturner/distinctset-empty-row
Return zero-bit row (with Index/Field) instead of nil in executeDistinctShardSet
2021-01-26 20:50:38 -06:00
Travis
48ac989e6a
Return zero-bit row (with Index/Field) instead of nil in executeDistinctShardSet 2021-01-26 15:47:28 -06:00
Travis
315cad679d
Return zero-bit row (with Index/Field) instead of nil in executeDistinctShardSet 2021-01-26 15:41:47 -06:00
Travis
4f47862b48
remove code which was forcing etcd logging 2021-01-26 15:40:58 -06:00
Nia Weiss
ac09c11bad
Invoke precalls directly in count operations
This changes Count(Precall()) operations to execute the precall directly inside of the count operation, bypassing the transformation to a Precomputed() call.
Eliminating the Precomputed() step causes Count(Distinct()) to work properly on negative integers.
2021-01-26 12:44:03 -05:00
Maxton Huff
8c36da9eeb Merge branch 'mmap' of github.com:Maxtonian/pilosa into mmap 2021-01-26 11:27:12 -06:00
Maxton Huff
3982a8e970 format messages and change mmap comparison logic 2021-01-26 11:26:36 -06:00
Maxton Huff
bd680ef144
Merge branch 'master' into mmap 2021-01-26 10:21:18 -06:00
seebs
89f1dfb239
Merge pull request #1367 from seebs/countRange
RBF countRange: Handle partial counts on bitmapPtr containers
2021-01-26 09:51:09 -06:00
Maxton Huff
3809fe6734 add error check 2021-01-26 09:35:51 -06:00
Travis
b80f5099b2
more coordinator/primary cleanup 2021-01-25 23:20:08 -06:00
Maxton Huff
55a9952b92 mmap limit comparison error message 2021-01-25 16:19:12 -06:00
Seebs
a238afb21a Handle BitmapPtr cells in countRange
We need to be able to count bits in BitmapPtr containers. This only
comes up if you have a non-container-aligned range count, which we
never do in real production yet, but the API allows it so it should
work. In order to do this, we need to provide the tx to countRange
so it can grab pages as needed. Arguably, we should be able to avoid
actually creating/copying that page since we're only using it
internally, never returning it, but this is a pretty rare case
and probably not performance-critical.
2021-01-25 15:41:35 -06:00
Seebs
d1a9c91a96 Test CountRange on non-container ranges.
This test was supposed to check against all the container types,
but especially bitmaps, but turns out not to work because the
containers turn into RLE containers. Oops. Now, we start with
every-other-bit for the first 8k, then start filling in the holes,
so we get some bitmap containers and then start generating
RLE containers.
2021-01-25 15:41:35 -06:00
Nia
13c63baa14
Merge pull request #1365 from niaow/groupby-cluster-rows
CORE-28 Fix GroupBy with a global Rows filter
2021-01-25 15:37:48 -05:00
Nia
60ab9e84dd
Merge branch 'master' into groupby-cluster-rows 2021-01-25 15:26:13 -05:00
Travis Turner
f5c1454a0d
Merge pull request #9 from kuba--/get-coord
Replace Node(0) by GetCoordinator
2021-01-25 14:06:39 -06:00
Kuba Podgórski
32b5c5bcea Replace Node(0) by GetCoordinator 2021-01-25 19:54:25 +01:00
Nia
ed9fc962d5
Merge pull request #1359 from niaow/intersectany-single-word-run
CORE-31 Fix intersectionAnyRunBitmap when processing single-word runs
2021-01-25 11:16:30 -05:00
Nia
70d87a7950
Merge branch 'master' into intersectany-single-word-run 2021-01-25 11:03:51 -05:00
Nia Weiss
dde318ac8c
Move globally computed GroupBy rows calls into EmbeddedData
This fixes a bug where a globally computed Rows call would be computed with a subset of the shards.
2021-01-25 10:17:58 -05:00
Ben Johnson
66bc79634b
Merge pull request #1363 from molecula/pilosa-bench-vars
Add ingest time & latency stats to query benchmarks
2021-01-25 08:16:34 -07:00
Cody Soyland
649202b081
Fix cluster size setter: expose failures 2021-01-25 10:16:19 -05:00
Ben Johnson
a30fd9957e
Merge branch 'master' into pilosa-bench-vars 2021-01-25 07:56:20 -07:00
Travis
ace4dea46f
address some test failures due to random ordered etcd ID 2021-01-25 00:52:49 -06:00
Travis
2f66501160
finish implementing snap := ClusterSnapshot() 2021-01-24 23:22:32 -06:00
Travis
1473e11a27
update test cluster GetNode() to consider the etcd-assigned ID (which affects node order) 2021-01-23 19:52:59 -06:00
Travis
a196e1e74c
use etcd for node.ID
this commit adds a temporation interface for starting gossip.
we needed this so we can start gossip AFTER setting up the node,
but before waitingForJoins.
2021-01-23 19:52:58 -06:00
Travis
208b81b5f4
fix merge error 2021-01-23 19:52:34 -06:00
Travis
c9e6f17ae0
Merge branch 'master' into disco 2021-01-23 19:22:20 -06:00
Cody Soyland
3da3d23b21
Merge pull request #1364 from codysoyland/lattice-submodule
Add git-submodule to manage UI version
2021-01-22 16:57:57 -06:00
Alan Bernstein
852057533b Add lattice submodule upgrade instructions 2021-01-22 16:51:17 -06:00
Cody Soyland
671c7262c9
Add lattice to PHONY 2021-01-22 16:26:09 -06:00
Cody Soyland
34f728521c
Add git-submodule to manage lattice version 2021-01-22 15:05:19 -06:00
Ben Johnson
acdff02fed Add ingest time & latency stats to query benchmarks 2021-01-22 11:41:44 -07:00
nagamocha3000
6c3c460c83
Merge pull request #1344 from nagamocha3000/bnm-fix-1080
Fix filtering on time fields in Rows() embedded within GroupBy
2021-01-22 19:56:08 +03:00
nagamocha3000
b5fdc6609a Update tests to remove sum column on GroupBy 2021-01-22 18:44:36 +03:00
Kuba Podgórski
2c4c722a1b
Merge pull request #1348 from travisturner/disco-storage-config
introduce storage.Config
2021-01-22 11:12:15 +01:00
Travis
19f91782e7
remove all instances of txsrc 2021-01-21 21:59:51 -06:00
Travis
13984353e4
remove instances of os.Getenv("PILOSA_TXSRC") 2021-01-21 21:18:46 -06:00
Nia Weiss
0d9179f10c
roaring: fix intersectionAnyRunBitmap when processing single-word runs
When a run started and ended within a single word, the entirety of the word would be checked.
This would cause small runs to be processed incorrectly, and caused Distinct-on-sets to select rows that did not match the specified filter.
2021-01-21 18:09:27 -05:00
nagamocha3000
16b5fbe40b
Merge branch 'master' into bnm-fix-1080 2021-01-21 17:37:08 +03:00
nagamocha3000
6cbcde3a82 Add more tests for GroupBy on Time fields 2021-01-21 16:20:46 +03:00
nagamocha3000
113bec2474 Remove unnecessary nil check 2021-01-21 15:48:52 +03:00
Travis
f292d6061a
replace pilosa.DefaultTxsrc with storage.DefaultBackend 2021-01-20 22:06:13 -06:00
Travis
08fae2be4c
introduce storage.Config 2021-01-20 22:05:38 -06:00
Alan Bernstein
b273f3ba60
Merge pull request #1327 from alanbernstein/sql-history
Include SQL string in query-history
2021-01-20 19:05:36 -06:00
Alan Bernstein
eaf3ef153e Test SQL behavior 2021-01-20 15:58:55 -06:00
Alan Bernstein
bed03ba490 Update tests 2021-01-20 10:48:35 -06:00
Alan Bernstein
a0d6c253d1 Pass SQL query string from mapper to tracker 2021-01-20 10:48:35 -06:00
Cody Soyland
06241d1f84
Merge pull request #1258 from codysoyland/distinct-failure
Test to demonstrate failure running Distinct
2021-01-20 10:37:47 -06:00
Cody Soyland
0a325dcdb8
Merge branch 'master' into distinct-failure 2021-01-19 16:50:25 -06:00
seebs
38ded7963e
Merge pull request #1342 from seebs/aggregate
Handle aggregate functions better in sql/grpc/json
2021-01-19 16:28:32 -06:00
Seebs
932e84b681 handling aggregate types: add to protobuf, etc
We want to distinguish different *kinds* of GroupCounts, so we're
making the GroupCounts parent object track its type so we can keep that
correct.

Adding this to protobuf, etc, then creates some weird behaviors
because sometimes we expect []GroupCount, and sometimes we expect
*GroupCounts. This implies changes to test cases. Also, the
changes to test cases imply that some test cases are probably now
wrong; for instance, they're expecting a "sum" column, equal to zero,
when no sum was requested.

We try to make the encoder handle a []*GroupCount gotten from another
node without panicing, and avoid breaking the semantics of the existing
messages, renumbering messages or components, etc.

Since a previous version, the `.Groups` member has been privatized,
and the `.Get()` convenience accessor has been renamed `.Groups()`
and is now used consistently in a way that should reduce the risk
of nil pointers causing crashes. Also, NewGroupCounts is used in
a couple more places.
2021-01-19 16:23:15 -06:00
Cody Soyland
4ebf6f6ff7 Customize serialization of []GroupCount based on aggregate type/presence 2021-01-19 12:10:56 -06:00
Travis Turner
07d9cbe380
Merge pull request #1345 from travisturner/disco-config
port disco config to ctl/server
2021-01-19 10:50:17 -06:00
nagamocha3000
0437f5d28a Handle case where row returned might be nil 2021-01-19 16:51:26 +03:00
Travis
f47800a920
add DisCo config to ctl/server 2021-01-18 23:47:35 -06:00
Ben Johnson
56c001d288
Merge pull request #1341 from molecula/bench-vars
Update benchmarks to use expvar URL list
2021-01-18 16:06:43 -07:00
nagamocha3000
d26c6b048e Sort all rowIDs gathered before storing them 2021-01-19 02:00:50 +03:00
nagamocha3000
9b23dcdd0a Gather rows for each fragment in a much smarter way 2021-01-19 01:44:54 +03:00
tgruben
ef05968e20
Merge pull request #1340 from jaten-molecula/noder_impl
Noder impl
2021-01-18 15:22:17 -06:00
Ben Johnson
01e6781abd Update benchmarks to use expvar URL list 2021-01-18 13:43:53 -07:00
jaten-molecula
3928b6854b
Merge pull request #1338 from jaten-molecula/etcd-listner
Etcd listener
2021-01-18 14:40:32 -06:00
Jason E. Aten
b1a0e0ae8b allow retry at the cluster level to work; remove retry for server/server.go Command.setupNetworking() that retries a single gossip node 2021-01-18 20:39:23 +00:00
Jason E. Aten
ed12f3585c etcd/embed.go implemented Noder 2021-01-18 20:30:21 +00:00
Jason E. Aten
9b635068d9 cleanup 2021-01-18 20:16:49 +00:00
Jason E. Aten
ad1c3ff3fb go mod tidy 2021-01-18 19:18:08 +00:00
Jason E. Aten
e58b464b29 add port.GetListeners 2021-01-18 18:42:21 +00:00
nagamocha3000
f51ff4dc85 Add tests for Rows() on time fields 2021-01-18 20:54:31 +03:00
Todd Gruben
766e3b90bc wip 2021-01-18 10:59:01 -06:00
Todd Gruben
de7d69234e initial listner 2021-01-18 10:34:18 -06:00
Travis Turner
d6d51705fa
Merge pull request #1334 from travisturner/disco-merge
Disco merge
2021-01-15 18:42:13 -06:00
Travis
1d55e671a2
go mod tidy and linter
fix race

cleanup
2021-01-15 17:48:44 -06:00
nagamocha3000
b77f9e8a43 Add timeFragments rowIterator 2021-01-15 23:36:54 +03:00
Travis
9855f4d0a0
Merge branch 'travis-test-ci' into disco-try 2021-01-15 14:31:19 -06:00
nagamocha3000
f91b4bc016 Add queries to test GroupBy Rows on time field 2021-01-15 22:58:18 +03:00
nagamocha3000
54d79d1e4d Populate 'places_visited' field for 'users' index 2021-01-15 22:50:54 +03:00
nagamocha3000
4dc3e49a0d Add test helper for inserting to time quantum fields 2021-01-15 22:42:37 +03:00
Jason E. Aten
8909517dfd
cluster_internal_tests use getport 2021-01-15 11:47:37 -06:00
Jason E. Aten
530fd4e768
GlobalPortMapper avoids many races in port allocation for cluster setup 2021-01-15 11:47:37 -06:00
Travis
4355bdd8f0
temporarily have cluster implement Noder 2021-01-15 11:47:37 -06:00
Travis
10380a1da1
Implement snap := ClusterSnapshot()
Below is the list of instance of `ClusterSnapshot()` in the latest
`with-etcd` code. Some of these may not yet exist in the `disco` branch,
but this commit is implementing any that currently apply.

==========================
Done:
==========================
index.go
930:	snap := NewClusterSnapshot(topo, topo.Hasher, topo.ReplicaN)
1072:	snap := NewClusterSnapshot(topo, topo.Hasher, topo.ReplicaN)

cmd/pilosa-fsck/fsck.go
786:	snap := pilosa.NewClusterSnapshot(cfg.topo, cfg.topo.Hasher, cfg.topo.ReplicaN)

boltdb/translate.go
558:	snap := pilosa.NewClusterSnapshot(topo, topo.Hasher, topo.ReplicaN)
1264:	snap := pilosa.NewClusterSnapshot(topo, topo.Hasher, topo.ReplicaN)

fragment.go
3448:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
3568:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
3620:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)

==========================
Remaining:
==========================

cluster.go
371:	snap := NewClusterSnapshot(NewLocalNoder(nodes), c.Hasher, c.ReplicaN)
474:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
639:	fSnap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
640:	toSnap := NewClusterSnapshot(to.noder, c.Hasher, to.ReplicaN)
703:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
1475:		snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
1502:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
1941:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
1986:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
2049:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
2126:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)

api.go
475:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)
604:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)
690:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)
1684:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)
1946:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)

executor.go
3781:	snap := NewClusterSnapshot(e.Cluster.noder, e.Cluster.Hasher, e.Cluster.ReplicaN)
4157:	snap := NewClusterSnapshot(e.Cluster.noder, e.Cluster.Hasher, e.Cluster.ReplicaN)
4200:	snap := NewClusterSnapshot(e.Cluster.noder, e.Cluster.Hasher, e.Cluster.ReplicaN)
4243:	snap := NewClusterSnapshot(e.Cluster.noder, e.Cluster.Hasher, e.Cluster.ReplicaN)
4517:	snap := NewClusterSnapshot(NewLocalNoder(e.Cluster.Nodes()), e.Cluster.Hasher, e.Cluster.ReplicaN)

holder.go
1465:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
1668:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
1889:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
1963:	snap := NewClusterSnapshot(c.Cluster.noder, c.Cluster.Hasher, c.Cluster.ReplicaN)
2021-01-15 11:47:37 -06:00
Travis
7875fb8e5a
remove pilosa.DefaultPartitionN 2021-01-15 11:47:37 -06:00
Jason E. Aten
dd7f0f3c88
use bbolt v1.3.5 that has fixed the checkptr bugs 2021-01-15 11:47:37 -06:00
Travis
f633fcd4ae
remove pilosa.URI 2021-01-15 11:47:36 -06:00
Travis
ff2d235702
change all references to use subpackages: topology, net 2021-01-15 11:47:36 -06:00
Travis
0add3fc7c6
fix linter and go.mod issues 2021-01-15 11:47:36 -06:00
Travis
85560323dc
add licence headers 2021-01-15 11:47:36 -06:00
Travis
b251d4c6c1
change bbolt version back to 1.3.3 2021-01-15 11:47:36 -06:00
Travis
9d8a6ad28d
add subpackages: topology, net 2021-01-15 11:47:35 -06:00
Kuba Podgórski
ba7108dedb Revert "Cleanup etcd dir"
This reverts commit 886ba15e88.
2021-01-15 17:50:34 +01:00
Kuba Podgórski
886ba15e88 Cleanup etcd dir 2021-01-15 15:41:16 +01:00
Kuba Podgórski
a4f9aee28e Set etcd log level to error 2021-01-15 14:11:48 +01:00
Kuba Podgórski
6cd8f6a970 Less TestMain_Set_Quick parallel tests 2021-01-15 13:24:41 +01:00
Kuba Podgórski
17b1eeb0d0 Increase timeout (30s) for cluster NORMAL state 2021-01-15 12:55:03 +01:00
Kuba Podgórski
64425736b0 Create disco dir outside pilosa 2021-01-15 12:30:57 +01:00
Travis
684b20edb3
disco open/close debugging 2021-01-14 23:02:58 -06:00
Kuba Podgórski
4afaaa5e25 remove zap 2021-01-14 20:59:17 +01:00
Kuba Podgórski
9a0facaaa3 set even more ports for Node Command 2021-01-14 20:20:23 +01:00
Kuba Podgórski
201e851511 set more ports for Node Command 2021-01-14 20:04:09 +01:00
Kuba Podgórski
33c4c77495 revert bind port to 0 2021-01-14 18:33:22 +01:00
Kuba Podgórski
36f17eee1d global mutex on GetPorts 2021-01-14 18:04:16 +01:00
Kuba Podgórski
a100a38b4a don't close disco on Server.Close 2021-01-14 17:47:06 +01:00
Kuba Podgórski
0e4a7a29fb close disco before holder 2021-01-14 17:35:30 +01:00
Kuba Podgórski
2713be9329 check error as string 2021-01-14 17:12:52 +01:00
Kuba Podgórski
1f6ed4feca bangbang theory 2021-01-14 16:25:44 +01:00
Antonio Navarro Perez
1a5ab4b155 Fix some more problems
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-01-14 13:10:51 +01:00
Antonio Navarro Perez
052aadb3b0 Wrap some missing constructors using ports.
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-01-14 10:48:46 +01:00
Travis
27614c42f7
Finish implementing port wrapper 2021-01-13 22:56:54 -06:00
Antonio Navarro Perez
d20b831084 Add port wrapper POC
Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2021-01-13 20:14:33 +01:00
Kuba Podgórski
61edff3eee Apply closed channel fix
45619a5b7b
2021-01-13 15:37:13 +01:00
Kuba Podgórski
4afb0ecc51 Close TCP listeneer on port mapper 2021-01-13 13:53:27 +01:00
Travis
877af6dad9
replace a MustNewCluster with MustRunCluster 2021-01-12 23:30:10 -06:00
Travis
ef8d0759d5
add retry to pg test ServerTLS() 2021-01-12 23:04:49 -06:00
Travis
f2234929d8
add retry to MustRunCluster 2021-01-12 22:09:09 -06:00
Travis
bc13834343
disco/etcd work: fix lots of races, start all cluster nodes at once.
port mapper gives out ports from 63000-65000 for the tests

fix another race

http test uses port.MustGetPort

rbf: remove :0 port request

ocd happy

test fix for grpc listener address already in use

test/disco allocates BindGRPC port from the port mapper

dump stack on each GetPort

verify each port is usable right away

server/config.go has Config.Validate() now

panic if gossip port is 0. validate server.Config

fix another gossip port 0

builds

quiet, don't dump stack on each port alloc

builds

happy linter

even gossip fallback should not be zero but rather use the port mapper
2021-01-12 21:06:12 -06:00
Ben Johnson
fbf546f131
Merge pull request #1319 from molecula/pilosa-bench 2021-01-12 16:51:27 -07:00
Ben Johnson
b7973e2612 Add read benchmarks 2021-01-12 13:48:09 -07:00
Matthew Jaffee
701d6448cc
Merge pull request #1307 from jaffee/1292-panic-groupby-int-distinct-aggregate
Fix potential panic when grouping on int field with Distinct aggregate
2021-01-08 16:38:00 -06:00
Matt Jaffee
48552553dc
guard against NPE when setting precomputed data
If a precomputed call returns a nil Row result somehow, that could
cause a nil pointer exception when handling the result in
handlePreCall.

In this particular case, A Distinct call on a BSI field with a filter
which returned no results could return a SignedRow{} with nil *Rows
inside of it. This only manifested if there was data in a single shard
as otherwise the reduce logic created a SignedRow with empty *Row
objects rather than nil ones. Isn't that fun?

Extra fun: the reason the filter was returning no results was not
because it was actually empty, but because of another bug where
constructing the Distinct calls to compute the aggregate of a GroupBy
doesn't take into account that the group might include an integer
field which means that the call needs to be constructed
differently. That bug is not fixed in this commit, hence the tests are
still failing, but not panicking.
2021-01-08 15:03:49 -06:00
Matthew Jaffee
616ba408f8
Merge pull request #1308 from codysoyland/groupby-distinct-int
Fix GroupBy Distinct aggregate on int field
2021-01-08 13:55:38 -06:00
Cody Soyland
83ce30f1c4
Fix GroupBy Distinct aggregate on int field 2021-01-08 13:35:58 -06:00
Ben Johnson
55fad52c59
Merge pull request #1306 from molecula/rbf-remove-cursor-arena
Remove RBF cursor arena.
2021-01-08 10:13:52 -07:00
Ben Johnson
489f33a173 Remove RBF cursor arena.
Previously there were two implementations of cursor reuse: sync pool &
an arena. This commit removes the arena in favor of the global pool.
2021-01-08 07:59:10 -07:00
Ben Johnson
1865de8248
Merge pull request #1301 from molecula/fix-rbf-cursor-close 2021-01-07 19:22:34 -07:00
jaten-molecula
b3854e867b
Merge branch 'master' into fix-rbf-cursor-close 2021-01-07 20:14:59 -06:00
Jason E. Aten
ecada682ae cluster_internal_tests use getport 2021-01-07 22:30:04 +00:00
jaten-molecula
0c1f2f06ba
Merge pull request #1304 from jaten-molecula/portmap
GlobalPortMapper avoids many races in port allocation for cluster setup
2021-01-07 16:24:02 -06:00
Jason E. Aten
1aabcb3d14 GlobalPortMapper avoids many races in port allocation for cluster setup 2021-01-07 22:20:49 +00:00
Cody Soyland
476767f150
Merge pull request #1285 from codysoyland/grpc-crd
Add create, read, and delete index methods to gRPC interface
2021-01-07 15:24:13 -06:00
Cody Soyland
4f57b4d07b
Remove TrackExistence configuration from gRPC CreateIndex 2021-01-07 15:19:08 -06:00
Cody Soyland
d8ebfda1bd
Undo error cause changes due to broken logic in other places, check for ConflictError explicitly 2021-01-07 14:49:18 -06:00
Travis Turner
4eb36a34f6
Merge pull request #1294 from travisturner/disco-cleanup
Disco cleanup
2021-01-07 14:08:55 -06:00
Cody Soyland
219714a18e
Fix linter problems 2021-01-07 13:50:59 -06:00
Travis
8dbfae1d86
temporarily have cluster implement Noder 2021-01-07 13:45:46 -06:00
Cody Soyland
daa8c9bd8b
Add tests for new gRPC create/get/delete calls 2021-01-07 13:05:48 -06:00
Cody Soyland
fdf5818fc2
Add create, read, and delete index methods to gRPC interface 2021-01-07 13:05:48 -06:00
Ben Johnson
93f06e0f9d Fix rbf.Cursor.Close() panic 2021-01-07 11:28:46 -07:00
Maxton Huff
17e010cca2
Merge pull request #1293 from Maxtonian/verbose-message
Fix formatting bug in verbose log message
2021-01-07 09:38:29 -06:00
Travis
134abda51b
Implement snap := ClusterSnapshot()
Below is the list of instance of `ClusterSnapshot()` in the latest
`with-etcd` code. Some of these may not yet exist in the `disco` branch,
but this commit is implementing any that currently apply.

==========================
Done:
==========================
index.go
930:	snap := NewClusterSnapshot(topo, topo.Hasher, topo.ReplicaN)
1072:	snap := NewClusterSnapshot(topo, topo.Hasher, topo.ReplicaN)

cmd/pilosa-fsck/fsck.go
786:	snap := pilosa.NewClusterSnapshot(cfg.topo, cfg.topo.Hasher, cfg.topo.ReplicaN)

boltdb/translate.go
558:	snap := pilosa.NewClusterSnapshot(topo, topo.Hasher, topo.ReplicaN)
1264:	snap := pilosa.NewClusterSnapshot(topo, topo.Hasher, topo.ReplicaN)

fragment.go
3448:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
3568:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
3620:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)

==========================
Remaining:
==========================

cluster.go
371:	snap := NewClusterSnapshot(NewLocalNoder(nodes), c.Hasher, c.ReplicaN)
474:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
639:	fSnap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
640:	toSnap := NewClusterSnapshot(to.noder, c.Hasher, to.ReplicaN)
703:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
1475:		snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
1502:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
1941:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
1986:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
2049:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)
2126:	snap := NewClusterSnapshot(c.noder, c.Hasher, c.ReplicaN)

api.go
475:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)
604:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)
690:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)
1684:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)
1946:	snap := NewClusterSnapshot(api.cluster.noder, api.cluster.Hasher, api.cluster.ReplicaN)

executor.go
3781:	snap := NewClusterSnapshot(e.Cluster.noder, e.Cluster.Hasher, e.Cluster.ReplicaN)
4157:	snap := NewClusterSnapshot(e.Cluster.noder, e.Cluster.Hasher, e.Cluster.ReplicaN)
4200:	snap := NewClusterSnapshot(e.Cluster.noder, e.Cluster.Hasher, e.Cluster.ReplicaN)
4243:	snap := NewClusterSnapshot(e.Cluster.noder, e.Cluster.Hasher, e.Cluster.ReplicaN)
4517:	snap := NewClusterSnapshot(NewLocalNoder(e.Cluster.Nodes()), e.Cluster.Hasher, e.Cluster.ReplicaN)

holder.go
1465:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
1668:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
1889:	snap := NewClusterSnapshot(s.Cluster.noder, s.Cluster.Hasher, s.Cluster.ReplicaN)
1963:	snap := NewClusterSnapshot(c.Cluster.noder, c.Cluster.Hasher, c.Cluster.ReplicaN)
2021-01-06 22:53:20 -06:00
Travis
3f26d667b4
remove pilosa.DefaultPartitionN 2021-01-06 22:45:44 -06:00
jaten-molecula
a6bf52d753
Merge pull request #1290 from travisturner/disco-subpackages
add subpackages: topology, net
2021-01-06 17:23:56 -06:00
Jason E. Aten
6a845f1de1 use bbolt v1.3.5 that has fixed the checkptr bugs 2021-01-06 23:19:53 +00:00
Travis
20816ffa20
remove pilosa.URI 2021-01-06 16:19:14 -06:00
Travis
4515a24e48
change all references to use subpackages: topology, net 2021-01-06 16:09:24 -06:00
Maxton Huff
d10e45648b change f.path to f.path() 2021-01-06 15:58:01 -06:00
Travis
f8e6115c0e
fix linter and go.mod issues 2021-01-06 15:01:50 -06:00
Travis
2c1a019c9e
add licence headers 2021-01-06 14:42:28 -06:00
Travis
bd989f464a
change bbolt version back to 1.3.3 2021-01-06 13:26:35 -06:00
Travis
0da35fb72b
add subpackages: topology, net 2021-01-06 13:21:36 -06:00
Matthew Jaffee
d6cba17a01
Merge pull request #1274 from jaffee/generalized-groupby-sort-2
Add ability to sort on count or aggregate in GroupBy. Fix bug with offset being unsupported. Fix bugs with limit interacting poorly with other arguments.
2021-01-05 09:41:18 -07:00
Matt Jaffee
216e28a77e
add getSorter tests, fix bugs 2021-01-05 09:54:46 -06:00
Matt Jaffee
6dccb3d6be
remove (unused) sorting code related to fields, add comments 2021-01-03 08:34:53 -06:00
Matt Jaffee
6094663e7a
fix bug with "having" and "limit" in GroupBy
the limit could get applied before "having" in some cases which could
result in results being discarded which met the having condition while
results were kept which did not, ultimately resulting in GroupBy
falsely reporting fewer results than actually existed.
2021-01-01 21:56:59 -06:00
Matt Jaffee
ea539d8241
simplify groupby sorting and fix bugs
Back out support for sorting on fields (only count and aggregate
supported for now).

Fix bug where default return of "true" caused sort to be unstable. (If
they are equal, Less should return false)

Fix bug where limit was being applied before sorting.

Fix bug where offset was not actually allowed to be an argument to
GroupBy (weird! guess we weren't testing that very well)

Apply "having" after calculating Count(Distinct) aggregate so that
having can apply to that.

Switch to stable sort to make testing easier.
2020-12-31 14:42:03 -06:00
Matt Jaffee
5fdae74812
draft of sorting groupby results 2020-12-31 14:41:52 -06:00
Matthew Jaffee
46bbff786e
Merge pull request #1245 from codysoyland/groupby-aggregate-distinct
Add Distinct call as GroupBy aggregate
2020-12-30 10:05:37 -07:00
Matt Jaffee
16fd6a7edd
add tests for GroupBy(Distinct), fix various problems
We execute the aggregate Distinct calls after the GroupBy is complete,
and we need these to act like non-remote calls in that they forward to
all nodes, but like remote calls in that they bypass key
translation. Added a "PreTranslated" flag to the QueryRequest to
achieve this.

Discovered an issue where a nil *Row in EmbeddedData would cause a
panic in the protobuf serialization. Changed the encoding code we
control to never pass a nil *Row.

Got fed up with lack of context on errors and added wrapping to all
calls under executor.executeCall as well as a few other places.

Handled a situation where not having data on a shard for a particular
field could cause a query to error instead of just treating that
fragment as being empty. (see the switch in executeDistinctShardSet)

Stopped GroupBy from executing the Count(Distinct) aggregate on Remote
calls.

Fixed a longstanding issue where errors retrieved from remote query
calls had a garbage character at the front due to treating a protobuf
payload as an error message instead of decoding it. (see
http/client.go)
2020-12-30 08:13:41 -06:00
Cody Soyland
fd7417a49b
Use shardwidth instead of hardcoded value 2020-12-30 08:12:09 -06:00
Cody Soyland
f099a90264
Modify aggregate distinct logic and add tests
Use execute instead of directly using executeCount
Address code review feedback (add additional filters if provided)
Add basic tests
2020-12-30 08:12:09 -06:00
Cody Soyland
b435e9d793
Add Distinct call as GroupBy aggregate 2020-12-30 08:12:08 -06:00
Matthew Jaffee
fd3a423342
Merge pull request #1248 from jaffee/make-tests-more-robust
fix test failures in case of running Pilosa on system
2020-12-29 15:46:19 -07:00
Matt Jaffee
bed2cffd5e
fix test failures in case of running Pilosa on system
If you're running a Pilosa with mostly default configuration on your
system, some of these tests would fail due to things like port
conflicts. These changes address the most common failures.
2020-12-29 13:57:18 -06:00
Cody Soyland
1fa2a65c0b
Test to demonstrate failure running Distinct 2020-12-28 16:50:06 -06:00
Matthew Jaffee
4447d6fa76
Merge pull request #1261 from jaffee/some-distinct-bugs
fix Count(Distinct) bug and add better tests
2020-12-28 15:24:50 -07:00
Matt Jaffee
1ed91ebad3
simplify error messages
also remove test which was accidentally committed
2020-12-28 16:06:40 -06:00
Matt Jaffee
790bea147f
make view and fragment not found errors constant
based on code review feedback
2020-12-28 15:59:49 -06:00
Matt Jaffee
a3b07ff519
re-add log line which has more utility than I thought
From Nia:
While debugging the Q2 bugs this was somewhat useful in analyzing cluster events. As for the spammy part. . . that seems to be more of an issue with spamming our resets than an issue with the log itself.
2020-12-28 15:30:38 -06:00
Matt Jaffee
21c67352af
remove paranoia mode in top level Pilosa 2020-12-28 15:25:13 -06:00
Matt Jaffee
757c8a86b5
add comments, simplify tests, move ToCSV code
generally, address code review feedback
2020-12-28 15:22:31 -06:00
Matt Jaffee
27ca9dab36
don't hide error getting sign bitmap 2020-12-28 11:14:04 -06:00
Matt Jaffee
446950979a
fix potential nil dereference in SignedRow.ToRows
This used to be possible to hit, but I think now that Distinct on a
set field returns a *Row rather than a SignedRow it isn't an issue. (I
wasn't able to trigger it in the tests). Adding the fix anyway as it
seems safer than not.

The rest of the changes are test infrastructure to make it easy to
call GRPC queries and verify the results as CSV.
2020-12-28 11:00:46 -06:00
Matt Jaffee
1372bafe02
fix bugs where row index and field weren't always being propagated
I used a "paranoia" check to find these, but then realized the check
had a ton of false positives and doing it properly wasn't going to be
straightforward. I'm leaving the paranoia stuff in unless there are
objections, because I've wanted it before and not had it.

I also removed a log line that is very verbose and I don't think helps
anyone.
2020-12-23 19:08:10 -06:00
Matt Jaffee
427e9cb538
fix executor tests which were expecting a signedrow from Distinct 2020-12-23 15:33:15 -06:00
Matt Jaffee
6ff6fa7bb8
fix comments/capitalization 2020-12-23 14:44:18 -06:00
Matt Jaffee
9ee5f52a11
fix some Distinct key translation issues (e.g. empty index)
This commit changes executeDistinct to return either a *Row or a
SignedRow (instead of only being able to return a SignedRow). Distinct
on a set field will return a *Row while an int field will still return
a signed row.

We then add Field and Index fields to the Row object so that we can
determine how to translate the rows IDs to keys (if needed). This adds
a lot of logic around the translation which fixes bugs where Distinct
calls would fail to get translated.

There are, I think, still issues if you were to try to join a keyed
field to a keyed index which wasn't explicitly specified as the
field's foreign index. The IDs in the field wouldn't be using the same
translation as the IDs in the index, so the query might appear to work
but give incorrect results.
2020-12-23 14:37:03 -06:00
Matt Jaffee
385381e5f3
fix issue where a shard with no data can cause query to fail
add Distinct test with integer data, and because one of the records
had a null value (and was in a shard by itself), it uncovered this
issue. I added a special error type if a view or fragment is not found
when so that we can match against it and ignore it when calculating
the results for a query.

I also added an implementation within executeCount to handle the
SignedRow case, but discovered that handlePrecalls always dumps the
negative data and that will be a bigger thing to fix
2020-12-23 14:37:03 -06:00
Matt Jaffee
121f3fb610
fix Count(Distinct) bug and add better tests
the Distinct call would get precomputed correctly, but then the
executeCount would happen in the available shards context of the
index. So if the index only had records in (e.g.) shards 10,12,18,22,
and all the values of the Distinct call were in shard 0, you'd see 0
results.

The fix skips the whole map/reduce step of executeCount (which was
basically fake anyway when the argument is precomputed), and just adds
up all counts of all the precomputed segments.

This currently won't properly count Distinct values from an int field
which contains negative numbers... going to add a test and fix for
that next.

There is also still a key translation bug which is why the one test
case is commented out... fix coming for that soon as well.
2020-12-23 14:37:03 -06:00
Ben Johnson
fc7f7d6a7c
Merge pull request #1260 from molecula/bench-1month 2020-12-22 09:42:55 -07:00
Ben Johnson
02c4c1dff4
Merge branch 'master' into bench-1month 2020-12-22 08:51:18 -07:00
Ben Johnson
c189cb8e81
Merge pull request #1259 from molecula/bench-chmod-x
Make scripts/bench.sh executable
2020-12-22 08:51:03 -07:00
Ben Johnson
64f2ff6b78 Change benchmark script to test against GH 1 month of data 2020-12-22 08:10:29 -07:00
Ben Johnson
34c46cf084 Make scripts/bench.sh executable 2020-12-22 07:44:43 -07:00
tgruben
4b36805190
Merge pull request #1254 from jaten-molecula/migration_speedup
smaller batches of write Tx help boost migration speed
2020-12-21 13:28:31 -06:00
Jason E. Aten
1efff0c99b smaller batches of write Tx help boost migration speed 2020-12-21 19:00:13 +00:00
tgruben
e290e13d0b
Merge pull request #1252 from jaten-molecula/minimal_view_opening
pilosa: only open views with data
2020-12-18 18:41:44 -06:00
jaten-molecula
264f4382d5
Merge branch 'master' into minimal_view_opening 2020-12-18 18:19:24 -06:00
Ben Johnson
2d35f0d96a
Merge pull request #1243 from molecula/nightly-benchmark
Add nightly benchmark script.
2020-12-18 17:18:36 -07:00
jaten-molecula
94c38a59af
Merge branch 'master' into nightly-benchmark 2020-12-18 18:09:35 -06:00
Jason E. Aten
035073555a pilosa: only open views with data
- Previously, on timequantum schemas, we would
create and open a view for the cartesian
product of every possible view and shard.

- This caused us to be very slow on re-open,
and to use lots of memory for views that
held nothing.

- This change makes startup faster, memory
use much lower, and should speed migration.
2020-12-19 00:03:31 +00:00
Matthew Jaffee
7b6c6303ce
Merge pull request #1246 from jaffee/1242-createdAtBug
Fix field "createdAt" race by sending schema changes to coordinator
2020-12-18 12:06:29 -07:00
Ben Johnson
d635ece5a9 Add workflow name to benchmark 2020-12-18 09:33:50 -07:00
Matt Jaffee
b8cbd54d1b
forward all CreateIndex/CreateField requests to coordinator
this should avoid a race condition with CreateField where createdAt
can get out of sync if there are multiple concurrent requests.

The client methods didn't allow specification of the URI, so I
modified the implementation to find the coordinator and send to it
explicitly.
2020-12-18 10:16:46 -06:00
Matt Jaffee
58b9418f3c
add failing test for field creation race 2020-12-17 16:30:23 -06:00
Ben Johnson
cfdc7f4c63 Add nightly benchmark script.
This commit adds a script for executing a nightly benchmark and posting
the results to Slack.
2020-12-17 09:23:40 -07:00
jaten-molecula
513743f30d
Merge pull request #1241 from jaten-molecula/tests_for_NewBitmapBitmapFilter
add tests for NewBitmapBitmapFilter constructor
2020-12-16 21:39:18 -06:00
Jason E. Aten
0db4914bc4 add tests for NewBitmapBitmapFilter constructor
- document sort.Stable need
2020-12-17 00:27:34 +00:00
seebs
ad35f11a27
Merge pull request #1208 from seebs/fastRows2
Performance improvements for transactional backends scanning fragments
2020-12-16 17:14:54 -06:00
jaten-molecula
5b43513063
Merge branch 'master' into fastRows2 2020-12-16 17:09:46 -06:00
Seebs
cc5e822799 fix comment, remove unneeded step
It turns out NewSliceBitmap can take an initial set of values
already.
2020-12-16 17:00:34 -06:00
Nia
26ab79ecb8
Merge pull request #1238 from niaow/fix-snapshot-queue
Fix automatic snapshot queue enable check
2020-12-16 17:01:09 -05:00
jaten-molecula
6263f0bcfd
Merge branch 'master' into fix-snapshot-queue 2020-12-16 13:45:04 -06:00
Seebs
4ddbadcea7 review issues: fix unclearSets (now sliceDifference) and prune/fullPrune
unclearSets was completely broken and I have no idea why the test I thought
was testing it didn't actually catch that problem. Added unit tests and fixed
the logic. Improved/clarified prune and fullPrune, and unexported their
names because why export methods on an unexported type.

Also improve some comments and rename a variable or two to improve clarity.
2020-12-16 13:18:18 -06:00
Seebs
0952db5af7 Add (temporary, perhaps) locking on TestTx_CountRange
On roaring, CountRange needs to have exclusive access to a fragment, but
doesn't currently require a lock, because it's usually used from inside
other already-locked things.
2020-12-16 13:18:18 -06:00
Seebs
de14762661 create Tx tests for CountRange
CountRange for RBF had a subtle bug which wasn't noticed, so, let's
have some CountRange testing and also a benchmark.

We also fix a couple of subtle bugs caught in the process of developing
and testing this.

SliceContainers will allow nil containers, but doesn't return them when
iterating because there's various things that can panic if called on a nil
container. Since countEmptyContainers() has to traverse the whole bitmap
anyway, it doesn't matter which it counts, so we replace it with
countNonEmptyContainers(), and adjust test cases accordingly. This fixes
an issue where if roaring is smart enough to insert a nil container
into a SliceContainers, trying to write it to a file produces an invalid
bitmap with offsets off by 16 and one container fewer than its header predicts.

RBF: don't try to count 0 bits in a container

If we're to the "last container", and we'd be counting all the bits less than
zero, we can skip that. This avoids hitting a bug, which is that c.countRange
doesn't handle BitmapPtr.
2020-12-16 13:16:46 -06:00
Seebs
17c24c236a don't try to use the rowCache for CountRange
Several issues:
1. tx.frag could be non-nil but not the fragment requested.
2. start and end need not be exact row boundaries.
3. therefore this could be returning the count of the row containing
"start", for a fragment other than the one requested.
4. also in fact the rowcache wasn't populated before this so in one
memory profile, this function alone was responsible for nearly
100GB of cached values...
2020-12-16 13:16:46 -06:00
Seebs
dec0a00155 add container N to ConsiderKey 2020-12-16 13:16:46 -06:00
Seebs
23e16474ae use ApplyFilter instead of roaring.ApplyFilterToIterator
In some cases, ApplyFilter can be significantly faster. On the other hand, it doesn't
matter as much as you might think on the mutex imports, because we've already sucked
most of the time out of those.
2020-12-16 13:16:46 -06:00
Seebs
e4e94a5668 prevent weird rare failures in mutex imports
Added additional mutex sample data and batches of it so we can
confirm that overwrite works. It didn't work, so that needed to be fixed.

Couple of things:
(1) Wasn't updating "last value seen" so the check for an unsorted list
didn't work.
(2) Also didn't handle the case where there were to-clear values higher
than any to-set value.

This could result in bits not getting cleared, which could result in
there being more than N bits to clear for N new bits. And that could cause
really strange problems when the input slices were parts of a single
larger slice, because bit positions to clear could get shoved in as
possible columns in a future batch.
2020-12-16 13:16:46 -06:00
Seebs
e99744c8da Do benchmarks with read-only Tx after committing write sometimes
For the Rows benchmark, we were continuing to use the original writable
transaction, meaning RBF was spending all its time looking up dirty
pages in the transaction's dirty page cache rather than working with
the disk in any way. It wasn't clear whether this was hurting or
helping performance, but it was clear that it wasn't testing the
"real" workload use case, where queries are done against the RBF
file rather than the dirty page cache.

Modify the benchmark to test it both ways for comparison. Answer:
The RBF file is faster than the in-memory map (!).
2020-12-16 13:16:46 -06:00
Seebs
9b13ab7dd3 use readLeafCellKey to read a leaf cell's key 2020-12-16 13:16:46 -06:00
Seebs
dc67149326 read leaf cells through a pointer
This reduces noticably the cost of reading leaf cells, by passing
a single pointer down the stack instead of the entire data structure
up the stack. It's only a few percent overall, but it's noticeable.
2020-12-16 13:16:46 -06:00
Seebs
7c415b4217 Implement rbf-specific ApplyFilter
This gives RBF an ApplyFilter that can run without instantiating containers
when the filter it's using doesn't need them instantiated. We can also seek
ahead in cases where we know the next key we care about is not just the next
key numerically.
2020-12-16 13:16:46 -06:00
Seebs
2c4aff2d18 add benchmarks for f.rows()
This is a simplistic benchmark for f.rows() to let us evaluate its performance
in preparation for trying to do some profiling and tuning.
2020-12-16 13:16:46 -06:00
Seebs
30d5f891c0 create naive ApplyFilter 2020-12-16 13:16:46 -06:00
Seebs
59d89dda99 Allow arbitrary and potentially more efficient filtering of bitmaps
This is a partial solution to a nasty performance problem, which is that
a ContainerIterator has to *generate* all the containers. With roaring, this
was cheap because they already exist in memory; with transactional backends,
it's an allocation per container, *even for the containers we don't use*.

This design admits filters which can distinguish between answers they
can give just based on keys and times when they actually need containers
instantiated, and can also give hints as to future answers -- saying "yes"
or "no" to entire rows at a time, or indicating when they're done.

This is only part of the solution; we also need a Tx API hook for
doing scans like this which doesn't rely on ContainerIterator.
2020-12-16 13:16:46 -06:00
jaten-molecula
440b90f3c8
Merge pull request #1240 from jaten-molecula/roaring_printutil
roaring: print utility AsContainerMatrixString for diagnostics
2020-12-16 13:02:47 -06:00
Jason E. Aten
1a6f573739 roaring: print utility AsContainerMatrixString for diagnostics
AsContainerMatrixString returns a string showing
 the matrix of rows in a shard, showing the count of hot (1) bits
 in each container.
2020-12-16 18:50:45 +00:00
Nia Weiss
eab70e2314
use the txf to determine if snapshots are needed 2020-12-16 11:00:27 -05:00
Nia Weiss
aaf94c6aeb
fix the automatic snapshot queue enable check
The "needs snapshot queue" check was broken, as it only checked inside a loop over indices.
If there are no indexes yet (or more likely if the indices have not yet been loaded off of disk), then this would never use the snapshot queue on roaring.
2020-12-16 08:15:17 -05:00
Cody Soyland
87bf0df786
Merge pull request #1234 from codysoyland/rbf-usage-calc
Fix disk usage calculation in RBF backend
2020-12-15 15:57:17 -06:00
Cody Soyland
4cb21da6e9 Fix disk usage calculation in RBF backend 2020-12-15 13:39:27 -06:00
Cody Soyland
765bac992d
Merge pull request #1225 from codysoyland/upgrade-gopsutil
Upgrade gopsutil
2020-12-14 11:36:07 -06:00
Cody Soyland
5eb726ce59 Upgrade gopsutil 2020-12-14 10:58:28 -06:00
tgruben
3beaed1645
Merge pull request #1220 from jaten-molecula/avoid_dynamic_dispatch
FragSpec as struct, fragment fields to avoid dynamic dispatch
2020-12-14 09:21:57 -06:00
Jason E. Aten
b254c6776b FragSpec as struct, fragment fields to avoid dynamic dispatch
- allow inlining of getters index(), view().
 - GOMAXPROCS set to 128
2020-12-12 16:39:24 +00:00
tgruben
b0755577b3
Merge pull request #1218 from jaten-molecula/short_txkey
short_txkey elides index and shard from the txkey
2020-12-11 17:30:40 -06:00
Jason E. Aten
b52a814b3c short_txkey elides index and shard from the txkey
- use short_txkey for rbf
 - short_txkey breaks a bunch of bolt_test.go, so leave it on (long) txkey for now.
 - remove SliceOfShards method from Tx interface
2020-12-11 22:24:56 +00:00
tgruben
c5302f2f57
Merge pull request #1212 from tgruben/fragment-refactor
Fragment refactor (wip)
2020-12-11 15:08:19 -06:00
Todd Gruben
8ad7afbe43 FragProxy reduces string memory consumption drastically
for datasets with lots of views, because we don't
replicate path, index, field, view strings so often.
2020-12-11 21:01:15 +00:00
jaten-molecula
30502c99ab
Merge pull request #1214 from jaten-molecula/readwrite_locks
use tx.mu.RLock for OffsetRange, Lock for AddRoaring
2020-12-11 08:13:52 -06:00
Jason E. Aten
2b569b1edf use tx.mu.RLock for OffsetRange, Lock for AddRoaring 2020-12-11 13:53:27 +00:00
tgruben
f5e656138f
Merge pull request #1211 from jaten-molecula/skip_serz_1node
avoid serializing for sync shards in 1 node cluster situation
2020-12-10 17:16:10 -06:00
Jason E. Aten
7571792401 avoid serializing for sync shards in 1 node cluster situation 2020-12-10 20:54:32 +00:00
Maxton Huff
8c20255b12
Merge pull request #1210 from Maxtonian/lonquerytime2
deprecate cluster.long-query-time and create long-query-time
2020-12-10 11:14:09 -06:00
Maxton Huff
dee700741a deprecate cluster.long-query-time and create long-query-time
moved lonquerytime from cluster into server and moved cluster.longquerytime into top level config
kept cluster.longquerytime for backwards compatibility, favored if both longquerytime options are present
2020-12-10 10:51:31 -06:00
tgruben
087418566b
Merge pull request #1204 from jaten-molecula/clear_cursors
reset cursor stacks before reuse
2020-12-09 19:01:08 -06:00
jaten-molecula
21cb390d2f
Merge branch 'master' into clear_cursors 2020-12-09 17:01:21 -06:00
Jason E. Aten
81b9586a4b reset cursor stacks before reuse 2020-12-09 21:41:41 +00:00
Cody Soyland
1990ecf2b6
Merge pull request #1205 from codysoyland/docker-build-make
Use "make" inside docker build so that CGO_ENABLED uses exported value from Makefile
2020-12-09 15:02:04 -06:00
Cody Soyland
f351b7efa6 Use "make" inside docker build so that CGO_ENABLED uses exported value from Makefile 2020-12-09 13:21:07 -06:00
Cody Soyland
1add244f8a
Merge pull request #1201 from codysoyland/default-roaring
Default TxSrc to roaring
2020-12-09 09:36:28 -06:00
Cody Soyland
c1fe8b214a Default TxSrc to roaring 2020-12-09 09:31:40 -06:00
Cody Soyland
53f6a127af
Merge pull request #1198 from codysoyland/docker-build-test
Disable cgo on all builds, add additional tests for docker
2020-12-09 09:17:03 -06:00
Cody Soyland
5d18c0af2b Enable cgo on test -race 2020-12-09 09:00:03 -06:00
Cody Soyland
bc94c7bcdf Remove lmdb dependency and references, vendor Barrier 2020-12-09 08:43:23 -06:00
Cody Soyland
eef6359db3 Disable cgo on all builds, add additional tests for docker 2020-12-08 19:42:51 -06:00
tgruben
d05531b77a
Merge pull request #1197 from jaten-molecula/rowcache_off_by_default
rowcache off by default. pilosa server --rowcache-on turns it back on.
2020-12-08 19:32:19 -06:00
Jason E. Aten
03a54c6d5f rowcache off by default. pilosa server --rowcache-on turns it back on. 2020-12-08 23:18:45 +00:00
tgruben
d4d30e160b
Merge pull request #1196 from jaten-molecula/diagn
pilosa debugstats and rbf tooling for enhanced debugging/diagnostics
2020-12-08 16:58:54 -06:00
Jason E. Aten
82d07bc123 debugstats and rbf tooling for enhanced debugging/diagnostics 2020-12-08 22:47:40 +00:00
tgruben
9f7fa7eaad
Merge pull request #1195 from jaten-molecula/rbf_doc
document pattern of branch splits
2020-12-08 16:19:56 -06:00
tgruben
63d67ac65e
Merge branch 'master' into rbf_doc 2020-12-08 15:52:46 -06:00
tgruben
662073c284
Merge pull request #1194 from jaten-molecula/fix_freepageset
fix bug in pgno computation in freePageSet
2020-12-08 15:52:25 -06:00
Jason E. Aten
cbff5bd29d document pattern of branch splits 2020-12-08 20:50:29 +00:00
Jason E. Aten
96abbfa059 fix bug in pgno computation in freePageSet 2020-12-08 20:45:54 +00:00
Cody Soyland
bd060b6fd2
Merge pull request #1191 from codysoyland/docker-disable-cgo
Dockerfile: switch back to alpine and disable cgo
2020-12-07 10:07:56 -06:00
Cody Soyland
2bd27cdf5e Upgrade alpine and disable cgo 2020-12-07 09:26:52 -06:00
Cody Soyland
5d08d54518 Revert "ubuntu 20:10 image instead of alpine, for cgo support"
This reverts commit ef156f6172.
2020-12-07 09:26:52 -06:00
Nia
8a6d20d314
Merge pull request #1168 from niaow/pilosa-id-gen
Add ID auto-generation on the coordinator
2020-12-07 09:58:13 -05:00
Nia
a4f538ffec
Merge branch 'master' into pilosa-id-gen 2020-12-07 09:46:58 -05:00
Nia
2a863e5c13
clarify OptServerOpenIDAllocator
Co-authored-by: Matthew Jaffee <matthew.jaffee@gmail.com>
2020-12-07 08:08:51 -05:00
jaten-molecula
d38184a5ff
Merge pull request #1183 from jaten-molecula/rm_lmdb
remove lmdb as tx backend
2020-12-04 17:32:15 -06:00
Jason E. Aten
7a9e0969cb remove lmdb as a Tx backend
- test only still uses a Barrier utility from the go-lmdb package;
  it could be ported in at some point.
2020-12-04 23:17:59 +00:00
Cody Soyland
4f14774883
Merge pull request #1174 from codysoyland/query-timing
Add query duration to gRPC responses
2020-12-04 15:47:03 -06:00
Cody Soyland
fc3b64e500 Add table conversion to duration timing 2020-12-04 15:19:12 -06:00
Cody Soyland
c33eafc27e Add tests for streaming queries 2020-12-04 15:19:12 -06:00
Cody Soyland
6830657d12 Add query duration to gRPC responses
This adds a "duration" parameter to RowResponse and TableResponse, which
will be populated with the query duration in nanoseconds.

For QueryPQLUnary and QuerySQLUnary, the duration is a included in the
returned TableResponse.

For QuerySQL and QueryPQL, only the first RowResponse in the stream will
contain the duration.
2020-12-04 15:19:12 -06:00
Ben Johnson
26789ef0b5
Merge pull request #1163 from molecula/page-pool
Add sync.Pool for RBF pages
2020-12-04 08:08:11 -07:00
Nia Weiss
7ea2e4b7e3
add ID auto-generation on the coordinator 2020-12-03 13:04:14 -05:00
Ben Johnson
79e6156003 Add sync.Pool for RBF pages 2020-12-03 07:32:36 -07:00
Ben Johnson
1ce15a51c9
Merge pull request #1157 from molecula/put-leaf-cell-faster 2020-12-01 15:49:16 -07:00
jaten-molecula
836540151b
Merge branch 'master' into put-leaf-cell-faster 2020-12-01 16:24:09 -06:00
tgruben
dd856378d1
Merge pull request #1156 from jaten-molecula/container_key_span
RoaringIterator.ContainerKeySpan method
2020-12-01 16:22:57 -06:00
Ben Johnson
df958f40dd Optimize putLeafCellFast() 2020-12-01 12:12:54 -07:00
jaten-molecula
53b64bd939
Merge branch 'master' into container_key_span 2020-12-01 09:15:11 -06:00
Matthew Jaffee
c8c7b98654
Merge pull request #1142 from alanbernstein/update-ui-paths
Maintain list of frontend routes, update 'vds' to 'tables'
2020-12-01 07:42:50 -07:00
Jason E. Aten
6f4ca78bc4 RoaringIterator.ContainerKeySpan method
- enables rbf ingest optimization. When we know there won't be
   updates involved we can bulk import faster.
2020-12-01 01:52:58 +00:00
Alan Bernstein
4dc38bee02 Maintain list of frontend routes, updates 'vds' to 'tables' 2020-11-25 13:30:28 -06:00
Nia
df13c72351
Merge pull request #1145 from niaow/err-id-on-keyed
Report an error when an ID is used on a keyed field
2020-11-25 13:48:04 -05:00
Nia Weiss
353fd3937d
report an error when an ID is used on a keyed field 2020-11-25 11:37:18 -05:00
Alan Bernstein
9e3e0a6be7
Merge pull request #1013 from alanbernstein/query-activity-api
Add query history endpoint
2020-11-24 08:46:43 -06:00
Alan Bernstein
65877c1e56 Store start instead of age, skip remote, fix timing bug 2020-11-23 21:31:40 -06:00
Alan Bernstein
0c8e4afe45 Set test nodeIDs to guarantee iteration order in executor 2020-11-23 20:23:28 -06:00
Alan Bernstein
a8a7e53382 Add query-history test 2020-11-23 20:23:28 -06:00
Alan Bernstein
c5a7a259aa Make minor fixes to query tracker 2020-11-23 20:23:28 -06:00
Alan Bernstein
2bc2a32263 Make query history length configurable 2020-11-23 20:23:27 -06:00
Alan Bernstein
b172f4d05b Include index in query history response 2020-11-23 20:23:27 -06:00
Alan Bernstein
542a6ffdb6 Gather query history from remote nodes 2020-11-23 20:23:27 -06:00
Alan Bernstein
bbd147d18f Replace query history map with ringBuffer 2020-11-23 20:23:27 -06:00
Alan Bernstein
65de5df2a9 Update tracker test 2020-11-23 20:23:27 -06:00
Alan Bernstein
c94d242097 Add basic implementation of query history endpoint 2020-11-23 20:23:27 -06:00
seebs
55d0c12703
Merge pull request #1131 from seebs/randomerQuery
Improve random-query
2020-11-23 11:58:53 -06:00
Seebs
3d802f428b add Distinct, be more consistent about using correct rand.Rand
The RandomQueryConfig has its own seeded RNG, but we didn't always use
it (especially in the last two commits, but also I think in one previous
thing), so let's use it more consistently.

We check for int fields (as opposed to decimal), and if we find them,
we add Distinct to our list of potential queries to use if and only
if we've got a depth of at least one so there'd be a child query under
the current query, and if we do, grab one of the int (not decimal)
fields and do a query on that.
2020-11-23 09:54:59 -06:00
Seebs
796d646a0c handle integer fields
Extend field handling to include int (and decimal) fields, allowing them
to have range operations specified on them.
2020-11-23 09:51:29 -06:00
Seebs
2a2a8abbd4 support time fields
For time fields, allow specifying a range of times, then 19/20 times,
specify "from" and "to" times in that range when querying those fields,
rather than just looking at the standard view all the time.
2020-11-23 09:51:29 -06:00
Seebs
48b97d6ad4 report QPS after last query
More generally, report QPS not at 0 queries, which is boring, but every
100 queries *and* after the last query if the last query wasn't at a
multiple of 100 queries. Makes the output slightly more useful, I think.
2020-11-23 09:51:29 -06:00
Matthew Jaffee
7271fbf396
Merge pull request #1015 from alanbernstein/dont-create-keys-directory
Check index.keys before opening translate store to avoid unnecessary keys directory
2020-11-20 14:30:37 -07:00
Matt Jaffee
a48bf28be2
don't try to translate keys on unkeyed indexes
this causes a few things to error earlier than they otherwise would
have, hence the changed tests.
2020-11-20 14:48:28 -06:00
Alan Bernstein
063a3b96e3
Check index.keys before opening translate store 2020-11-20 12:43:15 -06:00
Nia
106952dc5e
Merge pull request #1106 from niaow/topk-time
TopK on time
2020-11-20 13:24:05 -05:00
Nia
c8ab2a9fb3
Merge branch 'master' into topk-time 2020-11-20 13:11:51 -05:00
Nia Weiss
d7b9568960
add licesnse header to bsi_test.go 2020-11-20 12:40:28 -05:00
Nia Weiss
410a372351
clarify bsi-building preconditions 2020-11-20 12:38:53 -05:00
Nia Weiss
f9c196e418
skip roaring add test in race
Otherwise it overloads the race detector.
2020-11-20 12:16:09 -05:00
tgruben
72f4024e99
Merge pull request #1122 from jaten-molecula/inlined_immutable_map_rb
rbf: use an inlined immutable.Map<uint32, int64> for the PageMap
2020-11-20 10:44:44 -06:00
Nia Weiss
5d2c42b7bf
address documentation todo in pivotDescending 2020-11-20 11:13:44 -05:00
Matthew Jaffee
64b83137a0
add tests for addBSI 2020-11-20 11:07:30 -05:00
Nia Weiss
46818863e8
implement TopK on time
This replaces the former TopK BSI building algorithm, as the row cache was too expensive.
Additionally, BSI addition has been optimized with specialized adders inside of roaring.
2020-11-20 11:06:55 -05:00
Jason E. Aten
e1bb6e303a rbf: use an inlined immutable.Map<uint32, int64> for the PageMap
- goes 7% faster on kitchen sink import test

- reduces total allocations by 5% on same test.
2020-11-20 00:49:41 +00:00
jaten-molecula
47202b0ed2
Merge pull request #1095 from molecula/fast-write
Implement optimized fast leaf write.
2020-11-19 16:04:31 -06:00
Ben Johnson
a9831ad5a1 Replace literals with leafCellHeaderSize 2020-11-19 14:18:53 -07:00
Ben Johnson
d125c68275 Fix estimated page size calculation to include index padding. 2020-11-19 14:12:43 -07:00
Ben Johnson
33334511c4
Merge branch 'master' into fast-write 2020-11-19 13:44:09 -07:00
jaten-molecula
5b8cda3c88
Merge pull request #1120 from molecula/fix-root-record-overflow
Fix rbf write root record iterator reset
2020-11-19 13:11:09 -06:00
Ben Johnson
a31487b873 Fix rbf write root record iterator reset 2020-11-19 11:15:24 -07:00
jaten-molecula
61bdc2257b
Merge pull request #1111 from jaten-molecula/sync_pool
rbf: reuse cursors with sync.Pool/arena
2020-11-19 11:17:20 -06:00
Jason E. Aten
9c7bc603af rbf: reuse cursors with sync.Pool or arena
- the sync.Pool default uses little memory under CI.

- arena approach provides ability to control the maximum memory
  used by rbf Cursors.

- cursor caching is adjustable with --rbf-cursor-cache
  currently 0 by default (meaning use sync.Pool), and
  larger than 0 meaning use an arena of this size.
  With the arena, 20 or less is needed to pass CI.

- rbf test suite runs ~ 4x faster

- kitchen sink ingest test runs 16% faster.

- report TotalAlloc in CALLSTATs

fixes #1105
2020-11-19 17:02:49 +00:00
jaten-molecula
274a95c4da
Merge pull request #1115 from molecula/remove-rbtree
Use immutable.SortedMap for root records
2020-11-19 11:00:57 -06:00
Ben Johnson
26d0e9d958
Merge branch 'master' into remove-rbtree 2020-11-19 07:27:09 -07:00
tgruben
b849fe4b98
Merge pull request #1116 from jaten-molecula/pilosa_txsrc
use pilosa server --txsrc instead of --tx to prevent viper env var shadowing
2020-11-18 14:37:10 -06:00
Jason E. Aten
524c78623f repair pilosa/ctl/server_test too 2020-11-18 18:53:22 +00:00
Ben Johnson
0175c66756 Use immutable.SortedMap for root records
This commit fixes a bug where the root record cache was being
updated in-place causing a race condition with other transactions
using it. The cache implementation has been changed from `rbtree`
to an `immutable.SortedMap`.
2020-11-18 11:22:52 -07:00
Jason E. Aten
06eb3afaaa use pilosa server --txsrc to prevent viper env var shadowing from stopping PILOSA_TXSRC getting through 2020-11-18 18:21:31 +00:00
jaten-molecula
a9c1ff3047
Merge pull request #1107 from jaten-molecula/fix_tx
restore the env variable PILOSA_TXSRC's affect
2020-11-16 17:26:22 -06:00
Jason E. Aten
744827d5cc restore the env variable PILOSA_TXSRC's affect 2020-11-16 23:18:50 +00:00
Ben Johnson
89ae5ad4b7
Merge branch 'master' into fast-write 2020-11-16 09:10:01 -07:00
Ben Johnson
519dc5069d Implement optimized fast leaf write.
This commit adds an optimized implementation for `putLeafCell()` if
the insert/update will not cause the page to overflow.
2020-11-16 08:13:35 -07:00
Nia
6dfbbf91d6
Merge pull request #1098 from niaow/topn-v3
Add TopK with perpendicular BSI bitmaps
2020-11-16 08:39:50 -05:00
Nia Weiss
02498ce57a
add TopK with perpendicular BSI bitmaps 2020-11-13 18:31:55 -05:00
tgruben
43443d10ff
Merge pull request #1097 from jaten-molecula/bitmap_foreach
rbf: BitN needs int32 to hold its maximum value.
2020-11-13 17:12:19 -06:00
Jason E. Aten
4120024b10 rbf: BitN needs int32 to hold its maximum value.
- decrease ArrayMaxSize and RLEMaxSize by 1
  to make space
- add TestForEachRange, fix bugs found in ForEach,
  where the call f() logic was backwards.
2020-11-13 22:59:18 +00:00
tgruben
b2e9e3904a
Merge pull request #1094 from jaten-molecula/elem_rb
rbf: keep ElemN and BitN up to date.
2020-11-13 15:44:15 -06:00
Jason E. Aten
d46b603cd6 rbf: keep ElemN and BitN up to date.
- fix a bug in computing leafCell.BitN in a run after a bit Remove
- shrink bitmaps on remove
- util_test.go has Cursor.DebugSlowCheckAllPages to verify;
  used by cursor_test.go
2020-11-13 21:18:09 +00:00
Cody Soyland
dc0ac0ccd0
Merge pull request #1092 from codysoyland/ci-go-version-cve-2020-28362
Ci: Go version update for CVE-2020-28362
2020-11-13 11:48:16 -06:00
Cody Soyland
e53b74261b Update default Go version 2020-11-13 11:23:39 -06:00
Cody Soyland
a2f49b6a84 Fix yaml syntax, add requires section 2020-11-13 11:23:39 -06:00
Cody Soyland
dca606dea8 Add pilosa (binary build) to .gitignore 2020-11-13 11:23:39 -06:00
Cody Soyland
671250d273 Update Go version for CVE-2020-28362, use param matrix 2020-11-13 11:23:39 -06:00
tgruben
d15dc4204b
Merge pull request #1086 from jaten-molecula/rbtree_root_records
rbf: use a red-black tree to manage the root records list
2020-11-13 11:14:51 -06:00
Jason E. Aten
eae82b72c2 rbf: use a red-black tree to manage the root records list
- 40% faster on ingest_test when putting 10K roots/containers.
 - 15% fewer bytes allocated total
 - clarifying renames leafCell.N -> ElemN, allocate -> allocatePgno,
   deallocate -> freePgno
2020-11-13 16:49:26 +00:00
jaten-molecula
cb73c71e02
Merge pull request #1072 from molecula/uni-wal
Refactor RBF to use a single WAL file
2020-11-11 15:44:45 -06:00
jaten-molecula
563c70dc43
Merge branch 'master' into uni-wal 2020-11-11 15:27:15 -06:00
tgruben
b3d2704066
Merge pull request #1085 from jaten-molecula/uniq_dbnames
unique db names so parallel test runs don't collide
2020-11-11 14:26:04 -06:00
Jason E. Aten
fd9210b31c unique db names so parallel test runs don't collide 2020-11-11 20:04:02 +00:00
Ben Johnson
81a64c5902 Add RBF halting; remove time based checkpoint 2020-11-11 11:17:07 -07:00
Ben Johnson
9eba299d35 Restrict max RBF transaction size 2020-11-10 08:14:14 -07:00
Ben Johnson
78eb9e0711 Fix linter 2020-11-10 07:07:06 -07:00
Ben Johnson
52340212f6 Add RBF dirty page cache 2020-11-09 16:11:20 -07:00
Ben Johnson
8de1959938 Remove RBF exclusive/direct write. 2020-11-09 08:23:09 -07:00
Ben Johnson
3554048877 Refactor RBF to use a single WAL file 2020-11-09 08:03:22 -07:00
tgruben
e99f7f0fc3
Merge pull request #1074 from jaten-molecula/fsync_applies_to_all
apply --fsync flag to all tx backend
2020-11-06 12:34:28 -06:00
Jason E. Aten
a38d4fa46c apply --fsync flag to all tx backend
- rename from --rbf-fsync to --fsync, as it
   now effects bolt, lmdb too.
2020-11-06 18:11:02 +00:00
jaten-molecula
822c7482a5
Merge pull request #1071 from jaten-molecula/parallel_migration_rb
run migration in parallel
2020-11-05 14:09:31 -06:00
Jason E. Aten
7e22994a6d run migration in parallel
- migration can be slow. parallelize it.
2020-11-05 18:31:27 +00:00
tgruben
bc26de63b0
Merge pull request #1070 from jaten-molecula/slurp_profile_rbf_comments
rbf default. Add TODO comments, slurp -profile returns a cpu profile
2020-11-03 19:52:54 -06:00
Jason E. Aten
458095a707 rbf default. Add TODO comments, slurp -profile returns a cpu profile
- default Tx is once again RBF, changed from bolt.
- document the RBF code review comments that were not addressed
  before #1052 was merged, so they don't get lost.
- they should be easily addressed by replaying the entire WAL file
  rather than from the DB meta page 0 notion of the last WalID
- cleanup rbf/cfg/cfg.go stale comments, ensure default0 respected.
  1 msec checkpoint time, 1MB wal segment defaults.
- return a specific error, ErrNoMetaFound, from findNextWALMetaPage()
  rather than io.EOF, since there actually wasn't any file IO involved.
- add http handlers for /cpu-profile/start and /cpu-profile/stop
  in http/handler.go enable CPU profiling at specific time points
  during an ingest or other operation.
2020-11-04 01:36:17 +00:00
tgruben
a55cdad139
Merge pull request #1069 from jaten-molecula/faster_new_tx
take a mutex off the fast path of TxFactory.NewTx
2020-11-03 19:15:26 -06:00
Jason E. Aten
bf36f54b8d take a mutex off the fast path of TxFactory.NewTx 2020-11-04 01:04:04 +00:00
tgruben
40a773b839
Merge pull request #1068 from jaten-molecula/qcx_gettx_error
qcx.GetTx returns an error
2020-11-03 18:34:24 -06:00
Jason E. Aten
6aadd13095 qcx.GetTx returns an error
- to indicate that the query context is already
   done.
 - handles the case where the import worker is
   interrupted early by a ctx cancellation,
   thus avoiding a panic.
2020-11-04 00:01:02 +00:00
Ben Johnson
06cb04f87a
Merge pull request #1052 from molecula/fix-wal-not-found
Fix RBF WAL ID panic.
2020-11-03 11:16:33 -07:00
Ben Johnson
731a1ef25e Refactor RBF WAL to only only checkpoint-in-full. 2020-11-03 10:41:31 -07:00
Ben Johnson
ea3732fa62 Fix WAL ID not found panic.
This commit changes the checkpointing to determine a minimum WAL ID
for readers and a max ID based on the writer. Pages are checkpointed
from the WAL up to the writer's max WAL ID but segments are removed
only up to the reader's minimum WAL ID. This ensures that WAL pages
are not removed out from under current read transactions.
2020-11-03 10:41:31 -07:00
Ben Johnson
c47b49a06e
Merge pull request #1053 from molecula/increase-rbf-wal-write-cache 2020-11-03 07:37:05 -07:00
Ben Johnson
db74f0dffa Increase RBF WAL write cache size to 1MB.
Previously we dropped the cache size to 64KB but that seems much
too low. Write performance suffers considerably.
2020-10-30 17:09:33 -06:00
Matthew Jaffee
3ff85ccb53
Merge pull request #1051 from molecula/default-txn-bolt-fix-ci
default to Bolt txn due to CI failures blocking other team
2020-10-30 15:01:57 -05:00
Matt Jaffee
83dd8026d5
default to Bolt txn due to CI failures blocking other team
Our nightly CI has been failing for a week due to WAL issues and it's
making it difficult for Kuba and Antonio to do things on the
integration repo. Hoping bolt backend will solve that in the short
term. I think the issue is Pilosa #1046 (that's from memory though)
2020-10-30 13:55:36 -05:00
Ben Johnson
bb5153a7c1
Merge pull request #1049 from molecula/rbf-cli-help
Improve RBF CLI help
2020-10-30 08:38:14 -06:00
Ben Johnson
d5369a084e Improve RBF CLI help 2020-10-30 07:25:36 -06:00
tgruben
f446eee088
Merge pull request #1048 from jaten-molecula/delete_empty
DeleteEmptyContainer true by default now
2020-10-30 06:30:09 -05:00
Jason E. Aten
9c66cd5a81 DeleteEmptyContainer true by default now 2020-10-30 04:15:53 +00:00
tgruben
4113a3d85b
Merge pull request #933 from molecula/qcx_no_auto_reset
pilosa: no automatic reuse of Qcx
2020-10-29 20:03:42 -05:00
Jason Aten
016e5e0774 no automatic reuse of Qcx
Per slack discussion with Seebs and Nia,
we'll try not automatically resetting the Qcx.

The worry was that our goroutine shutdown
management is so poor that we are asking for
GetTx on a goroutine that still has a Qcx
from a query that was cancelled.

If this is the case, we will now panic instead of
issuing a new Tx. Then we can fix the poor
goroutine management.

 - also require Qcx.Finish or Abort before Reset
2020-10-30 00:36:46 +00:00
tgruben
51c9f4feeb
Merge pull request #1044 from jaten-molecula/startup_shards
don't apply startup shard cache to roaring with a specified view path
2020-10-29 18:24:57 -05:00
Jason E. Aten
18e253870e cleanup TypedDBPerShardGetShardsForIndex logic 2020-10-29 22:25:06 +00:00
Jason E. Aten
f8e7b27a6f don't apply startup shard cache to roaring with a specified view path
- avoids creating a new empty 8 byte shard file under all the
   views that don't have them already.
2020-10-29 22:09:55 +00:00
tgruben
ed6f59a827
Merge pull request #1042 from jaten-molecula/migration_logging
better migration logging
2020-10-29 04:38:53 -05:00
Jason E. Aten
2d55ffbd28 short circuit if no data to migrate 2020-10-29 02:44:22 +00:00
Jason E. Aten
d4df15721d allow migration of empty to empty 2020-10-29 02:41:09 +00:00
Jason E. Aten
aa47cf5bf4 fix verify test 2020-10-29 02:35:38 +00:00
Jason E. Aten
0e354aedf2 error expected trying to migration to roaring 2020-10-29 02:29:57 +00:00
Jason E. Aten
f9f94aab0d fix typo 2020-10-29 02:15:43 +00:00
Jason E. Aten
bceabc9127 error on un-implemented migrate to roaring 2020-10-29 02:11:28 +00:00
Jason E. Aten
3baa8ea0f6 check if roaring data present with RoaringHasData 2020-10-29 01:47:26 +00:00
Jason E. Aten
639e9b3bf0 quiet 2020-10-29 01:32:04 +00:00
Jason E. Aten
6e20e6439f more logging 2020-10-29 01:30:16 +00:00
Jason E. Aten
b1ff3791b8 better error when green does not exist on migration 2020-10-29 01:20:41 +00:00
Jason E. Aten
85fc785296 timed progress 2020-10-29 01:12:19 +00:00
Jason E. Aten
509348260f better migration logging 2020-10-28 22:54:58 +00:00
Ben Johnson
e332f6fd7e
Merge pull request #1018 from molecula/rbf-cli 2020-10-28 06:26:27 -06:00
jaten-molecula
6386587f12
Merge branch 'master' into rbf-cli 2020-10-28 05:35:43 -05:00
jaten-molecula
9d233c4849
Merge pull request #1040 from jaten-molecula/rowcache_lock
pilosa: write lock the fragment when rowcache used
2020-10-27 20:11:10 -05:00
Jason E. Aten
062bd5c8c7 pilosa: write lock the fragment when rowcache used
- only allocate the rowcache if it is in use (avoid allocation per fragment)
 - when the rowcache is use, fragment.go intRowIterator must write lock the
   fragment because the f.rowCache will be updated.
 - eliminate unused bitmapCache interface to keep the linter happy.
 - fixes #1035
2020-10-28 00:53:38 +00:00
jaten-molecula
1784384153
Merge pull request #1039 from jaten-molecula/rbf_logging
pilosa server --rbf-checkpoint-dur to 0 by default
2020-10-27 18:19:04 -05:00
Jason E. Aten
1ca8a45357 pilosa server --rbf-checkpoint-dur to 0 by default
- we return to checkpointing after every commit, by default.
  - the internal rbf logic is not ready to have
    checkpoints deferred. Doing so results in
    references to WAL segments that are not
    in the current slice of live segments.
2020-10-27 22:38:18 +00:00
jaten-molecula
c9912e3607
Merge branch 'master' into rbf-cli 2020-10-27 15:03:43 -05:00
Cody Soyland
7855cd4d21
Merge pull request #1038 from jaten-molecula/dockerfile_go1.14.10
use go1.14.10 for now because of https://github.com/molecula/pilosa/issues/1036
2020-10-27 14:04:03 -05:00
Jason E. Aten
24bd1543f3 Makefile to go1.14.10 2020-10-27 18:07:13 +00:00
Jason E. Aten
2fb53b982a update .circleci/config.yml to use go1.14.10 2020-10-27 18:00:15 +00:00
Jason E. Aten
03f24303d7 use go1.14.10 for now because of https://github.com/molecula/pilosa/issues/1036 2020-10-27 17:44:53 +00:00
Jason E. Aten
85f3fa9836 merge with the update to rbf to take a Config parameter 2020-10-27 15:11:45 +00:00
jaten-molecula
4543237e09
Merge branch 'master' into rbf-cli 2020-10-27 10:09:24 -05:00
jaten-molecula
305f81a310
Merge pull request #1034 from jaten-molecula/rbf_checkpoint_rb
performance tuning: rbfcfg package, binary search for wal segment
2020-10-27 10:07:47 -05:00
Ben Johnson
2b1d790625 Fix tree key formatting; add --with-tree option 2020-10-27 08:24:56 -06:00
Ben Johnson
7fa1a5edd2 Add RBF CLI commands 2020-10-27 08:12:22 -06:00
Jason E. Aten
957cba1768 performance tuning: rbfcfg package, binary search for wal segment
- rbfcfg package holds Config for --rbf- command line flags
- wal.go: replace linear search with bisection for wal segment
2020-10-27 00:49:56 +00:00
jaten-molecula
14cb29ea7d
Merge pull request #1024 from jaten-molecula/avoid_excessive_directory_scans
pilosa: avoid re-scanning shards during holder open
2020-10-23 20:31:05 -05:00
Jason E. Aten
233b3cbc0f versioned map cleanup 2020-10-24 00:35:25 +00:00
Jason E. Aten
c5e46e4618 one copy of shard map during a reload 2020-10-24 00:20:30 +00:00
Jason E. Aten
8ff6e8e0fd versioned readonly shards map 2020-10-23 23:50:22 +00:00
Jason E. Aten
2503fe5b66 pilosa: avoid re-scanning shards during Holder.Open()
- view.openFragmentInTx was forcing a directory scan
   for shards on every open fragment during Holder.Open().
   Seen by pprof profile having excessive allocations
   from dbshard.go listDirUnderDir().
2020-10-23 23:50:22 +00:00
seebs
2b6cb5fc6c
Merge pull request #1020 from seebs/distinctSet
Distinct operations on set fields
2020-10-23 17:09:23 -05:00
seebs
7558afd7ec
Merge branch 'master' into distinctSet 2020-10-23 16:41:00 -05:00
Cody Soyland
35706a3372
Merge pull request #1017 from codysoyland/docker-build
Fix Docker build target, enable when building Linux releases
2020-10-23 16:31:30 -05:00
Seebs
765d28bf9d add test case and bug fix for distinct code
The "seenThisRow" value was never getting cleared, which meant that
if the first container on a row didn't happen to contain any post-filter
bits, the rest of the row wouldn't get evaluated.
2020-10-23 16:18:19 -05:00
Cody Soyland
fc29bf5ec8 Fix Docker build target, enable when building Linux releases 2020-10-23 14:27:00 -05:00
Seebs
a2151358ba Partial implementation: Distinct() supporting set fields
Add an exported IntersectionAny() from roaring to let us quickly
check whether two containers have overlap, so we can avoid performing
intersections we don't need to when evaluating containers within
the same row as a previous match. (IntersectionCount on the whole
bitmap would imply doing up to 16 intersections even if we find a bit
right away.)

We also allow ForeignIndex to be set on set, mutex, and time fields,
since all of those could now be reasonable operands for Distinct
ops.

Not yet present: Handling time quantums, but that seems really
desireable.
2020-10-23 13:36:40 -05:00
Nia
c1db627593
Merge pull request #989 from niaow/translate-maybe
Allow querying without creating keys
2020-10-23 14:23:35 -04:00
Nia
3b93b767fa
Merge branch 'master' into translate-maybe 2020-10-23 13:59:10 -04:00
Nia Weiss
ddee7ae35e
address review comments for #989 translate-maybe 2020-10-23 10:59:08 -04:00
jaten-molecula
8f1aae9a69
Merge pull request #1016 from jaten-molecula/rowcache_optional
pilosa server --rowcache-off disables the row cache
2020-10-22 22:14:51 -05:00
Jason E. Aten
8d2ad048fa pilosa server --norowcache disables the row cache
- this can lessen memory pressure
- certain backends may not need it
- enables performance benchmarking and tuning
2020-10-22 22:20:48 +00:00
seebs
9eb251ec85
Merge pull request #69 from seebs/ctbench
Container op benchmarks
2020-10-22 15:03:09 -05:00
Seebs
8095455355 container performance benchmarking
This adds a series of archetypal containers that represent the
common use cases (arrays, bitmaps, or runs of various cardinalities)
and runs the basic operations against them for benchmarking purposes.

`benchpretty` is an app to snatch the BenchmarkCt* lines from
benchmark runs and display them in a possibly more usable form,
mostly as a precursor to cool analysis things.

This also adds a test to verify that intersectionCount(a, b)
is the same as intersect(a, b).N() for all the archetypal
containers.

This also includes a performance fix for intersectBitmapRun which
was spotted while running these tests.
2020-10-22 14:33:03 -05:00
Nia Weiss
afbbc93047
add basic tests for queries with missing keys 2020-10-22 13:19:05 -04:00
Nia Weiss
9204298d06
fix broken rebase on GetNodeUsage 2020-10-22 11:10:36 -04:00
Nia Weiss
8340b9ea64
re-apply single equals fix 2020-10-22 11:03:51 -04:00
Nia Weiss
b0a588f8dd
finish translate-if-exists 2020-10-22 10:50:09 -04:00
Nia Weiss
a74eda1eb0
cleanup of key translation fix 2020-10-22 10:50:08 -04:00
Nia Weiss
c60c699664
deal with linter false positives 2020-10-22 10:47:30 -04:00
Nia Weiss
da52b134bf
the tests pass now 2020-10-22 10:47:30 -04:00
Nia Weiss
5315579378
add some validation 2020-10-22 10:47:29 -04:00
Nia Weiss
1fe0edae08
fix find & create foreign index keys 2020-10-22 10:47:29 -04:00
Nia Weiss
a6e3723190
it mostly works now 2020-10-22 10:47:29 -04:00
Nia Weiss
13a19aeb42
query translation WIP 2020-10-22 10:47:29 -04:00
Nia Weiss
15036787a7
test new translation paths via API 2020-10-22 10:47:29 -04:00
Nia Weiss
8a130c150e
address review comments 2020-10-22 10:47:28 -04:00
Nia Weiss
22d6011d05
apply "maybe" key translation WIP 2020-10-22 10:47:25 -04:00
jaten-molecula
d12639b890
Merge pull request #1014 from jaten-molecula/log_in_utc
log in UTC in fixed width microseconds RFC3339 format
2020-10-21 20:01:36 -05:00
Jason E. Aten
aad38d1c60 log in UTC in fixed width microseconds 2020-10-21 18:36:28 +00:00
seebs
4cea813ae8
Merge pull request #999 from seebs/pqlCleanup
Fixes some minor PQL issues; adds support for case-insensitive PQL calls
2020-10-20 16:02:42 -05:00
jaten-molecula
fb6feb04f9
Merge branch 'master' into pqlCleanup 2020-10-20 15:21:54 -05:00
seebs
a1e1d86ae3
Merge pull request #1012 from seebs/ignoreCN
Supply "subject alternative name" for TLS certificates
2020-10-20 14:50:18 -05:00
Travis Turner
52b91b2df1
Merge branch 'master' into pqlCleanup 2020-10-20 14:19:45 -05:00
Seebs
5e36638e10 Supply "subject alternative name" for TLS certificates
Go killed off using the common name for hostnames starting with 1.15,
but this can be addressed by recreating the certs using a Subject
Alternative Name for the domain for "localhost". This allows tests
to pass without hanging, at least for me.
2020-10-20 14:14:26 -05:00
jaten-molecula
d929c945bc
Merge pull request #1011 from jaten-molecula/rbf_default
rbf is the default Tx type. Dogfood it.
2020-10-20 13:53:21 -05:00
Jason E. Aten
18ad4a8230 rename test-golang-1.14 -> test-golang-1.14.9 2020-10-20 13:37:13 -05:00
Travis Turner
4db93db0c1
Merge branch 'master' into pqlCleanup 2020-10-20 13:19:55 -05:00
Jason E. Aten
275779173d go1.15.3 support with GODEBUG=x509ignoreCN=0 2020-10-20 12:23:35 -05:00
Jason E. Aten
996b2ccb23 go1.13.15 -> go1.15.3 as our supported versions 2020-10-20 11:58:12 -05:00
Jason E. Aten
1216b93d73 rbf is the default Tx type. Dogfood it. 2020-10-20 11:07:07 -05:00
tgruben
c356498c19
Merge pull request #1010 from jaten-molecula/avoid_bg_deadlock
CI catches red blue-green tests. Qcx write flag
2020-10-20 11:01:53 -05:00
Travis Turner
7be3cd6a36
Merge branch 'master' into pqlCleanup 2020-10-20 10:59:48 -05:00
Jason E. Aten
2b4e6d25f5 CI catches red blue-green tests. Qcx write flag
- fix a CI/Makefile issue that was hiding red tests in CI.
 - the testv and testv-race targets now require /bin/bash
 - In executor.go, the top-level query context Qcx now
   has a write flag. It will upgrade read-Tx to write-Tx
   when Store() wraps some inner local-read operations,
   to avoid deadlocking against its own query. This deadlock
   happens in TestExecutor_Execute_SetRow/Set_NewRow
   under rbf_lmdb blue-green testing without the upgrade.
2020-10-20 10:38:40 -05:00
jaten-molecula
0dd3486b95
Merge pull request #1005 from jaten-molecula/bglimits
Fix blue-green Tx cleanup and document single import at once
2020-10-20 07:31:54 -05:00
Jason E. Aten
d9783406bd Fix blue-green Tx cleanup and document single import at once
- correct string constants for txtype so that
  blue-green cleanup correctly detects when
  2nd transaction in a pair has Committed and
  thus the blue-green RWMutex can be relased

- test that txtype.String() is consistent with
  the corresponding string constants.

- document in bluegreentx.go the current limitations
  of blue-green testing: only one github archive import
  (a single writing client) is supported by blue-green
  testing. Multiple importers will deadlock eventually
  on the DBShard.mut RWMutex. We could fix this by
  ordering the write locks and obtaining them in
  strictly increasing order (by shard number), but
  that would require alot of change to the executor
  and that would introduce more risk for a test-only
  pathway.
2020-10-20 07:09:08 -05:00
jaten-molecula
2ebff707a9
Merge pull request #1004 from jaten-molecula/bluegreenlock
introduce a per shard blue-green RWMutex
2020-10-19 18:02:29 -05:00
Jason E. Aten
81013999e5 introduce a per shard blue-green RWMutex
- allows blue-green testing with concurrent readers/writers.
 - otherwise we don't start/end the blue and green Tx
   together, and they get split by a read/write concurrently.
2020-10-19 17:28:35 -05:00
Travis Turner
f37a63e5cf
Merge branch 'master' into pqlCleanup 2020-10-19 15:45:04 -05:00
Cody Soyland
d3ae2614ce
Merge pull request #1001 from seebs/updateLint
uprev golangci-lint, fix a minor lint in rbf
2020-10-19 14:54:38 -05:00
Seebs
ed309821ae uprev golangci-lint, fix a minor lint in rbf
I have a newer staticcheck and golangci-lint on my laptop, and it started
complaining about something. The first comment added disables the check
in staticcheck-as-a-command, the second disables it when it's being done
by golangci-lint, which invokes the analysis passes directly and displays
the output differently, and also doesn't recognize the hints used by
staticcheck.

Newer golangci-lint doesn't find anything else that it wants to complain
about.
2020-10-19 14:25:11 -05:00
Seebs
6e725d50ce check error return from peg parser Init
The updated peg tool produces an Init that can return an error. As
of this writing, the error can't be non-nil unless you specified an
option which itself returned an error, but that could change later,
so let's be careful.
2020-10-19 13:47:42 -05:00
Seebs
e84d2d2a59 refactor number parsing a bit
There are subtle inconsistencies, like "01" being a valid decimal but not
a valid integer, which vaguely bug me. Cleaning this up, and the corresponding
parser logic.

A number can't have leading spaces because the grammar doesn't
put spaces in them in the first place, so stop accepting them in the
number syntax. This should never have any impact on anything,
it's just simpler.

Update a couple of test cases to reflect this -- no longer testing
that trailing spaces are okay, now testing that they're not, for
instance.
2020-10-19 13:37:21 -05:00
Seebs
c19d571112 more consistent spacing
We still prohibit a space before a leading '(', which maybe we shouldn't,
but we now allow spaces on both sides of a closing ')' more consistently.
Drop the unneeded "sp" before "close" in the special handling after
null, true, and false, because close now implies that.

Also, refactored the two instances of "sp '=' sp" into a thing called eq,
which may not be worth it.
2020-10-19 13:35:49 -05:00
Seebs
28d18920b9 Make PQL case-insensitive about call names.
Use "" strings for fixed string names. In startCall(), look up the
lowercase conversion of a call name in a table mapping all-lowercase
representations to canonical case, so we don't have to chase down
everyplace in the rest of the code base that assumes "Row" is
capitalized exactly like that.
2020-10-19 13:35:49 -05:00
Seebs
18ed02d7fb drop float/decimal distinction in PQL
PQL always produces decimals, which have effectively-arbitrary range,
but can convert them to floats when required; the executor then requests
this conversion in the handful of cases (SetRowAttrs and SetColumnAttrs)
where it wants floats rather than decimals.

Not yet fixed: The "Range" call may also be wrong now. It was specifying
an "fvalue" but is now effectively getting what used to be called a
"dvalue". However, so far as I can tell, that didn't work before either.
2020-10-19 13:35:49 -05:00
Seebs
b8bb438b69 trivial cleanup of PEG grammar
Drop irrelevant (), simplify the expression of the sp rule.

Perhaps shockingly, this *does not change the generated grammar at all*. The
generated code for:
	sp <- [ \t\n]*
and is identical to the code for:
	sp <- ( ' ' / '\t' / '\n' )*

And in fact, is spelled the latter way in the generated comments.
2020-10-19 13:35:49 -05:00
Seebs
0ea324129f update to new version of peg tool
Want to do some PQL cleanup. A new version of peg turns out to dramatically
alter performance in some cases, so I'm doing the commit for "don't change any
PQL, just change the version of peg" checkin separately.
2020-10-19 13:35:49 -05:00
tgruben
092177aea4
Merge pull request #997 from molecula/bolt_in_badger_out
Use boltdb instead of badger as our all-Go Tx oracle
2020-10-16 17:41:23 -05:00
Jason E. Aten
266b92c025 Use boltdb instead of badger as our all Go Tx oracle.
- remove all badgerdb code.
 - use boltdb instead.
2020-10-16 17:21:21 -05:00
Cody Soyland
3dff03907d
Merge pull request #942 from codysoyland/grpc-web
Add grpc-web to http handler
2020-10-16 15:46:25 -05:00
Cody Soyland
b86b0519af go mod tidy 2020-10-16 15:10:48 -05:00
Cody Soyland
a2ee047868 grpc-web cors test 2020-10-16 11:36:41 -05:00
Cody Soyland
31cd119a7e Move grpc.Server creation into initializer
This fixes an issue with the grpc-web middleware using a nil
grpc.Server instance.
2020-10-16 11:36:41 -05:00
Cody Soyland
04b1152224 Add grpc-web to http handler 2020-10-16 11:36:41 -05:00
jaten-molecula
8da638f685
Merge pull request #979 from seebs/bbolt
switch to etcd boltdb fork
2020-10-15 19:58:31 -05:00
Seebs
0905e858cd uprev golang to 1.14.9
1.14 had a bug in the checkptr code (well, not exactly a bug) which
made it enforce alignment requirements on x86. This turns out not
to be the problem I was seeing, but we should be on 1.14.9 anyway.

To keep this from breaking CI integration with Github, we also
use explicit job names instead of matrix-generated ones, and fix
the CI config syntax up a bit after almost getting that right the
first try. (This patch includes fixes contributed by Cody, and since
I had to rebase and re-approve AGAIN anyway, I might as well squash
the commit history up.)
2020-10-15 19:13:28 -05:00
Seebs
76fe49d390 un-disable checkptr by fixing the memory problems
Step one: switch to etcd.io's bbolt fork of boltdb.

The etcd-io fork of boltdb isn't archived, and has fixes for boltdb's
interactions with checkptr, allowing us to drop the checkptr-disabling
hackery.

This seems to be a drop-in replacement; etcd/bbolt says that the file
format is "fixed" (I believe in the sense of "unchanging"), and I can
run pilosa on an existing data directory with this.

Step two:

Fix missing caps in roaring.go that were also triggering the same
issues.
2020-10-15 19:12:47 -05:00
tgruben
de642ed90c
Merge pull request #993 from molecula/fix983
bluegreentx: default to not dumping full databases
2020-10-15 17:31:55 -05:00
Jason E. Aten
e5a56f1cd2 bluegreentx: default to not dumping full databases 2020-10-15 16:23:19 -05:00
Matthew Jaffee
c859a8aa2b
Merge pull request #981 from jaffee/single-equal-data-race
Fix data race on call map in single '=' logic
2020-10-15 11:40:16 -05:00
Matt Jaffee
00f1f70779
fix data race on call map in single = logic
Add test of single = int query over multiple shards which reproduces
the race

move the code which modifies the PQL call object if a Row query
on an int field uses a single = instead of ==. Instead of processing
this at the shard level, we'll process it during the initial
translation step so that it isn't operated on concurrently.
2020-10-15 10:26:14 -05:00
alanbernstein
4bf81444ba
Merge pull request #951 from molecula/shard-dist-api
Add ui-specific endpoint to report shard distribution data
2020-10-14 21:58:05 -05:00
Alan Bernstein
94e82aea86 Consider available shards 2020-10-14 21:11:02 -05:00
Alan Bernstein
ab502a0f8d Add basic test 2020-10-14 21:11:02 -05:00
Alan Bernstein
510902625e Update test hasher implementations 2020-10-14 21:11:02 -05:00
alan
2a902b3a7b Finish basic shard-distribution endpoint 2020-10-14 21:11:02 -05:00
Alan Bernstein
98cd2dc441 WIP shard distribution endpoint 2020-10-14 21:11:02 -05:00
Cody Soyland
8c9569faca
Merge pull request #982 from codysoyland/circle-config-fix
Fix PR detection logic in CI
2020-10-14 21:07:23 -05:00
Cody Soyland
316bd87a8a Fix PR detection logic in CI 2020-10-14 20:36:04 -05:00
jaten-molecula
fa21c81a27
Merge pull request #963 from molecula/rbf_config
rbf: add DBConfig
2020-10-14 20:12:46 -05:00
jaten-molecula
577600d17b
Merge branch 'master' into rbf_config 2020-10-14 19:57:05 -05:00
jaten-molecula
39a31cc63e
Merge pull request #976 from seebs/impossible
Check more carefully for, and also fix, containers with invalid N
2020-10-14 18:57:02 -05:00
jaten-molecula
eb4b9974ac
Merge branch 'master' into impossible 2020-10-14 18:40:50 -05:00
alanbernstein
ca223c4a79
Merge pull request #934 from alanbernstein/cluster-usage
Collect size-on-disk usage data from all nodes
2020-10-14 16:33:03 -05:00
Alan Bernstein
aff5c0fc57 Skip missing directories 2020-10-14 15:46:19 -05:00
Jason E. Aten
244ba21da7 better names 2020-10-14 13:19:14 -05:00
Jason E. Aten
3a40b586b3 disk usage per index 2020-10-14 12:53:35 -05:00
Alan Bernstein
e2cafd98ef Move index size calculation to TxFactory 2020-10-14 12:20:05 -05:00
Alan Bernstein
7a32eadc64 Move disk capacity lookup to gopsutil wrapper package 2020-10-14 12:20:05 -05:00
Alan Bernstein
6a298590be Set omitempty for disk capacity json 2020-10-14 12:20:05 -05:00
Alan Bernstein
ba4ca1a93e Include disk capacity in usage response 2020-10-14 12:20:05 -05:00
Alan Bernstein
2a44bdd25c Collect size-on-disk usage data from all nodes 2020-10-14 12:20:05 -05:00
Cody Soyland
e1e0b298f5
Merge pull request #964 from codysoyland/check-changelog-label
Check for changelog label in CI
2020-10-14 10:11:45 -05:00
Seebs
c88192b4ac Check more carefully for, and also fix, containers with invalid N
In rare cases, RBF can produce containers which have a recorded N value which
is incorrect. This rarely affects anything, but on some particular queries,
this can result in very strange outcomes, like array containers with more
than 1<<16 entries.

To fix this, we have toContainer specify that it doesn't know the correct
N for the bitmap containers it's creating, which costs extra time for counting,
and should be considered a temporary workaround.

Also, we add a CheckN() function which is controlled by the
roaringparanoia flag, and add a number of calls to it, for instance, as
deferred calls after every container operation when roaringparanoia is
enabled. This means that we get improved confidence that we've caught
the relevant errors, but is not suitable for production use.
2020-10-14 10:03:18 -05:00
Cody Soyland
ca5dbe8d39 Fix pull request filter 2020-10-14 09:42:07 -05:00
Cody Soyland
2ac09af894 Only run on pull requests 2020-10-14 09:29:51 -05:00
Cody Soyland
4e66bbb76b Check for changelog label in CI 2020-10-14 09:29:51 -05:00
seebs
6c14aa965d
Merge pull request #895 from seebs/appendSemantics
use append-like semantics consistently for *Container
2020-10-14 09:04:56 -05:00
jaten-molecula
3d4da8f51b
Merge branch 'master' into appendSemantics 2020-10-14 07:24:18 -05:00
jaten-molecula
20d4268676
Merge branch 'master' into rbf_config 2020-10-14 07:19:37 -05:00
jaten-molecula
a997e713dc
Merge pull request #977 from molecula/readers
pilosa-fsck: the -readers flag controls parallelism
2020-10-13 19:14:09 -05:00
Jason E. Aten
50a8db854d pilosa-fsck: the -readers flag controls parallelism
- add path info to the panic if we find a corrupt boltdb
   translation store.
2020-10-13 18:58:38 -05:00
J
3ad8ec7f0f rbf: add runtime options to DB struct
- FsyncEnabled and DoAllocZero moved to DB struct.
 - deletes unused xrbrsupport.go and cmd/convert
 - fixes #941
2020-10-12 18:35:00 -05:00
tgruben
db9e8cd8ef
Merge pull request #966 from molecula/fix843
pilosa/dbshard: allow deleteIndex and then re-use of index
2020-10-12 18:10:04 -05:00
Jason E. Aten
b3e6cdc0d8 pilosa/dbshard: allow deleteIndex and then re-use of index
- fixes #843
2020-10-12 17:46:06 -05:00
jaten-molecula
54255eae15
Merge pull request #957 from molecula/fix-tx-deadlock
Fix deadlock in importWorker()
2020-10-12 17:04:11 -05:00
Ben Johnson
676208ea73 Add test to reproduce deadlock 2020-10-12 12:32:58 -06:00
Ben Johnson
9b83b71c8f Fix error check reference in importWorker() 2020-10-12 11:28:18 -06:00
Ben Johnson
bfe570ef9d Fix deadlock in importWorker()
This commit wraps the work for a view in a function so that the
defer on the finisher executes after each view is processed instead
of at the end.
2020-10-12 11:25:28 -06:00
Cody Soyland
279be13a46
Merge pull request #958 from codysoyland/grpc-compat-update
Better VDSM gRPC compatibility
2020-10-12 09:27:04 -05:00
Cody Soyland
e40b224a4f
Merge branch 'master' into grpc-compat-update 2020-10-12 09:08:42 -05:00
tgruben
d3811634d6
Merge pull request #959 from molecula/parallel_fsck
pilosa-fsck: parallelize Index.ComputeTranslatorSummary
2020-10-09 16:12:36 -05:00
Jason Aten
8da15b18d4 pilosa-fsck: parallelize Index.ComputeTranslatorSummary
- add -index option
2020-10-09 15:53:29 -05:00
Cody Soyland
6c10917ceb Use vdsm.QueryPQLRequest for vdsm.QueryPQLUnary 2020-10-09 13:34:20 -05:00
Cody Soyland
3039aa44af Use copy of vdsm InspectRequest for better compatibility 2020-10-09 13:22:24 -05:00
Cody Soyland
a58c345232 Use copy of vdsm QueryPQLRequest for better compatibility 2020-10-09 13:22:24 -05:00
tgruben
d3ce4fa70e
Merge pull request #948 from molecula/randomquery
pilosa/cmd/random-query: generate random queries from existing schema/data
2020-10-09 12:16:28 -05:00
Jason Aten
937a1afade pilosa/cmd/random-query: generate random queries from existing schema
- fixes molecula/molecula#136
 - flag -n 0 does continuous queries until process is killed.
2020-10-08 18:38:01 -05:00
jaten-molecula
06ee8b16ac
Merge pull request #940 from molecula/fsck_2index_repair
pilosa-fsck: multi-index counts and repairs.
2020-10-07 07:35:08 -05:00
Jason Aten
a63c6ee2b2 pilosa-fsck: multi-index counts and repairs.
- multiple indexes repaired at once could crosstalk. Fixed.
 - the counts of keys and ids are now broken down by index.
2020-10-06 21:10:52 -05:00
tgruben
d41de17503
Merge pull request #931 from molecula/fsck_msg
pilosa-fsck: correct repair -> analysis in pilosa-fsck logging
2020-10-06 13:21:21 -05:00
jaten-molecula
bc8fc23ac9
Merge branch 'master' into fsck_msg 2020-10-06 13:12:46 -05:00
tgruben
3a742a0caa
Merge pull request #938 from molecula/ci_rbf
run CI on rbf and rbf_lmdb
2020-10-06 12:52:33 -05:00
Jason Aten
83f230bbfb run CI on rbf and rbf_lmdb 2020-10-06 12:22:03 -05:00
Ben Johnson
ab6581446d
Merge pull request #889 from molecula/rbf-immutable-wal 2020-10-06 10:45:47 -06:00
Ben Johnson
3b7758a4f2 Add comment explaining rbf.DB.checkpoint() args 2020-10-06 10:36:57 -06:00
Ben Johnson
2440413c49 Remove test skips based on race detector 2020-10-06 10:29:17 -06:00
Ben Johnson
7b64abbb53 Reduce default RBF DB size to 4GB; remove race skips 2020-10-06 09:36:31 -06:00
Ben Johnson
644969e6a9 Add log.* and tourna.* to gitignore 2020-10-06 09:36:31 -06:00
Ben Johnson
265452cf3d Add rbf.SyncEnabled 2020-10-06 09:36:31 -06:00
Ben Johnson
cf208cfaa3 Increase test http client timeout
The timeout was increased to allow additional time for RBF to process
a lot of individual `Set()` commands in `TestMain_RecalculateHashes`.
2020-10-06 09:36:31 -06:00
Ben Johnson
3852ac79c4 Add rbf.DB.TxN() function and test check 2020-10-06 09:36:31 -06:00
Ben Johnson
c978e2242e Skip some RBF tests during race detection 2020-10-06 09:36:31 -06:00
Ben Johnson
c51ba69c09 Fix RBF sync calls 2020-10-06 09:36:31 -06:00
Ben Johnson
3429421148 Fix RBF checkpoint off-by-one WAL ID issue 2020-10-06 09:36:31 -06:00
Ben Johnson
d826cec4b3 fix RBF WAL segment reference error 2020-10-06 09:36:31 -06:00
Ben Johnson
cdd10a26f0 Refactor RBF to use immutable list of WAL segments.
Previously, RBF shared a list of WAL segments between the DB & Tx.
However, this increased the need for mutexes to access the data.

WAL segments are effectively immutable on-disk so the list of segments
has been refactored so that changes to the segment list are done via
copy-on-write which allows read transactions to access segment data
without a mutex.

The database checkpointing can remove early, unused segments and
there is an update/add check to make sure that Tx segments pushed back
to the DB do not include removed segments.
2020-10-06 09:36:31 -06:00
tgruben
8dbfaf5045
Merge pull request #932 from jaten-molecula/pr919
api usage should ignore tx stores. fixes #919
2020-10-06 09:45:43 -05:00
jaten-molecula
ce3a51eb87
Merge branch 'master' into fsck_msg 2020-10-06 09:28:36 -05:00
Jason Aten
6ddeec2ee8 print time at end of fsck run, even if we return 1 to shell 2020-10-06 08:19:53 -05:00
jaten-molecula
4ca42d7f14
Merge branch 'master' into pr919 2020-10-05 21:29:28 -05:00
Travis Turner
12cd4ea69e
Merge pull request #922 from travisturner/design-typos
adjust some wording and typos in the fsck design doc
2020-10-05 20:57:44 -05:00
Jason Aten
c82a1593ff api usage should ignore tx stores. fixes #919
- avoid deadlock in txfactory_internal_test w Qcx
2020-10-05 20:51:38 -05:00
Jason Aten
2f9c51349a correct repair -> analysis in pilosa-fsck logging 2020-10-05 19:59:32 -05:00
Travis Turner
69e15b4719
Merge branch 'master' into design-typos 2020-10-05 18:45:24 -05:00
jaten-molecula
d55ce8723b
Merge pull request #917 from molecula/pr224
ensure that Inspect generates a result for every header item
2020-10-05 17:37:15 -05:00
jaten-molecula
a14b81edbf
Merge branch 'master' into design-typos 2020-10-05 17:29:42 -05:00
Kuba Podgórski
5e2a14400a
Add an extra else branches 2020-10-05 17:13:48 -05:00
Jason Aten
fd87e8d2f3
follow suggestion on https://github.com/molecula/idk/issues/224, does it fix Q2 delete consumer issue?
- apparently not, but this might still be worth doing.
2020-10-05 17:13:48 -05:00
Nia
84830d8361
Merge pull request #921 from niaow/fix-rows-type-error
Generate errors for all unsupported types in Rows calls
2020-10-05 16:32:37 -04:00
Travis
675373f0f3
adjust some wording and typos in the fsck design doc 2020-10-05 14:38:57 -05:00
Nia Weiss
bb0d8bea14
generate errors for all unsupported types in Rows calls 2020-10-05 15:37:05 -04:00
jaten-molecula
9d7945e5be
Merge pull request #918 from molecula/fsck-design
DESIGN.md for pilosa-fsck
2020-10-05 13:36:57 -05:00
Jason E. Aten
05d4b664df groom 2020-10-05 13:29:29 -05:00
Jason E. Aten
9dacbccf8d DESIGN.md for pilosa-fsck
- Orient users to pilosa-fsck by giving an overview of its operations.
2020-10-05 12:51:26 -05:00
jaten-molecula
75b8fa0aa8
Merge pull request #900 from molecula/pilosa-fsck-rb
pilosa-fsck: fsck-like scan and repair of pilosa backups
2020-10-02 16:53:57 -05:00
Jason E. Aten
fe425a84c0 pilosa-fsck: scan and repair of pilosa backups
- the -fix flag repairs replication errors by copying from the primary.
 - the -fixkeys flag repairs any string key translation issues.
 - make pilosa-fsck installs pilosa-fsck and builds release-pilosa-fsck.COMMIT.GOOS.tar.gz release tarbar
2020-10-02 16:47:56 -05:00
jaten-molecula
d9f8de170c
Merge pull request #906 from jaffee/revert-confirm-down-retries
retrun confirmDownRetries to 10, tourney mac compatible
2020-10-02 15:15:57 -05:00
Matt Jaffee
c2a93cc886
retrun confirmDownRetries to 10, tourney mac compatible
At some point the cluster code was modified to do 120 tries to confirm
if a node was down which is a bit excessive for production. My
understanding is that this was done to help trigger or fix a problem
during testing which is hopefully no longer relevant.

Also changed the tournament script to use what I think are more
standard bash-isms that work on mac. Please confirm this still works
on Linux as well.
2020-10-02 14:24:16 -05:00
seebs
df89ebf394
Merge pull request #844 from seebs/setRowCache
Update cache entries when setting a row even in shards with no new data
2020-10-02 13:20:54 -05:00
Seebs
aec11ff713 Update cache entries when setting a row even in shards with no new data
The logic assumes that the lack of a corresponding rowSegment means that
there's no changes, but that's not true -- we just deleted all the
existing data! Update to match clearRow behavior better.

Also, add a corresponding test case for this.

Also, change references to 'defaultSnapshotQueue' to use
[fragment].holder.SnapshotQueue, because defaultSnapshotQueue was
the queueless queue, but holders were getting a snapshot queue,
meaning that "awaiting" a snapshot could result in moving on
and closing the holder before the actual snapshot queue finished
snapshotting.
2020-10-02 12:57:18 -05:00
Nia
7006233cf8
Merge pull request #915 from niaow/distinct-error-handling
Fix panic when "field" parameter not present on Distinct call (error instead)
2020-10-01 14:58:29 -04:00
Nia
ad0f0b1725
Merge branch 'master' into distinct-error-handling 2020-10-01 14:47:16 -04:00
alanbernstein
afc6f432bd
Merge pull request #647 from alanbernstein/ui-feature-support
Add more info to some endpoints to support UI
2020-10-01 13:19:35 -05:00
Nia Weiss
415f7d20b8
add field parameter error handling to Distinct 2020-10-01 12:09:34 -04:00
Alan Bernstein
8a3d93fe78 Move TransactionList endpoint to UI namespace 2020-10-01 10:45:08 -05:00
Alan Bernstein
46d010fe18 Remove 'NodeStates' from /status until it is reliable 2020-10-01 10:43:49 -05:00
Alan Bernstein
1a04e94fc1 Remove clusterID and default name to ID 2020-10-01 10:43:49 -05:00
Alan Bernstein
5705b45864 Add a CLI flag for cluster name and include it in /status response 2020-10-01 10:43:49 -05:00
Alan Bernstein
8fad2b92c2 Add all node states to /status response 2020-10-01 10:43:49 -05:00
Alan Bernstein
664c911791 Include replicaN in /info response 2020-10-01 10:43:49 -05:00
alanbernstein
11e4bbfc67
Merge pull request #907 from alanbernstein/cluster-data-endpoint
Add single-node 'bytesOnDisk' object to /status response
2020-10-01 10:42:27 -05:00
Alan Bernstein
b6af0e5219 Move usage data to new ui-specific endpoint 2020-10-01 10:25:48 -05:00
Alan Bernstein
6f2fe3afe1 Address linter issue 2020-10-01 10:25:48 -05:00
Alan Bernstein
474261f12f Add single-node 'bytesOnDisk' object to /status response 2020-10-01 10:25:48 -05:00
Nia
cac89f4c96
Merge pull request #913 from niaow/misaligned-distinct
Fix misaligned bitmaps in Distinct
2020-10-01 11:17:29 -04:00
Nia Weiss
e0f9870378
fix misaligned bitmaps in Distinct
This resolves an issue in which a filter would eliminate all bits in all shards other than shard 0.
2020-10-01 10:07:08 -04:00
Nia
f030792b8a
Merge pull request #905 from niaow/syncrace
Fix race condition when resetting translation
2020-09-30 09:26:43 -04:00
Nia
c31d2f143c
Merge branch 'master' into syncrace 2020-09-30 09:17:59 -04:00
Cody Soyland
86c5e040b1
Merge pull request #870 from codysoyland/grpc-compat
Fully backwards-compatible VDSM gRPC interface
2020-09-29 15:58:20 -06:00
Jason Aten
0e8564e2be fix license exceptions for vdsm/proto 2020-09-29 15:30:41 -05:00
Cody Soyland
949ca882fc Remove unused helper func 2020-09-29 15:30:12 -05:00
Cody Soyland
fdce92eb40 Use shared types from pilosa proto file and enable generic proxying of query calls 2020-09-29 15:30:12 -05:00
Cody Soyland
83704e7973 Proxy unary methods to Pilosa gRPC handler 2020-09-29 15:29:37 -05:00
Cody Soyland
c1e50ed909 Remove VDS references from pilosa proto file, begin porting VDSM service 2020-09-29 15:29:37 -05:00
Nia Weiss
1b210080c6
fix race condition when resetting translation
Previously, we never waited for translation sync goroutines to stop.
That issue should be mostly harmless in the normal path.
Additionally, this waits for the translation sync to shut down when stopping the server.
2020-09-29 13:54:16 -04:00
Seebs
fbb648b1fb enforce append-like semantics for *Container more consistently
The copy-on-write/rowCache changes require that functions that
modify containers be able to generate new containers. Once that
became possible, some significant pool of other operations
started relying on it -- for instance, operations might return
a new container even though they're in theory "in place" operations.

I developed a tool for checking for unused function return
values (github.com/molecula/noticeme), and ran it on this, and
picked out the places where `*Container` values were generated
but not used, and some of them seem to be potentially-real
bugs, and a few are probably harmless. Updated code to make
those diagnostics go away.
2020-09-28 12:19:24 -05:00
tgruben
82cdffd309
Merge pull request #899 from jaten-molecula/better_err_on_closed_db
better error reporting when making Tx on closed lmdb
2020-09-26 09:59:15 -05:00
Jason Aten
5a3170a9a4 better error reporting when making Tx on closed lmdb
- return error instead of panic.
2020-09-26 06:24:58 -05:00
Nia
3d07d13a7c
Merge pull request #897 from niaow/no-explicit-recalculate
Stop explicitly recalculating caches in tests
2020-09-25 11:18:37 -04:00
Nia Weiss
79f68f7a2e
stop explicitly recalculating caches in tests
This is no longer necessary, as caches now recalculate on read.
Also, in general a user will not explicitly request recalculation, so it would make sense for our tests to reflect that.
2020-09-25 10:36:00 -04:00
jaten-molecula
f026c43649
Merge pull request #891 from molecula/optimize_directadd
Bitmap.DirectAdd avoids returning overfull containers
2020-09-23 17:25:29 -05:00
Jason Aten
7ae8accfa8 Bitmap.DirectAdd avoids returning overfull containers
- log Debugf when we repair a fragment block
- better run-run roaring testing for over-sized containers
- add which fragment path to panic on container too big
- include container contents in roaring hash for pilosa-chk/pilosa-check-backup
2020-09-23 17:13:25 -05:00
Nia
4b5572da1d
Merge pull request #893 from niaow/limit-cluster
Fix Limit when used as an input to another query
2020-09-23 13:51:11 -04:00
Nia
e0f25f1d20
Merge branch 'master' into limit-cluster 2020-09-23 13:46:02 -04:00
Nia Weiss
2158417f34
fix Limit when used as an input to another query 2020-09-23 13:08:48 -04:00
Kuba Podgórski
8b855b97d0
Merge pull request #892 from kuba--/fix-545
Translate field IDs on coordinator
2020-09-23 17:49:15 +02:00
Kuba Podgórski
ba5438e02b Trabnslate field IDs on coordinator 2020-09-23 15:21:33 +02:00
jaten-molecula
f7afd5d2e1
Merge pull request #875 from molecula/remove_debug_tooling
turn on row cache. tx: remove debug tooling
2020-09-22 15:56:02 -05:00
Jason Aten
55d4c29933 turn off debug machinery on tx backends
- enable row cache again. Was off for tx perf measurement.
 - centralize UseRowCache choice to just one point, in rbf.EnableRowCache
2020-09-22 15:47:52 -05:00
Kuba Podgórski
886318931d
Merge pull request #882 from kuba--/fix-869
Fix holes in grpc response for inspect
2020-09-22 14:20:10 +02:00
Kuba Podgórski
b54a289cd8 Fix holes in grpc response for inspect 2020-09-22 12:02:26 +02:00
jaten-molecula
ba2851229d
Merge pull request #871 from molecula/bluegreen_verify
blue_green verify accepts empty fragments
2020-09-18 11:55:22 -04:00
Jason Aten
57be5392cf blue_green verify accepts empty fragments 2020-09-18 10:49:36 -05:00
tgruben
8ec10ec1e8
Merge pull request #868 from molecula/with_primary_instead_owner
Translate only on coordinator/primary
2020-09-17 17:12:56 -05:00
Kuba Podgórski
650244214d Translate only on coordinator/primary
- This is the commit message #3:
2020-09-17 17:03:29 -05:00
jaten-molecula
7dc59c4d9c
Merge pull request #831 from molecula/rbf-tx-cursor-stack-allocate
Stack allocate return from rbf.Tx.cursor()
2020-09-16 23:40:32 -04:00
Jason Aten
9b99009871 allow rbf-tx-cursor-stack-allocate to merge; fix conflict with the new HasData code 2020-09-16 22:35:30 -05:00
jaten-molecula
c04642f34b
Merge branch 'master' into rbf-tx-cursor-stack-allocate 2020-09-16 23:21:35 -04:00
jaten-molecula
0f5838816b
Merge pull request #857 from molecula/rbf-fix-direct-write-corruption
Fix RBF write corruption during direct write.
2020-09-16 23:07:57 -04:00
jaten-molecula
71033f78b5
Merge branch 'master' into rbf-fix-direct-write-corruption 2020-09-16 22:32:47 -04:00
Nia
16c5212e2d
Merge pull request #858 from niaow/deprecate-inspect
Add a deprecation warning to Inspect
2020-09-16 15:31:57 -04:00
Nia Weiss
f03ba0e682
add a deprecation warning to Inspect 2020-09-16 12:30:12 -04:00
Ben Johnson
6918fe2f60
Merge branch 'master' into rbf-fix-direct-write-corruption 2020-09-16 09:55:26 -06:00
jaten-molecula
75b01ba87d
Merge pull request #850 from molecula/db_has_data_rb
blue_green verification and migration capabilities.
2020-09-16 11:22:34 -04:00
Ben Johnson
458984c756 Fix RBF write corruption during direct write.
This commit fixes an issue where direct writes would overwrite the
source page where data was being copied from because writes are
immediate (instead of going to the WAL first).
2020-09-16 08:59:53 -06:00
Jason Aten
31d54010f8 blue_green verification and migration capabilities.
- on startup in blue_green mode, we will migrate
   blue to green if blue is empty.
 - otherwise, when blue has data, we verify
   against green before proceeding with the
   blue_green run.
 - small optimization in the rbf cursorx.go to
   short-circuit processing on a nil bitmap.
   This avoids a roaringparanoia tag panic.
 - back out holdbkg.go, was too slow.
   add a distinct Holder.imu lock instead.
2020-09-16 09:41:05 -05:00
Kuba Podgórski
dd4ffff704
Merge pull request #853 from kuba--/fix-translate_index_keys
Fix translation index keys
2020-09-16 15:21:31 +02:00
Kuba Podgórski
fa159c9a17
Merge branch 'master' into fix-translate_index_keys 2020-09-16 15:09:49 +02:00
jaten-molecula
47926092ee
Merge pull request #855 from molecula/cleanup_cherrypick
cleanup lmdb tests that were leaving test directories behind
2020-09-16 07:51:23 -04:00
Jason Aten
c093aa9d0e cleanup lmdb tests 2020-09-16 06:46:12 -05:00
Kuba Podgórski
ab26134992
Merge branch 'master' into fix-translate_index_keys 2020-09-16 10:39:32 +02:00
Kuba Podgórski
a8a9a73b6c Fix translation index keys 2020-09-16 10:36:44 +02:00
tgruben
793cf934b8
Merge pull request #848 from molecula/fix_843
don't panic if dbs is reopened under roaring only. fixes #843
2020-09-15 16:54:52 -05:00
Jason Aten
439ac243b4 don't panic if dbs is reopened under roaring only. fixes #843 2020-09-15 15:52:05 -05:00
Kuba Podgórski
e83e18832a
Merge pull request #847 from kuba--/fix-writable
Fix TranslateStore writable
2020-09-15 20:36:27 +02:00
Kuba Podgórski
dcc237413e
Merge branch 'master' into fix-writable 2020-09-15 19:14:24 +02:00
Nia
c7a0b17600
Merge pull request #846 from niaow/typenames
Fix type names in PQL Extract and SQL Show
2020-09-15 13:13:32 -04:00
Kuba Podgórski
76715a3f9d Fix TranslateStore writable 2020-09-15 19:09:59 +02:00
Nia Weiss
19e0f3601b
fix type names in PQL Extract and SQL Show 2020-09-15 12:53:21 -04:00
tgruben
9649819c09
Merge pull request #845 from molecula/rebal_together_rb
fine tune Tx placement, make it lazier so we don't create extra shards.
2020-09-14 18:34:15 -05:00
jaten-molecula
28fa1d036e
Merge branch 'master' into rebal_together_rb 2020-09-14 19:21:31 -04:00
Jason Aten
748f6a61bc fine tune Tx placement, isolate Tx backends more.
- Tx creation is lazier so we don't create xtra shards.

 - Then the dir scan for blue-green state checking finds only the right shards.
2020-09-14 18:03:25 -05:00
Travis Turner
37196b5e03
Merge pull request #834 from travisturner/metric-typos
Fix typos in transaction metric names
2020-09-14 17:32:53 -05:00
Travis Turner
d2c6a8ddde
Merge branch 'master' into metric-typos 2020-09-14 17:20:49 -05:00
seebs
72b1eec2e9
Merge pull request #829 from seebs/storeDistinct
Test cases for Store(Distinct)
2020-09-14 14:28:05 -05:00
Seebs
e7b239d2d8 Test cases for Store(Distinct)
This adds testing for Store(Distinct(...)) with and without filters, to verify that
we can, in fact, store the results of a Distinct() query directly. This was at one
point unsupported, now we think it should work so we're testing it.

The change to the testdata is because the specific structure used for this test doesn't
work with a keyed index, and changing things to be "foreign keys" seems annoying and
more complicated, but possibly that should become part of a future test.

There was talk of testing this with non-BSI fields, but they don't seem to
actually work with Distinct right now, so that will be later.
2020-09-14 14:15:29 -05:00
seebs
88d0f541aa
Merge pull request #841 from seebs/setMapped
export SetMapped from roaring, use it in Tx stores
2020-09-14 14:15:11 -05:00
Seebs
8ab9174a09 export SetMapped from roaring, use it in Tx stores
Thaw() is supposed to always provide writable storage, which it does
by ensuring that containers aren't frozen, but also by cloning or
copying their data if the data is marked as being memory-mapped.

But only the roaring backend had the ability to mark data as memory-mapped,
because that wasn't exported. Fixed this, and added corresponding code
to badger, lmdb, and rbf.
2020-09-14 14:08:00 -05:00
Ben Johnson
343c446b7e
Merge pull request #839 from molecula/rbf-fix-checkpoint
Remove tx before issuing checkpoint.
2020-09-14 12:56:03 -06:00
jaten-molecula
d0ce2e1207
Merge branch 'master' into rbf-fix-checkpoint 2020-09-14 13:58:24 -04:00
alanbernstein
1e40af7e25
Merge pull request #830 from alanbernstein/metrics-json-fix
Fix panicking metrics.json endpoint
2020-09-14 12:28:39 -05:00
Ben Johnson
77661a891d Remove tx before issuing checkpoint. 2020-09-14 10:36:59 -06:00
Alan Bernstein
18a593008a Add simple tests for metrics endpoints 2020-09-14 11:34:59 -05:00
Alan Bernstein
acbd6ec37c New channel per node 2020-09-14 11:34:59 -05:00
jaten-molecula
fc2518e2d1
Merge pull request #838 from molecula/fix_rr_leaks
fix TestImportClearRestart resource leaks under roaring, better skipForRoaring func
2020-09-14 11:38:26 -04:00
Jason Aten
7028bcfc9d fix resource leaks in fragment_internal_test.go under roaring, better skipForRoaring func
- add tournament.sh to do all pair-wise comparisons of blue-green backends.
- isolate txstores away from roaring index/ directories with indexname.index.txstores@@@ dirs.
2020-09-13 22:45:39 -05:00
Travis Turner
a0db828701
Merge pull request #835 from travisturner/port-vdsm-metrics
Port over VDSM metrics
2020-09-11 16:28:36 -05:00
Travis
41e0465eda
Port over VDSM metrics 2020-09-11 16:03:50 -05:00
Travis
75644af64d
Fix typos in transaction metric names 2020-09-11 15:18:39 -05:00
tgruben
5e00dbadc2
Merge pull request #812 from molecula/bgdev_rb
blue_green migration; holdbkg.go holder goroutine.
2020-09-11 14:32:09 -05:00
Jason Aten
2eb097c14d blue_green migration. holdbkg.go holder goroutine.
- blue_green for doing migration. Called before Holder.Open finishes.
- holdbkg.go added for index lookup. Less wedging between a deadlock and a race.
- fix fault under read-only map under lmdb at
  TestExecutor_Execute_Row_Range/RowIDColumnID by doing cow in roaring.
- roaring -tags gofuzz builds again
- roaringparanoia build tag added to make test targets in Makefile
- add rbf.NewDBWithAllocZero for out-of-bounds memory checks
- .circleci/config.yml test-shardwidth-22 with large run container, kept OOM-ing we suspect.

Fixes #819
2020-09-11 14:24:15 -05:00
Antonio Navarro Perez
a68ee73f00
Merge pull request #782 from ajnavarro/remove-blake3-duplicated-code 2020-09-11 11:23:25 +02:00
jaten-molecula
2cc7c829cd
Merge branch 'master' into remove-blake3-duplicated-code 2020-09-11 01:14:02 -04:00
Ben Johnson
5b72a68628 Stack allocate return from rbf.Tx.cursor() 2020-09-10 14:58:22 -06:00
Nia
be944a6247
Merge pull request #822 from niaow/inspect-panic
Fix inspect panic from incorrect handling of the many types of empty argument
2020-09-09 09:39:20 -04:00
Nia Weiss
6ff224308d
fix inspect panic from incorrect handling of the many types of empty argument 2020-09-09 09:11:21 -04:00
seebs
db578423bb
Merge pull request #818 from seebs/roaringDoc
Roaring documentation updates and fixes resulting from them
2020-09-08 22:41:48 -05:00
Seebs
c079d4764b Check for possibly-dirty N values in containers modified in-place
After documenting the semantics, I noticed an arguable hole in them,
which is that you could Freeze() a dirty container, and then Repair()
wouldn't work on it. On further study, I added a roaringparanoia
check for attempts to access the N of dirty containers.

It turns out there's several such. But also, it turns out, there's
circumstances where unionInPlace is relying on the assumption that
N is valid, which it isn't always for dirty containers. Also, there's
at least one case where we rely on the assumption that forcibly
thawing a container, then calling unionInPlace on it, always modifies
that container. But that's not supposed to be true for an empty
container -- an empty container might be better handled by just
returning the container it's being unioned with. So, we drop the
unnecessary thaw (all the *InPlace ops are already thawing if/when
they need to), but we use the return from unionInPlace.
2020-09-08 13:16:54 -05:00
Seebs
17ba2e35a9 call helper functions every time to get new run slices
If you just stash the results of the function when defining the test cases, the
outcome is in part that you are reusing the same slices for multiple things. So,
for instance, if you perform a union on the OddBitsSet slice, with the EvenBitsSet
slice, the result is to overwrite the first entry in that slice with the 0-ffff
run... But the original slice still exists, and then we reuse it and get a slice
with a bit count of around 98,000. The underlying issue is that doContainer()
is calling NewContainerRun(), which is simply using the provided slice, not
copying it -- which is intentional, but the test has to be careful about it.

We call repair on the one we think should be a bitmap. Theoretically
maybe we should also repair the other one in case unionRunRun some day
starts returning unrepaired bitmaps, which in principle it's allowed to
do...
2020-09-08 12:38:49 -05:00
Seebs
ecacbf65d4 Document copy-on-write semantics, at all.
The copy-on-write semantics were previously documented only in
the 125-line commit log from the patch which introduced them. Add
documentation for them in a few likely places.
2020-09-08 11:44:56 -05:00
Ben Johnson
8397696a59
Merge pull request #813 from molecula/import-roaring-direct
Add direct import option; remove tx from fragment.Open()
2020-09-08 08:19:24 -06:00
Ben Johnson
a51c530763 Add direct import option; remove tx from fragment.Open() 2020-09-08 08:13:16 -06:00
Ben Johnson
62635e7668
Merge pull request #811 from molecula/fix-wal-replay
Fix RBF WAL replay/truncation
2020-09-08 08:11:00 -06:00
Ben Johnson
f2bde49d25 Fix RBF WAL replay/truncation 2020-09-07 09:39:26 -06:00
Antonio Navarro Perez
ca340f7e62 [hash] Remove duplicated blake3 code
blake3 code is used in several places on the code. The file was
duplicated on root and rbf package.

To avoid cyclic dependencies, I moved it to hash package. Some methods
must be public to use them in different places.

HashOfDir method was removed. Not used.

Signed-off-by: Antonio Navarro Perez <antnavper@gmail.com>
2020-09-07 12:24:22 +02:00
jaten-molecula
1994560cf6
Merge pull request #803 from molecula/fgen_refined
refine our f.gen nil handling to support blue/green
2020-09-04 18:52:32 -04:00
Jason Aten
63187f59ee refine our f.gen nil handling to support blue/green 2020-09-04 17:28:38 -05:00
Ben Johnson
278d518f03
Merge pull request #800 from molecula/rbf-exclusive-write
Add RBF exclusive lock mode
2020-09-04 13:41:52 -06:00
Ben Johnson
90663e070e
Merge branch 'master' into rbf-exclusive-write 2020-09-04 13:10:02 -06:00
jaten-molecula
bb101ebef2
Merge pull request #802 from molecula/fgen
restore former f.gen nil behavior
2020-09-04 14:56:45 -04:00
Ben Johnson
159d01b55d Add exclusive write option for RBF.
This commit adds the ability to start a transaction with an exclusive
lock for the entire database. This ensures no other read or write
transactions can run at the same time. Writes in this mode write
directly to the database and skip the WAL entirely.
2020-09-04 12:46:42 -06:00
Jason Aten
4b6e773c7c panic if f.gen is nil because it means the storage wasn't open 2020-09-04 13:19:46 -05:00
jaten-molecula
aebe028854
Merge pull request #777 from molecula/dbshard2
database per shard, HolderConfig, rbf bit-wise import speedups.
2020-09-04 14:04:13 -04:00
Ben Johnson
150c8a5b06 database per shard, HolderConfig, rbf bit-wise import speedups.
- introduce Query Context (Qcx) for managing database-per-shard.
- replaces the MultiTx, so mtx.go is retired and removed.
- introduces the HolderConfig struct and all Holders now have
  a path from birth.
- rbf speedups on bitwise writes
- badgerdb is removed due to unresolvable write conflicts.

fixes #703 #676
2020-09-04 13:00:33 -05:00
Nia
60da12a8e5
Merge pull request #784 from niaow/remove-sql-limit
Remove SQL artificial limit
2020-09-04 08:46:33 -04:00
Nia
ec41481523
Merge branch 'master' into remove-sql-limit 2020-09-04 08:11:48 -04:00
jaten-molecula
921f15991b
Merge pull request #788 from molecula/fldschk
pilosa-chk: show col, row translation, -v for fragment details
2020-09-03 19:20:11 -04:00
Jason Aten
1e87d113f1 pilosa-chk: col, row translation reported, -v shows fragment checksum 2020-09-03 18:14:49 -05:00
tgruben
17ddcacbd4
Merge pull request #787 from molecula/chktrans
cmd/translatorchk checksums and summarizes key counts from column key translators
2020-09-03 15:29:31 -05:00
Jason Aten
56803e6632 pilosa/cmd/translatorchk checksums and summarizes key counts from column key translators.
opens ~/.pilosa/index/_keys boltdbs and hashes the StringKey->ID mappings.
2020-09-03 15:23:05 -05:00
Nia Weiss
b676292d67
add named returns to clarify extractLimitOffset 2020-09-03 10:37:09 -04:00
Nia Weiss
daa784319c
remove SQL artificial limit 2020-09-03 09:14:11 -04:00
jaten-molecula
d3485dbdb3
Merge pull request #776 from niaow/configure-slurp
Configure slurp
2020-09-03 02:33:58 -04:00
jaten-molecula
0a548a9009
Merge branch 'master' into configure-slurp 2020-09-03 01:56:30 -04:00
Nia
82e5f09cb3
Merge pull request #779 from niaow/pg-race
Fix race condition in pg cancellation test
2020-09-02 19:07:28 -04:00
Nia Weiss
c9995bfae1
fix race condition in pg cancellation test 2020-09-02 19:01:47 -04:00
Nia
bd1b76e25e
Merge pull request #760 from niaow/pg-local-cancel
Add support for local cancellation to postgres endpoint
2020-09-02 15:05:31 -04:00
Nia
219e22cc64
Merge branch 'master' into pg-local-cancel 2020-09-02 14:02:18 -04:00
Nia Weiss
95d261b4d7
configure slurp 2020-09-02 12:53:16 -04:00
jaten-molecula
c213cb5457
Merge pull request #762 from molecula/optimize-import
rbf bitwise import optimizations
2020-09-01 21:44:46 -04:00
jaten-molecula
55cb448c37
Merge branch 'master' into optimize-import 2020-09-01 21:18:57 -04:00
Travis Turner
836d055978
Merge pull request #759 from travisturner/join-bug
fix bug on left/right join mapping
2020-09-01 19:06:49 -05:00
Kuba Podgórski
6255c3f07f
Merge branch 'master' into join-bug 2020-09-02 01:51:48 +02:00
Travis Turner
72c068a64f
Merge pull request #773 from travisturner/row-pointer
return *Row instead of Row on empty key result
2020-09-01 18:31:29 -05:00
Travis
32b5826d1a
fix bug on left/right join mapping 2020-09-01 18:22:55 -05:00
Travis
d02cb10687
return *Row instead of Row on empty key result 2020-09-01 17:34:29 -05:00
alanbernstein
58007ab7ef
Merge pull request #765 from alanbernstein/lattice-release
Add embedded UI to default release process
2020-09-01 13:27:08 -05:00
Alan Bernstein
007b3ffc3c re-re-arrange error checks 2020-09-01 11:32:58 -05:00
Alan Bernstein
4ce3879e2c Revert UI->Lattice name change, correct the ordering of error checks in statikHandler 2020-09-01 10:16:31 -05:00
Alan Bernstein
a597a79e2d Add embedded UI to default release process 2020-09-01 10:16:31 -05:00
Kuba Podgórski
2d202d6aa3
Merge pull request #766 from kuba--/fix-null
support null results
2020-09-01 15:33:02 +02:00
Kuba Podgórski
ceb72fc3a9 support null results 2020-09-01 13:00:30 +02:00
Nia
1e5f0ecc5d
Merge pull request #763 from niaow/sql-leak
Fix SQL memory leak
2020-08-31 14:38:23 -04:00
Nia Weiss
d421558f58
fix SQL memory leak 2020-08-31 13:10:49 -04:00
Nia
96a8fd5cb7
Merge pull request #724 from niaow/pg-primitive
Add primitive types to pg encoder
2020-08-31 13:04:39 -04:00
Nia Weiss
9f368b06bd
add licesnse header to pg formatter test 2020-08-31 12:42:37 -04:00
Nia Weiss
542eb2dba3
pg formatter tests 2020-08-31 12:39:55 -04:00
Nia Weiss
cfcc1da0bb
add primitive types to pg encoder 2020-08-31 12:27:10 -04:00
Nia
9b12c01c2b
Merge pull request #736 from niaow/dirtycache
Force ranked cache recalculation in Top after a skipped invalidation
2020-08-31 11:56:50 -04:00
Nia
ac57a0bd42
Merge branch 'master' into dirtycache 2020-08-31 11:28:52 -04:00
Ben Johnson
1672158e65
Merge branch 'master' into optimize-import 2020-08-31 08:58:12 -06:00
Ben Johnson
627b50d89d misc import optimizations 2020-08-31 08:46:53 -06:00
alanbernstein
b2cad11c99
Merge pull request #733 from alanbernstein/enlattice
Embed lattice via statik
2020-08-31 09:40:02 -05:00
Alan Bernstein
b14ebcadae Unexport statik filesystem 2020-08-31 09:02:46 -05:00
Cody Soyland
a3e122dc5e Fix CORS support by applying middleware to router. 2020-08-31 09:02:46 -05:00
Alan Bernstein
f9d3040827 Update gitignore and makefile 2020-08-31 09:02:46 -05:00
Alan Bernstein
384b6511cd Replace null with [] in /schema field response 2020-08-31 09:02:46 -05:00
Alan Bernstein
659a2bb560 Silence stderr in makefile 2020-08-31 09:02:46 -05:00
Alan Bernstein
6e917b6a9a Log lattice version info 2020-08-31 09:02:46 -05:00
Alan Bernstein
99869ce792 Minor fixes 2020-08-31 09:02:46 -05:00
Alan Bernstein
b039bd50a1 Switch to mux PathPrefix matcher entirely 2020-08-31 09:02:46 -05:00
Alan Bernstein
19ee27fdb6 Use SPA handler to serve from filesystem, to test routing behavior 2020-08-31 09:02:46 -05:00
Alan Bernstein
d912403eb2 Add missing file 2020-08-31 09:02:46 -05:00
Alan Bernstein
88a288e775 Embed lattice via statik 2020-08-31 09:02:46 -05:00
Kuba Podgórski
b88c5cd5ea
Merge pull request #753 from kuba--/grpc-errcode
Add rich error types to gRPC interface
2020-08-31 15:45:24 +02:00
Kuba Podgórski
bfff643f34 Fix error code for PostVDS 2020-08-31 12:16:07 +02:00
Kuba Podgórski
f7a0e5f536 Fix error code for DeleteVDS 2020-08-31 12:14:58 +02:00
Kuba Podgórski
bf17385409
Merge branch 'master' into grpc-errcode 2020-08-31 10:25:35 +02:00
Nia Weiss
bf7e4b5583
add support for local cancellation to postgres endpoint 2020-08-29 14:56:49 -04:00
Nia
9c0d45a2d9
Merge pull request #752 from niaow/batch-translate
Batch the translation of field keys in results
2020-08-28 15:25:19 -04:00
Nia
5bc5991bd7
Merge branch 'master' into batch-translate 2020-08-28 15:09:05 -04:00
Kuba Podgórski
25ead95967
Merge branch 'master' into grpc-errcode 2020-08-28 20:42:28 +02:00
Nia Weiss
8549b74421
merge groupcount translations check into an else-if 2020-08-28 14:22:35 -04:00
Nia
a872548b01
Merge pull request #756 from niaow/postgres-sql-empty
Write empty column headers in postgres when there is no response
2020-08-28 14:20:22 -04:00
Nia Weiss
57fdabfe40
write empty column headers in postgres when there is no response 2020-08-28 13:28:50 -04:00
Travis Turner
81d32a6eeb
Merge pull request #751 from travisturner/sql-mapper-stuff
add sql mapper routes for count(*) on joins
2020-08-28 11:55:49 -05:00
Travis Turner
27c2368b9a
Merge branch 'master' into sql-mapper-stuff 2020-08-28 11:43:16 -05:00
Nia Weiss
0a9699490b
batch the translation of field keys in results 2020-08-28 11:56:37 -04:00
Kuba Podgórski
2b1c9950f4 Add rich error types to gRPC interface 2020-08-28 17:24:49 +02:00
jaten-molecula
f2fb2c98f8
Merge pull request #737 from molecula/bulk-import-value
Implement TxBitmap to cache up many bit changes in a Tx
2020-08-28 00:43:46 -04:00
Travis
ae07aacd51
add sql mapper routes for count(*) on joins 2020-08-27 22:49:54 -05:00
jaten-molecula
4883424205
Merge branch 'master' into bulk-import-value 2020-08-27 21:43:32 -04:00
Nia
9c621d7622
Merge pull request #742 from niaow/pg-require-tls
Fix postgres configuration
2020-08-27 12:49:45 -04:00
Nia Weiss
f0f8336f57
rename postgres.addr to postgres.bind for consistency 2020-08-27 11:35:54 -04:00
Ben Johnson
e3db6c9cec Implement bulk value import 2020-08-27 09:20:23 -06:00
Nia Weiss
68542ddc35
force ranked cache recalculation in Top after a skipped invalidation 2020-08-27 11:05:18 -04:00
Nia Weiss
288593231f
require TLS when configured 2020-08-27 10:59:40 -04:00
Nia Weiss
47dd6b5b8f
fix postgres endpoint config 2020-08-27 10:49:43 -04:00
Nia Weiss
c2823a933b
add a config option to require TLS on postgres 2020-08-27 10:49:43 -04:00
Kuba Podgórski
475a9e3910
Merge pull request #732 from kuba--/translatekey-writable
Add writable argument to TranslateKey functions.
2020-08-27 16:15:49 +02:00
Kuba Podgórski
248ec3a296
Merge branch 'master' into translatekey-writable 2020-08-27 16:10:29 +02:00
Kuba Podgórski
6b9eed3af4
Merge pull request #743 from kuba--/fix-info
Pass name to newNotFoundError
2020-08-27 16:08:40 +02:00
Kuba Podgórski
2ca8ca0605 Pass name to newNotFoundError 2020-08-27 15:35:23 +02:00
Nia
c3174efdeb
Merge pull request #740 from niaow/xor-array-array
Speed up xorArrayArray
2020-08-26 17:30:57 -04:00
Nia Weiss
6e06cc0c30
speed up xorArrayArray 2020-08-26 17:14:24 -04:00
Kuba Podgórski
9cf58ddb1c Add writable argument to TranslateKey functions. 2020-08-26 09:57:50 +02:00
Kuba Podgórski
ca5e27ad8e
Merge pull request #721 from kuba--/invalid-query/fix-706
Fix https://github.com/molecula/pilosa/issues/706
2020-08-25 21:33:54 +02:00
Kuba Podgórski
b67148ccfc
Merge branch 'master' into invalid-query/fix-706 2020-08-25 20:38:30 +02:00
Nia
6db4c8bb3a
Merge pull request #725 from niaow/storekeyed
Fix Store() into a keyed set
2020-08-25 14:08:46 -04:00
Kuba Podgórski
24980c7af8
Merge branch 'master' into invalid-query/fix-706 2020-08-25 19:30:03 +02:00
Nia Weiss
a8e7c2d0ef
fix Store() into a keyed set 2020-08-25 11:39:03 -04:00
jaten-molecula
8ad3dd2de6
Merge pull request #728 from molecula/skip_cluster_tests_bg
TestClusterResize_AddNode,AddNodeConcurrentIndex skipped blue-green roaring
2020-08-25 04:06:49 -04:00
tgruben
06281fc0c8
Merge branch 'master' into skip_cluster_tests_bg 2020-08-25 02:30:00 -05:00
tgruben
15315e47ee
Merge pull request #729 from molecula/fix683
test roaring.Container.UnionInPlace does not overflow
2020-08-25 02:29:29 -05:00
jaten-molecula
bc18e4dc42
Merge branch 'master' into skip_cluster_tests_bg 2020-08-25 03:28:00 -04:00
Jason Aten
ca7552b4a8 test that roaring.Container.UnionInPlace does
not overflow two big arrays into an invalid array.

recreate badloader from git history, at 85fa67e8. Could not
reproduce this, but lots of container usage
also got updated in the meantime.

Fixes #683
2020-08-24 17:06:41 -05:00
jaten-molecula
c5660ed712
Merge pull request #701 from molecula/fix-rbf-race
Remove duplicate checkpoint() invocation
2020-08-24 16:19:20 -04:00
jaten-molecula
ec02d5a00e
Merge branch 'master' into fix-rbf-race 2020-08-24 16:06:25 -04:00
jaten-molecula
0e6b65d3c2
Merge branch 'master' into skip_cluster_tests_bg 2020-08-24 16:02:13 -04:00
Jason Aten
48f31ddce7 TestClusterResize_AddNode and TestClusterResize_AddNodeConcurrentIndex skipped under blue-green test with roaring 2020-08-24 14:57:08 -05:00
alanbernstein
14a9a838eb
Merge pull request #690 from alanbernstein/prometheus-json
Add metrics.json endpoint using prometheus/prom2json
2020-08-24 14:29:27 -05:00
Alan Bernstein
9b027a89b9 Return dict of all node metrics 2020-08-24 14:04:02 -05:00
Alan Bernstein
d9b670c83c Add metrics.json endpoint using prometheus/prom2json 2020-08-24 14:04:02 -05:00
Sarah
6c4e8aeff5
Merge branch 'master' into fix-rbf-race 2020-08-24 13:23:56 -05:00
jaten-molecula
0e4144c302
Merge pull request #709 from molecula/audit3rb
testhook: Leak auditing infrastructure
2020-08-24 12:32:20 -04:00
Seebs
cecaf99ee4 testhook: leak auditing infrastructure
The testhook/ package provides an easy way to set up multiple
hooks to run before/after tests are run.

The audit hooks track open and closes of storage backends,
files, indexes, and holders, for example. A tempdir wrapper
creates temporary directories which are automatically cleaned up
when the test ends. Any kind of resource creation that
should be closed at test conclusion can be tracked. We
will complain at the end of the TestMain if resources are
leaking.

Leaks under go1.13:

We use a wrapper function which is a no-op for go 1.13, but actually
calls testing.TB.Cleanup in go1.14, so we can still build with 1.13 even though
tests will leak files all over the place there. Because of this,
don't run the testhook tests when using 1.13, as they'll always fail.

- the test/pilosa.go http client now times out after 10 seconds
to help diagnose hung server situations.

- Makefile targets added to get better progress reports.
2020-08-24 11:26:39 -05:00
jaten-molecula
7e326fb833
Merge pull request #722 from tgruben/rbf-add
copied optimized add/remove to rbf
2020-08-24 11:42:57 -04:00
Todd Gruben
edf6608129 copied optimized add/remove to rbf
use large test container for CI
2020-08-24 10:37:25 -05:00
Kuba Podgórski
397d37a129 Fix https://github.com/molecula/pilosa/issues/706 2020-08-24 15:34:09 +02:00
Kuba Podgórski
bc3f329e8f
Merge pull request #720 from kuba--/sql-drop
Add support for SQL 'drop table...'
2020-08-24 14:52:49 +02:00
Kuba Podgórski
ceda4ab61b Add support for drop table 2020-08-24 13:24:18 +02:00
tgruben
9caa670c90
Merge pull request #719 from tgruben/lmdb-add
copied badger addRemove implementation to lmdb
2020-08-23 08:50:07 -05:00
tgruben
9e94c86932
Merge branch 'master' into lmdb-add 2020-08-23 08:40:16 -05:00
Todd Gruben
4dd4b441c4 copied badger addRemove implementation to lmdb 2020-08-23 08:39:03 -05:00
jaten-molecula
4a6d8bc5df
Merge branch 'master' into fix-rbf-race 2020-08-22 23:23:57 -04:00
Nia
0ce9062588
Merge pull request #716 from kuba--/sql-show
Add support for SHOW queries
2020-08-21 19:46:47 -04:00
Kuba Podgórski
ad9e3338b5 Add support for SHOW queries 2020-08-22 01:25:35 +02:00
Nia
c137efbe44
Merge pull request #707 from niaow/pg-sql
Add SQL to postgres endpoint
2020-08-21 19:13:26 -04:00
Kuba Podgórski
cb89a4a831
Merge branch 'master' into pg-sql 2020-08-22 01:01:22 +02:00
Kuba Podgórski
37a4cda454
Merge pull request #563 from kuba--/fix-210/translate-entry
Fix 210/translate entry
2020-08-22 00:52:53 +02:00
Kuba Podgórski
7c13fa71d7
Merge branch 'master' into fix-210/translate-entry 2020-08-22 00:18:34 +02:00
Kuba Podgórski
6d0baa82b3
Update http/translator_test.go
Co-authored-by: Travis Turner <travis@pilosa.com>
2020-08-22 00:18:25 +02:00
Kuba Podgórski
cc66775ea4
Update http/translator_test.go
Co-authored-by: Travis Turner <travis@pilosa.com>
2020-08-22 00:18:19 +02:00
Nia
842377ba17
Merge pull request #713 from niaow/dont-log-100000-times
Stop logging in TestStartupInvalidLength
2020-08-21 17:29:52 -04:00
Nia Weiss
dd73bf3960
stop logging in TestStartupInvalidLength 2020-08-21 17:20:10 -04:00
jaten-molecula
8d397babdf
Merge pull request #710 from molecula/clear_importvals
ImportRequest.Clear and ImportValuesRequest.Clear respected by api.Import() and api.ImportValues()
2020-08-21 15:42:24 -05:00
tgruben
056d5990da
Merge branch 'master' into clear_importvals 2020-08-21 15:33:04 -05:00
Jason Aten
40a9d01f46 ImportRequest.Clear and ImportValuesRequest.Clear respected by api.Import() and api.ImportValues()
- tested in TestAPI_ClearFlagForImportAndImportValues api_test.go
2020-08-21 15:17:44 -05:00
Nia Weiss
49c3bd9701
add SQL to postgres endpoint 2020-08-21 14:47:59 -04:00
Ben Johnson
91c8c5b5e9
Merge branch 'master' into fix-rbf-race 2020-08-21 10:33:43 -06:00
Kuba Podgórski
a2f24bc115
Merge pull request #663 from kuba--/sql-mapper
SQL mapper
2020-08-21 17:24:59 +02:00
Ben Johnson
162bd0303a Remove duplicate checkpoint() invocation 2020-08-21 08:25:04 -06:00
Kuba Podgórski
17fa1e578b Add benchmark for translation reader 2020-08-21 15:15:41 +02:00
Kuba Podgórski
bbbeb22d31
Merge branch 'master' into sql-mapper 2020-08-21 03:17:46 +02:00
tgruben
57babb3269
Merge pull request #700 from molecula/atomicrecord
AtomicRecord allows the client to request atomic updates.
2020-08-20 17:42:15 -05:00
Jason Aten
df5dd1557e AtomicRecord allows the client to request atomic updates.
- Atomic record contains multiple ImportRequest and
   ImportValueRequest, plus ability to Clear individual requests.
 - adds http handlers for importing AtomicRecord.
2020-08-20 17:33:52 -05:00
Kuba Podgórski
0e0a405184
Merge branch 'master' into sql-mapper 2020-08-20 21:53:59 +02:00
Nia
272f6708a3
Merge pull request #679 from niaow/pg
Add a postgres endpoint to pilosa
2020-08-20 14:24:56 -04:00
Kuba Podgórski
6fa69fb81a
Merge branch 'master' into sql-mapper 2020-08-20 20:17:53 +02:00
Nia Weiss
14676c0713
remove postgres debugging types 2020-08-20 14:17:50 -04:00
Nia
44061923c7
Update pg/message/io.go
Co-authored-by: Travis Turner <travis@pilosa.com>
2020-08-20 14:14:14 -04:00
Nia Weiss
128e02046a
add a postgres endpoint to pilosa 2020-08-20 11:29:16 -04:00
alanbernstein
68b17312e0
Merge pull request #687 from alanbernstein/unicode
Use _buffer instead of buffer
2020-08-19 17:12:26 -05:00
Alan Bernstein
6fc5465aaa Use rune slice in all cases, add tests 2020-08-19 16:32:27 -05:00
Alan Bernstein
0a96043c23 Use _buffer instead of buffer 2020-08-19 16:32:27 -05:00
Kuba Podgórski
0be436e18d
Merge branch 'master' into sql-mapper 2020-08-19 21:33:58 +02:00
Ben Johnson
0a37f396f8
Merge pull request #671 from molecula/wal-write-cache
Add RBF WAL write cache
2020-08-19 09:54:55 -06:00
Ben Johnson
9dbb82cf3e WAL mutex fixes 2020-08-19 08:42:53 -06:00
Ben Johnson
51504f4fe4 Add WAL write cache mutex; update name; add benchmarks 2020-08-19 08:33:19 -06:00
Ben Johnson
5849794a1b Add RBF WAL write cache 2020-08-19 08:33:19 -06:00
Cody Soyland
776de471db
Merge pull request #693 from molecula/ubuntu_dockerfile
ubuntu 20:10 image instead of alpine, for cgo support
2020-08-18 20:40:26 -05:00
Jason Aten
ef156f6172 ubuntu 20:10 image instead of alpine, for cgo support 2020-08-18 16:55:44 -05:00
Kuba Podgórski
2b34976c22 porting sqlmapper from vdsm 2020-08-18 15:53:26 +02:00
Cody Soyland
039780a85e
Merge pull request #685 from molecula/discard-test-386
no more test-386
2020-08-17 20:15:14 -05:00
Jason Aten
aea7d4a812 no more test-386
- lmdb won't build under 386
 - still have to keep lmdb_other.go for arm/arm64
2020-08-17 19:54:50 -05:00
jaten-molecula
ba1d5e9f9f
Merge pull request #681 from molecula/fix-rbf-reopen
Fix RBF checkpoint on reopen. Fixes #673
2020-08-17 19:16:17 -05:00
jaten-molecula
3e4da916e8
Merge branch 'master' into fix-rbf-reopen 2020-08-17 19:09:55 -05:00
tgruben
d84ae88944
Merge pull request #677 from molecula/lmdb_as_backend
add lmdb, Tx call stats, and prep for db/shard.
2020-08-17 18:43:57 -05:00
Jason Aten
123ce41840 add lmdb, Tx call stats, and prep for db/shard.
- lmdb as a backend (lmdb.go)
   (lmdb is the fastest known transactional storage backend)
 - per Tx call statics report enabled with PILOSA_CALLSTAT=true (stattx.go)
 - framework for per-shard db (dbshard.go)
 - txfactory handles any pair under blue-green testing (txfactory.go)
 - enable CGO in Dockerfiles for lmdb
2020-08-17 18:26:58 -05:00
seebs
4f7e4feaf8
Merge pull request #680 from seebs/cachefix
when updating a container, drop the single-container cache
2020-08-17 15:03:10 -05:00
Ben Johnson
b1e806a518 Fix RBF checkpoint on reopen.
Previously, the `rbf.DB.opened` flag was set after `checkpoint()`
when reopening, however, this flag is checked by `checkpoint()` so
it was not properly executing.
2020-08-17 13:28:28 -06:00
Seebs
16ba54293a when updating a container, drop the single-container cache
This can cause incredibly weird and hard-to-debug problems if the previous
container value is still in the cache after an update, and in particular,
can result in having a stale container value cached after a roaring import
that modified the container. Coupled with another bug which could corrupt
containers on a delete, this produces a very strange bug where a value is
present in a fragment, but an attempt to delete it reports failure.
2020-08-17 11:23:47 -05:00
Travis Turner
c5e9b8d917
Merge pull request #674 from travisturner/container-corrupt
stop setting N on a frozen container
2020-08-16 15:59:58 -05:00
Travis
ff5925aa8b
stop setting N on a frozen container 2020-08-14 17:25:14 -05:00
Matthew Jaffee
cd83f7965c
Merge pull request #672 from molecula/remove-transaction.md
remove old transactions doc
2020-08-14 14:40:10 -05:00
Matt Jaffee
b11bdeab87
remove old transactions doc 2020-08-14 11:57:28 -05:00
jaten-molecula
05ca83c2f5
Merge pull request #669 from molecula/autocommit2
build-tag out lmdb-go from builds; lower autocommit limits to avoid ErrTxnTooBig; improve txn size estimation
2020-08-13 11:52:42 -05:00
Jason Aten
c90c4c275d lower autocommit limits to avoid ErrTxnTooBig; improve txn size estimation 2020-08-13 16:42:47 +00:00
Travis Turner
1f53e86e47
Merge pull request #662 from travisturner/transaction-list
transactions as a list endpoint; added Transaction.CreatedAt
2020-08-13 08:40:57 -05:00
Travis
1837811ce1
transactions as a list endpoint; added Transaction.CreatedAt 2020-08-12 23:11:54 -05:00
tgruben
0dea018fb7
Merge pull request #665 from molecula/autocommit
tested working autocommit approach
2020-08-12 21:56:03 -05:00
Jason Aten
5e49e10cda tested working autocommit approach 2020-08-13 01:12:14 +00:00
jaten-molecula
c7d6229380
Merge pull request #664 from molecula/bigtx
PutContainer() handles large txn with autocommit
2020-08-12 19:18:19 -05:00
Jason Aten
6dc9727796 PutContainer() handles large txn with autocommit 2020-08-12 23:15:23 +00:00
jaten-molecula
973e9a7955
Merge pull request #659 from molecula/rbf_99pct
all test green on rbf. WOOT.
2020-08-12 16:13:47 -05:00
Todd Gruben
547ee14f5b all test green on rbf. WOOT.
- rbf had races around the new rootRecords cache in tx
 - rbf tx needed a write lock on the db now that rootRecords are written
 - added a global registry for rbfDB to correctly dedup instances
 - implement DeleteFragment, DeleteIndex for rbf
 - use badger style keys for rbf to allow content checksumming to be list
    containers in the same order
 - lots of other integration of rbf into pilosa layer.
2020-08-12 21:08:30 +00:00
Cody Soyland
123e0b6376
Merge pull request #644 from codysoyland/grpc-crd-sql
Add gRPC methods to support the functionality of VDSM
2020-08-12 14:55:24 -05:00
Cody Soyland
21456827ae
Merge branch 'master' into grpc-crd-sql 2020-08-12 14:21:53 -05:00
Cody Soyland
3361033c5b Add PostVDS and DeleteVDS 2020-08-12 14:21:22 -05:00
Cody Soyland
3771bd43b5 Add note about gRPC unary methods and futures 2020-08-12 14:08:30 -05:00
Nia
50a2e3c5fa
Merge pull request #650 from jaddr2line/limit
Add a "Limit" query
2020-08-12 14:04:12 -04:00
Nia
911c039991
Fix incorrect negative in Limit query documentation
Co-authored-by: Travis Turner <travis@pilosa.com>
2020-08-12 13:53:57 -04:00
Jaden Weiss
40a6fbd79e
add a "Limit" query 2020-08-12 12:27:23 -04:00
Nia
2a1fafb227
Merge pull request #652 from jaddr2line/constrow
Add ConstRow query
2020-08-12 12:22:06 -04:00
Nia
a19ca16810
Merge branch 'master' into constrow 2020-08-12 11:47:46 -04:00
Travis Turner
683b8dfe31
Merge pull request #660 from travisturner/error-rows-int
error on Rows(field=<int>)
2020-08-11 19:44:46 -05:00
Travis
eae038a07e
error on Rows(field=<int>) 2020-08-11 18:07:03 -05:00
Jaden Weiss
0e16192aeb
add ConstRow query 2020-08-11 08:25:32 -04:00
Jaden Weiss
96c2364c1b
Merge pull request #642 from jaddr2line/query-extract
Add an "Extract" query
2020-08-10 19:32:36 -04:00
Jaden Weiss
590bd07995
add an "Extract" query 2020-08-10 09:33:55 -04:00
Cody Soyland
559a2c6864 Add GetVDS and GetVDSs gRPC implementations 2020-08-07 16:28:06 -05:00
Ben Johnson
2bc3442ae8
Merge pull request #649 from molecula/fix-rbf-rollback
Fix RBF checkpoint high water mark
2020-08-07 14:29:31 -06:00
Ben Johnson
faa1662bf6 Fix RBF checkpoint high water mark
Previously, the `checkpoint()` function determined the segments to drop
based on the current active transactions' WAL ID references. However, if
no transactions are active then the checkpoint would drop segments too
aggressively.

This changes the determination by using the highest WAL ID that is
actually checkpointed to disk to determine the high water mark. If no
page are checkpointed then no segments can be dropped.
2020-08-07 10:07:33 -06:00
Ben Johnson
5644867507
Merge pull request #643 from molecula/fix-rbf-hanging-tests
Fix RBF/pilosa hanging tests
2020-08-07 10:06:57 -06:00
Cody Soyland
35675a3e59 Add stubbed gRPC types to support python-molecula
This adds the following rpc calls: GetVDS, GetVDSs, PostVDS, DeleteVDS, QuerySQL, QuerySQLUnary

Currently, they are not implemented.
2020-08-06 14:19:16 -05:00
Ben Johnson
78f9fbe332 Fix RBF/pilosa hanging tests 2020-08-06 11:43:41 -06:00
alanbernstein
5306426b19
Merge pull request #641 from alanbernstein/more-docs-updates
Fix various docs issues
2020-08-05 12:34:57 -05:00
Alan Bernstein
5f26290f92 Fix various docs issues 2020-08-05 12:26:22 -05:00
Ben Johnson
3fb2cccb00
Merge pull request #637 from molecula/rbf-fixes
Multiple RBF test fixes
2020-08-05 09:02:06 -06:00
Ben Johnson
f8cacd8081 Multiple RBF test fixes 2020-08-05 08:20:34 -06:00
Travis Turner
df709af10e
Merge pull request #638 from travisturner/fix-executeclearrow
safe cast of bool in executeClearRow
2020-08-04 15:52:48 -05:00
Travis
ddee2cb0a8
safe cast of bool in executeClearRow 2020-08-04 15:16:23 -05:00
tgruben
7f6c6956d8
Merge pull request #635 from molecula/efence_off
DetectMemAccessPastTx flag added, default false.
2020-08-03 22:03:36 -05:00
tgruben
86b5d89bc9
Merge branch 'master' into efence_off 2020-08-03 21:24:23 -05:00
alanbernstein
dede69f04d
Merge pull request #590 from alanbernstein/improve-tx-error-messages
Improve 'shouldn't ever happen' error messages
2020-08-03 12:44:30 -05:00
alanbernstein
27edff60b0
Merge branch 'master' into improve-tx-error-messages 2020-08-03 12:34:22 -05:00
Jason Aten
b806322c5a DetectMemAccessPastTx flag added, default false. Allow badger to run at full speed rather than with debugging code on by default 2020-08-01 21:40:54 -04:00
tgruben
0820babc44
Merge pull request #634 from molecula/unionfix
Follow roaring.Union() with optimize() to avoid overly large containers.
2020-08-01 08:58:47 -05:00
Jason Aten
394b8522d1 Follow roaring.Union() with optimize() to avoid overly large containers.
The cmd/loader is a preliminary sketch of the load testing tool.
2020-07-31 20:10:43 -04:00
tgruben
d0c2b80021
Merge pull request #631 from molecula/rbf_thurs
rbf: OffsetRange, ImportRoaringBits, CountRange work
2020-07-30 19:30:04 -05:00
Jason Aten
a3d802f8a3 rbf: OffsetRange, ImportRoaringBits, CountRange work
green:
TestFragment_RowsIteration/combinations
TestFragment_RoaringImportTopN

red: (needs Ben's attention)
PILOSA_TXSRC=rbf go test -v -run TestFragment_TopN_IDs  -tags=' shardwidth20'  "-gcflags=all=-d=checkptr=0"

also red: (one for Ben)
TestCursor_FirstNext_Quick/9 is throwing
  panic: cannot find segment containing WAL page: 1
  as we check the error back from checkpoint() in Rollback().
2020-07-30 20:20:38 -04:00
jaten-molecula
2fb76ba919
Merge pull request #626 from molecula/rbf_dump
rbf Dump() and DumpString() debug methods.
2020-07-30 13:57:30 -04:00
Jason Aten
8903d8c117 rbf Dump() and DumpString() debug methods. 2020-07-30 13:50:36 -04:00
jaten-molecula
d2586210a2
Merge pull request #621 from molecula/bluegreen_atg
blueGreenTx roaring vs badger is all tests green (atg)
2020-07-30 12:04:11 -04:00
Jason Aten
72c893a3d1 blueGreenTx roaring vs badger is all tests green (atg).
back to github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200709123515-8e896a7af361  b/c github.com/dgraph-io/badger/v2 v2.0.1-rc1.0.20200718033852-37ee16d8ad1c had issues with CI on 386 and arm
2020-07-30 11:50:25 -04:00
Cody Soyland
5c5cd1e1fd
Merge pull request #620 from codysoyland/go-mod-tidy
Add CI job to ensure go mod files are tidy
2020-07-29 18:18:37 -05:00
Cody Soyland
55313bd69d Add CI job to ensure go mod files are tidy. 2020-07-29 15:28:58 -05:00
Ben Johnson
55c0785215
Merge pull request #597 from molecula/rbf-tx
Implement pilosa.Tx for RBF
2020-07-29 11:42:20 -06:00
Ben Johnson
64de208170 Implement pilosa.Tx for RBF 2020-07-29 11:25:41 -06:00
jaten-molecula
4cdf62ab89
Merge pull request #615 from molecula/parallelized_open_frag
Parallelize view.OpenFragmentsInTx
2020-07-28 11:18:13 -04:00
Jason E. Aten
71eccd121d fix race in view.openFragmentsInTx 2020-07-28 07:55:28 -04:00
Jason Aten
38eea9b4a7 reparallelize view.go openFragmentsInTx() 2020-07-28 07:55:28 -04:00
jaten-molecula
1a89fc27a1
Merge pull request #605 from molecula/badger_atg
Tx integration milestone
2020-07-27 20:44:12 -04:00
Jason Aten
ac7be132ef Tx integration milestone
a) All tests green under -race for both PILOSA_TXSRC=roaring and PILOSA_TXSRC=badger.

b) Distinct is merged back into mainline pilosa.

Seebs notes on the Distinct work:

merge Distinct plugin back into main source tree, convert to Tx

We drop all references to the Preemptively Deprecated Don't You Dare
Use This extension interface, and move the one and only extension we had
(Distinct) into the main executor.

Also this fixes an arguable bug, which is that Container.AsBitmap()
would panic on a nil parameter, but it should have returned an empty
bitmap, because a nil *Ccontainer is a valid empty container. This
simplifies logic significantly in Distinct.

Fixes #569 #570 #571 #572 #573 #584 #585
2020-07-27 19:29:46 -04:00
Ben Johnson
efc90a6d36
Merge pull request #596 from molecula/rm-rbf-fun-dot
Remove generation of rbf/fun.dot in tests
2020-07-23 10:12:17 -06:00
Ben Johnson
75930ed82f Remove generation of rbf/fun.dot in tests 2020-07-23 09:37:50 -06:00
alanbernstein
7c94828a3c
Merge pull request #589 from alanbernstein/broken-index-translation
Fix broken index key translation in state DEGRADED
2020-07-22 21:22:06 -05:00
Alan Bernstein
5ffc7d7b59 Move checkClusterStatus to test package 2020-07-22 19:54:44 -05:00
Travis
339b76a091 use c.Topology, when available, to determine partitionNodes 2020-07-22 16:41:53 -05:00
Alan Bernstein
a727c74d35 Use nodes from topology to calculate partitionNodes 2020-07-22 16:41:53 -05:00
Alan Bernstein
6c8e2e9450 Add test 2020-07-22 16:41:53 -05:00
Alan Bernstein
fa77a36e83 Improve 'shouldn't ever happen' error messages 2020-07-22 16:36:02 -05:00
Jaden Weiss
fd65384faa
Merge pull request #583 from jaddr2line/bsi-test
Test every possible BSI comparison up to 6 bits
2020-07-21 15:58:31 -04:00
Jaden Weiss
9072b4c290
test every possible BSI comparison up to 6 bits 2020-07-21 13:56:36 -04:00
seebs
f5a228e56d
Merge pull request #579 from seebs/shutdownresize
Handle cluster shutdown during a resize
2020-07-21 12:45:18 -05:00
seebs
aae1d25152
Merge branch 'master' into shutdownresize 2020-07-21 12:27:33 -05:00
Jaden Weiss
adde0fa0bc
Merge pull request #564 from jaddr2line/fix-between-common-bits
Fix BSI range queries with nonzero common upper bits and oversized BSI queries
2020-07-21 13:24:00 -04:00
Jaden Weiss
9fb5f8b349
Merge branch 'master' into fix-between-common-bits 2020-07-21 13:19:15 -04:00
Seebs
99420b564e Handle cluster shutdown during a resize
The new logic to send resize instructions more makes it easier
to hit this, but it's probably always been a theoretically possible
bug to hit: If you are shutting a cluster down, then you stop accepting
connections, which means that if you have an existing resize job, you
can't get responses for it. Which means that the other nodes will
fail to notify you of the success or failure of resize instructions,
so the code waiting on the resize job's status waits forever.

When closing, we bail immediately on that; we don't need to wait for
those notifications. We still have a buffer, and a reasonable confidence
that we'll never write more than one result status, so if one of them
*does* somehow show up and cause the job to have a status,
writing the status won't block.
2020-07-21 12:16:38 -05:00
jaten-molecula
4c0d66703e
Merge pull request #582 from molecula/fix575b
remove premature configuration of Txsrc in test config
2020-07-20 21:04:46 -04:00
Jaden Weiss
e6b4cc2f32
fix oversized rangeEQ 2020-07-20 20:43:50 -04:00
Jaden Weiss
b9b0dd293f
fix rangeBetween when there are nonzero common upper bits and oversized rangeGT 2020-07-20 20:38:32 -04:00
Jason Aten
f5688fa700 remove premature configuration of Txsrc in test config 2020-07-20 20:22:47 -04:00
jaten-molecula
d23ea94ec0
Merge pull request #581 from molecula/fix575
pilosa server --tx compatible with PILOSA_TXSRC. fixes #575
2020-07-20 18:48:40 -04:00
Jason Aten
7fe7ed907f env PILOSA_TXSRC is reinjected into the env if pilosa server --tx overrides it. fixes #575
1. Tests can choose the Tx engine desired by setting the PILOSA_TXSRC
      env variable. For example:

         PILOSA_TXSRC=badger go test -v -run TestImportClearRestart

   2. pilosa server --tx is enabled now.

     Examples:
      pilosa server --tx roaring    # gives the legacy approach.
      pilosa server --tx rbf        # will activate RBF
      pilosa server --tx badger     # will activate BadgerDB
      pilosa server --tx badger_rbf # will run Blue-Green badger to RBF comparisons.

      and so forth. See pilosa server -h or txfactory.go for all valid --tx choices.

   3. Mechanism that makes both tests(1) and pilosa server(2) work at once:
       pilosa/server/server.go injects PILOSA_TXSRC into env to
       communicate with NewIndex in pilosa/index.go.
2020-07-20 17:56:12 -04:00
jaten-molecula
22fd24566a
Merge pull request #580 from molecula/fix568
green TestImportClearRestart on PILOSA_TXSRC=badger. fixes #568
2020-07-20 17:24:29 -04:00
Jason Aten
8a1dabb3ba 60m timeout on race 2020-07-20 17:09:32 -04:00
Jason Aten
f59f8a369e green TestImportClearRestart on PILOSA_TXSRC=badger. fixes #568 2020-07-20 16:32:34 -04:00
jaten-molecula
1c9ef3d321
Merge pull request #565 from molecula/tx_roaring_badger
integration of Tx, RoaringTx and BadgerTx implementations.
2020-07-20 16:01:45 -04:00
Jason Aten
97b530ca78 integration of Tx, RoaringTx and BadgerTx implementations.
- all tests green on RoaringTx
  - RoaringTx on by default
  - blueGreenTx testing framework available for A-vs-B comparison
    of Tx implementations
  - flag -tx added to server command line but not wired to
    change NewIndex() selection yet.
  - 918 green tests, 14 tests red on BadgerTx.

    A full list of the 14 red tests on BadgerTx follows.
    Note that these red tests represent not defects in BadgerDB
    or BadgerTx but rather failures of the pre-existing pilosa infrastructure to yet
    be fully adapted from files to using a transactional storage engine.

    As such these are tests that RBF should not be expected to
    pass yet either.

    Fixing the pilosa infrastructure to allow these tests
    to go green under Badger is the next and highest priority
    order of business, but RBF can get much testing benefit
    from the 918 green tests we do have, and hence we merge
    as much as we have today.

    The 14 red tests when NewIndex() is set to use
    BadgerTx are as follows. Note in particular
    that pilosa cluster resizing is not working yet under a
    transactional store.

     TestCluster_ResizeStates/Multiple_nodes,_with_data
     TestImportClearRestart/0MaxOpN10000
     TestImportClearRestart/1MaxOpN10000
     TestImportClearRestart/2MaxOpN10000
     TestImportClearRestart/3MaxOpN10000
     TestExecutor_Execute_Existence/Row
     TestExecutor_ForeignIndex
     TestExecutor_Execute_CountDistinct/Distinct
     TestExecutor_Execute_CountDistinct/Count(Distinct)
     TestExecutor_Execute_CountDistinct/GroupBy(Distinct)
     TestExecutor_BareDistinct
     TestExecutor_Execute_TopNDistinct/TopN
     TestHolderSyncer_IntField/BasicSync
     TestHolderSyncer_IntField/MultiShard
2020-07-20 15:50:08 -04:00
seebs
ab6a3aff10
Merge pull request #458 from seebs/eaddrinuse
Fix very-sporadic EADDRINUSE failures in CI testing (and related cluster test issues)
2020-07-20 10:58:48 -05:00
Seebs
364b533ead various cluster test fixups/cleanups
Some cluster tests failed sporadically. In order to fix them, I
introduced some debugging-related functionality, which revealed
several new bugs that were actually existing bugs we just happened
not to hit in testing. This combines various fixes.

We start with "make the nodes used in testing have distinct names
based on the test case name", which lets us discover that we are
leaking clusters, which continue to sit around talking with each
other. That in turn causes significantly higher load on access to
ephemeral ports, which causes sporadic failures when we shut a
node down and try to restart it, but something else has gotten assigned
its ephemeral port number since then.

Part of the fix is to try to rebind on port 0 if an attempt to
bind to a specified port over 32k fails. This is a guess; the
actual ephemeral port range could be 16k+, 32k+, or 48k+, or just
about anything else really, but it seems reasonable in
practice.

There were bugs in the oft-repeated loops to await the cluster
achieving a given state, and it could hang forever if it didn't,
so we add a timeout and a standard function on the test.Cluster
type to handle that. Note that the timeout seems irrelevant; in
every case I've tried, a timeout of 0 is fine because the node
start doesn't complete until the cluster state has changed.

Add a method to test.Command to run a query, expecting a specific
result. Also clean up some of the formatting and generation of
queries, and allow parameterized (badly) queries. This lets us fix
a subtle bug, which is that test cases were depending on assumptions
about shardwidths. Also improve the diagnostic output from some of
these functions so test failures are more comprehensible.

But actually that dependency on shardwidths was ALSO revealing a
genuine underlying bug, which is that a node resize did not correctly
propagate the schema to a new node if there was no data present
on shards that node would own. We now also have a test case that
hits that (or would, if we hadn't fixed it).

Add comments explaining the server options parameters for MustNewCluster
and MustRunCluster.

Also, we implement the ReadFrom and WriteTo behaviors for
InMemTranslateStore, without which some of the cluster resize tests
fail. Props to the comment for specifically stating that they wouldn't
work if that happened, which probably saved me several hours of
debugging. The implementations may not be robust, but
InMemTranslateStore is intended to be used only in lightweight
and transient testing.
2020-07-20 10:45:59 -05:00
Seebs
ef8b054367 move Cluster type and methods into existing almost-empty cluster.go 2020-07-20 10:45:47 -05:00
tgruben
1067d29784
Merge pull request #547 from tgruben/refactor-putleaf
refactor putleaf
2020-07-17 13:39:35 -05:00
Todd Gruben
cd4bd016f9 skipping a test for ci issue 2020-07-17 09:30:07 -05:00
Todd Gruben
848359a36b skipped test for race wip 2020-07-17 09:15:20 -05:00
Todd Gruben
e61f0f6b1f missing liscense 2020-07-17 09:09:42 -05:00
tgruben
88bf29ea40
Merge branch 'master' into refactor-putleaf 2020-07-17 09:06:31 -05:00
Todd Gruben
9bbceb931a missing license 2020-07-17 09:05:53 -05:00
Todd Gruben
7c5c693fcb linter fix 2020-07-17 09:03:32 -05:00
Todd Gruben
59d2d89a5c removed leafArg and added conatinertypebitmapptr; lint fixes 2020-07-17 02:16:35 -05:00
Jaden Weiss
3f45a90582
Merge pull request #549 from jaddr2line/microseconds
Add microseconds to log
2020-07-16 17:13:10 -04:00
Jaden Weiss
de061ff21d
Merge branch 'master' into microseconds 2020-07-16 17:01:50 -04:00
Todd Gruben
bbd83e4618 . 2020-07-16 08:31:09 -05:00
Kuba Podgórski
2ee5e3d8e5
Merge pull request #538 from kuba--/translation-coordinator
Translation coordinator
2020-07-15 22:53:18 +02:00
Kuba Podgórski
ce628c96cd
Merge branch 'master' into translation-coordinator 2020-07-15 22:45:43 +02:00
Kuba Podgórski
1d6a4dea88
Merge pull request #554 from kuba--/i0-i1
Remove test leftovers
2020-07-15 14:06:23 +02:00
Kuba Podgórski
559e71f62a Remove test leftovers (holder's path). 2020-07-15 13:50:59 +02:00
Jaden Weiss
5579d632c7
Merge pull request #539 from jaddr2line/remove-arm64-binary
remove an arm64 pilosa binary that was committed for some reason
2020-07-14 20:08:23 -04:00
Kuba Podgórski
1edd773e90
Merge branch 'master' into remove-arm64-binary 2020-07-15 01:42:26 +02:00
Jaden Weiss
c99d35a793
Merge pull request #552 from jaddr2line/queries-docs
Add /queries endpoint to API reference
2020-07-14 18:26:27 -04:00
Jaden Weiss
b442ff8336
add /queries endpoint to API reference 2020-07-14 15:58:59 -04:00
Jaden Weiss
9036a16b08
add microseconds to log 2020-07-14 11:44:55 -04:00
Todd Gruben
e68f0a0d8f missing license 2020-07-14 09:00:09 -05:00
Todd Gruben
b61bdbd7a0 fix linter errors 2020-07-14 08:54:30 -05:00
Todd Gruben
374a4ec9ce fixed missing refactor test;refactor GetBitmap 2020-07-14 07:57:02 -05:00
Todd Gruben
b8fe08c765 simplify Walker interface 2020-07-13 20:34:33 -05:00
Todd Gruben
d6986b78a5 . 2020-07-13 20:08:22 -05:00
Todd Gruben
b2b614a686 refactor cursor.GetBitmap->tx.GetBitmap;rename to WalkRootRecordPages;err check 2020-07-13 19:32:26 -05:00
Todd Gruben
b11b43af43 refactor putleaf 2020-07-13 10:48:25 -05:00
Travis Turner
3c619fa2ef
Merge pull request #543 from travisturner/foreign-index-todos
Get ForeignIndex keys in GroupBy
2020-07-11 19:45:31 -05:00
Travis Turner
9f80619f19
Merge branch 'master' into foreign-index-todos 2020-07-11 18:24:55 -05:00
Kuba Podgórski
92ab76b621
Merge pull request #399 from molecula/alisharawal-patch-1
Update README.md
2020-07-11 21:28:14 +02:00
Kuba Podgórski
51ba2492e9
Merge branch 'master' into translation-coordinator 2020-07-11 19:22:48 +02:00
Kuba Podgórski
51891040d0
Merge branch 'master' into alisharawal-patch-1 2020-07-11 19:17:30 +02:00
Travis
a9dc8b8add
translate GroupBy previous value from foreign index 2020-07-11 10:18:45 -05:00
Travis
8f6b876af0
get ForeignIndex keys in GroupBy 2020-07-10 22:48:35 -05:00
alanbernstein
07d3cfe23b
Merge pull request #542 from alanbernstein/validate-transaction-id
Restrict allowed characters in transaction IDs
2020-07-10 20:18:42 -05:00
Kuba Podgórski
0fc7b89b48
Merge branch 'master' into remove-arm64-binary 2020-07-11 01:59:35 +02:00
Kuba Podgórski
010ab5ef8b Extend translate coordinator test 2020-07-11 01:51:03 +02:00
Alan Bernstein
65febc37fd Allow '' in ID regex 2020-07-10 18:07:17 -05:00
Alan Bernstein
7c37ececfd Restrict allowed characters in transaction IDs 2020-07-10 17:58:47 -05:00
Jaden Weiss
a947bc8ad9
Merge pull request #540 from jaddr2line/fix-inspect-query-validate
Fix incorrect validation of query specification in Inspect
2020-07-10 15:56:07 -04:00
Jaden Weiss
2f8d8345c1
fix incorrect validation of query specification in Inspect 2020-07-10 14:35:30 -04:00
Jaden Weiss
8940402e76
remove an arm64 pilosa binary that was committed for some reason 2020-07-10 13:28:27 -04:00
Travis Turner
c7ccd62b3b
Merge pull request #537 from travisturner/grpc-port-0
Replace grpc port code that I removed for some reason
2020-07-10 11:06:40 -05:00
Travis
85bd306eb5
replace grpc port code that i removed for some reason 2020-07-10 10:57:20 -05:00
Jaden Weiss
bb9b3d4e6f
Merge pull request #527 from jaddr2line/like
Add `Rows(like=...)` and `UnionRows` queries
2020-07-09 19:10:29 -04:00
Jaden Weiss
239aacc160
Merge branch 'master' into like 2020-07-09 19:04:03 -04:00
Jaden Weiss
62ce26e7b8
Merge pull request #534 from jaddr2line/inspect-query-v2
Add support for inspecting with a query
2020-07-09 14:09:47 -04:00
Jaden Weiss
f4e9e1688f
add support for inspecting with a query 2020-07-09 13:29:15 -04:00
Travis Turner
85d1fa30dc
Merge pull request #530 from travisturner/advertise-grpc
add --advertise-grpc configuration option
2020-07-09 11:38:18 -05:00
Travis
944a6dca78
add --advertise-grpc configuration option 2020-07-09 11:17:12 -05:00
Ben Johnson
3c021fc2e3
Merge pull request #526 from molecula/rbf
Roaring Bitmap Format
2020-07-08 13:39:37 -06:00
Ben Johnson
de51b538f3 rbf: roaring bitmap format
Co-authored-by: Todd Gruben <todd@pilosa.com>
2020-07-08 13:27:18 -06:00
Jaden Weiss
4bacab6524
update query language docs to include like and UnionRows 2020-07-08 13:08:11 -04:00
Jaden Weiss
c9edccb267
add executor tests and license headers for like & UnionRows 2020-07-08 12:55:18 -04:00
Jaden Weiss
7a16ffff68
add UnionRows query 2020-07-08 12:55:18 -04:00
Jaden Weiss
227881cb67
simplify suffix matching 2020-07-08 12:55:17 -04:00
Jaden Weiss
0611ef3418
initial implementation of Rows like 2020-07-08 12:55:17 -04:00
Jaden Weiss
ed8e5a933e
optimize & document & test like matcher
optimize suffix matching
add some descriptive comments to the like matcher
test all paths in the like tokenizer and matcher
2020-07-08 12:55:17 -04:00
Jaden Weiss
9eb8fcb37f
initial impl of like 2020-07-08 12:55:17 -04:00
alanbernstein
7f1b1f63ef
Merge pull request #506 from alanbernstein/docs-updates
Docs updates
2020-07-07 15:27:07 -05:00
alanbernstein
0aae064310
Merge branch 'master' into docs-updates 2020-07-07 15:17:42 -05:00
Alan Bernstein
94038f4446 Update wording 2020-07-07 03:48:37 -05:00
Ben Johnson
d53d8ef010
Merge pull request #508 from molecula/tx
Tx Interface
2020-07-02 17:20:23 -06:00
Ben Johnson
bf55bbc717 Tx Interface
This commit adds a transaction interface which will be used in the
future to add support to RBF (Roaring B-tree Format).
2020-07-02 10:43:15 -06:00
Kuba Podgórski
549c98dc64
Merge pull request #447 from kuba--/union-run-run
Add unionRunRunInPlace
2020-07-02 11:05:27 +02:00
Kuba Podgórski
751383ecb1
Merge branch 'master' into union-run-run 2020-07-02 10:52:59 +02:00
Jaden Weiss
a52c5d803d
Merge pull request #510 from jaddr2line/roaring-cleanup-3
Roaring cleanup
2020-07-01 17:21:14 -04:00
Jaden Weiss
6d692487ed
Merge branch 'master' into roaring-cleanup-3 2020-07-01 17:15:10 -04:00
Kuba Podgórski
ec73bf5906
Merge branch 'master' into union-run-run 2020-07-01 22:25:06 +02:00
Kuba Podgórski
e777a28283
Merge pull request #513 from kuba--/todo-501
Address the overflow issue with values outside the int64 range
2020-07-01 21:09:09 +02:00
Kuba Podgórski
4bed1df101 Address the overflow issue with values outside the int64 range 2020-07-01 20:40:47 +02:00
Kuba Podgórski
d6caf34c02
Merge pull request #509 from kuba--/todo-503
Add test for Rows on bool
2020-07-01 16:32:24 +02:00
Kuba Podgórski
f0abb5e8b4
Merge branch 'master' into todo-503 2020-07-01 16:23:38 +02:00
Kuba Podgórski
e52b1c04fc
Merge pull request #512 from kuba--/todo-504
FieldValue - check if column arg exists
2020-07-01 16:06:16 +02:00
Kuba Podgórski
5bbb3e2065 FieldValue - check if column arg exists 2020-07-01 11:36:42 +02:00
Kuba Podgórski
58964947d4
Update executor_internal_test.go
Co-authored-by: Travis Turner <travis@pilosa.com>
2020-07-01 10:17:30 +02:00
Kuba Podgórski
f921c5ded0 Add test for Rows on bool 2020-07-01 01:30:36 +02:00
Jaden Weiss
3e0ce32d00
roaring cleanup 2020-06-30 16:38:16 -04:00
Alan Bernstein
3841419907 Use more believable words 2020-06-30 12:23:36 -05:00
Alan Bernstein
31ae30f703 Replace smart quotes 2020-06-30 11:26:25 -05:00
Alan Bernstein
5a6db1cc2b Document topn heuristic behavior 2020-06-30 11:26:16 -05:00
Jaden Weiss
ad2390444a
Merge pull request #500 from molecula/seebs-big-inspect-pr
Improve inspect output, switch roaring over to using new unmarshal, handle inspecting whole holders
2020-06-29 15:31:01 -04:00
Jaden Weiss
31014d11e5
remove unnecesary slice operation when processing holder 2020-06-29 15:22:27 -04:00
Seebs
4d494f6699
shared/generic functionality for iterating holders
This is sort of large, but it's annoyingly difficult to
separate out.

The basic idea is to allow us to have a single holder-iterating
block of code, which is associated with the holder, that can be used
for various things, like the snapshot queue background scan, or
for inspect operations.

We invent the concept of a HolderFilter, which is a thing that
can decide what things in a holder it cares about, and a HolderOperator,
which can also process those things selectively.

In the process, we fix up a couple of subtle bugs in the
inspect logic; specifically, the assumption that the mapped flag could
tell you whether a container was modified by the ops log doesn't
work with mmap, so we have a shiny new flag which is used to track
that, internal to the roaring/container code.

All of this leads to the actual *point* of this exercise, which is
making it easier to create an /inspect endpoint which produces almost
the same data we'd have gotten from `pilosa inspect` on a data directory;
the distinction is that it doesn't try to identify the distinction
between data from disk and data from operations since the file was
loaded. Possibly it should, but it doesn't yet.

The snapshot queue is now implemented using the HolderOperator
design, which requires some subtle changes to how it works, but
overall makes it easier to follow the snapshot queue logic,
and also shares that logic with the way Inspect works.

The holder's snapshot queue is now provided by the server, in
a default environment.

The queueless snapshot queue no longer triggers snapshots on
enqueue -- it turns out that breaks badly, because a key
point about enqueueing a snapshot is that it's safe to do it
*during* a transaction on that fragment, and triggering a
snapshot during a transaction actually causes horrible errors
as the ops log ends up being the old file, which we close.
Related to this, we also need to prevent closed fragments from
trying to snapshot, so we track fragment openness when opening
or closing, and bail on trying to snapshot a fragment which is closed.

We also stop using the queueless snapshot queue during tests,
because that's a horrible idea.

We copy a little bit of the partition logic from the cluster code so
we don't have to expose it all, this lets us check whether the node
we're looking at is the one which should be primary for a given shard,
and if not, identify which node would be. This works only when
pointed at a data directory, for now.

The test cases for the holder have to be internal, because pilosa
doesn't export view/fragment, just Index/Field. This means that the
holder test cases can't just use the test/* package, so they duplicate
some of its logic, approximately.
2020-06-29 15:18:47 -04:00
Seebs
2826ecc0b7
track retries correctly in truncation case 2020-06-29 15:13:51 -04:00
Seebs
176d49e4b5
use syswrap to close file after opening it with syswrap 2020-06-29 15:13:50 -04:00
Seebs
3e7f0b32e9
drop old Call data while processing a list of calls
We don't need the Calls anymore, and especially Precomputed calls
(like Distinct) could be a significant memory load that's increased
as we process additional calls, so we drop the Precomputed references.
We can't drop the calls entirely -- translation can require lookups of
call arguments.
2020-06-29 15:13:50 -04:00
Seebs
7e7051d387
don't try to truncate files when invoked read-only 2020-06-29 15:13:50 -04:00
Seebs
ceaf5c15d1
thread the holder through things, and improve snapshot queue logic
This is logically two separate things, but the individual changes
are thoroughly intertwined in the code.

The first change is a logical change to the design of the snapshot
queue, which is that it now adjusts the maxOpN the background scan
targets, allowing it to lower that value over time when things are
quiet. We do this because it turns out that on large data sets,
this can make a factor-of-four difference in memory usage!

So, in general, on a quiet system, each pass through the holder
aims for about 1/4 of the existing fragments to get snapshotted.
When there's more load, we adjust those values up.

We also make the snapshot queue a bit less chatty, to make testing
less annoying -- we only print stats if the queue enqueues at least
two snapshots, or skips any.

The second change is threading the holder through things. We've
always threaded the logger through, and then added the snapshot
queue, and some of the Inspect-related work led to wanting to
have a way to thread options through, so what if we just threaded
the holder itself through, and removed the direct copying around
of the logger, snapshot queue, and so on. Similarly, everything
can now use holder.PartitionN instead of having to get its own
copy of PartitionN handed out to each index.

This does imply ensuring that test cases always get a reasonable
default holder.

This is a precursor to adding additional information to the holder,
such as whether it's in a special read-only mode, which would imply
not modifying on-disk files. This is already semi-supported for
the specific case of the background snapshot queue and cache flushing,
which are attached to the (created in a previous commit) new
holder Activate method, instead of being automatic on holder Open.

The change to a snapshot queue can also cause races in tests, because
the fragment.Clean method's "sanity check" accesses a fragment without
a lock. Fix that. Since there's a couple of t.Fatalf(), but we need
to release the lock before closing, we use an anonymous function
with a defer to handle that. Whee!
2020-06-29 15:13:50 -04:00
Seebs
121717594b
improve inspect output, switch roaring over to using new unmarshal
At some point the code changeover to use roaring iterators for
unmarshal got dropped, but the old unmarshal code is way harder to
make work for inspect, so this change is back.

This exports some of the names from the things returned by Info,
but also adds a roaring function to use the unmarshalling logic on
arbitrary data, allowing us to get more insight into a file -- in
particular, letting us distinguish between the bitmaps specified by
the roaring data and the bitmaps resulting from applying the ops log.
2020-06-29 15:13:47 -04:00
Jaden Weiss
c1612851af
Merge pull request #498 from jaddr2line/transaction-test-timeout
TestTransactionManager: raise transaction timeouts to avoid sporadic failures
2020-06-29 14:42:21 -04:00
Jaden Weiss
0d05e413d3
TestTransactionManager: raise transaction timeouts to avoid sporadic failures 2020-06-29 13:44:20 -04:00
Jaden Weiss
a175858375
Merge pull request #496 from jaddr2line/molecula-rebrand
Rebrand pilosa binaries
2020-06-26 17:51:21 -04:00
Jaden Weiss
fedb1f7dbd
set version to match Molecula convention 2020-06-26 17:41:19 -04:00
Jaden Weiss
4a4252bb28
Merge pull request #1 from codysoyland/enterprise-removal
Remove a few more enterprise references
2020-06-26 17:24:02 -04:00
Cody Soyland
4f22c388b3 Remove a few more enterprise references 2020-06-26 15:57:21 -05:00
Jaden Weiss
cd317d7e91
tweak VERSION_ID 2020-06-26 16:49:06 -04:00
Jaden Weiss
aa1995073f
rebrand pilosa binaries
This change rebrands the Pilosa binaries from "Pilosa Enterprise" to "Molecula Pilosa" and simplifies the version info string.
2020-06-26 16:49:05 -04:00
Kuba Podgórski
d99971a6c2
Merge branch 'master' into union-run-run 2020-06-26 22:32:07 +02:00
Kuba Podgórski
8b33a073b4
Merge pull request #495 from kuba--/int-eq
Support '=' condition for int/decimal fields
2020-06-26 22:30:03 +02:00
Kuba Podgórski
4351464f84
Merge branch 'master' into int-eq 2020-06-26 21:26:44 +02:00
Jaden Weiss
a78b1cfe19
Merge pull request #446 from jaddr2line/fastrank
Remove allocations from ranked cache when possible
2020-06-26 12:46:58 -04:00
Kuba Podgórski
3782c3ac14 Support '=' condition for int/decimal fields 2020-06-26 18:14:59 +02:00
Jaden Weiss
94b55f8556
remove allocations from ranked cache when possible 2020-06-26 12:12:51 -04:00
Jaden Weiss
079bee5711
Merge pull request #489 from jaddr2line/field-cleanup
Remove unused field code
2020-06-26 11:37:15 -04:00
Jaden Weiss
5523587435
pilosa: remove unused field code 2020-06-26 10:14:56 -04:00
Kuba Podgórski
76324f1498
Merge branch 'master' into union-run-run 2020-06-26 01:28:25 +02:00
Jaden Weiss
0a030e9a77
Merge pull request #482 from jaddr2line/rm-invalid-unsafe
Remove invalid uses of unsafe from roaring containers
2020-06-25 15:02:33 -04:00
Jaden Weiss
934048bb02
roaring: remove invalid uses of unsafe 2020-06-25 11:48:21 -04:00
Kuba Podgórski
47481432ef
Merge pull request #468 from kuba--/fix-DEGRADED
Lets the remote node to proceed
2020-06-25 17:05:30 +02:00
Kuba Podgórski
80cfb5c182
Merge branch 'master' into fix-DEGRADED 2020-06-25 16:41:41 +02:00
Kuba Podgórski
0bdb420b4c
Merge pull request #475 from kuba--/fix-iface-conv
Make a safe cast
2020-06-25 15:36:53 +02:00
Kuba Podgórski
ed86f6ea5d Make a safe cast 2020-06-25 14:44:14 +02:00
Cody Soyland
bc9d13206f
Merge pull request #490 from codysoyland/ci-fixes
Fix/refactor CircleCI config
2020-06-24 13:52:45 -05:00
Cody Soyland
2024228153 Fix/refactor CircleCI config
- Fix incorrect usage of workspaces (vendor dir in current directory no
  longer primary cache of go modules)
- Refactor checkout, github-auth, and mod cache into a reusable command
- Fix issue with dockerhub upload and github authentication
2020-06-24 13:45:17 -05:00
Kuba Podgórski
413ce4f1ab
Merge branch 'master' into fix-DEGRADED 2020-06-24 19:56:24 +02:00
Jaden Weiss
2925101b09
Merge pull request #487 from jaddr2line/cluster-message-error
Differentiate between cluster message request errors and cluster message processing errors
2020-06-24 09:44:03 -04:00
Jaden Weiss
b5b60b8912
http: differentiate between cluster message request errors and cluster message processing errors 2020-06-24 09:23:08 -04:00
Kuba Podgórski
905cda7f08 Add benchmarks 2020-06-23 22:18:13 +02:00
Kuba Podgórski
443f2d8f7c The third attempt to implement unionRunRunInPlace 2020-06-23 22:18:13 +02:00
Kuba Podgórski
eddbb7d0b0 Optimize run intervals by combnining neighbours 2020-06-23 22:18:13 +02:00
Kuba Podgórski
2b0cd2f234 Add unionRunRunInPlace 2020-06-23 22:18:13 +02:00
Jaden Weiss
89ac3f4737
Merge pull request #486 from jaddr2line/handlerfixes
Fix incorrect error handling in HTTP handler and output raw error text when JSON is not selected
2020-06-23 12:57:55 -04:00
Jaden Weiss
66aef92cfa
http: fix incorrect error handling and output raw error text when JSON is not selected 2020-06-23 12:26:37 -04:00
Cody Soyland
16ebdf290d
Merge pull request #479 from codysoyland/ci-dockerhub-fix
Fix and simplify CI DockerHub integration
2020-06-23 09:13:41 -05:00
Cody Soyland
7cb9548097 Fix and simplify CI DockerHub integration 2020-06-19 11:41:54 -05:00
Jaden Weiss
5dc02a3998
Merge pull request #474 from jaddr2line/timeclr
Fix Clear() returning `false` when it should return `true`
2020-06-19 09:03:42 -04:00
Jaden Weiss
a270bff67b
fix Clear() returning false when clearing a bit with no time views 2020-06-19 08:51:08 -04:00
Kuba Podgórski
739935c3f6
Merge branch 'master' into fix-DEGRADED 2020-06-18 16:13:58 +02:00
tgruben
21888703e5
Merge pull request #469 from tgruben/splat-init
Functionalize  fillerBitmap initialization
2020-06-17 09:39:16 -05:00
tgruben
3103da2c19
Update roaring/container_stash.go
Co-authored-by: Jaden Weiss <jaden@jadendw.dev>
2020-06-17 08:51:25 -05:00
Todd Gruben
f47888989a shorten fillerBitmap initialization 2020-06-17 07:12:24 -05:00
Kuba Podgórski
87306d3145 Lets the remote node to proceed, instead of waiting in DOWN state because cluster is in STARTING state. 2020-06-17 11:37:30 +02:00
Jaden Weiss
7f4142497e
Merge pull request #467 from jaddr2line/splat
Optimize `splatRun`
2020-06-16 13:50:27 -04:00
Jaden Weiss
8fc7861148
roaring: optimize splat 2020-06-16 13:04:50 -04:00
Travis Turner
cf24ee161f
Merge pull request #465 from travisturner/document-shift
Add comments warning that Shift() is unsupported
2020-06-15 17:53:38 -05:00
Travis
c5786e1d78
Add comments warning that Shift() is unsupported 2020-06-15 17:16:00 -05:00
alisharawal
4a68b46597
Merge branch 'master' into alisharawal-patch-1 2020-06-15 11:15:14 -05:00
Jaden Weiss
d9baea83f4
Merge pull request #454 from jaddr2line/groupbyoffset
Apply base in GroupBy on BSI
2020-06-11 17:24:39 -04:00
Jaden Weiss
837d0a1465
Merge branch 'master' into groupbyoffset 2020-06-11 12:20:35 -04:00
Jaden Weiss
32e47642ae
address review of "Apply base in GroupBy on BSI" 2020-06-10 17:49:00 -04:00
tgruben
8bc303793c
Merge pull request #453 from tgruben/includes-perf
Optimized performance of row.Includes
2020-06-10 15:50:50 -05:00
Jaden Weiss
535257af75
apply base in GroupBy 2020-06-10 16:16:53 -04:00
Todd Gruben
416f332070 Optimize row.Includes 2020-06-10 13:12:38 -05:00
Jaden Weiss
ec9474114a
Merge pull request #449 from jaddr2line/fixbsioffbyone
Fix BSI comparison match-all-but-one operation
2020-06-10 10:41:35 -04:00
Jaden Weiss
8887927dbd
add regression test for BSI match-all-but-one operations 2020-06-10 10:09:33 -04:00
Jaden Weiss
d478dd9d94
fix BSI comparison match-all-but-one operation 2020-06-10 09:23:39 -04:00
Kuba Podgórski
058ed747c7
Merge pull request #437 from kuba--/err-check
Return error instead of panicking on Store(Distinct())
2020-06-09 14:53:23 +02:00
Kuba Podgórski
9c3b080bf0 Check result before return 2020-06-09 11:39:16 +02:00
Cody Soyland
a519907822
Merge pull request #440 from codysoyland/ci-size
Use xlarge executor in CircleCI
2020-06-08 15:24:31 -05:00
Cody Soyland
8352f5d273 Add configurable resource class, enable only for test-race. 2020-06-08 15:20:31 -05:00
Cody Soyland
ecbb5b2a0d Use xlarge executor in CircleCI 2020-06-08 15:20:31 -05:00
Jaden Weiss
12e6534244
Merge pull request #426 from jaddr2line/simplebsi
Simplify BSI comparisons
2020-06-08 16:14:41 -04:00
Jaden Weiss
ee8036d376
Merge branch 'master' into simplebsi 2020-06-08 16:07:29 -04:00
Jaden Weiss
120cc02536
process BSI ops more efficiently 2020-06-08 14:52:19 -04:00
Jaden Weiss
721a968d63
Merge pull request #438 from jaddr2line/cpumhz
fix CPU speed on non-Intel platforms
2020-06-08 13:34:27 -04:00
Jaden Weiss
a4e53b4bc1
Merge branch 'master' into cpumhz 2020-06-08 13:26:49 -04:00
seebs
c0c027ef67
Merge pull request #429 from seebs/racetime
Improve time requirements for tests with race detector on
2020-06-08 12:25:07 -05:00
Seebs
44569fa210 Reduce iterations in TestFragment_RowsIteration
We don't really learn more from trying every multiple of 10,000 than we do
from trying maybe 32 values, and it's worse at larger shard widths.
2020-06-08 12:10:40 -05:00
Seebs
52aa3e2e23 Improve container/bitmap comparison logic for testing
We have a "deadcode" bitmapsEqual which is actually used in testing but
probably shouldn't be, and we don't have a good container equality test.

Problem is, equality tests are sort of slow in the things-are-equal case,
which is the most common case, so we've got some moderately-specialized
code here; specifically, special comparison code that takes advantage
of knowing that if two containers have the same number of bits, you only
have to check whether all the bits from one are present in the other,
because that can't be true for differing containers with the same number
of bits. This reduces the runtime for the ContainerCombinations case
from about 24 seconds to a bit under 2 on my laptop, or from around
10 minutes to about 37 seconds with the race detector on.

Also simplify the InPlaceWrapper functions not to invoke bitmaps, because
it's not really necessary.
2020-06-08 12:10:40 -05:00
Seebs
3f0c9925f4 Don't test quite so many values for BtreeSeek and BtreeDelete
BtreeSeek is O(N^2) on its N, and there's not a ton of extra utility
to testing a larger range of values, so we reduce N by a bit, cutting
runtime from ~10s to <1s on my laptop. Also reduce the scale of the
BtreeDelete1/BtreeDelete2 tests a bit because, again, lots of runtime
for little marginal information.
2020-06-08 12:10:40 -05:00
Seebs
e223c79ace Don't use a whole shard of values for Execute_All test.
This is pretty expensive even for default shard width, and very expensive
for ShardWidth = 1<<22, and we don't really get much extra benefit from
having a million values instead of a hundred or so.
2020-06-08 12:10:40 -05:00
Seebs
1484674a1c Add and use bitmap-to-slice-or-set comparison functions
The generation of slices from things, and use of reflect.DeepEqual to compare
the slices, is a lot more expensive than it needs to be. Omitting it removes most
of the runtime of the marshal tests.
2020-06-08 12:10:40 -05:00
Seebs
1952a43ed4 Write fewer bits to test the rowcache behavior
The failure mode in question was pretty predictable and tied to number of
snapshots, not to number of bits written, so we can probably use a lot fewer
bits and still get good results, but this is really slow under -race testing.
2020-06-08 12:10:40 -05:00
Seebs
1460756b3f Provide option for adjusting node timeouts, set it for tests.
There's no reason to have 10-20 seconds of delays for testing this,
because in testing, we're running things on the local machine and don't
need to worry about significant network lag. Make retry count and delay
settable options, and set them lower. Moves the Replica2 test in
server/server_test.go from ~21s to ~2s.
2020-06-08 12:10:40 -05:00
Seebs
55ff03a2d6 Lower scale of some random-value tests
The random-value tests can be pathological, and in particular, the
test of arbitrarily-spaced values is in effect O(N^2), and with race
testing on, that test *alone* can take ten minutes to run, but
it's not really all that exciting. We just reduce a bunch of values
and/or test fewer things for these, which doesn't significantly alter
coverage, but reduces test runtime on my laptop with `-race` from
21 minutes to a bit under 5.
2020-06-08 12:10:40 -05:00
Jaden Weiss
7695e63bc5
fix CPU speed on non-Intel platforms 2020-06-08 11:40:53 -04:00
Jaden Weiss
0a17b3713c
Merge pull request #428 from jaddr2line/cleanshutdown
Cleanly shut down the executor
2020-06-05 18:32:57 -04:00
Jaden Weiss
b0a0524ffe
cleanly shut down the executor 2020-06-05 15:25:35 -04:00
Jaden Weiss
0ce5d92407
simplify BSI comparisons 2020-06-05 14:13:29 -04:00
seebs
33728e65d9
Merge pull request #408 from seebs/execontext
thread contexts better through executor
2020-06-04 15:18:12 -05:00
seebs
610d72dbfc
Merge branch 'master' into execontext 2020-06-04 14:57:16 -05:00
Jaden Weiss
0095810e4d
Merge pull request #419 from jaddr2line/trackqueries
track active queries
2020-06-04 14:58:22 -04:00
Jaden Weiss
06517075bf
add unit test to active query tracker 2020-06-04 14:05:06 -04:00
Jaden Weiss
1099a57945
fix pretty printing of active queries list to handle special characters and multiline queries 2020-06-04 14:04:46 -04:00
Jaden Weiss
023efcaba6
track active queries 2020-06-04 10:50:15 -04:00
Seebs
439c710ca9 thread contexts better through executor
When a mapper hits an error, we want it to immediately tell the
other things in that same mapper that they can stop now. But we
don't want to propagate that all the way back up; if a specific
node has a failure executing a query, we will in some cases want
to send a new query to other backup nodes, so the overall
context isn't cancelled yet.

In general, mapFn and reduceFn have been closures that inherit
a context from the function defining them -- but we don't want
that! We want them to be stopped if their specific mapper gets
cancelled, too, because otherwise they can consume a lot of
resources long after the mapper has stopped being interested
in them.  So now those are parameters passed into them,
and mapperLocal puts *those* contexts in the jobs shoved into
the job queue, and the workers pass the context in to the
mapFn/reduceFn.

We also check responses from reduceFn now; both mapReduce
and mapperLocal check for a possible error, and return that,
and reduce functions doing anything nontrivial check their
context.

We also add a few more explicit checks for context cancellation
in various places, especially in the GroupByIterator which is
what bit us that one time. The explicit check against ctx.Err
is officially safe as of Go 1.9 or so. (It was previously
unspecified, but on further study, the Go team concluded that
no actual implementation did anything else, and existing code
was already depending on that.) This also affects the rows
function, because that could potentially take quite a while to
run for a large fragment.
2020-06-03 16:09:01 -05:00
seebs
33a90fd328
Merge pull request #297 from seebs/nofreeze
Don't automatically freeze the results of RowSegment ops
2020-06-03 14:54:12 -05:00
Seebs
6abe7dc12f Don't automatically freeze the results of RowSegment ops
I think when this code was written, I thought "freeze" would be
really cheap. It's not actually that cheap. As a result, freezing
things preemptively when it may be that nothing ever tries to write
to them anyway is possibly disadvantageous, to the tune of being
roughly 20% of a sample profile we were shown. Instead, we don't
mark the components "writable", so if anything wants to write to
them, it'll end up freezing itself new copies of their bitmaps
later. But in practice that probably doesn't happen.
2020-06-03 13:21:41 -05:00
Kuba Podgórski
0bba9c81e8
Merge pull request #417 from kuba--/rev-mtx
Change order of cluster/index locks
2020-06-03 15:37:20 +02:00
Kuba Podgórski
0320228b99 Change order of cluster/index locks 2020-06-03 15:09:56 +02:00
Kuba Podgórski
a8e6846e78
Merge pull request #401 from kuba--/etag
Add (in memory) CreatedAt to index and fields
2020-06-03 15:09:22 +02:00
Kuba Podgórski
bb048da241
Update docs/api-reference.md
Co-authored-by: Matthew Jaffee <matthew.jaffee@gmail.com>
2020-06-03 14:47:51 +02:00
Kuba Podgórski
6a892102e4 Update api-reference.md 2020-06-03 13:26:16 +02:00
Kuba Podgórski
d8a417f657 Move applyCreatedAt from mergeClusterStatus directly to ClusterStatus message, to avoid deadlocks 2020-06-03 13:26:16 +02:00
Kuba Podgórski
0c98c887ac Pass Schema in ClusterStatus message 2020-06-03 13:26:16 +02:00
Kuba Podgórski
ba7f039dd1 Rename etag to createdAt 2020-06-03 13:26:16 +02:00
Kuba Podgórski
3d270f45d2 Add (in memory) ETag to index and fields 2020-06-03 13:26:16 +02:00
tgruben
43195ae2dd
Merge pull request #416 from tgruben/fix-grpc-address
add address for listening
2020-06-02 16:25:53 -05:00
Todd Gruben
fdaae31c2c add address for listening 2020-06-02 15:39:28 -05:00
Matthew Jaffee
31c5e7363d
Merge pull request #412 from jaffee/escape-query-strings-411
modify PQL parser to handle escapes in string values
2020-05-29 08:51:54 -05:00
Matt Jaffee
1c1204fc77
modify PQL parser to handle escapes in string values
This modifies the parser to properly "unquote" incoming strings. So if
a string comes in double or single quoted, we approximately follow Go
rules for removing the quotes and processing escape sequences.

The differences from Go are:
1. we only support backslash, quote, tab and newline escape
sequenences.
2. Single quoted strings are supported and work just like double
quoted strings.
3. The peg parser won't actually accept backquoted strings (I don't
think)

Fixes: #411
2020-05-29 07:58:50 -05:00
tgruben
c177bf831d
Merge pull request #409 from tgruben/transaction-doc-update
correction to endpoint
2020-05-29 07:22:18 -05:00
tgruben
242b3d4b14
Merge branch 'master' into transaction-doc-update 2020-05-29 07:02:02 -05:00
seebs
6aa5041de6
Merge pull request #313 from seebs/roaring4g
Handle file sizes over 4GB
2020-05-28 22:55:24 -05:00
Seebs
1ca9435af9 Handle file sizes over 4GB
We only have 4 bytes for offsets, but what if a file is
over 4GB? Someone came to us with a file with 265 *million* containers,
in a single fragment, which means that over 3GB of their 4.7GB file
is actually just the container headers alone. But we can't easily make
the offsets larger, or change the file format.

So we don't. We just track how many 4GB hunks of the file we've
been through and bump that every time the 32-bit offset wraps. And this
appears to... just work.

This is fixed for both the roaring iterator and the old unmarshalBinary
logic. The logic to handle this will work on 32-bit hosts in the sense
that it will correctly error out for excessively large file sizes or
container counts, but it doesn't actually handle the large files since
it can't.
2020-05-28 17:08:32 -05:00
Todd Gruben
4d1ce90b32 correction to endpoint 2020-05-28 15:36:00 -05:00
tgruben
a777eddfcf
Merge pull request #405 from tgruben/trace-tagging
added some context to tracing
2020-05-28 13:34:19 -05:00
tgruben
5cd15b250a
Merge branch 'master' into trace-tagging 2020-05-27 15:46:51 -05:00
Todd Gruben
4274d2d141 convert to camelCase 2020-05-27 15:23:13 -05:00
Kuba Podgórski
6ed3bde54e
Merge pull request #407 from kuba--/status
Add grpc uri to status
2020-05-27 17:26:32 +02:00
Kuba Podgórski
604f3b3373 Add grpc uri to status 2020-05-27 16:41:38 +02:00
Jaden Weiss
e0291e9d25
Merge pull request #398 from jaddr2line/transactionmetrics
add metrics for transactions
2020-05-27 08:52:53 -04:00
Jaden Weiss
efef42ae97
Merge branch 'master' into transactionmetrics 2020-05-27 08:36:23 -04:00
Todd Gruben
022019c6cc removed shard level tracing tag 2020-05-26 23:23:57 -05:00
Travis Turner
ffa40b1bdb
Merge pull request #387 from travisturner/int-eq-null
Add support for `intfield == null`
2020-05-26 21:05:42 -05:00
Todd Gruben
a2f825a32e added some context to tracing 2020-05-26 17:18:23 -05:00
Jaden Weiss
a4643084bd
Merge branch 'master' into transactionmetrics 2020-05-26 17:55:12 -04:00
Jaden Weiss
5644fb2275
add metrics for transactions 2020-05-26 17:51:28 -04:00
Travis
e4b9293f26
Add support for int == null 2020-05-22 12:29:52 -05:00
Travis Turner
d36f397a35
Merge pull request #404 from travisturner/row-todos
clean up the TODOs and some comments
2020-05-22 12:05:58 -05:00
Travis
041726fbf7
clean up the TODOs and some comments 2020-05-22 11:00:22 -05:00
Travis Turner
2586661812
Merge pull request #402 from travisturner/roaring-tests
Address TODOs in roaring tests
2020-05-21 19:50:38 -05:00
Travis
0a94f8393f
Address TODOs in roaring tests
In addition to adding some tests, this commit moves the
`GenerateUint64Slice()` helper function into  a new `generator` package
so that it can be used in both internal and non-internal tests.
2020-05-21 13:28:54 -05:00
Jaden Weiss
c04143fd61
Merge pull request #394 from jaddr2line/nextdelete
fix use-after-free in b-tree bitmap update
2020-05-20 13:39:05 -04:00
alisharawal
aa0cfecdb3
Update README.md 2020-05-20 11:37:22 -05:00
Jaden Weiss
6e3e513425
roaring: fix use-after-free in b-tree bitmap update 2020-05-20 12:01:21 -04:00
Travis Turner
8eae053fe6
Merge pull request #395 from travisturner/roaring-todos
clarify a few of the TODO comments
2020-05-19 15:16:05 -05:00
Travis
631d3deeed
clarify a few of the TODO comments 2020-05-19 13:50:48 -05:00
Travis Turner
4b4fd590ca
Merge pull request #389 from travisturner/proto-todos
finish implementing PairField proto encoding
2020-05-19 08:54:58 -05:00
Travis
4fb3820afb
finish implementing PairField proto encoding 2020-05-18 20:19:22 -05:00
Travis Turner
231fef27eb
Merge pull request #390 from travisturner/deadline-skew
increase test deadlineSkew to 1s
2020-05-18 20:18:51 -05:00
Travis
42814bb70c
increase test deadlineSkew to 1s 2020-05-18 19:57:44 -05:00
Travis Turner
63dd5e1174
Merge pull request #386 from travisturner/bsigroup-edges
Fix edge case bugs in range queries
2020-05-18 15:02:50 -05:00
Travis
d0de49ef39
handle edge cases in range queries 2020-05-16 10:35:35 -05:00
seebs
c6d61391d2
Merge pull request #249 from seebs/roaringrow
use roaring row support internally
2020-05-15 17:00:17 -05:00
Seebs
0ddc968001 cache result of marshalling import-was-OK message
This message gets generated millions of times and it's unchanging
for the life of the program, and small.
2020-05-15 16:22:08 -05:00
Seebs
79940cf077 encoding/proto: allow distinct serializers
We want to be able to control whether or not we use roaring to
serialize Rows, which means serializers have to be able to be
distinct.

We also make corresponding changes to http/handler.go to have
it use the exported serializers directly rather than the API's
serializer (which is always the base protobuf serializer
right now, and if it weren't, that would be bad because we
were assuming it was).

When we're accepting protobuf from a pilosa server, flag that
we'll accept roaring bitmaps as opposed to the naive column
representation.
2020-05-15 16:22:08 -05:00
Seebs
ce0761050e less spammy snapshotqueue
During testing we spawn a lot of tiny snapshot queues. Make the message
less spammy by printing it only if any enqueues were skipped (shouldn't
ever happen) or more than one thing got enqueued (likely in real usage,
but doesn't happen in testing usually).
2020-05-15 16:22:08 -05:00
Kuba Podgórski
3151d83136
Merge pull request #383 from kuba--/grpc-err/356
Wrap grpc resp.Err
2020-05-15 23:14:41 +02:00
Kuba Podgórski
3fe85d0f91 Move grpc_internal_test to grpc_test 2020-05-15 19:52:03 +02:00
Kuba Podgórski
ea08cce8fe
Update api.go
Co-authored-by: Travis Turner <travis@pilosa.com>
2020-05-15 19:39:36 +02:00
Kuba Podgórski
f40601f6f5 Wrap grpc resp.Err 2020-05-15 18:16:31 +02:00
Kuba Podgórski
e39334ca92
Merge pull request #377 from kuba--/opt-indiagnostics/310
Disable diagnostics by default
2020-05-15 02:09:31 +02:00
Kuba Podgórski
7ee8f80012
Merge branch 'master' into opt-indiagnostics/310 2020-05-15 00:53:33 +02:00
Kuba Podgórski
fc9e75edc2
Merge pull request #378 from kuba--/off-ae/340
Turn anti-entropy off by default
2020-05-13 14:26:13 +02:00
Kuba Podgórski
fd27cbb886
Update server/config.go
Co-authored-by: Matthew Jaffee <matthew.jaffee@gmail.com>
2020-05-12 18:51:53 +02:00
Kuba Podgórski
889f79d11a Turn anti-entropy off by default 2020-05-12 16:49:43 +02:00
Kuba Podgórski
368cb8cb53 opt-in diagnostics 2020-05-12 15:37:47 +02:00
Travis Turner
2f44a16755
Merge pull request #374 from travisturner/todo-fixes
tidy up some of the TODO comments
2020-05-10 21:45:13 -05:00
Travis
bc8244a581
well, put the TODO back, just in a different place 2020-05-10 19:18:54 -05:00
Travis
d546b8ac01
use pilosa.ErrNotImplemented for unused interface implementations 2020-05-10 18:50:05 -05:00
Travis
9255d43e9a
tidy up some of the TODO comments 2020-05-09 22:26:12 -05:00
Cody Soyland
16f0b5eaba
Merge pull request #343 from codysoyland/branch-rename
Rename enterprise branch to master
2020-05-08 17:50:02 -05:00
Cody Soyland
b96666d06a Rename enterprise branch to master 2020-05-08 16:29:17 -05:00
Kuba Podgórski
5578eb8daa
Merge pull request #258 from kuba--/intersect-inplace
The first implementation of intersect in place
2020-05-07 11:23:40 +02:00
Kuba Podgórski
c802caeddd The first implementation of intersect in place 2020-05-06 23:59:07 +02:00
Kuba Podgórski
1a00008dbd
Merge pull request #339 from kuba--/getridof-rowid
get rid of rowID from groupby on ints response
2020-05-06 23:43:56 +02:00
Kuba Podgórski
19df3211f9 get rid of rowID from groupby on ints response 2020-05-06 23:23:43 +02:00
Travis Turner
04f09870ec
Merge pull request #338 from travisturner/remove-lookup
remove extra index lookup
2020-05-06 13:54:18 -05:00
Travis
2ca4e971f1
remove extra index lookup 2020-05-06 13:04:46 -05:00
Travis Turner
994ac5aad8
Merge pull request #337 from travisturner/fieldvalue
add FieldValue call
2020-05-06 12:29:39 -05:00
Travis
a91014c7bb
add FieldValue call 2020-05-06 11:52:27 -05:00
Travis Turner
a72de2c68a
Merge pull request #329 from travisturner/cluster-startup
avoid deadlock on translationSync.Reset during startup
2020-05-05 08:56:23 -05:00
Travis
92a94c9ec1
remove noSleep option 2020-05-05 08:31:43 -05:00
Travis
7b36f417d8
avoid deadlock on translationSync.Reset during startup 2020-05-05 08:31:42 -05:00
Travis Turner
f9cb7abccf
Merge pull request #334 from travisturner/block-limits
Fix off-by-one maxRowID in block limits
2020-05-04 14:02:30 -05:00
Travis
de0785d305 add a test for the "clears" bug 2020-05-01 16:15:42 -05:00
Travis
1f308066a7 fix test error messages 2020-05-01 15:54:56 -05:00
Travis
b25796f532 Fix off-by-one maxRowID in block limits
In the case where a block merge needed to occur
on a replica containing a row on the edge of the block,
the existing logic would inadvertently clear the first
row in the next block. This PR fixes that.
2020-05-01 15:15:47 -05:00
Matthew Jaffee
8e0a787ec0
Merge pull request #332 from jaffee/tracing-off
change default tracing config to 'off'
2020-04-30 21:25:02 -05:00
Matt Jaffee
8aa7a76d31
change default tracing config to 'off'
also fix a typo
2020-04-30 15:02:15 -05:00
Cody Soyland
ea99f32d36
Merge pull request #327 from codysoyland/docker-bind-grpc
Bind to public interface in docker image
2020-04-28 14:45:06 -05:00
Cody Soyland
0c7a83dc0b Bind to public interface in docker image 2020-04-28 14:20:22 -05:00
Travis Turner
95d44dce28
Merge pull request #318 from travisturner/config-cmd
suppress test config arguments from pilosa config output
2020-04-24 13:23:36 -05:00
Travis
9405463911 suppress test config arguments from pilosa config output 2020-04-24 11:02:42 -05:00
Travis Turner
022b135538
Merge pull request #316 from travisturner/json-header
Ensure content-type header is application/json where appropriate
2020-04-23 22:10:44 -05:00
Travis
af6eb94c1d increase deadlineSkew so TestTransactionsAPI doesn't fail during race test 2020-04-23 17:26:35 -05:00
Travis
5da907d469 ensure content-type header is application/json where appropriate 2020-04-23 16:24:40 -05:00
Travis Turner
8cf06bf5d9
Merge pull request #314 from travisturner/decimal-adjust-precision
Adjust decimal precision if we have decimal places to sacrifice.
2020-04-23 08:43:23 -05:00
Travis
432e18d571 return early on mantissa=0 2020-04-22 19:11:23 -05:00
Travis
809a02d986 Adjust decimal precision if we have decimal places to sacrifice. 2020-04-22 17:10:05 -05:00
Travis Turner
2795a3f7e2
Merge pull request #309 from molecula/transactions
Transactions
2020-04-22 15:52:42 -05:00
Matt Jaffee
97ae8e0db7
add kuba testcase, fix race
we fix the race by not returning pointers to the things which we're
keeping in the in-memory store
2020-04-22 15:17:25 -05:00
Matt Jaffee
85f57f9975
fix lint 2020-04-22 14:30:14 -05:00
Matt Jaffee
7c7836f16f
convert transactions to be pointers everywhere
I think this will improve the transaction response messages Kuba
mentioned where it was an empty transaction instead of a nil or not
there... if not it should make it easier to do that anyhow.
2020-04-22 14:01:24 -05:00
Matt Jaffee
9dbc6f89db
address minor feedback from previous PR 2020-04-22 12:31:25 -05:00
Matt Jaffee
7da137277c
tweak comment, add validation TODO 2020-04-22 10:42:59 -05:00
Matthew Jaffee
afcb3e7f96
Merge pull request #2 from travisturner/backups
minor code adjustments during review
2020-04-22 07:35:05 -05:00
Travis Turner
c9b7ed51aa
Update deadline comment
Co-Authored-By: Matthew Jaffee <matthew.jaffee@gmail.com>
2020-04-21 17:49:57 -05:00
Travis
08583cf2d0 minor code adjustments during review 2020-04-21 16:54:17 -05:00
Matt Jaffee
a3c5f4822e
keep the zone info back in deadline strings (but output in UTC)
instead of defining them as being in UTC, but not including the zone
info, we will keep the standard format with zone info, but always
output the time in UTC. This means that we can parse incoming
deadlines that happen to have zone information, though I don't think
we ever need to.
2020-04-21 12:29:19 -05:00
Matt Jaffee
5e29effa93
don't wrap error, dedup compare transactions code 2020-04-20 22:30:14 -05:00
Matt Jaffee
b23d27f507
add cluster state validation to API methods for transactions 2020-04-20 22:22:40 -05:00
Matt Jaffee
662ed4f324
invert if statements and fix typos 2020-04-20 22:12:07 -05:00
Matt Jaffee
432ab57822
add license headers 2020-04-20 14:41:05 -05:00
Matt Jaffee
89c1d48a0f
transaction deadline format UTC, lint
also change "deadlineSkew" comparison in tests to account for race tests in CI
seeing false differences
2020-04-20 14:37:28 -05:00
Matt Jaffee
c36952a0f1
propagate context throughout transaction stuff 2020-04-20 13:30:48 -05:00
Matt Jaffee
41975de6b8
add transactions external documentation
- make sure client reads/closes all bodies
- support blank transaction ID in http handler
2020-04-20 13:30:48 -05:00
Matt Jaffee
210c7239ab
add HTTP handlers and client for transactions 2020-04-20 13:30:48 -05:00
Matt Jaffee
9ad1106647
implement transaction API layer and intra-cluster messaging
also adds a "noSleep" option to the server command to avoid the 5
second sleep we introduced on startup for non-coordinator cluster
nodes. The sleep doesn't seem to be needed in the tests and makes them
much slower.
2020-04-20 13:30:48 -05:00
Matt Jaffee
088e60b830
better defer that Unlock 2020-04-20 13:30:48 -05:00
Matt Jaffee
38cec6f20e
add TransactionManager and TransactionStore for transactions/backups
This all needs to be wired into API/Server/Cluster/Holder etc. but I
think the TransactionManager will be a pretty good building block for
managing transaction state at the coordinator level.
2020-04-20 13:30:48 -05:00
Seebs
c3ef9a1768
draft outline of transaction API 2020-04-20 13:30:47 -05:00
Cody Soyland
a353527705
Merge pull request #307 from codysoyland/copy-reopen
Copy reopen.FileWriter into pilosa
2020-04-20 12:41:09 -05:00
Cody Soyland
761b090f3c Fix linter error 2020-04-20 12:10:44 -05:00
Cody Soyland
5e1c72e6f2 Copy reopen.FileWriter into pilosa 2020-04-20 11:58:09 -05:00
Travis Turner
53500e5ad5
Merge pull request #304 from travisturner/grpc-listener
move gRPC listener creation outside of grpcServer
2020-04-18 13:14:12 -05:00
Travis
7de8399b17 move gRPC listener creation outside of grpcServer
For tests, we need to create the grpc listener with port 0 in order to
automatically assign a port. This PR moves the lister creation outside
of the grcpServer itself so that we can access that auto-created port.
2020-04-18 11:38:15 -05:00
Travis Turner
72d496f5c7
Merge pull request #302 from travisturner/grpc-client-queryunary
add QueryUnary to the grpc client api
2020-04-17 16:32:41 -05:00
Travis
2b98ef5edb add QueryUnary to the grpc client api 2020-04-17 16:12:10 -05:00
seebs
26091bd3ed
Merge pull request #301 from codysoyland/makefile-checkptr
Use makefile variable for NOCHECKPTR
2020-04-17 15:57:33 -05:00
Cody Soyland
3b5908332d Use makefile variable for NOCHECKPTR 2020-04-17 15:15:43 -05:00
seebs
f8f924e972
Merge pull request #300 from seebs/groupby
GroupBy should terminate even if the last result is empty
2020-04-17 15:13:49 -05:00
Seebs
3a7ab3b8eb GroupBy should terminate even if the last result is empty
If you have two criteria, and the last result you generate is
empty, the nextAtIdx iterator for i==1 will try to continue
poking the i==0 iterator. That one produces a nil result, and
declares the entire group-by iterator done... But the nextAtIdx
call above it isn't checking that, and just loops forever.
This causes some queries to become stuck permanently, consuming
ridiculous amounts of resources almost entirely focused on
calling Intersect millions of times to get empty results.
2020-04-17 14:39:03 -05:00
Cody Soyland
398ce117ec
Merge pull request #287 from codysoyland/logger
Reopen log file on SIGHUP
2020-04-17 12:40:25 -05:00
Cody Soyland
1058440cfe Do not reuse error object (data race) 2020-04-16 17:08:50 -05:00
Cody Soyland
e4cd1b8871 Add -v flag to test-race 2020-04-16 17:08:50 -05:00
Cody Soyland
a00e93f699 Add TODO about fork 2020-04-16 17:08:50 -05:00
Cody Soyland
2155d6cab8 Move some things around, fix linter warnings. 2020-04-16 17:08:50 -05:00
Cody Soyland
a66ee26a6b Reopen log file on SIGHUP 2020-04-16 17:08:50 -05:00
Cody Soyland
08fa90e0f3 Reduce duplication of setupLogger arch-specific code 2020-04-16 17:08:50 -05:00
Travis Turner
46fb6859ed
Merge pull request #296 from travisturner/grpc-tabler-rowser
gRPC tabler rowser
2020-04-16 15:19:47 -05:00
Travis
c45a4bf3dc ToTable and ToRows interface for gRPC 2020-04-16 14:16:54 -05:00
Travis Turner
0691b6c015
Merge pull request #294 from travisturner/overflow-fix
error on potential overflow
2020-04-15 16:24:37 -05:00
Travis
80f1bdebd7 error on potential overflow 2020-04-15 15:50:03 -05:00
Travis Turner
468b69fba9
Merge pull request #291 from travisturner/range-problems
fix some range query problems
2020-04-15 15:27:12 -05:00
Travis
8a22a3ede3 fix some range query problems 2020-04-15 14:42:16 -05:00
Travis Turner
37f05fc3ea
Merge pull request #288 from travisturner/upgrade-min-max
upgrade decimal min/max with scale
2020-04-15 08:08:00 -05:00
Travis
79a6c1e5ab upgrade decimal min/max with scale 2020-04-15 00:14:07 -05:00
seebs
f41bced2ec
Merge pull request #286 from seebs/storeauto
in Store/SetRow, create field if it doesn't already exist
2020-04-14 15:33:10 -05:00
Seebs
70bfe86f75 in Store/SetRow, create field if it doesn't already exist
If you try to Store to a nonexistent field, we create an automatic
Set field with no cache for it, assuming it won't be used for TopN
queries. If you want TopN to work, you need to actually create it
yourself.
2020-04-14 15:12:36 -05:00
alanbernstein
18d01dd62a
Merge pull request #280 from alanbernstein/snake-case-node
Snakify
2020-04-11 13:25:58 -05:00
Alan Bernstein
615c1bd186 Snakify 2020-04-10 22:15:43 -05:00
Matthew Jaffee
76404142ba
Merge pull request #246 from molecula/prometheus-improvements
Prometheus improvements
2020-04-10 21:55:35 -05:00
Matt Jaffee
68276159ca
don't access req.Query before knowing req is a QueryRequest 2020-04-10 21:07:43 -05:00
Alan Bernstein
18c6d8f76f
Update a few metric names 2020-04-10 20:59:20 -05:00
Alan Bernstein
71b9762501
Address review feedback again 2020-04-10 20:59:20 -05:00
Alan Bernstein
9947c92e8e
Add stats labels and slow-query log in GRPC endpoints 2020-04-10 20:59:20 -05:00
Alan Bernstein
eaf21eb19b
Add metrics for GRPC request timing 2020-04-10 20:59:19 -05:00
Alan Bernstein
5df680fb9f
Remove old metric from tests 2020-04-10 20:59:19 -05:00
Alan Bernstein
d79f04b7b3
Remove MetricMaximumRow 2020-04-10 20:59:19 -05:00
Alan Bernstein
a7bfacbee2
Revert "Add tags to MaxRow metric"
This reverts commit 6013e7211b3aef93d0880401c8ef74b34a620328.
2020-04-10 20:59:19 -05:00
Alan Bernstein
b37a0addb3
Add tags to MaxRow metric 2020-04-10 20:59:19 -05:00
Alan Bernstein
b1838159f2
Minor fixes 2020-04-10 20:59:19 -05:00
Alan Bernstein
df2503dfa6
Switch to Timing helper function 2020-04-10 20:59:19 -05:00
Alan Bernstein
2423ecf8d5
Update some metric names to follow conventions better 2020-04-10 20:59:19 -05:00
Alan Bernstein
f883d61c28
Consolidate BlockRepair metrics with tags 2020-04-10 20:59:18 -05:00
Alan Bernstein
389acfc8ed
Fix minor issues with metric labels and tests 2020-04-10 20:59:18 -05:00
Alan Bernstein
c2c0a5c32f
Address review feedback 2020-04-10 20:59:18 -05:00
Alan Bernstein
8b405c226c
Add 'prometheus' option in other help text/comments 2020-04-10 20:59:18 -05:00
Alan Bernstein
a3fb1c022b
Use metrics consts in tests 2020-04-10 20:59:18 -05:00
Alan Bernstein
8c9db373d0
Fix some metrics names 2020-04-10 20:59:18 -05:00
Alan Bernstein
5137f56f9c
Use const from package 2020-04-10 20:59:18 -05:00
Alan Bernstein
34c6d42063
Fix broken metrics label and log when others are encountered 2020-04-10 20:59:17 -05:00
Alan Bernstein
3c275681d2
Profile -> Column 2020-04-10 20:59:17 -05:00
Alan Bernstein
b1adcd91fc
Use consistent metric name convention 2020-04-10 20:59:17 -05:00
Alan Bernstein
70111b5604
Define metrics names as constants 2020-04-10 20:59:17 -05:00
Alan Bernstein
84e6a25bad
Update help message 2020-04-10 20:59:17 -05:00
Alan Bernstein
857ddf73c2
Reduce snapshot verbosity 2020-04-10 20:59:17 -05:00
Alan Bernstein
eceef6b42b
Use 'query_' prefix to identify query metrics 2020-04-10 20:59:16 -05:00
tgruben
550fcec9ee
Merge pull request #279 from tgruben/fix-closers
Closed all post request bodies and optimized available shard with new view capabilities
2020-04-10 20:29:04 -05:00
Todd Gruben
ccc7ca3aa5 close not needed 2020-04-10 20:12:32 -05:00
Todd Gruben
5590f1d954 lint fix 2020-04-10 19:07:01 -05:00
Todd Gruben
ef5a8cefef Added request Close and optimized availble shard with new view capabilities 2020-04-10 17:59:44 -05:00
seebs
4325d62fe7
Merge pull request #277 from seebs/between
Return empty rows for impossible ranges
2020-04-10 16:21:09 -05:00
Seebs
017e65cd99 Return empty rows for impossible ranges
If the high end of a range is below the low end of the range, there's
no values in it, so we can short-circuit that. If we don't, if the
low end is zero or higher, and the high end is below zero, we can
get very surprising behaviors, such as accepting values up to the
inverse of the high end. Add a test case for this and treat it the
same as a low range end above the field's maximum or a high end
below the field's minimum, returning an empty row immediately.
2020-04-10 13:24:08 -05:00
seebs
9b002bcc24
Merge pull request #271 from seebs/decimalfault
Handle nonexistent shards in min/max decimal queries.
2020-04-09 22:01:07 -05:00
Seebs
8e662d33a5
Handle nonexistent shards in min/max decimal queries.
If a shard has never had any decimal values in it at all for a
field, the ValCount object returned has no DecimalVal, which could
cause a segfault if we don't check for it. Add a test case which
sporadically triggers that behavior (it's timing/luck related,
unfortunately), and then also fix it.
2020-04-09 21:30:34 -05:00
Matthew Jaffee
179cab91e7
Merge pull request #275 from travisturner/serialize-null
serialize null operation (!= null)
2020-04-09 21:25:05 -05:00
Travis
88b2d79812 serialize null operation (!= null) 2020-04-09 17:56:27 -05:00
alanbernstein
0e6ed80bd4
Merge pull request #269 from alanbernstein/long-query-full
WIP Show full query string when logging slow queries
2020-04-09 16:12:11 -05:00
Alan Bernstein
92416018d5
Use more general log message 2020-04-09 15:53:40 -05:00
Alan Bernstein
5aebb242f8
Fix off-by-one error 2020-04-09 15:53:40 -05:00
Alan Bernstein
e3ace544ca
Show full query string when logging slow queries 2020-04-09 15:53:39 -05:00
tgruben
57b2f32fa1
Merge pull request #260 from tgruben/sync-start
delay start for non-coordinator
2020-04-09 14:42:41 -05:00
Todd Gruben
e7bbc3a0a8 Added delay to allow cooridinator a head start in launch on multi node clusters.
considered using Cluster.Disabled to identify if pilosa was stand alone but settled
on using an empty gossip seeds list
2020-04-09 14:20:01 -05:00
alanbernstein
bdfad719df
Merge pull request #263 from alanbernstein/grpc-multi
Support multiple dialTargets and cycle through on connection reset
2020-04-08 13:39:58 -05:00
alanbernstein
1846d21765
Merge pull request #1 from travisturner/dialtargets
cycle through dial targets regardless of error
2020-04-08 12:55:17 -05:00
Travis
8f0ae1b6f5 cycle through dial targets regardless of error 2020-04-08 12:29:15 -05:00
Alan Bernstein
adb21589f0 Support multiple dialTargets and cycle through on connection reset 2020-04-08 10:09:49 -05:00
seebs
1b5d86c8f0
Merge pull request #240 from seebs/q2perf
improve performance of difference/not
2020-04-07 20:24:51 -05:00
Seebs
be379e7806 cache AvailableShards
The computation of available shards is cheap, because realistically, virtually
no one has enough shards that the resulting bitmap is more than one container.

We don't try to fix this at the field/index levels because it's significantly
harder to do there, but I think the creation of these bitmaps is probably
the most expensive part, and switching the unions to union-in-place probably
reduces cost significantly.

Note that the bitmaps being unioned almost certainly have exactly one small
container in them.
2020-04-07 19:33:21 -05:00
Seebs
6c797e0c4e TODO => TODONE: use masks for runToBitmap
Had the code lying around from mad science elsewhere, backported.
2020-04-07 19:33:21 -05:00
Seebs
d4e496887b make differenceRunBitmap smarter
We avoid using bitmapContains so often because that turns out to be expensive.
Also, if we produce more than runMaxSize runs, we're going to convert to
a bitmap container (or possibly an array container if there were over
2048 items, but they're all singletons), and we can streamline that by just
converting the source to bitmap and returning differenceBitmapBitmap, which
is faster in this case.

This appears to overall take about half as long in the workload I was
looking at.
2020-04-07 19:33:20 -05:00
Kuba Podgórski
7868188670
Merge pull request #200 from kuba--/groupby-int/124
Group by on ints
2020-04-08 01:47:17 +02:00
Kuba Podgórski
1217deee1c Rebase 2020-04-08 01:06:18 +02:00
tgruben
64caffebe8
Merge pull request #196 from tgruben/async-available-shards
limit frequency of writes for available shards broadcast
2020-04-06 09:08:04 -05:00
Todd Gruben
6712f8cf06 removed debug log 2020-04-06 08:43:30 -05:00
Todd Gruben
5470753cb5 fix conflict 2020-04-05 18:37:11 -05:00
Travis
0e2bb550db add deleted (rebalanced) shards to remoteAvailableShards 2020-04-05 18:37:11 -05:00
Todd Gruben
6bd81b87eb unexport availableShardFileFlushDuration 2020-04-05 18:37:11 -05:00
Todd Gruben
000ea90877 unbuffer channel 2020-04-05 18:34:43 -05:00
Todd Gruben
af068e08e7 cleanup and comments 2020-04-05 18:34:43 -05:00
Todd Gruben
40a3dce93c Co-authored-by: Travis Turner <github@calfrope.com> 2020-04-05 18:34:43 -05:00
Todd Gruben
bb04f7f6ac limit frequency of writes for available shards 2020-04-05 18:31:28 -05:00
Cody Soyland
0a86f6a97b Increase gRPC maximum message length 2020-04-03 16:35:57 -05:00
Travis
b7fcfb41d9 add proto OldMin/OldMax for backward compatibility 2020-04-03 12:25:07 -05:00
Travis Turner
48879107b0
Merge pull request #244 from travisturner/fix-race
make sure frag.maxRow() call is lock-protected
2020-04-02 23:52:38 -05:00
Travis
b4f1781d30 make sure frag.maxRow() call is lock-protected 2020-04-02 23:25:57 -05:00
seebs
632f6856ab
Merge pull request #229 from seebs/checkptr
disable checkptr with go 1.14
2020-04-02 22:19:45 -05:00
seebs
a20532073b
Merge branch 'enterprise' into checkptr 2020-04-02 20:48:49 -05:00
alanbernstein
4faacad4cf
Merge pull request #242 from molecula/prometheus-options
Add options to prometheus client to support setting namespace
2020-04-02 20:24:15 -05:00
Alan Bernstein
dad4ccf103 Propagate namespace to tags client 2020-04-02 19:29:46 -05:00
Alan Bernstein
110d2b6024 Restore lost comment 2020-04-02 19:07:43 -05:00
Alan Bernstein
f15d031c55 Add options to prometheus client to support setting namespace 2020-04-02 19:05:55 -05:00
Travis Turner
7432546af8
Merge pull request #241 from travisturner/shardwidth22-tests
alter tests to allow for shardwidth22
2020-04-02 18:25:29 -05:00
Travis
182c1d3c42 alter tests to allow for shardwidth22
also, reset BitDepth on field and bsiGroup during
importRoaringOverwrite
2020-04-02 17:32:49 -05:00
Cody Soyland
da503776e2
Merge pull request #237 from codysoyland/ci-tweaks
CI: Modify Docker Hub rules and use "make test-race" for running race detector
2020-04-02 12:25:40 -05:00
Cody Soyland
6a639efdba Modify Docker Hub deployment filter rules.
The documentation is unclear/incorrect, and these filters aren't
behaving correctly. This is an attempt at fixing that. More info at:
https://discuss.circleci.com/t/job-runs-even-when-tags-ignore-filter-is-triggered-when-combined-with-branches-only/20664/11
2020-04-02 12:14:37 -05:00
Cody Soyland
14319cc54b Use "make test-race" instead of custom test flags in CI 2020-04-02 12:14:37 -05:00
Seebs
c6799bd604 disable checkptr with go 1.14
The checkptr feature is actually probably right about a few
things in roaring and boltdb, but we can ignore them for now, and
that prevents checking for races, so we disable that temporarily.

Also supply NOCHECKPTR in non-race tests because CI uses "make test"
with -race in $TESTFLAGS and we might do that on other occasions.
2020-04-02 11:37:06 -05:00
Matthew Jaffee
44fcbee447
Merge pull request #235 from jaffee/nil-check-indexmeta
add nil check for index meta
2020-04-02 11:33:25 -05:00
Matt Jaffee
35fa26918d
add nil check for index meta 2020-04-02 11:09:07 -05:00
Travis Turner
794bc5b168
Merge pull request #232 from travisturner/decimal-grcp
convert grpc response to use pql.Decimal
2020-04-02 07:55:26 -05:00
Travis
4d985653ae convert grpc response to use pql.Decimal 2020-04-01 23:59:50 -05:00
Travis Turner
0b480f8405
Merge pull request #231 from travisturner/reintroduce-decimal
Reintroduce decimal
2020-04-01 21:44:26 -05:00
Travis
22cca67d6a Revert "back out the pql.Decimal changes"
This reverts commit 741ba9b268.
2020-04-01 17:46:46 -05:00
Matthew Jaffee
e77bf45643
Merge pull request #227 from travisturner/backout-decimal
back out the pql.Decimal changes
2020-04-01 11:32:02 -05:00
Travis
741ba9b268 back out the pql.Decimal changes 2020-04-01 11:10:33 -05:00
Cody Soyland
1284791d22
Merge pull request #224 from codysoyland/ci-fixes
CI fixes: quote TESTFLAGS and fix stable release filter
2020-04-01 09:41:38 -05:00
Cody Soyland
dc5a471939 Downgrade golangci-lint to 1.23.8 (attempt fix for OOM failures) 2020-04-01 09:07:11 -05:00
Cody Soyland
39d83e7b6f Add no_output_timeout for the race detector 2020-04-01 09:07:11 -05:00
Cody Soyland
01033d4fff CI fixes: quote TESTFLAGS and fix stable release filter 2020-04-01 09:07:11 -05:00
Kuba Podgórski
b0f1ee3fce
. (#225) 2020-04-01 15:19:05 +02:00
seebs
c6083d6816
Merge pull request #163 from seebs/distinctshards
Address issues with Distinct failures in testing, or across shards, or in cases where the range of Distinct results is not the same as the range of shards available in any index.
2020-03-31 21:06:16 -05:00
Travis
0374bda45f Adjust bare-distinct logic.
If an index is provided to a bare distinct which happens
to be the index handling the query, then the query needs
to behave as if no index argument was provided.

For example:

When querying against index `i`,
```
Distinct(index="i", field="ints")`
```
should behave exactly like
```
Distinct(field="ints")
```
2020-03-31 19:51:06 -05:00
Seebs
a495b6c227 make Distinct work across nodes, probably
Problem: A top-level bare "Distinct" call returns results only
for shards on the current node.

Analysis: We don't actually want to limit Distinct calls to "available"
shards at all. We just want to run them on everything. But we already
did that in generating the precomputed results; all we need to do is,
if we get a non-shard-specific request for precomputed values, just
return all the values.

It's pretty hard to create logic for this using our fancy mapReduce,
but also we could just... not do that.
2020-03-31 19:51:06 -05:00
seebs
12ba11a437
Merge pull request #215 from seebs/mmap-v-cache
clear container lookup cache when updating every container, handle nils with differenceInPlace, use transaction/ops log for mergeBlock.
2020-03-31 19:49:43 -05:00
Seebs
76e7470559 make mergeBlock use transactions
mergeBlock was bypassing the transaction setup stuff, which means that
if we ran out of open files, mergeBlock wouldn't generate ops log
entries (!), also it didn't update the cache (!). This came up because
it also didn't enjoy the "catch your segfaults and issue a diagnostic"
behavior offered by the generation code.

Switch to computing positions directly and calling importPositions,
which does a transaction.
2020-03-31 16:22:41 -05:00
Seebs
28b9d6d7fc ditch lastKey cache on UpdateEvery
UpdateEvery can change every key, and I think it strongly suggests no
reasonable expectation of repeated access to a previously-accessed key,
but also it can change the containers and replace them.

We were avoiding caching mapped containers in some but not all cases,
and that was causing segfaults. But really, the *problem* is that
the remap operation wasn't clearing (or updating) the cache. Cleaning
that up allows us to take advantage of the caching performance advantage
even when working with read-only/mapped bitmaps.

The only way to hit this:

* Have mmapped containers to begin with.
* Do reads so those containers get frozen.
* Access, either reading or writing, a specific container with key K.
* Snapshot, so the bitmap gets its containers replaced.
* Remember, they have to be frozen -- if they aren't frozen,
  we'll update the containers in place.
* Now have GC run so it actually unmaps the data.
* Now try to write to the container with key K *before reading or
  writing any other key*. You have to get through the whole snapshot
  and GC process without any other reads or writes.
* You get the cached value. You try to use it. You explode.

The sliceContainers code was also setting lastKey to 0 in some cases,
but also setting lastContainer to nil, so this wouldn't have caused
problems, but just to be careful, I've standardized on ^uint64(0)
for everything.
2020-03-31 16:20:05 -05:00
Seebs
1ac00291f3 Add test for the weird remapping/cache interaction.
This test is really a test of a very specific bit of the internals
of containers_btree/containers_slice, but we can't easily test it from
there because they don't have all the logic for remapping files.

The underlying issue is that they maintain a single-item "most recent
container" cache, and this wasn't getting updated during the remap
operations, happening through containers.UpdateEvery. The fix is
probably just to make sure that UpdateEvery invalidates the cache.
2020-03-31 16:20:05 -05:00
Seebs
d26e221a91 don't call isArray on a nil *Container
differenceInPlace wasn't checking for nil containers, which are
theoretically valid empty containers. Also added a couple of other
N==0 checks to streamline the higher-level operation.
2020-03-31 16:20:05 -05:00
Cody Soyland
3b6a26e5c6
Merge pull request #219 from codysoyland/ci-updates
Add updated CircleCI config
2020-03-31 16:18:10 -05:00
Cody Soyland
3a7f385a01 Add updated CircleCI config
- Remove YAML magic
- Remove a lot of duplication
- Update linter
- Use parameterized jobs and matrix build
- Update Docker Hub CD to produce versioned and "latest" images
- Add custom shard width test to workflow
2020-03-31 15:17:11 -05:00
Travis Turner
b5aa280ced
Merge pull request #220 from travisturner/decimal-yaml
yaml marshal/unmarshal for pql.Decimal
2020-03-31 13:53:00 -05:00
Travis
7cb265098f yaml marshal/unmarshal for pql.Decimal 2020-03-31 12:43:42 -05:00
Kuba Podgórski
6dc3837c9a
WIP: fix 'unknown call: Distinct' error (#213) 2020-03-31 16:29:14 +02:00
Travis Turner
dca2120c06
Merge pull request #199 from travisturner/cluster-resize-translation-partitions
include translate partitions in cluster resize instructions
2020-03-30 22:01:09 -05:00
Kuba Podgórski
ac76f6227d
Make internal.IndexMeta.TrackExistence true 2020-03-30 21:24:16 -05:00
Travis
98c5603965
close reader. include all replias in translation partition rebalance 2020-03-30 21:24:16 -05:00
Travis
4c311aa1a7
write to temp partition file. use io.Copy 2020-03-30 21:24:16 -05:00
Travis
2724ecfd5f
WIP: include translate partitions in cluster resize instructions
This commit adds `TranslationSources` to the cluster
`ResizeInstruction`. These are the sources of translation
partitions which the receiving node needs in order to support
partition distribution in the new, resized cluster.

This also fixes a bug where index options were not being
encode in the proto Index object. That meant that the schema
transferred via protobuf was not correct. The reason why
things normally worked is because index creation typically
happens on the CreateIndex message, which does include the
options.

TODO:

- [ ] implement the TranslateStore interface for `InMemTranslateStore`
and `mock.TranslateStore`
- [ ] surely need some more tests around the `ReadFrom` and `WriteTo`
2020-03-30 21:24:16 -05:00
Travis Turner
2ad06f9423
Merge pull request #212 from travisturner/decimal-min-max-args
support pql.Decimal for decimal field min/max arguments
2020-03-30 14:32:02 -05:00
Travis
80da129861 require scale argument for decimal fields 2020-03-30 13:38:50 -05:00
Travis
1da7cf09bb support pql.Decimal for decimal field min/max arguments 2020-03-27 16:02:47 -05:00
Cory LaNou
2a4088e0ec
Merge pull request #206 from corylanou/test-helpers
Make better use of t.Helper
2020-03-25 07:35:35 -05:00
Cory LaNou
391fda9849
Merge branch 'enterprise' into test-helpers 2020-03-24 15:51:01 -05:00
corylanou
f84185230d
make use of t.Helper 2020-03-24 15:00:32 -05:00
Cody Soyland
7ba5c0e3d3
Merge pull request #201 from codysoyland/queryunary
Add QueryPQLUnary gRPC call
2020-03-23 16:58:27 -05:00
Cody Soyland
1aa1ec51aa Add QueryPQLUnary gRPC call 2020-03-23 16:24:31 -05:00
Cory LaNou
69a1365bf0
Merge pull request #202 from corylanou/sum/194
Fixed sum for negative values
2020-03-23 16:22:11 -05:00
corylanou
f32f9f64a4
fix sum for negative values 2020-03-23 14:02:46 -05:00
Travis Turner
532f746f25
Merge pull request #195 from travisturner/sync-mutex-bool
support mutex/bool fields in anti-entropy
2020-03-19 11:47:37 -05:00
Travis Turner
5cfb29beb2
Merge branch 'enterprise' into sync-mutex-bool 2020-03-19 11:28:56 -05:00
Travis Turner
564eee0bdf
Merge pull request #190 from travisturner/decimal-between
serialize decimal between pql for internode queries
2020-03-19 11:26:12 -05:00
Travis
57c30b9dae support mutex/bool fields in anti-entropy 2020-03-19 11:11:33 -05:00
Travis
4d38723fd4 serialize decimal between pql for internode queries 2020-03-19 07:50:43 -05:00
Travis Turner
419c2179b5
Merge pull request #185 from travisturner/decimal-min-max-overflow
Avoid overflow on decimal min/max default values
2020-03-18 08:01:40 -05:00
Travis
298f290e86
Avoid overflow on decimal min/max default values
If the min/max provided are already on the boundary of int64,
then we don't want to operate on them and cause overflow.
there are still overflow scenarios where a user provides a
min/max which is not on the boundary, but overflow once the
scale is applied. This does not address those cases, but at
least it addresses the default case (where a min/max is not
provided)
2020-03-18 07:41:35 -05:00
Kuba Podgórski
73ca124944
Fix runCountRange when range start == interval start (#181)
When the interval is a proper superset of the range with start equal to
interval start, the range must be considered a superset or it will be
completly ignored (since it neither a subset nor it overlaps)

Co-authored-by: Pierre Fersing <pierre.fersing@bleemeo.com>
2020-03-17 20:31:35 +01:00
Travis Turner
ba5b133e1e
Merge pull request #180 from travisturner/mu-anti-entropy
add mutex for anti-entropy and node join/leave
2020-03-17 13:05:53 -05:00
Travis
fbbd474978 add mutex for anti-entropy and node join/leave 2020-03-17 12:46:09 -05:00
Travis Turner
22ae1139d1
Merge pull request #172 from travisturner/float-to-decimal
use pql.Decimal instead of float64
2020-03-16 08:35:19 -05:00
Travis
c60241b5a9 Get rid of Sign from pql.Decimal struct
It turns out that it's not very useful to keep the sign
value as a separate argument in the pql.Decimal struct.
This commit incorporates it into Value, and makes Value
an `int64` (for some bone-headed reason I had made it a
`uint32` before which is just dumb).
2020-03-15 23:00:00 -05:00
Travis
30e08eb532 add error conditions to tests 2020-03-15 16:18:59 -05:00
Travis
513edeae9c fix min/max bug for decimal fields 2020-03-14 22:35:24 -05:00
Travis
963affcc30 WIP: use pql.Decimal instead of float64
This commit introduces a new type: pql.Decimal
We use that instead of float64 in order to ensure
that the string representation is consistent.

One unfortunate discovery during implementation is
that the RowAttrs and ColAttrs support floats, and
the PEG file was treating them as such. So I had
to split the PEG definitions into float-specific
items and decimal-specific items.
2020-03-14 22:33:52 -05:00
Travis Turner
334eb3cd08
Merge pull request #175 from travisturner/int-min-max-with-offset
Fixes the min/max bug for `int` fields with offset.
2020-03-14 15:18:48 -05:00
Travis
3863ab4b41 Fixes the min/max bug for int fields with offset.
Methods `MinForShard` and `MaxForShard` were not adjusting
their return value by the offset.
2020-03-14 14:01:40 -05:00
Travis Turner
0d55d6eab2
Merge pull request #160 from travisturner/int-fragment-sync-better-fix
support fragment sync for int and decimal fields
2020-03-13 18:42:12 -05:00
Travis
a5cba75855 fix typos in comment 2020-03-13 12:15:54 -05:00
Travis
3b676a7cbd fix linter warnings 2020-03-13 12:15:54 -05:00
Travis
cbf80370cb support fragment sync for int and decimal fields
This PR adds support for anti-entropy syncing for integer
and decimal fields. It differs from the logic for other
field types in that it does not rely on a consensus to determine
what the value should be; instead, it considers the correct
values to be those of the primary replica. From there, data
is pushed to all non-primary replicas.
2020-03-13 12:15:54 -05:00
Cody Soyland
8b5848f615
Merge pull request #164 from codysoyland/dockerfile-env-config
Use env variables instead of flags in Dockerfile
2020-03-12 14:44:45 -05:00
Cody Soyland
c6a293f818 Use env variables instead of flags in Dockerfile
This allows you to override those attributes without overriding the
entire command.
2020-03-12 11:22:31 -05:00
Travis Turner
93a804f7ab
Merge pull request #165 from travisturner/range-ast-fix
fix Call stringer for range conditional
2020-03-12 08:29:38 -05:00
Travis
0c6f0e2ba5 fix Call stringer for range conditional 2020-03-11 22:53:37 -05:00
Travis Turner
d76e8fc17c
Merge pull request #162 from travisturner/makefile-helpers
add linter and test-race targets to makefile
2020-03-11 10:10:41 -05:00
Travis
dde1e26baa add linter and test-race targets to makefile 2020-03-11 09:24:00 -05:00
Travis Turner
cdbb274a2b
Merge pull request #157 from travisturner/int-fragment-sync-quick-fix
temporary fix for int field replica sync bug
2020-03-09 15:22:41 -05:00
Travis Turner
f747501473
Merge branch 'enterprise' into int-fragment-sync-quick-fix 2020-03-09 14:56:06 -05:00
Matthew Jaffee
d0aad872e2
Merge pull request #144 from jaffee/min-con-reuse
Min con reuse
2020-03-09 14:54:56 -05:00
Matt Jaffee
f0f86500c7
add minimal fix for connection reuse issue - @tgruben has a more complete fix 2020-03-07 09:46:47 -06:00
Travis
70c3cf1775 include a basic test which covers the temp fix 2020-03-05 21:16:10 -06:00
Travis
86da5c7adf temporary fix for int field replica sync bug 2020-03-05 20:57:16 -06:00
Travis Turner
b99bdb8169
Merge pull request #156 from travisturner/forward-translation-to-coordinator
forward field translation request to coordinator
2020-03-05 17:53:35 -06:00
Travis
3e4f7dd3f3 change translateFieldKeys to variadic function 2020-03-05 15:38:34 -06:00
Travis
d06ffd207f forward field translation request to coordinator 2020-03-05 14:54:23 -06:00
seebs
bbeacbe3c3
Merge pull request #147 from seebs/emptylog
don't fill up empty space with non-functional ops logs
2020-03-04 18:28:55 -06:00
Seebs
eb263b7666 don't fill up empty space with non-functional ops logs
Two changes:

1. Don't write batch/roaring adds or removes when N is 0, because
a write of no bits is not a meaningful write.
2. When unmarshalling roaring things, if a roaring bitmap didn't
change many bits, treat it as having changed at least 1 bit per 8 bytes,
so an 8KB hunk of roaring data counts as 1K changes, which will
nudge us towards snapshotting. This should keep us from having
Large Files show up so much.

This was particularly noticeable on the existence field, which
tends to a steady state of "completely full" very quickly in a lot
of cases.
2020-03-04 18:10:10 -06:00
Kuba Podgórski
53c486fce0
Remove not needed translationSyncer from holder. (#152) 2020-03-05 00:19:58 +01:00
Travis Turner
78327904ff
Merge pull request #145 from travisturner/translate-partition-better-fix
add translationSyncer interface
2020-03-03 19:42:50 -06:00
Travis
842c820366 add translationSyncer interface
This PR adds a translationSyncer interface; I tried to include
comments in the code explaining what's going on. This is taken
from those comments:

translationSyncer provides an interface allowing a function
to notify the server that an action has occurred which requires
the translation sync process to be reset. In general, this
includes anything which modifies schema (add/remove index, etc),
or anything that changes the cluster topology (add/remove node).
I originally considered leveraging the broadcaster since that was
already in place and provides similar event messages, but the
broadcaster is really meant for notifiying other nodes, while
this is more akin to an internal message bus. In fact, I think
a future iteration on this may be to make it more generic so
it can act as an internal message bus where one of the messages
being published is "translationSyncReset".
2020-03-03 14:21:45 -06:00
Travis Turner
92eae8e715
Merge pull request #146 from travisturner/remove-errant-print
remove errant println from test
2020-03-03 12:39:28 -06:00
Travis
7aea54936e remove errant println from test 2020-03-03 11:27:36 -06:00
Travis Turner
13e7679fd9
Merge pull request #138 from travisturner/translate-partition-quick-fix
very crude fix for the translate key read-only bug
2020-02-29 16:18:50 -06:00
Travis
717bd09e97 include the test which covers this scenario 2020-02-29 08:43:10 -06:00
Travis
fb8f612afe very crude fix for the translate key read-only bug
This PR forces the non-coordinator nodes to reset their translation
sync (and therefore their own cosideration of read-only partitions)
any time they receive a `ClusterStatus` message. So basically, as the
cluster grows during the startup process, each node will reset their
translation sync.

This is NOT a good solution log term, but it should address the
immediate problem.

Things to note:
- the coordinator sync isn't getting reset, but that's ok, because the
immediate problem is a partition marked as read-only when it shouldn't
be; i.e. it's ok to have the inverse (a partition not marked as
read-only when it should be) because that partition won't receive
requests anyway.
- the last node to start is already correct and doesn't really need to
reset its sync.
- there are many other scenarios not covered by this fix.

Based on this theory:

```
i have another theory that i’m going to try to test.
this one would only apply in the case where a multi-node cluster is restarted with an existing, keyed index.
- start node0: it thinks it’s responsible for all partitions (nothing is read-only)
- start node1: it thinks it’s responsible for ~1/2 of the partitions and marks the other 1/2 as read-only
- start node2: it thinks it’s responsible for ~1/3 of the partitions and marks the other 2/3 as read-only
now if node0 is the coordinator receiving all translation requests, that still might not explain what’s happening, because in that case it would just do all the translating. i think. but either way, i should make sure that scenario is not happening, but i think it may be.

actually, that might explain it, because what would happen when the coordinator received a translation request, is that it would handle the 1/3 that it owned (now that the cluster is 3 nodes), and it would send the other 2/3 out to the other 2 nodes. but where it sent the requests wouldn’t line up with what the nodes thought they were responsible for based on the restart order
in this example, node 1 would receive requests for the wrong partitions
```
2020-02-29 08:43:05 -06:00
Matthew Jaffee
fcbebcf1b6
Merge pull request #103 from seebs/gencrash
don't mark a source as changed before we've finished remapping
2020-02-21 17:00:19 -06:00
Seebs
d742c67317
avoid race on max count reads and writes 2020-02-21 16:38:36 -06:00
Seebs
ba7db3028b
sanity-check: check whether containers are flagged as mapped before mapping
In the old unmarshal code, the decision to mark a thing as mapped (always
yes) happens separately from setting the mapping. What if this could ever
somehow possibly go wrong? Let's sanity-check that to be extra careful.
2020-02-21 16:38:35 -06:00
Seebs
7841a660a8
make sure setArray isn't copying mapped data addresses by accident in unionInPlace 2020-02-21 16:38:35 -06:00
Seebs
99d865c2ea
ensure that we've unrequested mapping when applying empty storage 2020-02-21 16:38:35 -06:00
Seebs
337e451cc7
lint and review changes
Log an error in the probably-irrelevant case where we ended up with
a file, but Stat failed, which shouldn't ever happen we hope anyway.

Also explicitly discard the status from RemapRoaringStorage in a case
where we don't care.
2020-02-21 16:38:35 -06:00
Seebs
cb686dcad0
make mmap test experiment with different amounts of mapping
This is sort of prototype-ish, but the idea is that we use SetMaxMapCount
from syswrap, which already exists, to let us test edge cases like
"what happens if you only sometimes have mapped data".
2020-02-21 16:38:35 -06:00
Seebs
63fb2f8539
generation testing and paranoia features
We might have a problem with a stale mmap, and to try to narrow it down
a bit, we add some sanity-checking features and panic recovery to the
generation Transaction code.

This is pretty experimental.
2020-02-21 16:38:35 -06:00
Seebs
372389fd30
don't corrupt files when mmap fails
In some cases, after a snapshot, if mmap fails, we could write
a duplicate of the bitmap to the file, creating cryptic "unknown
op type: 60" messages. This doesn't fix those files, but it stops
making them.
2020-02-21 16:38:35 -06:00
Seebs
f9e7fee47d
don't mark a source as changed before we've finished remapping
Also, check the remap operation for errors, and if an error occurs,
try to remap to nil (which shouldn't be able to fail).
2020-02-21 16:38:34 -06:00
Matthew Jaffee
ebab831a43
Merge pull request #113 from molecula/minMaxFloatHandling
min and max should properly scale their output for decimal fields
2020-02-21 16:38:11 -06:00
Matthew Jaffee
8c9b717b05
fix "worhtless" typo in comment 2020-02-21 16:00:31 -06:00
Matt Jaffee
fe46c84d19
also fix Sum query, but don't convert to float until the last step
this avoids compounding floating point errors while summing up the
numbers, and means less logic needs to change. Should probably convert
min and max to use this approach as well, though they don't suffer
from the compounding error issue, it is simpler.
2020-02-21 14:11:30 -06:00
Matt Jaffee
7321f9427c
min and max should properly scale their output for decimal fields
this involved adding an optional float value to the ValCount struct
which complicated result types, necessitated grpc changes, and needed
quite a few tests at different layers.
2020-02-21 14:11:29 -06:00
Matthew Jaffee
d369e3b4bf
Merge pull request #125 from travisturner/time-panic
send nil time value to prevent downstream panic
2020-02-21 14:08:53 -06:00
Travis Turner
52d450cbaf
Merge branch 'enterprise' into time-panic 2020-02-21 10:31:24 -06:00
Travis
13a1b3a2c1 send nil time value to prevent downstream panic 2020-02-18 15:55:40 -06:00
Kuba Podgórski
f3f11f4a44
Let translate keys as empty strings (#120) 2020-02-18 12:54:24 +01:00
Kuba Podgórski
57eb741c24
Don't allow an int and decimal fields to be created with keys=true (#118) 2020-02-14 08:47:31 +01:00
Kuba Podgórski
59f5d4f7d6
Do not clear existence column (#117) 2020-02-13 07:08:45 +01:00
Travis Turner
4713ccd0c8
Merge pull request #110 from travisturner/translatestore-fixes
WIP: Thread OpenTranslateStore through Holder to Index
2020-02-12 11:56:49 -06:00
Ben Johnson
c8cefea897
Fix test performance 2020-02-12 10:25:26 -06:00
Travis
d9ef4c0986
use OpenInMemTranslateStore by default in tests 2020-02-12 10:25:25 -06:00
Travis
4dd530e956
open bolt translate store partitions asynchronously 2020-02-12 10:25:25 -06:00
Travis
49c8bf01a0
WIP: Thread OpenTranslateStore through Holder to Index 2020-02-12 10:25:25 -06:00
Cody Soyland
f9f6fce6b4
Merge pull request #111 from codysoyland/go-1.14-rc
Add Go 1.14-rc to CI
2020-02-10 07:59:48 -06:00
Cody Soyland
88c3477010 Add Go 1.14-rc to CI 2020-02-06 19:46:01 -06:00
Kuba Podgórski
e77c69d212
Update handler.go (#108) 2020-02-05 22:14:25 +01:00
tgruben
fc6fd150ba
Merge pull request #106 from tgruben/bug-105
handle missing index in join properly
2020-02-05 10:29:56 -06:00
Todd Gruben
0acac34fee travis suggetions 2020-02-04 15:21:55 -06:00
Todd Gruben
3140b2d8cb handle missing index in join properly 2020-02-04 11:55:49 -06:00
Kuba Podgórski
3bb45ea2c0
Fix Set operation for float numbers on decimal fields. (#101) 2020-02-03 19:29:15 +01:00
Kuba Podgórski
7c395ac4d1
Simplify Holder's logic for CreateIndex (#104) 2020-02-03 17:41:06 +01:00
Travis Turner
b693688677
Merge pull request #60 from molecula/translation-sharding
Translation sharding
2020-01-31 10:44:51 -06:00
Travis
9b4c7610e6 Merge branch 'enterprise' into translation-sharding 2020-01-31 10:13:44 -06:00
tgruben
eca14d8608
Merge pull request #97 from tgruben/row-difference-in-place
Difference in place at row level
2020-01-30 15:10:23 -06:00
Travis Turner
8626a2a710
Merge pull request #99 from travisturner/translation-sharding
Ensure ForeignIndex key translation happens in API.
2020-01-30 14:42:41 -06:00
tgruben
1be22f13e8
Merge pull request #2 from travisturner/row-difference-in-place
fix differenceInPlace test
2020-01-30 14:31:30 -06:00
Todd Gruben
f498a40d97 go mod tidy 2020-01-30 14:28:44 -06:00
Travis
0bdcb5ab0a fix differenceInPlace test 2020-01-30 13:38:31 -06:00
Travis
61e527251a fix some comments 2020-01-30 10:56:03 -06:00
Todd Gruben
8de32fd62a high level support for difference in place 2020-01-30 08:11:43 -06:00
Travis
e40400b130 Ensure ForeignIndex key translation happens in API.
For Fields with ForeignIndex (which have keys), the API was missing
the logic to do that translation against the translateStore of
the foreign index. This commit adds that logic, as well as some
missing translateStore-related logic in the gRPC code.
2020-01-28 22:46:12 -06:00
tgruben
32b92abd6e
Merge pull request #94 from tgruben/diff-inplace
Adding roaring in place difference support
2020-01-23 08:23:47 -06:00
tgruben
014c3a98a5
Merge pull request #1 from travisturner/diffinplace
tidy comments and remove pilosa dependency
2020-01-22 12:09:50 -06:00
Travis
bb80d1ed2d tidy comments and remove pilosa dependency 2020-01-22 11:59:32 -06:00
Todd Gruben
f40ced47fa included previous patterns for in place testing 2020-01-21 16:56:33 -06:00
Travis Turner
43b8d7827a
Merge pull request #90 from travisturner/translation-sharding
Field.ForeignIndex translation on ImportValue()
2020-01-17 17:25:14 -06:00
Travis
d41ee99052 linter fix 2020-01-17 14:46:43 -06:00
Travis
b620e37e51 move the foreign index key check into applyTranslateStore() 2020-01-17 14:41:41 -06:00
Travis
f001ad199f use translateIndexKeys instead of translateIndexKeySet in ImportValue() 2020-01-17 11:58:15 -06:00
Travis
efffa39c2c check foreign index on field open 2020-01-17 11:42:21 -06:00
Travis
90a2e116a7 update translateResult to translate foreign index keys on SignedRow results 2020-01-17 11:10:42 -06:00
Travis
0ba5b48fca Field.ForeignIndex translation on ImportValue() 2020-01-16 22:23:29 -06:00
Ben Johnson
10ccb6d523 translate foreign index 2020-01-16 13:53:12 -06:00
Ben Johnson
4020f8c73e fix cross-index translation 2020-01-15 14:28:06 -06:00
Travis
54679c12c4 post merge, needs review of TODOs 2020-01-14 22:10:12 -06:00
Travis
df51f07f96 Merge branch 'enterprise' into translation-sharding 2020-01-14 20:05:12 -06:00
Travis Turner
0459285101
Merge pull request #87 from travisturner/grpc-connection-reset
reset grpc connection after TransientFailure
2020-01-14 16:26:02 -06:00
Travis
757df0d284 reset grpc connection after TransientFailure 2020-01-14 15:18:25 -06:00
Travis
f232ec4277 Merge remote-tracking branch 'upstream/enterprise' into enterprise 2020-01-14 15:18:09 -06:00
Matthew Jaffee
12c6cd1c4e
Merge pull request #88 from jaffee/grpc-mutex-string-bug
mutex field data type should be string not []string
2020-01-12 18:27:47 -06:00
Matt Jaffee
ff9ad9a4fe
mutex field data type should be string not []string 2020-01-12 17:38:43 -06:00
tgruben
ba70bf3079
Merge pull request #89 from tgruben/bug-q2-double-delete
bit remove leaves internals corrupt on empty edge case
2020-01-12 16:25:31 -06:00
tgruben
3261ec4dc4
Merge branch 'enterprise' into bug-q2-double-delete 2020-01-12 16:09:12 -06:00
Todd Gruben
99108a1c63 bit remove leaves internals corrupt on empty edge case 2020-01-12 12:00:00 -06:00
Travis
89f6429dac Merge remote-tracking branch 'upstream/enterprise' into enterprise 2020-01-10 15:45:25 -06:00
Travis Turner
9015c00da9
Merge pull request #84 from travisturner/foreign-index
Add FieldOption.ForeignIndex
2020-01-10 15:45:02 -06:00
Travis
a6a2f84bd5 During Holder.Open, apply foreign index after all indexes open
In the case where a field with a foreign index opens before the
foreign index has opened (and is available as a reference in the
holder), push the field into a queue to have its foreign index
applied once all indexes have opened.
2020-01-10 12:28:28 -06:00
Travis
3d3286a9ca fix an issue caused by empty column list defaulting to IDs 2020-01-10 12:28:28 -06:00
Travis
f79fde43e3 exclude internal fields (i.e. _exists) from Inspect output 2020-01-10 12:28:28 -06:00
Travis
742135dc10 Get ForeignIndex string value when reading BSI field.
In the `Inspect` function in `server/grpc.go`, getting
the value of an `int` field with a foreign index to
an index with `Keys()`, we need to return the string
key value instead of the BSI int value for the field.

This commit also changes the method `Field.keys()` to be
exported as `Field.Keys()` so that it's accessible in
the server package.
2020-01-10 12:28:28 -06:00
Travis
35f9dfa374 remove write portion of extension data race 2020-01-10 12:28:28 -06:00
Travis
881d3bef06 Adjust the FieldOption logic to be in place prior to field.Open().
This commit changes the order of FieldOption application so that
it's always set before field.Open() is called.

This was required because field.Open() now uses some of the values
from FieldOptions to determine if/when to use a particular
translateStore. For example, when FieldOptions.ForeignIndex is set,
the translateStore from the foreign index is retrieved during
field.Open().
2020-01-10 12:28:28 -06:00
Matt Jaffee
4d8f307c5e handle string values in ImportValueRequest sorting 2020-01-10 12:28:28 -06:00
Matt Jaffee
132cf7cc1c add StringValues to proto ImportValueRequest, update proto versions
I ran:

brew upgrade protobuf
GO111MODULE=off go get -u github.com/gogo/protobuf/protoc-gen-gofast

I'm not sure if everything is still going to work, but I'm excited to
find out!
2020-01-10 12:28:27 -06:00
Travis
b22d0143e4 loadNewExtensions is unused, but included for completeness 2020-01-10 12:28:27 -06:00
Travis
1542cbefc0 Add FieldOption.ForeignIndex
This allows a BSI field to have an option indicating
that it is a foreign key to another index. If the foreign
index has column keys, then this field handles string values
by using the foreign index's translate store.
2020-01-10 12:28:27 -06:00
Travis
5ca37bf3f3 reset grpc connection after TransientFailure 2020-01-10 11:49:33 -06:00
Matthew Jaffee
7aef0743e1
Merge pull request #86 from jaffee/field-char-limit
allow field and index names up to 230 characters
2020-01-09 14:43:55 -06:00
Matt Jaffee
0a1de81441
allow field and index names up to 230 characters
The lowest limitation I've seen on any filesystem we care about is 255
characters. 230 leaves enough space that an index or field could be
backed up and have a timestamp and file extension appended while
still allowing for much longer index and field names.
2020-01-09 13:02:22 -06:00
Ben Johnson
cda2729935 fix bitdepth race 2020-01-08 09:47:43 -07:00
Ben Johnson
1f6910b0b8 fix group by test 2020-01-08 09:47:43 -07:00
Ben Johnson
a043490996 add multi-shard translation 2020-01-08 09:47:43 -07:00
Ben Johnson
bdfdeb1291 fix lint 2020-01-08 09:47:43 -07:00
Ben Johnson
a189477ba3 rebase & fix test const 2020-01-08 09:47:43 -07:00
Ben Johnson
1409ab5664 fix data race 2020-01-08 09:47:43 -07:00
Ben Johnson
1b068f75a8 Fix inmem read only translation bug 2020-01-08 09:47:43 -07:00
Ben Johnson
2f76283f03 fix replication errors & test races 2020-01-08 09:47:43 -07:00
Ben Johnson
9647d9b4bb fixing additional tests 2020-01-08 09:47:43 -07:00
Ben Johnson
c0a129979e fix tests 2020-01-08 09:47:43 -07:00
Ben Johnson
e3606d6615 fix id generation 2020-01-08 09:47:43 -07:00
Ben Johnson
82910911dd refactoring id partitioning 2020-01-08 09:47:43 -07:00
Ben Johnson
f31d68739e holder syncer translate implementation 2020-01-08 09:47:43 -07:00
Ben Johnson
b3e86e8394 refactoring stores back into index/field 2020-01-08 09:47:43 -07:00
Ben Johnson
7215bfd16c Implement translator store sharding 2020-01-08 09:47:43 -07:00
Travis Turner
cabfa3c456 add a test for pilosa/#2084 2020-01-08 09:47:43 -07:00
tgruben
457789effd
Merge pull request #62 from tgruben/clearvalue
add support to clear value for column
2020-01-07 13:12:21 -06:00
Todd Gruben
643884aeb3 refactored clear to fix q2;removed unused comment 2020-01-07 12:55:32 -06:00
Todd Gruben
26e3460413 removed view creation from ClearValue 2020-01-07 10:55:45 -06:00
Todd Gruben
d843959904 fixed comments; removed create fragment 2020-01-07 10:39:56 -06:00
Todd Gruben
75e017cf4f Merge remote-tracking branch 'upstream/enterprise' into clearvalue 2020-01-07 10:28:47 -06:00
Cody Soyland
29f7448b89
Merge pull request #83 from codysoyland/expvar-compatibility
Initialize expvar lazily to prevent panic if importing both Pilosa v1 and v2
2020-01-02 17:56:42 -06:00
Cody Soyland
8d32005ede Initialize expvar lazily to prevent panic if importing both Pilosa v1 and v2. 2020-01-02 15:43:34 -06:00
Travis Turner
5643afac47
Merge pull request #82 from travisturner/row-response-sorter
WIP: RowResponseSorter for sorting a list of RowResponse based on sort params
2019-12-31 13:18:05 -06:00
Travis
0fffd9a0cb RowResponseSorter for sorting a list of RowResponse based on sort paraters 2019-12-31 11:52:01 -06:00
Travis Turner
c247805d96
Merge pull request #81 from travisturner/inspect-field-output
Remove empty field check in Inspect()
2019-12-27 13:42:36 -06:00
Travis Turner
98df5672e9
Merge branch 'enterprise' into inspect-field-output 2019-12-27 13:26:38 -06:00
Travis Turner
768de9dc3a
Merge pull request #80 from travisturner/row-response-error
Add StatusError to RowResponse for better error handling.
2019-12-27 13:25:38 -06:00
Travis
3be4141382 Return the correct data type label in grpc header
Based on the pilosa field type, return the correct data type
label in the gRPC column header.
2019-12-27 12:43:45 -06:00
Travis
73090e05c8 Add StatusError to RowResponse for better error handling.
This PR adds a `StatusError` to the `pproto.RowResponse` type, which
allows a stream to pass an error on the stream (encoded into
the `RowResponse.StatusError`). This can be checked downstream
for matching `EOF` or `err != nil` and handled appropriately.

This is helpful mainly with the `RowResponse` reducers which run in
goroutines. Instead of trying to manage a separate channel of errors
from those goroutines, we just follow the grpc model and send the
error with the stream.
2019-12-27 12:43:45 -06:00
Travis Turner
94f97297eb
Merge pull request #77 from travisturner/all-shard
Allow All() to be called at the shard level
2019-12-27 12:35:41 -06:00
Travis
d34e38f134 Remove empty field check in Inspect()
The check for field existence is not necessary; since we
add the `_id` field to every response then at the very
least that field will be returned.

This check was preventin a query like `select _id from ...`
from returning any results.
2019-12-26 22:27:46 -06:00
Travis
586a13e942 Allow All() to be called at the shard level 2019-12-20 22:44:46 -06:00
Cody Soyland
7b30b91448
Merge pull request #74 from codysoyland/docker-build-vendor
Vendor modules before building docker image so private modules can be downloaded
2019-12-20 17:52:26 -06:00
Cody Soyland
d4117f3137 Vendor modules before building docker image so private modules can be downloaded 2019-12-20 16:05:18 -06:00
seebs
47316d9f2f
Merge pull request #70 from seebs/unionAA
Simplify unionArrayArray
2019-12-20 13:49:51 -06:00
seebs
d4d3d75e28
Merge branch 'enterprise' into unionAA 2019-12-20 13:28:57 -06:00
Matthew Jaffee
d86a3c3f2f
Merge pull request #55 from seebs/pluginfix
Pluginfix
2019-12-20 12:53:09 -06:00
Matt Jaffee
fe0f57651e
build with distinct by default 2019-12-20 12:21:47 -06:00
Cody Soyland
49b2029656
Run "go mod vendor" outside of Docker so authenticated modules may use system credentials 2019-12-20 12:21:47 -06:00
Seebs
7e1fd8392f
go.mod/go.sum changes for using molecula/ext
This pins us to the initial external release of molecula/ext, which
with any luck will be the only one. (Narrator: It was not to be the
only one.) We also use GOPRIVATE so we don't need a replace directive.
2019-12-20 12:21:47 -06:00
Seebs
0eba050054
stop using pkg/plugin, start using build tags
After a few experiments with pkg/plugin, I'm ready to concede that the
people warning me it was unsuitable for production use were in fact
correct.

In the brave new world, the "ext" package is moved to its own module
outside pilosa. This means that importing it doesn't imply any need to
version-check against pilosa; we can just use versioned copies of the
ext package, which can be public because it doesn't contain anything
we need to care about keeping proprietary.

Then we can, conditional on build tags, import modules from a
neighboring repo which contains the actual implementations, and if
they're imported, their init functions register them.
2019-12-20 12:21:47 -06:00
Seebs
f51c2dbc42
use extensions through build tags 2019-12-20 12:21:47 -06:00
Travis Turner
179fb910f7
Merge pull request #71 from travisturner/all-limit-offset
Add All() support to PQL, including limit and offset
2019-12-18 22:10:42 -06:00
Travis
361e51cb41 Add All() support to PQL, including limit and offset
This PR is meant to get all columns from an index
based on the TrackExistence row.

`All()` is a PQL function that can be used as a typical
row object. Optional arguments are `limit` and `offset`.
2019-12-18 18:00:15 -06:00
Seebs
83aa505673 Simplify unionArrayArray
Also short-circuit it in some cases.
2019-12-17 15:30:56 -06:00
Travis Turner
1af016df84
Merge pull request #68 from travisturner/linter-fix
Fix an impossible code path raised by the linter
2019-12-17 09:04:37 -06:00
Travis
532caa0fbf fix an impossible code path raised by the linter 2019-12-16 21:56:57 -06:00
Travis Turner
6f556fb880
Merge pull request #63 from travisturner/row-field-label
Wrap return types: RowIdentifiers, Pair, and []Pair
2019-12-16 07:42:20 -06:00
Travis
4f7f4f58b1 add field to SignedRow, and implement its grpc response 2019-12-14 15:56:06 -06:00
Travis
3b7b54094a update clustertests to use v2 (and go 1.13) 2019-12-13 18:45:43 -06:00
Travis
5cb37834a0 Wrap return types: RowIdentifiers, Pair, and []Pair
This PR adds a field name (string) to the return types
which represent the values from a specific field. For example,
a TopN query on field `x` would be `TopN(x)` and have results
like:
```
[]Pair{
  {ID: 14, Count: 10},
  {ID: 3, Count: 8},
  {ID: 7, Count: 3},
}
```
In order to know what field this result type refers to, we wrap
`[]Pair` in a new struct called `PairsField` which contains an
addition `Field` string where `x` is stored.

This is useful for informing the gRPC server how to construct
more appropriate headers for the result stream (in this case,
the column headers can now be "x" and "count").

Similar logic was applied to `RowIdentifiers` and `Pair` as well.
2019-12-13 15:36:51 -06:00
Travis Turner
c5aeed0715
Merge pull request #57 from tgruben/fix-minmax-count
return total match counts for either min or max
2019-12-13 15:28:27 -06:00
Todd Gruben
4523a4d693
removed uneeded test run 2019-12-13 15:10:28 -06:00
Todd Gruben
16171b3e65
return total match counts for either min or max 2019-12-13 15:10:28 -06:00
Todd Gruben
95f2864abe applied suggestions by @travisturner 2019-12-11 12:13:57 -06:00
Todd Gruben
7a2d90ade8 add support to clear value for column 2019-12-09 16:28:03 -06:00
Travis Turner
c4e339f72b
Merge pull request #59 from travisturner/not-found-code
Add grpc NotFound code where applicable
2019-12-03 17:44:30 -06:00
Travis
a5652a182c add grpc NotFound code where applicable 2019-12-03 11:53:20 -06:00
Matthew Jaffee
521ea603d0
Merge pull request #52 from molecula/import-col-attrs
Import col attrs
2019-12-02 01:25:08 -06:00
Matt Jaffee
87ee83f4cb
check errors in test to fix lint 2019-12-01 07:33:25 -06:00
Matt Jaffee
9e3029b969
re run generate-protoc 2019-12-01 07:33:24 -06:00
Alan Bernstein
e470b3276e
Add generated proto 2019-12-01 07:33:24 -06:00
Alan Bernstein
cf7d668b49
Support import column attrs in client 2019-12-01 07:33:24 -06:00
Alan Bernstein
c3e8284f6c
Test for presence of column attrs 2019-12-01 07:33:24 -06:00
Alan Bernstein
628def3db7
Clarify some error messages 2019-12-01 07:33:24 -06:00
Alan Bernstein
aba67364b1
Add support for importing column attrs 2019-12-01 07:33:23 -06:00
Travis Turner
76bb3985f0
Merge pull request #53 from travisturner/having-between
Add support for BETWEEN type conditions in the having clause.
2019-11-30 21:58:45 -06:00
Travis
52debbc389 Add support for BETWEEN type conditions in the having clause.
There is a TODO in the `StringWithSubj` method because the value
types really depend on the subject type (for example, `count` uses
uint64, while `sum` uses int64). I'm waiting to address this
until we decide how to handle sums of floats (Decimal), because
that will affect this logic as well.
2019-11-30 11:59:09 -06:00
Travis Turner
0247a9073c
Merge pull request #51 from travisturner/groupby-having
Add "having" support to GroupBy() queries
2019-11-29 23:01:15 -06:00
Travis
24d02c1920 Add "having" support to GroupBy() queries
This PR adds support for a `having` argument in a `GroupBy` query.
Usage looks like this:
```
GroupBy(Rows(a), having=Condition(count > 10))
GroupBy(Rows(a), aggregate=Sum(field=b), having=Condition(sum > 100))
```
2019-11-28 18:40:57 -06:00
Travis Turner
bc0018b67b
Merge pull request #50 from travisturner/datatype-fixes
Add StreamClient and StreamServer interfaces
2019-11-27 17:21:55 -06:00
Travis
3bc0dc28f0 Add StreamClient and StreamServer interfaces
In order to standardize results as streams of RowResponse,
this PR introduces two interfaces `StreamClient` and
`StreamServer`) which mirror the grpc stream interfaces.
Upstream users (sqlmapper, vdsm, etc) can implement
instances of these interfaces to ensure that results can
stream through the entire sytem in an expected way.

This PR also fixes a couple of missing data types.
2019-11-27 16:10:46 -06:00
Matthew Jaffee
210676c927
Merge pull request #39 from molecula/groupby-sum
Groupby sum
2019-11-27 16:04:42 -06:00
Matt Jaffee
114c1a9df8
remove unecessary span from executor tracing 2019-11-27 11:09:06 -06:00
Matt Jaffee
60397d3e8f
add more tracing around groupBy 2019-11-27 11:00:13 -06:00
Matt Jaffee
f2f9ea01dc
get group by aggregates working with PQL validation and grpc streaming 2019-11-27 11:00:13 -06:00
Ben Johnson
ea9914dba0
Add optional GroupBy() 'aggregate' field.
This commit adds an `aggregate` field that allows a `Sum()` call
to be executed for every returned group.
2019-11-27 11:00:13 -06:00
Matt Jaffee
81a4d32cdd
allow IDs to be passed even when keys enabled
This change allows one to query Pilosa fields and indexes directly
with integer row and column ids even when key translation is
enabled. This was previously disallowed during query
translation... I'm not sure why, but it can be quite useful for
debugging and testing to be able to use IDs directly. I have a test in
go-pilosa which uses this functionality.

I also simplified a bunch of the test code which was of the form:
```
else {
    if blah {
    }
}
```

to be:

```
else if blah {
```

which I think is pretty harmless.

I also changed a snapshot log line that has been bugging me to be
Debug level so that it isn't generating lots of useless logs for long
running Pilosa instances.
2019-11-27 08:41:40 -06:00
tgruben
16d5db97a6
Merge pull request #47 from tgruben/inspect-fix
fixed bug in slice container seek
2019-11-26 11:35:51 -06:00
Todd Gruben
ca0247e35b fixed bug in slice container seek 2019-11-26 09:21:52 -06:00
seebs
407c309640
Merge pull request #46 from seebs/distinctfix
Distinctfix
2019-11-22 17:29:24 -06:00
Seebs
d79ecbad86 recompute shards for cross-index calls
It turns out that we need to recompute the set of shards whenever
a query is cross-index. Otherwise we get partial results in unexpected
ways sometimes.
2019-11-22 16:02:47 -06:00
Seebs
36ef82d7ac Zero bitmap storage when reusing it for container-as-bitmap
If you don't do this, it works fine the first time you use a given
storage, but after that you start seeing spurious bits.
2019-11-22 16:02:42 -06:00
Seebs
397d93e84b provide an empty filter when a filter was empty 2019-11-22 16:02:31 -06:00
Seebs
26326ac74c recompute shards for cross-index queries
When computing results on another index, recompute list of
shards for that index.
2019-11-22 16:02:26 -06:00
Seebs
6ad39a376e handle precalls and cross-index queries better
There's two actual changes here, but they're closely related.

First, handle named parameters for precalls, not just indexed parameters.
Second, when doing translation for a call, check whether it specifies an
index, and if it does, use that index instead of the current index for
the translation.
2019-11-22 16:02:20 -06:00
seebs
16c3cfa727
Merge pull request #42 from seebs/sqdeadlock
use the right lock for Enqueue
2019-11-18 21:53:00 -06:00
seebs
01309e4fc5
Merge branch 'enterprise' into sqdeadlock 2019-11-18 20:51:40 -06:00
Cody Soyland
d3c8728821
Merge pull request #19 from codysoyland/ci-updates
Update CI to support Pilosa Enterprise (private dependencies)
2019-11-18 13:52:20 -06:00
Cody Soyland
58182ff563 Pilosa Enterprise private CI 2019-11-18 13:30:32 -06:00
Travis Turner
295adbfe67
Merge pull request #44 from travisturner/cache-threshold-deletes
Fixed ranked cache logic to support reducing cached values below the threshold
2019-11-18 12:10:46 -06:00
Travis
ed82a535e5 Fix ranked cache logic to support reducing cached values below
the threshold.

Prior to this commit, if a cache value was reduced to a value
that fell below the threshold, the operation would be ignored
and the cached value would remain at the old, higher value.

This commit also fixes logic which reduces a cached value within
the framework of uint64 values by subracting the absolute value
of the negative value (since adding a negitive doesn't work with
unsigned integers).
2019-11-18 11:39:50 -06:00
Travis Turner
32f754899e
Merge pull request #43 from travisturner/translate-race-in-test
allow for translate store race in test
2019-11-15 16:33:30 -06:00
Travis
0a69fca657 allow for translate store race in test (by using retry)
In this case, the test is reading from the translateStore
replica before the translateStore replication has had time to
deliver its log to the replica. The only way to truly address
this in the translate store would be to route all key misses
that happen on a read-only replica to the primary translate
store (or somehow know when the primary is done sending to
replicas) for actual verification that the key does not exist.
That's more involved than we want to do here; this PR just
addresses the problem in the test.
2019-11-15 07:57:47 -06:00
Seebs
f204b37760 use atomics instead of locking for stats 2019-11-14 17:40:14 -06:00
Seebs
bab077199c use the right lock for Enqueue
The request for a non-read lock blocks until all existing read
locks exit, meaning that if an Immediate operation is already
going for a fragment, an Enqueue operation will hang forever
holding the fragment's lock, while the Immediate operation has
probably relinquished the fragment's lock to wait for the
queue worker to process it. But the queue worker can't process
it, because the incoming Enqueue still holds the fragment's
lock. Solution: Don't block the Enqueue operation like that.
It shouldn't coexist with things that actually change the sq
channels, like Stop(), but it is fine for it to coexist with
other queue operations.
2019-11-14 17:00:34 -06:00
seebs
9cec40e69d
Merge pull request #41 from seebs/roaringProto
Stop using Roaring in protobuf messages until it's supported elsewhere
2019-11-14 12:45:35 -06:00
Seebs
6fc6cc4350 Stop using Roaring in protobuf messages until it's supported elsewhere
go-pilosa uses protobuf to talk to us but doesn't support the roaring
format. Conveniently, there's a kill switch.
2019-11-14 10:54:40 -06:00
Matthew Jaffee
fa9c911860
Merge pull request #37 from travisturner/rename-bool-label
Rename bool label from changed to result
2019-11-13 14:30:14 -06:00
Travis
e8cd48155a
Rename bool lable from changed to result 2019-11-13 14:12:52 -06:00
Matthew Jaffee
4dfeb89b43
Merge pull request #36 from travisturner/includescolumn-keys
Add column keys support to IncludeColumn
2019-11-13 14:09:24 -06:00
Travis
625125bac6 add column keys support to IncludeColumn 2019-11-13 11:34:21 -06:00
Matthew Jaffee
013ee21621
Merge pull request #28 from molecula/pql-float-values
Pql float values
2019-11-13 11:04:36 -06:00
Matt Jaffee
0e445db7ff
improve error message checking field type in import roaring 2019-11-13 10:07:24 -06:00
Travis
26fc621f09
Support integer predicates in Decimal field range queries. 2019-11-13 10:07:24 -06:00
Matt Jaffee
0ac778516e
check error, make linter happy 2019-11-13 10:07:24 -06:00
Matt Jaffee
14dfc9e31d
fix comment typo for BTWN_LTE_LT 2019-11-13 10:07:24 -06:00
Matt Jaffee
9c8ad727b5
allow floats in PQL queries for decimal fields
had to workaround some cruft in the parser that was trying to only
support a BETWEEN query as LTE, LTE. Now we have operations for all
combinations of LT and LTE.

unrelated - changed the port a test was binding to as it conflicted
with a port I was using locally.
2019-11-13 10:07:24 -06:00
Matt Jaffee
0fec16a141
fix integer bug on less than queries.
this was introduced recently to fix another bug. the comment above it
is correct, just the logic was off-by-one. The test shows the issue
and was confirmed to reproduce it and then fix it.
2019-11-13 10:07:23 -06:00
Travis Turner
7401fd1333
Merge pull request #33 from travisturner/grpc-logger
Fixed gRPC server logger; pass logger through from main
2019-11-13 09:56:04 -06:00
Travis Turner
afd1c004f9
Merge branch 'enterprise' into grpc-logger 2019-11-13 08:31:26 -06:00
Travis Turner
d3432478f9
Merge pull request #34 from travisturner/bool-returns
Fix makeRows in gRPC hander to handle a bool result
2019-11-13 08:24:43 -06:00
Travis
7fd5248d98 makeRows in gRPC hander now handles a bool result
This PR adds bool support to the makeRows function
in the gRPC handler.
2019-11-12 16:13:52 -06:00
seebs
1fea1ea375
Merge pull request #22 from seebs/fsckSnapshotExtension
This is a collection of changes that have been pending forever. It improves the snapshot queue performance, adds some amount of recovery for corrupt filles, reduces memory usage in the rowcache, and adds an extension interface. Yes, they should probably have happened separately over time, things happened.
2019-11-12 14:50:34 -06:00
Seebs
1e0873c70b lock BufferLogger for reads/writes
With the new addition of the holder background scan, it's possible
for an open holder to write log messages at arbitrary times. The
TestHolder_Open/ErrIndexName test checks the contents of the output
buffer, but those contents could be changing if the background task
happens to run at the right time. Use trivial locking around that
so that this shouldn't happen.
2019-11-12 12:15:13 -06:00
Seebs
03f3f424aa don't lint PEG files
I was pretty sure I'd done this, but I guess not: Skip linting
the PEG files.
2019-11-12 12:15:13 -06:00
Seebs
8cc7a176b5 license header fixups
Fix up license headers for the extension code, and add the proto
file to the list of things we don't check license headers for.
2019-11-12 12:15:13 -06:00
Seebs
c5136b14db ensmarten snapshot queue
The snapshot queue needs a bit more subtlety. In some cases,
we really do want to do a snapshot right now -- these shouldn't
have to wait for possibly a hundred or more other snapshots
to complete.

In other cases, we don't really care that much whether we do
a snapshot, and just dropping it is probably fine.

To accommodate this, we distinguish between "urgent" and
"normal" snapshots, and between "Immediate" (does an urgent
snapshot, waits for it) and "Enqueue" (might enqueue a snapshot
but *also might not* if we're already busy). There's a
corresponding "Await" to wait for a snapshot, if one is
pending, but not if one isn't.

We also have a background scan that checks the holder. It will
scan pretty actively when it's finding fragments that need
snapshots (no enqueued snapshot, opN > MaxOpN). It pauses
for a second after every hundred fragments that didn't need
snapshots, and for a minute after each holder scan that didn't
find any. So, if you don't need snapshots, it does basically
nothing, if you do, it'll be moderately aggressive about
submitting tasks -- but it always waits if there's *any*
requested snapshots in the queues.

Updates since initial draft:

Check results from Await more consistently, and in one case, use Immediate
instead and then check its error.

Fix a race condition.  The race condition comes about if:

1. You have a limited enough worker pool that this can happen.
(In testing we tend to have a worker pool of 1.)
2. A fragment is in the normal, non-urgent, queue already.
3. An immediate request comes in for that fragment. This always
happens *with the fragment lock held*.
4. A worker thread grabs that fragment from the queue.
5. The worker thread now waits on the lock. Meanwhile, the
immediate request blocks on sending the fragment to the urgent
queue.
6. The worker can't read the urgent queue, and the immediate
request can't send it, so the immediate request can't proceed.

What's supposed to happen is that the immediate request sends
the thing, and gets into Await(), which sleeps on a condition
variable using the lock, which is to say, releases the lock.

The obvious resolution is to let go of the lock, send the
message, and then reclaim the lock. But then we have the
possibility that the message sent ends up with a timestamp
right after a snapshot that happened *after* the Immediate
request was started. Oops. So we create the request, then let
go of the lock, then send the request, then reclaim the lock
and go into the Await state. All is well.

This is on top of more general use of wait groups, etcetera,
to allow us to ensure that any holder scans terminate *before*
we close the channels they might otherwise be trying to write to.
So, shutdown process is now:

* grab lock on queue (workers and scanners don't use the lock)
* mark snapshotqueue done
* wait for holder scans to complete/exit
* close and nil out all the channels
* release lock

Anything trying to submit to this needs to hold the lock, unless
it's a holder scan, so either it got the lock before we did and already
submitted the thing, or it will get the lock after this and not find
a channel to write to; it's just the holder scanner that has an
ongoing thing that might have started a write to the channel *without*
a lock held, because it's expected that it might have to wait minutes
or hours before the write will complete because it's a background task.

Also, rework the background holder scan to grab lists of
indexes/fields/views/fragments, then scan the grabbed/copied lists,
rather than iterating over maps, allowing us to grab the lock when
we're about to access a thing and let it go when done.

There might be a simpler/cleaner way to do this but opinions on how
safe it is are very mixed, so in the mean time, I'm making the range
behavior not depend at all on there being no writes to the various tiers
of holder/index/view/fragment during the background scans.
2019-11-12 12:15:13 -06:00
Seebs
3b696da34a plugins and precomputed data
So in some cases, when we do a query, the results of one
part of the query are innately shared-across-nodes; for
instance, a hypothetical Distinct query. More generally,
we allow cross-index queries; calls can have "index=foo"
in them.

This patch lets us handle that without duplicating that
query all over. Before we actually start doing the
separate calls, we run the query once from the coordinating
node, then patch the results in, and send relevant subsets
over to each client, etcetera. Also provides slightly
friendlier (and I hope faster) support for converting
bitmaps to/from sets of rows.

We also add an extension interface, and some fancy stuff
to let us define new calls, which use this. They're sort
of tied together because the first extension I wanted to
implement needed precomputed calls. The extension API
lets us create extensions using `pkg/plugin` (with all its
associated limitations, unfortunately), then query them
at load time for functionality.

This also implies some revamping of the argument
validation for PQL, like verifying that functions exist
and knowing things about their argument types.

So basically this is an overly intrusive patch, and would
be better as separate patches, but they're hard to detangle.

add trivial execution-time profiling

What if you could ?profile=true on a query and get some
numbers back? That'd be really cool.

We already have tracing/spans, but right now, those only generate
any data if you have something set up for them to trace to. Add a
fancy wrapper that lets us generate our own tracing data, and dump
it into the request response, if ?profile=true.

add a sample extension, add missing features to extension interface

Implement a naive probabilistic filter extension as an example of
what an extension looks like. In the process, discover multiple
omissions in the bitmap API. Well, I did *say* it was experimental.
2019-11-12 12:14:29 -06:00
Seebs
b25eb8f596 Sources and Generations: tracking mmapped files
This code represents an attempt at providing reliable tracking
of whether any bitmaps still in use have access to a given block
of mmapped data, allowing us to unmap the data when nothing is using
it anymore.

The basic approach is as follows: Each mmap is associated with
a new object, called a "generation". A generation reflects
a particular instance of a given file being mapped. When a
bitmap is built from an mmapped data source, the bitmap is
given a pointer to the generation as its Source. When bitmap
operations combine containers from other bitmaps, they
produce new bitmaps that are tagged with the combined set of
sources.

When we snapshot a file, or for some other reason wish to remap
it, the corresponding bitmap has all its containers updated to
use the new storage, and the bitmap's source is changed. However,
previously-handed-out containers might still have references to the
old storage. Those containers would be in bitmaps with the old
source.

After a bunch of study of trying to reference-count and track
this, I realized: We don't actually need to do that, because we
already have something suitable for determining whether anything
can reach a given object. It's the garbage collector.

So we set a finalizer on the generation object, which handles
unmapping. There's additional sanity-checks here to confirm things
like "we thought this generation should be expiring", and we
track timestamps. We could also have things check whether a
given bitmap's source was marked as obsolete "a while ago", but
that isn't implemented yet.

There's a debug version of this which tracks finalization, creation,
and ending timestamps, and has a call to provide diagnostics for
this. Identical generation IDs get separated out with random
suffixes in this case -- there's sometimes a second or third
instance of the same name due to a holder closing and reopening,
but this basically only happens in testing.

Note that generations are still used even when there's no mmapping,
but unless debugging is turned on, they shouldn't propagate much --
we don't consider a generation to be the source of a bitmap unless
the bitmap actually mapped things from that generation's mmapped
storage, or debugging is on.

There's a couple of other, possibly more subtle, changes and
bug fixes that got caught by the testing on this:
* If a fragment is partially opened and then opening some later
  part fails, we close the earlier parts before returning the
  error so we aren't leaving it partially open.
* Several operations on segments which were requesting that a
  frozen copy of a bitmap be created are now actually *replacing*
  their bitmap with the frozen bitmap, rather than discarding it.
* intersectRunRun, if it decides to create an array or bitmap,
  will yield that container instead of discarding it.

And why all of this? Why, so we can actually implement the thing
where when a fragment has a valid roaring bitmap, but the ops log
is corrupt, we can truncate the corrupt part of the ops log and
reopen it. Which I did.

When the generationdebug build tag is in use, every generation
has a finalizer all the time. When it's not, they only get finalizers
when we expect them to be done -- say, when closing a fragment.
This is because finalizers appear to be possibly-expensive.

There's some logical cleanup to openStorage here, dividing part
of its work into applyStorage and importStorage, which have a common
case for handling "there's no data in this file".
2019-11-12 12:14:29 -06:00
Seebs
6654466033 partially implement truncation of fragments for corrupt ops log
Which is to say don't actually implement it, because openStorage
is too messy right now, but this is the rest of the framework,
and now I'm going to digress into fixing openStorage.
2019-11-12 12:14:29 -06:00
Seebs
538768ea9d handle truncated/damaged .available.shards
The available shards file is just a hint to save us a bit
of time later; we don't need it to run and it can get updated
pretty easily later. If we have problems reading it, we
should just report the error, nuke the file, and continue
without it.
2019-11-12 12:14:29 -06:00
Travis
b8f665db1a pass logger through to the grpc server and handler 2019-11-12 11:08:25 -06:00
seebs
1262cd18e0
Merge pull request #30 from seebs/intfixes
Fix an error that could cause imported values to keep high-order bits from previously imported values, and another that could cause BSI fields to store extra bits they don't need.
2019-11-12 00:02:04 -06:00
seebs
b3adf2d4f6
Merge branch 'enterprise' into q2-11-7 2019-11-11 21:39:45 -06:00
Cody Soyland
5194ede82c
Merge pull request #31 from codysoyland/proto-pkg-name
Change proto package name to "pilosa" to not conflict with molecula
2019-11-11 20:51:52 -06:00
Cody Soyland
69e5e523c1
Merge branch 'enterprise' into proto-pkg-name 2019-11-11 17:26:44 -06:00
Seebs
a804a0dfb1 always treat BSI fields as having at least their depth
If you imported only small values, BSI fields could end up
not bothering to clear higher bits in existing values, which
produced strange behaviors.

We also move the computation of requiredDepth, and the change
to the field, down, combining it with the other checks of the
values for min/max being in range.

Without this, a data set with a ludicrously large value in it
could break a BSI field's depth even though the import would then
reject it.
2019-11-11 16:55:26 -06:00
Travis Turner
1a44f02e3c reset fragment.rowCache after importValue 2019-11-11 16:54:51 -06:00
Travis Turner
10514f7ced
Merge pull request #25 from travisturner/includes-column
Add an IncludesColumn() function to PQL
2019-11-11 12:55:23 -06:00
Cody Soyland
b9335c9f5c Change proto package name to "pilosa" to not conflict with molecula. Upgrade protoc to 3.10.1 2019-11-11 12:24:38 -06:00
Travis
ed37ef5dcf Add an IncludesColumn() function to PQL
Usage:
`IncludesColumn(Intersect(Row(a=1), Row(b=2)), column=10)`

The above query will return a `bool` indicating whether the
intersection of rows a-1 and b-2 contains column 10. Because
a single column is specified, this executes on a single shard
(shard=0 in this example).
2019-11-11 08:17:28 -06:00
Travis Turner
198626e657
Merge pull request #29 from travisturner/linter-fixes
fix golangci-lint complaints
2019-11-11 08:06:35 -06:00
Travis
87b8edc4c5 fix golangci-lint complaints 2019-11-10 17:58:46 -06:00
Travis Turner
2a5d79ad83
Merge pull request #26 from travisturner/proto-licence-exception
add proto/pilosa.pb.go to license.exceptions list
2019-11-10 16:31:00 -06:00
Travis
3129b1c841 add proto/pilosa.pb.go to license.exceptions list 2019-11-10 11:33:29 -06:00
Travis Turner
6632821617
Merge pull request #24 from travisturner/cache-size-none
fix cacheSize when cacheType is none (and cacheSize is 0)
2019-11-08 22:30:17 -06:00
Travis
a842dd521c fix cacheSize when cacheType is none (and cacheSize is 0)
There was an edge case where setting cacheType to none
wouldn't zero out its cacheSize. This fixes that edge case.
2019-11-08 15:58:49 -06:00
Matthew Jaffee
d6f2196bf1
Merge pull request #16 from pilosa/tls-grpc
use TLS settings when setting up GRPC server or client
2019-10-30 19:35:56 -05:00
Matt Jaffee
6f21887259
use TLS settings when setting up GRPC server or client 2019-10-30 17:38:48 -05:00
Matthew Jaffee
468cf98811
Merge pull request #15 from pilosa/decimal-to-grpc
add decimal field support to Inspect
2019-10-30 13:33:55 -05:00
Matt Jaffee
a414cada4f
add decimal field support to Inspect
I tested this manually with BloomRPC and curl, but need to write real
tests. Also need to get floats for decimal fields coming out of QueryPQL.
2019-10-30 11:13:48 -05:00
Matthew Jaffee
8f64a4f585
Merge pull request #11 from pilosa/decimal-support
support for decimal fields
2019-10-29 16:49:20 -05:00
Matt Jaffee
a9a4d244ef
fix a bug in the "less than" logic 2019-10-29 16:36:15 -05:00
Matt Jaffee
5dcabfcc7f
support for decimal fields
This commit adds a Decimal field type which is implemented mostly with
the Int field. It adds an optional "Scale" value to the Int field
which means that the values stored in that field are actually meant to
be divided by 10^Scale before being interpreted.

In order to make use of this functionality, we extend the importValue
request to allow a slice of floats rather than just int64. If the
slice of floats is present, each float in the slice is multiplied by
10^Scale and converted to an int64 before being imported. If a slice
of int64 is imported to a Decimal field, it is treated normally, and
scale is ignored. This allows the conversion to be handled at the
client side if desired.

Currently there are Field level methods for querying Float values out
of a decimal field, but no support in PQL or the executor for getting
float values. Going to wait until I can use the generic result type
before doing that, so for now, any values queried will be the scaled
integer values.

needed to add client support for importing float values, and did this
by adding a more general and simplified client method for value
imports.

rewrote api.ImportValue to use the new method which should be more
performant and efficient.

allow floats to be "pilosa import"ed into decimal fields
2019-10-29 16:36:14 -05:00
seebs
4ef7f7e26b
Merge pull request #12 from seebs/profile
Profiling and a couple of minor fixes
2019-10-29 15:24:51 -05:00
Seebs
616ed39771 Skip longest tests when running -short
The cluster timeout/down tests are way more than half the total
time for "go test", and are very unlikely to be of interest in regular
usage, although they matter for CI. Skip them when doing short
tests.
2019-10-29 15:24:09 -05:00
Seebs
7a381f7eaf allow years other than 2017 in licenses
Also clean up the license hash checking a bit. We trim vendor early
in find so we don't have to walk the whole vendor tree only to grep
the files out, and we don't check the license hashes of the exceptions,
and the exceptions are now a plain text file of non-regex strings
we match exactly. Also the license hash code is only written once.

This will help us a lot if development on Pilosa continues through
2018 or later.
2019-10-29 15:24:09 -05:00
Seebs
820c5ce220 add trivial execution-time profiling
What if you could ?profile=true on a query and get some
numbers back? That'd be really cool.

We already have tracing/spans, but right now, those only generate
any data if you have something set up for them to trace to. Add a
fancy wrapper that lets us generate our own tracing data, and dump
it into the request response, if ?profile=true.

We track wall-clock execution time, plus possible arbitrary K/V
pairs. Memory stats are not included, because obtaining them is
surprisingly expensive.
2019-10-29 15:23:37 -05:00
Travis Turner
9a2f5b3b4c
Merge pull request #10 from travisturner/grpc
initial gRPC server implementation
2019-10-29 14:39:16 -05:00
Travis
a7bb90fcd0 initial gRPC server implementation
add makeRows() tests
register the gRPC server
use api.Index() instead of api.Schema()

support most field types in Inspect() query

currently, there's no support for `time` fields.
those will be dependent upon the output format
and the ability to materialize the timestamp from
the time views.

this commit also changes the response type of the
`Inspect()` query to be a tabular `RowResponse`.
2019-10-29 14:27:07 -05:00
Travis
77a81eb2e1 fix bug preventing a Rows() query on a bool field 2019-10-29 14:27:07 -05:00
1582 changed files with 48664 additions and 415371 deletions

316
.circleci/config.yml Normal file
View file

@ -0,0 +1,316 @@
version: 2.1
executors:
golang:
parameters:
version:
type: string
default: "1.15.8"
resource_class:
type: string
default: medium
docker:
- image: circleci/golang:<< parameters.version >>
resource_class: << parameters.resource_class >>
working_directory: /go/src/github.com/pilosa/pilosa
commands:
add-github-auth:
steps:
- run: git config --global url."https://${GITHUB_USER}:${GITHUB_PERSONAL_ACCESS_TOKEN}@github.com/".insteadOf "https://github.com/"
- run: git config --global url."https://${GITHUB_USER}:${GITHUB_PERSONAL_ACCESS_TOKEN}@github.com/".insteadOf "git@github.com:"
restore-mod-cache:
steps:
- restore_cache:
key: mod-cache-{{ checksum "go.sum" }}
save-mod-cache:
steps:
- save_cache:
key: mod-cache-{{ checksum "go.sum" }}
paths:
- /go/pkg/mod/
checkout-plus:
steps:
- add-github-auth
- checkout
- restore-mod-cache
skip-if-root-unchanged:
description: "skips the parent job if the PR includes no changes to pilosa"
steps:
- run: |
ROOT_CHANGED_FILES="$(git diff --name-only HEAD $(git merge-base master HEAD) | grep -v '^lattice/')" || true
echo "ROOT_CHANGED_FILES = $ROOT_CHANGED_FILES"
if [ -z "$ROOT_CHANGED_FILES" ] ; then
echo "halting step"
circleci step halt
fi
skip-if-lattice-unchanged:
description: "skips the parent job if the PR includes no changes to lattice"
steps:
- run: |
LATTICE_CHANGED_FILES="$(git diff --name-only HEAD $(git merge-base master HEAD) | grep '^lattice/')" || true
echo "LATTICE_CHANGED_FILES = $LATTICE_CHANGED_FILES"
if [ -z "$LATTICE_CHANGED_FILES" ] ; then
echo "halting step"
circleci step halt
fi
jobs:
setup:
executor:
name: golang
steps:
- checkout-plus
- run: go mod download
- save-mod-cache
check-license-headers:
executor:
name: golang
steps:
- checkout-plus
- skip-if-root-unchanged
- run: make check-license-headers
linter:
executor:
name: golang
steps:
- checkout-plus
- skip-if-root-unchanged
- run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sudo sh -s -- -b /usr/local/bin v1.31.0
- run: make golangci-lint
go-mod-tidy:
executor:
name: golang
steps:
- checkout-plus
- skip-if-root-unchanged
- run: go mod tidy
- run: git diff --exit-code -- go.mod go.sum
check-changelog-label:
executor:
name: golang
steps:
- run: '[[ -n $CIRCLE_PULL_REQUEST ]] || circleci step halt || true' # Skip if this is not a pull request
- run: curl https://$GITHUB_USER:$GITHUB_PERSONAL_ACCESS_TOKEN@api.github.com/repos/molecula/pilosa/pulls/$(basename $CIRCLE_PULL_REQUEST) | jq "[.labels[] | .name | startswith(\"changelog\")] | any" -e
test-build-arm:
executor:
name: golang
steps:
- checkout-plus
- skip-if-root-unchanged
- run: make build GOOS=linux GOARCH=arm GOARM=5
- run: make build GOOS=linux GOARCH=arm GOARM=6
- run: make build GOOS=linux GOARCH=arm GOARM=7
- run: make build GOOS=linux GOARCH=arm64
test:
parameters:
resource_class:
type: string
default: medium
golang_version:
type: string
default: "1.15.8"
shard_width:
type: string
default: "20"
test_make_target:
type: string
default: "test"
test_flags:
type: string
default: ""
goarch:
type: string
default: amd64
executor:
name: golang
version: << parameters.golang_version >>
resource_class: << parameters.resource_class >>
steps:
- checkout-plus
- skip-if-root-unchanged
- run: sudo apt-get update
- run: sudo apt-get install lsof
- run:
command: make << parameters.test_make_target >> SHARD_WIDTH=<< parameters.shard_width >> GOARCH=<< parameters.goarch >>
no_output_timeout: 30m
test-external-lookup:
docker:
- image: circleci/golang:1.15.8
- image: circleci/postgres:13.2-ram
environment:
POSTGRES_PASSWORD=password
steps:
- checkout-plus
- skip-if-root-unchanged
- run: sudo apt-get update
- run: sudo apt-get install postgresql-client
- run: (for i in `seq 1 20`; do pg_isready -h localhost && exit 0 || sleep 1; done; exit 1)
- run:
command: make test-external-lookup EXTERNAL_LOOKUP_DSN=postgresql://postgres:password@localhost/circle_test?sslmode=disable
no_output_timeout: 30m
cluster-tests:
executor:
name: golang
steps:
- checkout-plus
- skip-if-root-unchanged
- setup_remote_docker
- run: make clustertests-build
release:
executor:
name: golang
steps:
- checkout-plus
- attach_workspace:
at: .
- setup_remote_docker:
version: 19.03.13 # see https://support.circleci.com/hc/en-us/articles/360050934711
- run: echo -n $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
- run: make docker-release
- store_artifacts:
path: build
- persist_to_workspace:
root: .
paths: build
publish_release:
executor:
name: golang
steps:
- attach_workspace:
at: .
- run: go get github.com/tcnksm/ghr
- run: ghr -t ${GITHUB_PERSONAL_ACCESS_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${CIRCLE_TAG} ./build/
docker-build:
executor:
name: golang
steps:
- checkout-plus
- setup_remote_docker:
version: 19.03.13 # see https://support.circleci.com/hc/en-us/articles/360050934711
- run: echo -n $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
- run: make docker GO_VERSION=1.15.8
- run: docker run pilosa:$(git describe --tags) help
dockerhub-upload-unstable:
executor:
name: golang
steps:
- checkout-plus
- setup_remote_docker:
version: 19.03.13 # see https://support.circleci.com/hc/en-us/articles/360050934711
- run: echo -n $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
- run: make docker
- run: docker run pilosa:$(git describe --tags) help
- run: make docker-tag-push DOCKER_TARGET=moleculacorp/pilosa:<< pipeline.git.branch >>
dockerhub-upload-stable:
executor:
name: golang
steps:
- checkout-plus
- setup_remote_docker:
version: 19.03.13 # see https://support.circleci.com/hc/en-us/articles/360050934711
- run: echo -n $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin
- run: make docker
- run: docker run pilosa:$(git describe --tags) help
- run: make docker-tag-push DOCKER_TARGET=moleculacorp/pilosa:<< pipeline.git.tag >>
- run: make docker-tag-push DOCKER_TARGET=moleculacorp/pilosa:latest
workflows:
build:
jobs:
- setup:
context: molecula
filters:
tags:
only: /^v.*/
- linter:
context: molecula
requires:
- setup
- check-license-headers:
context: molecula
requires:
- setup
- go-mod-tidy:
context: molecula
requires:
- setup
- check-changelog-label:
context: molecula
requires:
- setup
- test-build-arm:
context: molecula
requires:
- setup
- test:
name: test-golang-<< matrix.golang_version >>
resource_class: large
context: molecula
requires:
- setup
matrix:
parameters:
golang_version: ["1.14.15", "1.15.8", "1.16.3"]
- test:
name: << matrix.test_make_target >>
resource_class: xlarge
context: molecula
requires:
- setup
matrix:
parameters:
test_make_target: ["test-race", "test-txstore-rbf_bolt"]
- test:
name: test-shardwidth-22
context: molecula
shard_width: "22"
resource_class: large
requires:
- setup
- test-external-lookup:
context: molecula
requires:
- setup
- cluster-tests:
context: molecula
requires:
- setup
- docker-build:
context: molecula
requires:
- setup
- release:
context: molecula
requires:
- setup
filters:
tags:
only: /^v.*/
branches:
only: master
- publish_release:
context: molecula
requires:
- release
filters:
tags:
only: /^v.*/
branches:
ignore: /.*/
- dockerhub-upload-unstable:
context: molecula
requires:
- setup
filters:
branches:
only: master
- dockerhub-upload-stable:
context: molecula
requires:
- setup
filters:
tags:
only: /^v.*/
branches:
ignore: /.*/

5
.dockerignore Normal file
View file

@ -0,0 +1,5 @@
lattice/.git
lattice/node_modules
lattice/build
statik/statik.go
build

16
.github/ISSUE_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,16 @@
For bugs, please provide the following:
### What's going wrong?
### What was expected?
### Steps to reproduce the behavior
### Information about your environment (OS/architecture, CPU, RAM, cluster/solo, configuration, etc.)
For feature requests, please provide the following:
### Description
### Success criteria (What criteria will consider this ticket closeable?)

28
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,28 @@
## Overview
[Describe what this pull request addresses.]
Fixes #
## Pull request checklist
- [ ] I have read the [contributing guide](https://github.com/pilosa/pilosa/blob/master/CONTRIBUTING.md).
- [ ] I have agreed to the [Contributor License Agreement](https://cla-assistant.io/pilosa/pilosa).
- [ ] I have updated the [documentation](https://github.com/pilosa/pilosa/tree/master/docs).
- [ ] I have resolved any merge conflicts.
- [ ] I have included tests that cover my changes.
- [ ] All new and existing tests pass.
- [ ] Make sure PR title conforms to convention in CHANGELOG.md.
- [ ] Add appropriate changelog label to PR (if applicable).
## Code review checklist
This is the checklist that the reviewer will follow while reviewing your pull request. You do not need to do anything with this checklist, but be aware of what the reviewer will be looking for.
- [ ] Ensure that any changes to external docs have been included in this pull request.
- [ ] If the changes require that minor/major versions need to be updated, tag the PR appropriately.
- [ ] Ensure the new code is [properly commented](https://github.com/golang/go/wiki/CodeReviewComments#doc-comments) and follows [Idiomatic Go](https://dmitri.shuralyov.com/idiomatic-go).
- [ ] Check that tests have been written and that they cover the new functionality.
- [ ] Run tests and ensure they pass.
- [ ] Build and run the code, performing any applicable integration testing.
- [ ] Make sure PR title conforms to convention in CHANGELOG.md.
- [ ] Make sure PR is tagged with appropriate changelog label.

View file

@ -1,77 +0,0 @@
name: CD
on:
push:
branches: ["master"]
workflow_dispatch:
jobs:
validate:
runs-on: ubuntu-latest
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "^1.19.1"
- run: go version
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
args: --timeout=5m
- name: go vet
run: go vet ./...
- name: test
run: go test ./...
release:
needs: validate
runs-on: ubuntu-latest
outputs:
version: ${{ steps.semrel.outputs.version }}
steps:
- name: go-semantic-release
id: semrel
uses: go-semantic-release/action@v1.17.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
build:
needs: release
runs-on: ubuntu-latest
strategy:
matrix:
goos:
- "darwin"
- "linux"
- "windows"
goarch:
- "amd64"
- "arm64"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "^1.19.1"
- name: build
run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -o ./build/${{ matrix.goos }}-${{ matrix.goarch }}
- name: Upload binaries to release
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ./build/${{ matrix.goos }}-${{ matrix.goarch }}
asset_name: ${{ matrix.goos }}-${{ matrix.goarch }}
tag: ${{ github.ref }}

View file

@ -1,57 +0,0 @@
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the workflow will run
on:
pull_request:
branches: ["master"]
# 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:
validate-title:
name: Validate PR title
runs-on: ubuntu-latest
steps:
- uses: go-semantic-release/action@v1
id: semrel
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
dry: true
# golangci-lint must be run separately from "validate" as there are go mod issues if you run it after the vet
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
with:
go-version: 1.19
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:
# Optional: version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version
# version: v1.29
args: --timeout=8m
validate:
name: Code Checks
runs-on: ubuntu-latest
# 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@v3
- uses: actions/setup-go@v3
with:
go-version: "^1.19.1"
- run: go version
- name: go vet
run: go vet ./...

View file

@ -1,25 +0,0 @@
name: Release
on: workflow_dispatch
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
goos:
- "darwin"
- "linux"
goarch:
- "amd64"
- "arm64"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "^1.19.1"
- name: build
run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -o ./build/${{ matrix.goos }}-${{ matrix.goarch }}

74
.gitignore vendored
View file

@ -9,79 +9,5 @@ release-pilosa-fsck.*.*.tar.gz
/log.*
/tourna.log.*
pilosa
/featurebase
*.dot
.idea/
.*.swp
.terraform/
*.tfstate
launch.json
.terraform.lock.hcl
__pycache__/
report.xml
outputs.json
builds/
*.tfstate.backup
.vscode
batch/testdata/batch*.out
idk/testdata/idk*.out
idk/testenv/certs/*
# copy of .gitignore from archived idk repo
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
vendor
.terraform
terraform.tfstate*
bin
build
testenv
.pulled
pilosa-sec-data-idk
.idea/
tags.dot
*.log
*.swp
*__debug_bin
# SQL3
/sql3/sql3.html
staticcheck.conf
.quick
dax/dax-data
coverage-from-docker
*.client_id.txt

View file

@ -1,747 +0,0 @@
# You will see a couple of instances of:
# PKG_LIST=$(go list ./... | grep -Ev 'internal/clustertests|simulacraData|batch|idk|v3/dax/test/dax' | paste -s -d, -)
# This gets us a package list, comma-separated, which excludes the batch
# and IDK tests, and a couple of subdirs with specialized stuff. We can
# then use this with -coverpkg, or we can use ${PKG_LIST//,/ } to get a
# space-separated list for use with `go test` to run the tests for those
# directories only.
include:
- local: /.gitlab/batch-ci.yml
- template: Security/SAST.gitlab-ci.yml
- template: Security/License-Scanning.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
default:
retry:
max: 2 # This is confusing but this means "3 runs at max".
when:
- unknown_failure
- api_failure
- runner_system_failure
- job_execution_timeout
- stuck_or_timeout_failure
variables:
GOVERSION: "1.19.3"
GOFUTURE: "latest"
CI_IMAGE: "${CI_REGISTRY_IMAGE}/ci-builder:0.0.1"
CI_PRE_CLONE_SCRIPT: |
set -x
stages:
- ci_image_build
- lint
- test
- build
- post build
- integration
- gauntlet
- performance
- nonblocking
- cleanup_build
gosec-sast:
allow_failure: false
before_script:
- export GOPRIVATE=github.com/molecula/*
- apk add openssh-client
- eval $(ssh-agent -s)
- echo "$FB_SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- git config --global --add url."ssh://git@github.com/".insteadOf "https://github.com/"
- ssh-keygen -F github.com || echo "$SSH_KNOWN_HOSTS_HASHED" >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
script:
## securego/gosec works for scanning, but not converting to the gitlab report format.
- go install github.com/securego/gosec/v2/cmd/gosec@v2.12.0
- gosec -fmt=json -out=gosec.json -tests ./... || true
## gitlab's wrapper for gosec works for converting, but not for scanning.
- go install 'gitlab.com/gitlab-org/security-products/analyzers/gosec@v1.4.0'
- gosec convert gosec.json > gl-sast-report.json
.go-cache:
variables:
GOPATH: $CI_PROJECT_DIR/.go
before_script:
- mkdir -p .go
cache:
# this caching strategy makes it so each branch uses the same cache
key: "$CI_COMMIT_REF_SLUG"
paths:
- .go/pkg/mod/
smoke build:
image: golang:$GOVERSION
extends: .go-cache
stage: lint
allow_failure: false
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- echo "Let's just see if it compiles... (sometimes the linter gives unclear errors if it doesn't)"
- go build ./...
golangci-lint:
image: golangci/golangci-lint:v1.46.2
extends: .go-cache
stage: lint
allow_failure: true
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- echo "Checking for issues in new code"
- golangci-lint run -v --timeout=8m
go mod tidy:
stage: lint
image: golang:$GOVERSION
extends: .go-cache
rules:
- if: '$CI_COMMIT_TAG == null && ($CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web")'
script:
- go mod tidy
- git diff --exit-code -- go.mod go.sum
build lattice:
stage: test
image: node:14
variables:
AWS_PROFILE: "service-fb-ci"
AWS_ACCESS_KEY_ID: $AWS_FBCI_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_FBCI_SECRET_ACCESS_KEY
CI: "false"
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
before_script:
- curl -sS "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
- unzip -qq awscliv2.zip
- ./aws/install
- aws --version
- aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
- aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
- aws configure set region "us-east-2"
- aws configure set aws_profile $AWS_PROFILE
- aws sts get-caller-identity # ensure we have a valid AWS login
script:
- cd lattice
- cache=$(find . -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum | cut -d ' ' -f 1)
- echo "'$cache'"
- echo "looking for s3://molecula-artifact-storage/lattice/$cache/build.tar.gz"
# if is for if we had a cache object in S3
# else is for if we didn't have a cache object (and have to build).
- |
if aws s3api head-object --bucket molecula-artifact-storage --key "lattice/$cache/build.tar.gz"; then
# download object, extract, name the folder `build`
aws s3 cp "s3://molecula-artifact-storage/lattice/$cache/build.tar.gz" build.tar.gz
tar -xf build.tar.gz
else # cache file not found
yarn install --frozen-lockfile # CI needs to enforce that the lockfile doesn't need to be updated
yarn build
tar -czvf "$cache.tar.gz" build/
aws s3 mv "$cache.tar.gz" "s3://molecula-artifact-storage/lattice/$cache/build.tar.gz"
touch "$CI_COMMIT_SHA"
aws s3 mv "$CI_COMMIT_SHA" "s3://molecula-artifact-storage/lattice/$cache/$CI_COMMIT_SHA"
fi
- | # Ensure that we have build directory after the caching step
if [ ! -d build ]; then
echo "no build directory, erroring out" || exit 1
fi
- mv build ../
- cd ../
- rm -r lattice
- mv build lattice
- tar -czvf lattice.tar.gz lattice
artifacts:
paths:
- lattice.tar.gz
build featurebase:
stage: test
image: golang:$GOVERSION
extends: .go-cache
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- rm -r lattice
- tar -xvf lattice.tar.gz
- go install github.com/rakyll/statik@v0.1.7
- $GOPATH/bin/statik -src=lattice
- export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
- |
for goos in "darwin" "linux"; do
for goarch in "amd64" "arm64"; do
GOOS="${goos}" GOARCH="${goarch}" make build FLAGS="-o featurebase_${goos}_${goarch}"
done
done
artifacts:
paths:
- featurebase_*
needs:
- job: build lattice
build fbsql amd64:
stage: test
variables:
BUILD_NAME: build_${CI_COMMIT_SHA}_${CI_CONCURRENT_ID}
tags:
- shell
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
- date
- GOOS="linux" GOARCH="amd64" make docker-build-fbsql BUILD_CGO=1
- GOOS="darwin" GOARCH="amd64" make docker-build-fbsql
artifacts:
paths:
- ./build/fbsql_*
build fbsql arm64:
stage: test
variables:
BUILD_NAME: build_${CI_COMMIT_SHA}_${CI_CONCURRENT_ID}
tags:
- shell-arm64
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
- date
- GOOS="linux" GOARCH="arm64" make docker-build-fbsql BUILD_CGO=1
- GOOS="darwin" GOARCH="arm64" make docker-build-fbsql
artifacts:
paths:
- ./build/fbsql_*
build amd container fb:
stage: test
tags:
- shell
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
before_script:
- echo "${DOCKER_DEPLOY_TOKEN}" | docker login -u ${DOCKER_DEPLOY_USER} --password-stdin ${CI_REGISTRY}
script:
- tag=${CI_REGISTRY_IMAGE}/featurebase:linux-amd64-${CI_COMMIT_REF_SLUG}
- export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
- docker build --build-arg GO_VERSION=$GOVERSION --build-arg ARCH=amd64 --build-arg SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH -t $tag -f .gitlab/Dockerfile .
- docker push $tag
- echo Created docker featurebase image with tag "$tag"
needs:
- job: build featurebase
run jest tests:
stage: test
image: node:14
variables:
CI: "true"
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- echo "Testing lattice..."
- cd lattice
- npm install --force
- npm test -- --coverage --testResultsProcessor=jest-sonar-reporter
artifacts:
paths:
- lattice/coverage/lcov.info
# We run go test -race on all the standard packages, skipping the ones that have their
# own separate tests. we spin this off as nonblocking because it used to take a really
# long time and even now it's pretty slow.
run go tests race:
stage: nonblocking # don't let this job block any other jobs because it takes much longer than the other tests.
image: golang:$GOVERSION
extends: .go-cache
variables:
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_DATABASE: run_go_tests_race
POSTGRES_DB: run_go_tests_race
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_USER: postgres
POSTGRES_USER: postgres
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_PASSWORD: $POSTGRES_PASSWORD
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_HOST: postgres
services:
- postgres:14.7
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
needs: ["smoke build"] # we do block on smoke build though bc it's pretty dumb to test stuff if it doesn't build
script:
- echo "Running featurebase race tests..."
- PKG_LIST=$(go list ./... | grep -Ev 'internal/clustertests|simulacraData|batch|idk|v3/dax/test/dax' | paste -s -d, -)
- export TMPDIR=/mnt/ramdisk/test-$CI_JOB_ID
- mkdir -p $TMPDIR
- go test -race -v -timeout=10m ${PKG_LIST//,/ }
after_script:
- rm -rf /mnt/ramdisk/test-$CI_JOB_ID
tags:
- docker
# We run our base tests against $GOVERSION (a reasonably current version that we trust)
# and use shardwidth22 for them. This gives us a canary for things breaking for
# unusual shard widths.
run go tests:
stage: test
image: golang:$GOVERSION
extends: .go-cache
variables:
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_DATABASE: run_go_tests
POSTGRES_DB: run_go_tests
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_USER: postgres
POSTGRES_USER: postgres
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_PASSWORD: $POSTGRES_PASSWORD
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_HOST: postgres
services:
- postgres:14.7
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- echo "Running featurebase unit tests..."
- PKG_LIST=$(go list ./... | grep -Ev 'internal/clustertests|simulacraData|batch|idk|v3/dax/test/dax' | paste -s -d, -)
- export TMPDIR=/mnt/ramdisk/test-$CI_JOB_ID
- mkdir -p $TMPDIR
- go test -tags=shardwidth22 -timeout=10m -coverprofile=coverage.out -covermode=atomic -coverpkg=${PKG_LIST} ${PKG_LIST//,/ }
after_script:
- rm -rf /mnt/ramdisk/test-$CI_JOB_ID
artifacts:
paths:
- coverage.out
tags:
- docker
run go tests dax/test/dax:
stage: test
image: golang:$GOVERSION
extends: .go-cache
tags:
- docker
variables:
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_DATABASE: run_go_tests_dax
POSTGRES_DB: run_go_tests_dax
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_USER: postgres
POSTGRES_USER: postgres
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_PASSWORD: $POSTGRES_PASSWORD
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
FEATUREBASE_CONTROLLER_CONFIG_SQLDB_HOST: postgres
services:
- postgres:14.7
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- echo "Building FB and Datagen docker images for DAX tests"
- PKG_LIST=$(go list ./... | grep -Ev 'internal/clustertests|simulacraData' | paste -s -d, -)
- export TMPDIR=/mnt/ramdisk/test-$CI_JOB_ID
- mkdir -p $TMPDIR
- go test -coverprofile=coverage-dax-integration.out -covermode=atomic -coverpkg=${PKG_LIST} -timeout=20m ./dax/test/dax
after_script:
- rm -rf /mnt/ramdisk/test-$CI_JOB_ID
artifacts:
paths:
- coverage-dax-integration.out
# idk tests
run go tests idk race:
variables:
PROJECT: race_${CI_CONCURRENT_ID}
stage: nonblocking
retry: 1
script:
- echo "Running test-all-race"
- cd ./idk/
- echo $PROJECT
- echo $CI_COMMIT_REF_SLUG
- BRANCH_NAME=${CI_COMMIT_REF_SLUG} IDK_FEATUREBASE_TAG=${CI_COMMIT_TAG} IDK_FEATUREBASE_HASH=${CI_COMMIT_SHA} make test-all-race
after_script:
- cd ./idk/
- make save-pilosa-logs
- make shutdown
artifacts:
paths:
- ./idk/testdata/*_coverage.out
tags:
- shell
- aws
needs:
- job: build amd container fb
run go tests idk shard transactional:
variables:
IDK_DEFAULT_SHARD_TRANSACTIONAL: 1
PROJECT: shardttrans_${CI_CONCURRENT_ID}
stage: nonblocking
retry: 1
script:
- echo "Running shard transactional tests"
- cd ./idk/
- echo $PROJECT
- echo $CI_COMMIT_REF_SLUG
- BRANCH_NAME=${CI_COMMIT_REF_SLUG} IDK_FEATUREBASE_TAG=${CI_COMMIT_TAG} IDK_FEATUREBASE_HASH=${CI_COMMIT_SHA} make test-all
after_script:
- cd ./idk/
- make save-pilosa-logs
- make shutdown
artifacts:
paths:
- ./idk/testdata/*_coverage.out
- ./idk/testdata/*_logs.txt
tags:
- shell
- aws
needs:
- job: build amd container fb
run go tests idk 533:
variables:
USERNAME: fb-idk-access
PROJECT: test533_${CI_CONCURRENT_ID}
stage: nonblocking
retry: 1
script:
- echo "Running confluent 5.3.3 test-all"
- cd ./idk/
- echo $PROJECT
- echo $CI_COMMIT_REF_SLUG
- CONFLUENT_VERSION=5.3.3 BRANCH_NAME=${CI_COMMIT_REF_SLUG} IDK_FEATUREBASE_TAG=${CI_COMMIT_TAG} IDK_FEATUREBASE_HASH=${CI_COMMIT_SHA} make test-all
after_script:
- cd ./idk/
- make save-pilosa-logs
- make shutdown
tags:
- shell
- aws
artifacts:
paths:
- ./idk/testdata/*_coverage.out
needs:
- job: build amd container fb
run go tests idk sasl:
variables:
PROJECT: sasl_${CI_CONCURRENT_ID}
stage: nonblocking
retry: 1
script:
- echo "Running test-all-kafka-sasl"
- cd ./idk/
- echo $PROJECT
- echo $CI_COMMIT_REF_SLUG
- BRANCH_NAME=${CI_COMMIT_REF_SLUG} IDK_FEATUREBASE_TAG=${CI_COMMIT_TAG} IDK_FEATUREBASE_HASH=${CI_COMMIT_SHA} make test-all-kafka-sasl
after_script:
- cd ./idk/
- make save-pilosa-logs
- make shutdown
tags:
- shell
- aws
artifacts:
paths:
- ./idk/testdata/*_coverage.out
needs:
- job: build amd container fb
upload to sonarcloud:
stage: nonblocking
image: sonarsource/sonar-scanner-cli:4.7
variables:
SONAR_TOKEN: $SONAR_TOKEN
rules:
- if: '$CI_COMMIT_TAG == null && ($CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web")'
script:
- sonar-scanner -Dsonar.projectKey=molecula_featurebase -Dsonar.organization=molecula -Dsonar.sources=. -Dsonar.host.url=https://sonarcloud.io -Dsonar.go.coverage.reportPaths=coverage*.out,results/coverage*out,idk/testdata/*coverage.out,batch/testdata/*coverage.out,coverage-from-docker/*.out -Dsonar.javascript.lcov.reportPaths=lattice/coverage/lcov.info
needs:
- job: run go tests
- job: run jest tests
- job: external lookup tests
- job: run go tests idk race
optional: true
- job: run go tests idk shard transactional
optional: true
- job: run go tests idk sasl
optional: true
- job: run go tests idk 533
optional: true
- job: run go tests batch
optional: true
- job: run go tests dax/test/dax
optional: true
package for linux amd64:
stage: build
image: golang:$GOVERSION
extends: .go-cache
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
variables:
GOOS: "linux"
GOARCH: "amd64"
script:
- echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | tee /etc/apt/sources.list.d/goreleaser.list
- apt update && apt install nfpm=2.11.3
- make package
artifacts:
paths:
- "*.deb"
- "*.rpm"
upload_artifacts_to_nexus:
stage: post build
image: golang:$GOVERSION
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- curl -v --user "$NEXUS_YUM_CREDS" --upload-file *.arm64.rpm https://nexus.molecula.com/repository/molecula-yum/release/
- curl -v --user "$NEXUS_YUM_CREDS" --upload-file *.amd64.rpm https://nexus.molecula.com/repository/molecula-yum/release/
dependencies:
- package for linux amd64
- package for linux arm64
trigger_m-cloud-images:
stage: post build
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
needs:
- upload_artifacts_to_nexus
trigger: molecula/m-cloud-images
package for linux arm64:
stage: build
image: golang:$GOVERSION
extends: .go-cache
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
variables:
GOOS: "linux"
GOARCH: "arm64"
script:
- echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | tee /etc/apt/sources.list.d/goreleaser.list
- apt update && apt install nfpm=2.11.3
- make package
artifacts:
paths:
- "*.deb"
- "*.rpm"
build arm container fb:
stage: build
needs:
- "build featurebase"
tags:
- shell
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
before_script:
- echo "${DOCKER_DEPLOY_TOKEN}" | docker login -u ${DOCKER_DEPLOY_USER} --password-stdin ${CI_REGISTRY}
script:
- echo $CI_COMMIT_REF_SLUG
- tag=${CI_REGISTRY_IMAGE}/featurebase:linux-arm64-${CI_COMMIT_REF_SLUG}
- export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
- docker build --build-arg GO_VERSION=$GOVERSION --build-arg ARCH=arm64 --build-arg SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH -t $tag -f .gitlab/Dockerfile .
- docker push $tag
- echo Created docker featurebase image with tag "$tag"
### start idk builds ###
# building them all serially because otherwise you get container name conflicts.
idk build_amd64:
stage: build
variables:
BUILD_NAME: build_${CI_COMMIT_SHA}_${CI_CONCURRENT_ID}
tags:
- shell
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
- cd ./idk/
- date
- make docker-build GOOS="linux" GOARCH="amd64" BUILD_CGO=1
- date
- make docker-build GOOS="darwin" GOARCH="amd64"
- date
artifacts:
paths:
- ./idk/build/*
needs:
# doesn't actually need this... just want it to start executing before *all* the tests finish
- job: run go tests
idk build_arm64:
stage: build
tags:
- shell-arm64
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
- cd ./idk/
- date
- make docker-build GOOS="linux" GOARCH="arm64" BUILD_CGO=1 BUILD_NAME="linux-arm64"
- date
- make docker-build GOOS="darwin" GOARCH="arm64"
- date
artifacts:
paths:
- ./idk/build/*
needs:
# doesn't actually need this... just want it to start executing before *all* the tests finish
- job: run go tests
# building them all serially because otherwise you get container name conflicts.
# only do containers on default branch
idk package_docker_all:
stage: build
tags:
- shell
rules:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && ($CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web")'
script:
- export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
- make docker-idk GOOS="linux" GOARCH="amd64"
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- make docker-idk-tag-push GOOS="linux" GOARCH="amd64"
needs:
- job: idk build_amd64
- job: idk build_arm64
idk s3 dump:
stage: post build
allow_failure: false
variables:
PROFILE: "service-fb-ci"
AWS_SSH_PRIVATE_KEY: $AWS_FBCI_SSH_KEY
AWS_ACCESS_KEY_ID: $AWS_FBCI_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_FBCI_SECRET_ACCESS_KEY
tags:
- shell
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web"'
script:
- aws configure set aws_access_key_id $AWS_FBCI_ACCESS_KEY_ID
- aws configure set aws_secret_access_key $AWS_FBCI_SECRET_ACCESS_KEY
- aws configure set region "us-east-2"
- aws configure set aws_profile $PROFILE
- aws s3 cp ./idk/build/ s3://molecula-artifact-storage/idk/${CI_COMMIT_BRANCH}/${CI_COMMIT_SHORT_SHA}/ --recursive
- aws s3 cp ./idk/build/ s3://molecula-artifact-storage/idk/${CI_COMMIT_BRANCH}/_latest/ --recursive
needs:
- job: idk build_amd64
- job: idk build_arm64
idk s3 dump tag:
stage: post build
variables:
PROFILE: "service-fb-ci"
AWS_SSH_PRIVATE_KEY: $AWS_FBCI_SSH_KEY
AWS_ACCESS_KEY_ID: $AWS_FBCI_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_FBCI_SECRET_ACCESS_KEY
LOCATION: molecula-artifact-storage/idk/_tags
tags:
- shell
rules:
- if: '$CI_COMMIT_TAG != null && ($CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "schedule" || $CI_PIPELINE_SOURCE == "web")'
script:
- aws configure set aws_access_key_id $AWS_FBCI_ACCESS_KEY_ID
- aws configure set aws_secret_access_key $AWS_FBCI_SECRET_ACCESS_KEY
- aws configure set region "us-east-2"
- aws configure set aws_profile $PROFILE
- |
for goos in "darwin" "linux"; do
for goarch in "amd64" "arm64"; do
dir=idk-${CI_COMMIT_TAG}-${goos}-${goarch}
echo "Directory ${dir}"
mkdir ${dir}
mv ./idk/build/idk-${goos}-${goarch}/molecula-consumer-* ${dir}/
tar cvzf ${dir}.tar.gz ${dir}
aws s3 cp ${dir} s3://${LOCATION}/${CI_COMMIT_TAG}/${dir}/ --recursive
aws s3 cp ${dir}.tar.gz s3://${LOCATION}/${CI_COMMIT_TAG}/
done
done
needs:
- job: idk build_amd64
- job: idk build_arm64
### end idk builds ###
external lookup tests:
stage: integration
image: golang:$GOVERSION
extends: .go-cache
# TODO: no rules here, do we need to add the rules line?
variables:
POSTGRES_DB: $POSTGRES_DB
POSTGRES_USER: $POSTGRES_USER
POSTGRES_PASSWORD: $POSTGRES_PASSWORD
POSTGRES_HOST_AUTH_METHOD: trust
services:
- postgres:13.5
script:
- apt-get update --allow-releaseinfo-change -y
- apt-get install -y postgresql-client
- go test . -run "^TestExternalLookup" -externalLookupDSN postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres/$POSTGRES_DB?sslmode=disable
s3 dump:
stage: post build
variables:
PROFILE: "service-fb-ci"
AWS_SSH_PRIVATE_KEY: $AWS_FBCI_SSH_KEY
AWS_ACCESS_KEY_ID: $AWS_FBCI_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_FBCI_SECRET_ACCESS_KEY
tags:
- shell
rules:
- if: '$CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "web"'
script:
- aws configure set aws_access_key_id $AWS_FBCI_ACCESS_KEY_ID
- aws configure set aws_secret_access_key $AWS_FBCI_SECRET_ACCESS_KEY
- aws configure set region "us-east-2"
- aws configure set aws_profile $PROFILE
- |
for goos in "darwin" "linux"; do
for goarch in "amd64" "arm64"; do
aws s3 cp featurebase_${goos}_${goarch} s3://molecula-artifact-storage/featurebase/${CI_COMMIT_BRANCH}/${CI_COMMIT_SHORT_SHA}/featurebase_${goos}_${goarch}
aws s3 cp featurebase_${goos}_${goarch} s3://molecula-artifact-storage/featurebase/${CI_COMMIT_BRANCH}/_latest/featurebase_${goos}_${goarch}
aws s3 cp ./build/fbsql_${goos}_${goarch} s3://molecula-artifact-storage/featurebase/${CI_COMMIT_BRANCH}/${CI_COMMIT_SHORT_SHA}/fbsql_${goos}_${goarch}
aws s3 cp ./build/fbsql_${goos}_${goarch} s3://molecula-artifact-storage/featurebase/${CI_COMMIT_BRANCH}/_latest/fbsql_${goos}_${goarch}
done
done
needs:
- job: build featurebase
- job: build fbsql amd64
- job: build fbsql arm64
s3 dump tag:
stage: post build
variables:
PROFILE: "service-fb-ci"
AWS_SSH_PRIVATE_KEY: $AWS_FBCI_SSH_KEY
AWS_ACCESS_KEY_ID: $AWS_FBCI_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY: $AWS_FBCI_SECRET_ACCESS_KEY
LOCATION: molecula-artifact-storage/featurebase/_tags
tags:
- shell
rules:
- if: '$CI_COMMIT_TAG != null && ($CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "web")'
script:
- aws configure set aws_access_key_id $AWS_FBCI_ACCESS_KEY_ID
- aws configure set aws_secret_access_key $AWS_FBCI_SECRET_ACCESS_KEY
- aws configure set region "us-east-2"
- aws configure set aws_profile $PROFILE
- |
for goos in "darwin" "linux"; do
for goarch in "amd64" "arm64"; do
dir=featurebase-${CI_COMMIT_TAG}-${goos}-${goarch}
echo "Directory ${dir}"
mkdir $dir
mv featurebase_${goos}_${goarch} ${dir}/featurebase
mv ./build/fbsql_${goos}_${goarch} ${dir}/fbsql
cp NOTICE install/featurebase.conf install/featurebase.*.service ${dir}/
tar cvzf ${dir}.tar.gz ${dir}
aws s3 cp ${dir} s3://${LOCATION}/${CI_COMMIT_TAG}/${dir}/ --recursive
aws s3 cp ${dir}.tar.gz s3://${LOCATION}/${CI_COMMIT_TAG}/
done
done
needs:
- job: build featurebase
- job: build fbsql amd64
- job: build fbsql arm64

View file

@ -1,24 +0,0 @@
FROM alpine:3.14.2
LABEL maintainer "dev@molecula.com"
LABEL org.opencontainers.image.authors="dev@molecula.com"
ARG ARCH
WORKDIR /
RUN apk add --no-cache curl jq
COPY NOTICE .
COPY featurebase_linux_$ARCH featurebase
RUN chmod ugo+x .
EXPOSE 10101
VOLUME /data
ENV PILOSA_DATA_DIR /data
ENV PILOSA_BIND 0.0.0.0:10101
ENV PILOSA_BIND_GRPC 0.0.0.0:20101
ENTRYPOINT ["/featurebase"]
CMD ["server"]

View file

@ -1,28 +0,0 @@
run go tests batch:
variables:
PROJECT: batch_${CI_CONCURRENT_ID}
# this test relies on stuff that happens after build-lattice, which
# makes it pause the entire CI run waiting for this. we accept the
# small risk of wasting a build against the near certainty of spending
# five minutes running only one job.
stage: nonblocking
retry: 1
script:
- echo "Running test-all"
- cd ./batch/
- echo $PROJECT
- make build-featurebase
- make test-all
after_script:
- cd ./batch/
- make save-featurebase-logs
- make shutdown
artifacts:
paths:
- ./batch/testdata/*_coverage.out
- ./batch/testdata/*_logs.txt
tags:
- shell
- aws
needs:
- job: build amd container fb

View file

@ -1,83 +1,3 @@
run:
deadline: 5m
timeout: 5m
skip-dirs-use-default: true
#skip the protobuf generated files
skip-dirs:
- pb
- proto
skip-files:
- pql/pql.peg.go
linters:
enable:
# Recommended to be enabled by default (https://golangci-lint.run).
# - errcheck (lots to fix)
- gosimple
- govet
- ineffassign
- staticcheck
- typecheck
# - unused (about 20 to fix)
# Additional linters we choose to enable.
# - bodyclose (lots to fix, but we should)
- errchkjson
- errname
- gofmt
# - misspell (lots to fix, but we should)
- prealloc
# - predeclared (20 to fix)
# - stylecheck (quite a lot to fix, but we should definitely work on this)
- stylecheck
# - unconvert (not at all critical, but makes for cleaner code)
enable-all: false
disable-all: true
output:
# colored-line-number|line-number|json|tab|checkstyle|code-climate, default is "colored-line-number"
format: tab
# print lines of code with issue, default is true
print-issued-lines: true
# print linter name in the end of issue text, default is true
print-linter-name: true
linters-settings:
gofmt:
simplify: true
govet:
# report about shadowed variables
check-shadowing: true
# settings per analyzer
settings:
printf: # analyzer name, run `go tool vet help` to see all analyzers
funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
# enable or disable analyzers by name
# run `go tool vet help` to see all analyzers
enable:
- atomicalign
enable-all: false
disable:
- shadow
disable-all: false
stylecheck:
# ST1000: at least one file in a package should have a package comment
# ST1003: golang naming standards
# ST1016: methods on the same type should have the same receiver name
# ST1020: comment on exported function
checks: ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1020"]
issues:
exclude-use-default: false
max-issues-per-linter: 0
max-same-issues: 0
exclude:
- 'declaration of "(err|ctx)" shadows declaration at'
- 'Error return value of .(.*\.Help|.*\.MarkFlagRequired|(os\.)?std(out|err)\..*|.*Close|.*Flush|os\.Remove(All)?|.*printf?|os\.(Un)?Setenv). is not checked'

715
CHANGELOG.md Normal file
View file

@ -0,0 +1,715 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [1.4.0] - 2019-09-17
This version contains 99 contributions from 11 contributors. There are 94 files changed; 9,453 insertions; and 6,121 deletions.
**Attention**: Pilosa 1.4.0 changes the way that integer fields are stored. The upgrade from old format to new is handled automatically, however you will not be able to downgrade to 1.3 should you wish to do so. We *always* recommend taking a backup of your Pilosa data directory before upgrading Pilosa, but doubly so with this release.
### Added
- Update "Getting Started" documentation ([#2028](https://github.com/pilosa/pilosa/pull/2028))
- Add ability to disable tracing and use nopTracer ([#2029](https://github.com/pilosa/pilosa/pull/2029))
- Add test for no containers ([#2016](https://github.com/pilosa/pilosa/pull/2016))
- Add naive implementations of Roaring and fuzz test ([#2023](https://github.com/pilosa/pilosa/pull/2023))
- Add fuzzing code and readme.md to explain the fuzzer ([#2004](https://github.com/pilosa/pilosa/pull/2004))
- Add MinRow and MaxRow calls ([#1983](https://github.com/pilosa/pilosa/pull/1983))
- Add Prometheus stats backend ([#1992](https://github.com/pilosa/pilosa/pull/1992))
- Add extra tracing spans and metadata ([#1939](https://github.com/pilosa/pilosa/pull/1939))
- Add more Debugf() statements to the holder open process ([#1950](https://github.com/pilosa/pilosa/pull/1950))
- Add ability to post schema using holder.applySchema ([#1956](https://github.com/pilosa/pilosa/pull/1956))
### Changed
- Update CircleCI build with Go 1.13 and run enterprise tests ([#2064](https://github.com/pilosa/pilosa/pull/2064))
- Update Alpine to 3.9.4 in Dockerfile ([#2001](https://github.com/pilosa/pilosa/pull/2001))
- Add Prometheus tests, refactor http stats as middleware, minor fixes ([#1994](https://github.com/pilosa/pilosa/pull/1994))
- Add confirmation logic to catch false nodeLeave events ([#1993](https://github.com/pilosa/pilosa/pull/1993))
- Improve TopN() errors ([#1978](https://github.com/pilosa/pilosa/pull/1978))
- Make integer fields unbounded by using sign+magnitude representation ([#1902](https://github.com/pilosa/pilosa/pull/1902))
- Simplify contributing instructions by removing weird upstream thing ([#1966](https://github.com/pilosa/pilosa/pull/1966))
### Fixed
- Default BSI base value to min, max, or 0 depending on the min/max range ([#2050](https://github.com/pilosa/pilosa/pull/2050))
- Add worker pool for query processing ([#2034](https://github.com/pilosa/pilosa/pull/2034))
- Move Range deprecation message to higher level ([#2033](https://github.com/pilosa/pilosa/pull/2033))
- Use lock in view.deleteFragment while altering fragments ([#2026](https://github.com/pilosa/pilosa/pull/2026))
- Fix malformed offset bug in readOffsets and readWithRuns ([#2021](https://github.com/pilosa/pilosa/pull/2021))
- Fix various container iteration bugs in Roaring ([#2019](https://github.com/pilosa/pilosa/pull/2019))
- Fix malformed bitmap handling ([#2017](https://github.com/pilosa/pilosa/pull/2017))
- Fix fuzzer errors in roaring ([#2012](https://github.com/pilosa/pilosa/pull/2012))
- Save all state files atomically to avoid corruption ([#2000](https://github.com/pilosa/pilosa/pull/2000))
- Fix slice container updates ([#1997](https://github.com/pilosa/pilosa/pull/1997))
- Fix out of bounds panic to show error ([#1975](https://github.com/pilosa/pilosa/pull/1975))
- Fix error message returned by regex on field and index names ([#1973](https://github.com/pilosa/pilosa/pull/1973))
- Fix filter calls in GroupBy not being translated ([#1970](https://github.com/pilosa/pilosa/pull/1970))
- Fix TranslateFile behavior when reopened ([#1954](https://github.com/pilosa/pilosa/pull/1954))
- Remove buggy shard validation code ([#1951](https://github.com/pilosa/pilosa/pull/1951))
- Fix some lint warnings raised in VS-Code ([#1947](https://github.com/pilosa/pilosa/pull/1947))
### Performance
- Address some startup speed and performance issues ([#1988](https://github.com/pilosa/pilosa/pull/1988))
- Add a worker pool for importRoaring jobs ([#2048](https://github.com/pilosa/pilosa/pull/2048))
- Use UnionInPlace for computing time rows which involve multiple views ([#2041](https://github.com/pilosa/pilosa/pull/2041))
- Improve ingest performance with snapshot queue and unmarshaling improvements ([#2024](https://github.com/pilosa/pilosa/pull/2024))
- Improve row cache ([#1974](https://github.com/pilosa/pilosa/pull/1974))
### Removed
- Remove extraneous stat tags to improve prometheus performance ([#1996](https://github.com/pilosa/pilosa/pull/1996))
## [1.3.1] - 2019-05-01
This version contains 1 contribution from 1 contributor. There are 6 files changed; 10 insertions; and 95 deletions.
### Fixed
- Remove shard validation to fix bug where some nodes weren't loading their fragments. #1951 ([#1964](https://github.com/pilosa/pilosa/pull/1964))
## [1.3.0] - 2019-04-16
This version contains 98 contributions from 10 contributors. There are 144 files changed; 12,635 insertions; and 4,341 deletions.
### Added
- Add license headers and CI check ([#1940](https://github.com/pilosa/pilosa/pull/1940))
- Add support to modify shard width at build time ([#1921](https://github.com/pilosa/pilosa/pull/1921))
- Add 'bench' Makefile target and run fewer concurrency level benchmarks ([#1915](https://github.com/pilosa/pilosa/pull/1915))
- Add server stats to /info endpoint ([#1859](https://github.com/pilosa/pilosa/pull/1859))
- Implement config options for block profile rate and mutex fraction ([#1910](https://github.com/pilosa/pilosa/pull/1910))
- Implement global open file counter using syswrap (to scale past system open file limits) ([#1906](https://github.com/pilosa/pilosa/pull/1906))
- Implement global mmap counter with fallback (to scale past system mmap limits) ([#1903](https://github.com/pilosa/pilosa/pull/1903))
- Add shard width to index info in schema (allows client to get shard width at run time) ([#1881](https://github.com/pilosa/pilosa/pull/1881))
- Add shift operator ([#1761](https://github.com/pilosa/pilosa/pull/1761))
- Support advertise address and listen on 0.0.0.0 ([#1832](https://github.com/pilosa/pilosa/pull/1832))
- Added convenience function to efficiently calculate size of a roaring bitmap in bytes ([#1839](https://github.com/pilosa/pilosa/pull/1839))
- Make sure more tests and benchmarks can have their temp dir set by flag ([#1831](https://github.com/pilosa/pilosa/pull/1831))
- Add sliceascending/slicedescending striped benchmarks ([#1763](https://github.com/pilosa/pilosa/pull/1763))
- Add setValue test and benchmarks ([#1820](https://github.com/pilosa/pilosa/pull/1820))
- Add a test for groupby filter with RangeLTLT ([#1818](https://github.com/pilosa/pilosa/pull/1818))
- Add tests for GroupBy with keys; removes unused Bit message from proto ([#1811](https://github.com/pilosa/pilosa/pull/1811))
### Fixed
- Update to latest memberlist fork with race fixes ([#1944](https://github.com/pilosa/pilosa/pull/1944))
- Return original error instead of cause in handler ([#1943](https://github.com/pilosa/pilosa/pull/1943))
- Validate (and panic) on duplicate PQL arguments ([#1938](https://github.com/pilosa/pilosa/pull/1938))
- Add correct content type to query responses Fixes #1873 ([#1936](https://github.com/pilosa/pilosa/pull/1936))
- Address race condition by getting cluster nodes with lock ([#1931](https://github.com/pilosa/pilosa/pull/1931))
- Make sure to unmap containers before modifying ([#1876](https://github.com/pilosa/pilosa/pull/1876))
- Avoid probable race when creating fragments ([#1863](https://github.com/pilosa/pilosa/pull/1863))
- Improve help strings for metrics options ([#1887](https://github.com/pilosa/pilosa/pull/1887))
- Ensure ClearRow() arguments get translated ([#1848](https://github.com/pilosa/pilosa/pull/1848))
- Prevent omitting zero ids on columnattrs ([#1846](https://github.com/pilosa/pilosa/pull/1846))
- Set cache size to 0 if cache type is none ([#1842](https://github.com/pilosa/pilosa/pull/1842))
- Prevent deadlock in replication logic on reopening a store ([#1834](https://github.com/pilosa/pilosa/pull/1834))
- Pass loggers around properly in gossip ([#1835](https://github.com/pilosa/pilosa/pull/1835))
- Include read lock in cluster.Nodes() ([#1836](https://github.com/pilosa/pilosa/pull/1836))
- Raise an error on Rows() query against a time field with noStandardView: true ([#1826](https://github.com/pilosa/pilosa/pull/1826))
- Don't delete test fragment data (part of repo) ([#1827](https://github.com/pilosa/pilosa/pull/1827))
- Fix bug on upper end of bsi range queries ([#1822](https://github.com/pilosa/pilosa/pull/1822))
- Group by fixes ([#1802](https://github.com/pilosa/pilosa/pull/1802))
### Changed
- Switch to GolangCI lint ([#1924](https://github.com/pilosa/pilosa/pull/1924))
- Return empty result set when query empty ([#1937](https://github.com/pilosa/pilosa/pull/1937))
- Add Go 1.12 to CircleCI ([#1909](https://github.com/pilosa/pilosa/pull/1909))
- Ignore fragment files from shards node doesn't own ([#1900](https://github.com/pilosa/pilosa/pull/1900))
- Go module support. Use Modules instead of dep for dependencies ([#1616](https://github.com/pilosa/pilosa/pull/1616))
- Merge Range() into Row() call. ([#1804](https://github.com/pilosa/pilosa/pull/1804))
- Add from/to range arguments to Rows() call ([#1851](https://github.com/pilosa/pilosa/pull/1851))
- Fixes Store call error messages, Rows doesn't need field argument ([#1830](https://github.com/pilosa/pilosa/pull/1830))
### Performance
- BTree performance improvements ([#1916](https://github.com/pilosa/pilosa/pull/1916))
- Make Containers smaller, especially when they have small contents ([#1901](https://github.com/pilosa/pilosa/pull/1901))
- Address UnionInPlace performance regressions ([#1897](https://github.com/pilosa/pilosa/pull/1897))
- Small write path for import-roaring. Makes small imports faster ([#1892](https://github.com/pilosa/pilosa/pull/1892))
- Small write path for imports ([#1871](https://github.com/pilosa/pilosa/pull/1871))
- Remove copy for pilosa roaring files ([#1865](https://github.com/pilosa/pilosa/pull/1865))
- Disable anti-entropy if not using replication [performance] ([#1814](https://github.com/pilosa/pilosa/pull/1814))
- Group By—skip 0 counts as early as possible ([#1803](https://github.com/pilosa/pilosa/pull/1803))
## [1.2.0] - 2018-12-20
This version contains 155 contributions from 11 contributors. There are 113 files changed; 19,085 insertions; and 4,323 deletions.
### Added
- Cancel queries on Context.Done() ([#1773](https://github.com/pilosa/pilosa/pull/1773))
- Union In Place ([#1766](https://github.com/pilosa/pilosa/pull/1766), [#1774](https://github.com/pilosa/pilosa/pull/1774))
- Import benchmarking ([#1771](https://github.com/pilosa/pilosa/pull/1771))
- Add GroupBy() Filter ([#1753](https://github.com/pilosa/pilosa/pull/1753))
- Add /internal/translate/keys endpoint ([#1751](https://github.com/pilosa/pilosa/pull/1751))
- CircleCI: Add race detector to parallel build, default to Go 1.11. ([#1756](https://github.com/pilosa/pilosa/pull/1756))
- Add distributed tracing. ([#1684](https://github.com/pilosa/pilosa/pull/1684))
- Add NoStandardView field option ([#1733](https://github.com/pilosa/pilosa/pull/1733))
- Add some stat tracking to roaring implementation ([#1743](https://github.com/pilosa/pilosa/pull/1743))
- Add cluster fault testing using docker-compose and pumba ([#1717](https://github.com/pilosa/pilosa/pull/1717))
- Allow backslash, carriage return in PQL strings ([#1713](https://github.com/pilosa/pilosa/pull/1713))
- Add base system, curl and jq for debug and checks ([#1707](https://github.com/pilosa/pilosa/pull/1707))
- Add `Rows` and `GroupBy` functionality ([#1647](https://github.com/pilosa/pilosa/pull/1647))
- Add `clear` functional option for imports ([#1699](https://github.com/pilosa/pilosa/pull/1699))
- Implement tracking of available shards to help support sparse datasets ([#1600](https://github.com/pilosa/pilosa/pull/1600), [#1695](https://github.com/pilosa/pilosa/pull/1695), [#1624](https://github.com/pilosa/pilosa/pull/1624), [#1663](https://github.com/pilosa/pilosa/pull/1663))
- Add missing rowID/Key columnID/Key tests ([#1683](https://github.com/pilosa/pilosa/pull/1683))
- Add Store() operation to PQL ([#1666](https://github.com/pilosa/pilosa/pull/1666))
- Add diagnostics CPUArch field ([#1671](https://github.com/pilosa/pilosa/pull/1671))
- Add CircleCI step to generate Docker image and push to Docker hub ([#1673](https://github.com/pilosa/pilosa/pull/1673))
- Implement ClearRow() query ([#1645](https://github.com/pilosa/pilosa/pull/1645))
- Add support for Bool fields ([#1658](https://github.com/pilosa/pilosa/pull/1658))
- Make translate map size configurable ([#1653](https://github.com/pilosa/pilosa/pull/1653))
- Add DirectAdd function to roaring.Bitmap ([#1646](https://github.com/pilosa/pilosa/pull/1646))
- Implement Roaring import ([#1622](https://github.com/pilosa/pilosa/pull/1622), [#1738](https://github.com/pilosa/pilosa/pull/1738))
- Add Not() query ([#1635](https://github.com/pilosa/pilosa/pull/1635))
- Implement Options call and excludeRowAttrs, excludeColumns, columnAttrs and shards args ([#1631](https://github.com/pilosa/pilosa/pull/1631))
- Add field options to pilosa import ([#1625](https://github.com/pilosa/pilosa/pull/1625))
- Implement column existence tracking ([#1788](https://github.com/pilosa/pilosa/pull/1788), [#1672](https://github.com/pilosa/pilosa/pull/1672), [#1628](https://github.com/pilosa/pilosa/pull/1628))
### Changed
- Convert the anti-entropy logic to use `ImportRoaring` instead of `QueryNode` ([#1780](https://github.com/pilosa/pilosa/pull/1780))
- Simplify `require-*` logic in Makefile ([#1755](https://github.com/pilosa/pilosa/pull/1755))
- Cleanup logging ([#1748](https://github.com/pilosa/pilosa/pull/1748))
- Remove TravisCI, add CircleCI shield ([#1740](https://github.com/pilosa/pilosa/pull/1740))
- Upgrade Peg dependency and regenerate grammar ([#1725](https://github.com/pilosa/pilosa/pull/1725))
- Upgrade to protoc 3.6.1 (also updated protoc-gen-gofast) ([#1724](https://github.com/pilosa/pilosa/pull/1724))
- Move column attrs logic to executor ([#1677](https://github.com/pilosa/pilosa/pull/1677))
- Shrink container bit count to int32 ([#1664](https://github.com/pilosa/pilosa/pull/1664))
### Performance
- Remove bounds check ([#1619](https://github.com/pilosa/pilosa/pull/1619))
- Improve benchmarking and performance ([#1741](https://github.com/pilosa/pilosa/pull/1741))
### Fixed
- Ensure internal client closes all response bodies ([#1795](https://github.com/pilosa/pilosa/pull/1795))
- Allow translate log entry buffer to grow ([#1787](https://github.com/pilosa/pilosa/pull/1787))
- Add Gopkg.lock as a dependency for vendor target ([#1790](https://github.com/pilosa/pilosa/pull/1790))
- Cluster resize fix ([#1785](https://github.com/pilosa/pilosa/pull/1785))
- Attempt to fix deadlock by releasing view lock before broadcasting ([#1782](https://github.com/pilosa/pilosa/pull/1782))
- Fix bug where cluster goes into RESIZING instead of NORMAL ([#1777](https://github.com/pilosa/pilosa/pull/1777))
- Propogate updates to node details (not just additions and deletions) ([#1769](https://github.com/pilosa/pilosa/pull/1769))
- Fix arm64 support ([#1764](https://github.com/pilosa/pilosa/pull/1764))
- Fix data races ([#1750](https://github.com/pilosa/pilosa/pull/1750))
- Fix fragment checksums race condition ([#1749](https://github.com/pilosa/pilosa/pull/1749))
- Import cmd field type flag ([#1732](https://github.com/pilosa/pilosa/pull/1732))
- Increase the translate file size for tests/benchmarks ([#1744](https://github.com/pilosa/pilosa/pull/1744))
- Prevent panic in Bitmap.UnmarshalBinary when there is no data ([#1742](https://github.com/pilosa/pilosa/pull/1742))
- Remove unused rule from peg grammar ([#1737](https://github.com/pilosa/pilosa/pull/1737))
- Improve Internal Client errors ([#1729](https://github.com/pilosa/pilosa/pull/1729))
- Forward imports to non-coordinator shards ([#1719](https://github.com/pilosa/pilosa/pull/1719))
- Fix double escapes in PQL grammar ([#1727](https://github.com/pilosa/pilosa/pull/1727))
- Ensure btree comparison doesn't fail for smallish N ([#1712](https://github.com/pilosa/pilosa/pull/1712))
- Drop now-superfluous methodNotAllowedHandler ([#1711](https://github.com/pilosa/pilosa/pull/1711))
- Use pilosa.Logger everywhere ([#1674](https://github.com/pilosa/pilosa/pull/1674))
- Ensure view closes fragment on broadcast error ([#1675](https://github.com/pilosa/pilosa/pull/1675))
- Prevent closing os.Stderr (used in verbose test logging) ([#1696](https://github.com/pilosa/pilosa/pull/1696))
- Allow holder to close/open/close without panic on closing closed channel ([#1686](https://github.com/pilosa/pilosa/pull/1686))
- Fix bug with Range() queries with field keys ([#1679](https://github.com/pilosa/pilosa/pull/1679))
- Sync query validation for handlers ([#1676](https://github.com/pilosa/pilosa/pull/1676))
- Wrap translation store errors, decrease test map size to prevent failure on 32-bit ([#1665](https://github.com/pilosa/pilosa/pull/1665))
- Fix pass-by-value issue in proto decode ([#1662](https://github.com/pilosa/pilosa/pull/1662))
- Do not run prerelease in CI if this is a pull request ([#1655](https://github.com/pilosa/pilosa/pull/1655))
- Ensure mutex imports unset previous columns ([#1656](https://github.com/pilosa/pilosa/pull/1656))
- Treat import timestamps as UTC ([#1651](https://github.com/pilosa/pilosa/pull/1651))
- Remove unused log buffers from test cluster, fixes race ([#1612](https://github.com/pilosa/pilosa/pull/1612))
- Add --field-keys and --index-keys options to pilosa import ([#1621](https://github.com/pilosa/pilosa/pull/1621))
- Use passed stdin, stdout, and stderr in the cmd package ([#1620](https://github.com/pilosa/pilosa/pull/1620))
- Update Go client sample to match latest master ([#1614](https://github.com/pilosa/pilosa/pull/1614))
## [1.1.0] - 2018-08-21
This version contains 32 contributions from 5 contributors. There are 89 files changed; 2,752 insertions; and 1,013 deletions.
### Added
- Add CircleCI ([#1610](https://github.com/pilosa/pilosa/pull/1610))
- Add key translation to exports ([#1608](https://github.com/pilosa/pilosa/pull/1608))
- Support importing key values ([#1599](https://github.com/pilosa/pilosa/pull/1599), [#1601](https://github.com/pilosa/pilosa/pull/1601))
- Treat coordinator as primary translate store ([#1582](https://github.com/pilosa/pilosa/pull/1582))
- Add DEGRADED cluster state and handle gossip NodeLeave events correctly ([#1584](https://github.com/pilosa/pilosa/pull/1584))
- Add linters to gometalinter and fix related issues ([#1544](https://github.com/pilosa/pilosa/pull/1544), [#1543](https://github.com/pilosa/pilosa/pull/1543), [#1540](https://github.com/pilosa/pilosa/pull/1540), [#1539](https://github.com/pilosa/pilosa/pull/1539), [#1537](https://github.com/pilosa/pilosa/pull/1537), [#1536](https://github.com/pilosa/pilosa/pull/1536), [#1535](https://github.com/pilosa/pilosa/pull/1535), [#1534](https://github.com/pilosa/pilosa/pull/1534), [#1530](https://github.com/pilosa/pilosa/pull/1530), [#1529](https://github.com/pilosa/pilosa/pull/1529), [#1528](https://github.com/pilosa/pilosa/pull/1528), [#1526](https://github.com/pilosa/pilosa/pull/1526), [#1527](https://github.com/pilosa/pilosa/pull/1527))
- Add mutex field type ([#1524](https://github.com/pilosa/pilosa/pull/1524))
- Fragment rows() and rowsForColumn() ([#1532](https://github.com/pilosa/pilosa/pull/1532))
### Fixed
- Fix race on replicationClosing channel ([#1607](https://github.com/pilosa/pilosa/pull/1607))
- Prevent anti-entropy and cluster resize from running simultaneously ([#1586](https://github.com/pilosa/pilosa/pull/1586))
- Require a valid port that isn't greater than 65,535 ([#1603](https://github.com/pilosa/pilosa/pull/1603))
- Add view parameter to sync logic for syncing time fields ([#1602](https://github.com/pilosa/pilosa/pull/1602))
- Fix translator in cluster environment ([#1552](https://github.com/pilosa/pilosa/pull/1552))
- Use string prefix instead of equality so json error message will pass on all Go versions ([#1558](https://github.com/pilosa/pilosa/pull/1558))
## [1.0.2] - 2018-08-01
This version contains 11 contributions from 3 contributors. There are 30 files changed; 1,569 insertions; and 1,215 deletions.
### Fixed
- Fix documentation ([#1503](https://github.com/pilosa/pilosa/pull/1503), [#1495](https://github.com/pilosa/pilosa/pull/1495), [#1551](https://github.com/pilosa/pilosa/pull/1551))
- Fix places where empty IndexOptions were being used ([#1547](https://github.com/pilosa/pilosa/pull/1547))
- Fix translator syncing bug in cluster environments ([#1552](https://github.com/pilosa/pilosa/pull/1552))
- Fix race condition in translate_test ([#1541](https://github.com/pilosa/pilosa/pull/1541))
- Add IndexOptions to IndexInfo json response ([#1542](https://github.com/pilosa/pilosa/pull/1542))
- Add proper locking to cluster code to prevent races ([#1533](https://github.com/pilosa/pilosa/pull/1533))
- Re-export erroneously unexported func Row.Intersect ([#1502](https://github.com/pilosa/pilosa/pull/1502))
- Update parser to handle row keys on SetRowAttrs() ([#1555](https://github.com/pilosa/pilosa/pull/1555))
## [1.0.1] - 2018-07-11
This version contains 12 contributions from 4 contributors. There are 11 files changed; 133 insertions; and 39 deletions.
### Fixed
- Use `dep ensure -vendor-only` for build repeatability ([#1491](https://github.com/pilosa/pilosa/pull/1491))
- Make sure time range views are calculated correctly across months ([#1485](https://github.com/pilosa/pilosa/pull/1485))
- Fix up error handling, add a configurable timeout to http handler closing ([#1486](https://github.com/pilosa/pilosa/pull/1486))
- Add gossip Closer ([#1483](https://github.com/pilosa/pilosa/pull/1483))
- Update docs references to WebUI naming (console) and installation ([#1493](https://github.com/pilosa/pilosa/pull/1493))
## [1.0.0] - 2018-07-09
This version contains 218 contributions from 7 contributors. There are 184 files changed; 21,769 insertions; and 20,275 deletions.
### Added
- ID-Key Translation ([#1337](https://github.com/pilosa/pilosa/pull/1337))
- Add CORS support to handler ([#1327](https://github.com/pilosa/pilosa/pull/1327))
### Changed
- HTTP handler updates ([#1408](https://github.com/pilosa/pilosa/pull/1408), [#1399](https://github.com/pilosa/pilosa/pull/1399), [#1441](https://github.com/pilosa/pilosa/pull/1441), [#1375](https://github.com/pilosa/pilosa/pull/1375), [#1433](https://github.com/pilosa/pilosa/pull/1433), [#1444](https://github.com/pilosa/pilosa/pull/1444), [#1388](https://github.com/pilosa/pilosa/pull/1388), [#1309](https://github.com/pilosa/pilosa/pull/1309), [#1302](https://github.com/pilosa/pilosa/pull/1302), [#1304](https://github.com/pilosa/pilosa/pull/1304), [#1465](https://github.com/pilosa/pilosa/pull/1465), [#1466](https://github.com/pilosa/pilosa/pull/1466))
- Refactor/improve tests ([#1437](https://github.com/pilosa/pilosa/pull/1437), [#1434](https://github.com/pilosa/pilosa/pull/1434), [#1435](https://github.com/pilosa/pilosa/pull/1435), [#1425](https://github.com/pilosa/pilosa/pull/1425), [#1418](https://github.com/pilosa/pilosa/pull/1418), [#1419](https://github.com/pilosa/pilosa/pull/1419), [#1413](https://github.com/pilosa/pilosa/pull/1413), [#1394](https://github.com/pilosa/pilosa/pull/1394), [#1387](https://github.com/pilosa/pilosa/pull/1387), [#1386](https://github.com/pilosa/pilosa/pull/1386), [#1378](https://github.com/pilosa/pilosa/pull/1378), [#1364](https://github.com/pilosa/pilosa/pull/1364), [#1348](https://github.com/pilosa/pilosa/pull/1348), [#1340](https://github.com/pilosa/pilosa/pull/1340), [#1297](https://github.com/pilosa/pilosa/pull/1297))
- Simplify inter-node communication ([#1428](https://github.com/pilosa/pilosa/pull/1428), [#1427](https://github.com/pilosa/pilosa/pull/1427), [#1412](https://github.com/pilosa/pilosa/pull/1412), [#1398](https://github.com/pilosa/pilosa/pull/1398), [#1391](https://github.com/pilosa/pilosa/pull/1391), [#1389](https://github.com/pilosa/pilosa/pull/1389))
- Make gossip's interface to Pilosa the API struct ([#1452](https://github.com/pilosa/pilosa/pull/1452))
- Rename slice to shard ([#1426](https://github.com/pilosa/pilosa/pull/1426))
- Clearbit for time fields ([#1424](https://github.com/pilosa/pilosa/pull/1424))
- Update docs ([#1390](https://github.com/pilosa/pilosa/pull/1390), [#1329](https://github.com/pilosa/pilosa/pull/1329), [#1305](https://github.com/pilosa/pilosa/pull/1305), [#1296](https://github.com/pilosa/pilosa/pull/1296), [#1461](https://github.com/pilosa/pilosa/pull/1461))
- Simplify server setup ([#1417](https://github.com/pilosa/pilosa/pull/1417), [#1393](https://github.com/pilosa/pilosa/pull/1393),[#1451](https://github.com/pilosa/pilosa/pull/1451))
- Refactor API ([#1407](https://github.com/pilosa/pilosa/pull/1407))
- Rewrite PQL parser and add various improvements/simplifications ([#1382](https://github.com/pilosa/pilosa/pull/1382), [#1402](https://github.com/pilosa/pilosa/pull/1402), [#1354](https://github.com/pilosa/pilosa/pull/1354), [#1463](https://github.com/pilosa/pilosa/pull/1463))
- Rename "frame" to "field" ([#1395](https://github.com/pilosa/pilosa/pull/1395), [#1362](https://github.com/pilosa/pilosa/pull/1362), [#1360](https://github.com/pilosa/pilosa/pull/1360), [#1358](https://github.com/pilosa/pilosa/pull/1358), [#1357](https://github.com/pilosa/pilosa/pull/1357), [#1355](https://github.com/pilosa/pilosa/pull/1355))
- Optimize count ([#1365](https://github.com/pilosa/pilosa/pull/1365))
- Simplify bitmap max function ([#1333](https://github.com/pilosa/pilosa/pull/1333))
- Rename "bit" to "column" for clarity ([#1326](https://github.com/pilosa/pilosa/pull/1326))
- Rename pilosa.Bitmap to Row ([#1311](https://github.com/pilosa/pilosa/pull/1311))
- Invert encoding/decoding and remove internal references ([#1454](https://github.com/pilosa/pilosa/pull/1454))
### Removed
- Rename (unexport) many items to reduce public API footprint prior to 1.0 release ([#1470](https://github.com/pilosa/pilosa/pull/1470), [#1458](https://github.com/pilosa/pilosa/pull/1458), [#1450](https://github.com/pilosa/pilosa/pull/1450), [#1449](https://github.com/pilosa/pilosa/pull/1449), [#1448](https://github.com/pilosa/pilosa/pull/1448), [#1447](https://github.com/pilosa/pilosa/pull/1447), [#1446](https://github.com/pilosa/pilosa/pull/1446), [#1438](https://github.com/pilosa/pilosa/pull/1438), [#1443](https://github.com/pilosa/pilosa/pull/1443), [#1440](https://github.com/pilosa/pilosa/pull/1440), [#1439](https://github.com/pilosa/pilosa/pull/1439), [#1409](https://github.com/pilosa/pilosa/pull/1409), [#1392](https://github.com/pilosa/pilosa/pull/1392), [#1374](https://github.com/pilosa/pilosa/pull/1374), [#1372](https://github.com/pilosa/pilosa/pull/1372), [#1369](https://github.com/pilosa/pilosa/pull/1369), [#1367](https://github.com/pilosa/pilosa/pull/1367), [#1366](https://github.com/pilosa/pilosa/pull/1366), [#1351](https://github.com/pilosa/pilosa/pull/1351), [#1420](https://github.com/pilosa/pilosa/pull/1420), [#1416](https://github.com/pilosa/pilosa/pull/1416), [#1397](https://github.com/pilosa/pilosa/pull/1397))
- Remove dead code ([#1432](https://github.com/pilosa/pilosa/pull/1432), [#1457](https://github.com/pilosa/pilosa/pull/1457), [#1421](https://github.com/pilosa/pilosa/pull/1421), [#1411](https://github.com/pilosa/pilosa/pull/1411), [#1377](https://github.com/pilosa/pilosa/pull/1377), [#1393](https://github.com/pilosa/pilosa/pull/1393), [#1462](https://github.com/pilosa/pilosa/pull/1462))
- Remove view argument from Field.SetBit and Field.ClearBit ([#1396](https://github.com/pilosa/pilosa/pull/1396))
- Remove WebUI (now contained in a separate package) ([#1363](https://github.com/pilosa/pilosa/pull/1363))
- Remove bench command ([#1347](https://github.com/pilosa/pilosa/pull/1347))
- Remove "view" from API, handler, docs ([#1346](https://github.com/pilosa/pilosa/pull/1346))
- Remove backup/restore stuff ([#1339](https://github.com/pilosa/pilosa/pull/1339), [#1341](https://github.com/pilosa/pilosa/pull/1341))
- Remove inverse frame functionality ([#1335](https://github.com/pilosa/pilosa/pull/1335))
- Remove rangeEnabled option ([#1332](https://github.com/pilosa/pilosa/pull/1332))
- Remove index and field MarshalJSON ([#1468](https://github.com/pilosa/pilosa/pull/1468))
### Fixed
- Fix a few data races ([#1423](https://github.com/pilosa/pilosa/pull/1423))
- Fix for crash while removing containers ([#1401](https://github.com/pilosa/pilosa/pull/1401))
- Allow dashes in frame names ([#1415](https://github.com/pilosa/pilosa/pull/1415))
- Fix generate-config command, use single toml lib ([#1350](https://github.com/pilosa/pilosa/pull/1350))
## [0.10.0] - 2018-05-15
This version contains 93 contributions from 8 contributors. There are 93 files changed; 4,495 insertions; and 5,392 deletions.
### Added
- Add B+Tree containers (Enterprise Edition) ([#1285](https://github.com/pilosa/pilosa/pull/1285))
- Add /info endpoint ([#1236](https://github.com/pilosa/pilosa/pull/1236))
### Changed
- Wrap errors ([#1271](https://github.com/pilosa/pilosa/pull/1271), [#1258](https://github.com/pilosa/pilosa/pull/1258), [#1274](https://github.com/pilosa/pilosa/pull/1274), [#1270](https://github.com/pilosa/pilosa/pull/1270), [#1273](https://github.com/pilosa/pilosa/pull/1273), [#1272](https://github.com/pilosa/pilosa/pull/1272), [#1260](https://github.com/pilosa/pilosa/pull/1260), [#1259](https://github.com/pilosa/pilosa/pull/1259), [#1256](https://github.com/pilosa/pilosa/pull/1256), [#1257](https://github.com/pilosa/pilosa/pull/1257), [#1261](https://github.com/pilosa/pilosa/pull/1261), [#1262](https://github.com/pilosa/pilosa/pull/1262), [#1263](https://github.com/pilosa/pilosa/pull/1263), [#1265](https://github.com/pilosa/pilosa/pull/1265))
### Removed
- Remove unused code ([#1286](https://github.com/pilosa/pilosa/pull/1286))
- Remove input definition, add install-stringer to Makefile ([#1284](https://github.com/pilosa/pilosa/pull/1284))
- Remove /id and /hosts endpoints. Add local ID to /status ([#1238](https://github.com/pilosa/pilosa/pull/1238))
- Remove API.URI ([#1255](https://github.com/pilosa/pilosa/pull/1255))
### Fixed
- Assorted docs fixes ([#1281](https://github.com/pilosa/pilosa/pull/1281), [#1269](https://github.com/pilosa/pilosa/pull/1269))
- Update PQL syntax in bench subcommand ([#1279](https://github.com/pilosa/pilosa/pull/1279))
- Update help menu in WebUI ([#1278](https://github.com/pilosa/pilosa/pull/1278))
- Fix dead lock ([#1268](https://github.com/pilosa/pilosa/pull/1268))
- Make sure gossipMemberSet.Logger is set during server setup ([#1266](https://github.com/pilosa/pilosa/pull/1266))
- Make sure ~ is expanded in NewServer; BroadcastReceiver uses temp path ([#1242](https://github.com/pilosa/pilosa/pull/1242))
- Avoid creating a slice of nil timestamps on Import() ([#1234](https://github.com/pilosa/pilosa/pull/1234))
- Fixup internal client ([#1253](https://github.com/pilosa/pilosa/pull/1253))
## [0.9.0] - 2018-05-04
This version contains 188 contributions from 12 contributors. There are 141 files changed; 17,832 insertions; and 7,503 deletions.
*Please see special [upgrading instructions](https://www.pilosa.com/docs/latest/administration/#version-0-9) for this release.*
### Added
- Add ability to dynamically resize clusters ([#982](https://github.com/pilosa/pilosa/pull/982), [#946](https://github.com/pilosa/pilosa/pull/946), [#929](https://github.com/pilosa/pilosa/pull/929), [#927](https://github.com/pilosa/pilosa/pull/927), [#917](https://github.com/pilosa/pilosa/pull/917), [#913](https://github.com/pilosa/pilosa/pull/913), [#912](https://github.com/pilosa/pilosa/pull/912), [#908](https://github.com/pilosa/pilosa/pull/908))
- Update docs to include cluster-resize config and instructions ([#1088](https://github.com/pilosa/pilosa/pull/1088))
- Add support for lists of gossip seeds for redundancy ([#1133](https://github.com/pilosa/pilosa/pull/1133))
- Add HTTP Handler validation ([#1140](https://github.com/pilosa/pilosa/pull/1140), [#1121](https://github.com/pilosa/pilosa/pull/1121))
- Add validation around node-remove conditions ([#1138](https://github.com/pilosa/pilosa/pull/1138))
- broadcast.SendSync field creation and deletion to all nodes ([#1132](https://github.com/pilosa/pilosa/pull/1132))
- Spread recalculate caches to all nodes. Fixes #1069 ([#1109](https://github.com/pilosa/pilosa/pull/1109))
- Add QueryResult.Type to protobuf message to distiguish results at the client ([#1064](https://github.com/pilosa/pilosa/pull/1064))
- Modify `pilosa import` to support string rows/columns ([#1063](https://github.com/pilosa/pilosa/pull/1063))
- Add some statsd calls to HolderSyncer ([#1048](https://github.com/pilosa/pilosa/pull/1048))
- Add support for memberlist gossip configuration via pilosa.Config ([#1014](https://github.com/pilosa/pilosa/pull/1014))
- Add local and cluster IDs ([#1013](https://github.com/pilosa/pilosa/pull/1013), [#1245](https://github.com/pilosa/pilosa/pull/1245))
- Add HolderCleaner and view.DeleteFragment ([#985](https://github.com/pilosa/pilosa/pull/985))
- Add set-coordinator endpoint ([#963](https://github.com/pilosa/pilosa/pull/963))
- Implement Min/Max BSI queries ([#1191](https://github.com/pilosa/pilosa/pull/1191))
- Log time/version to startup log ([#1246](https://github.com/pilosa/pilosa/pull/1246))
- Documentation improvements ([#1135](https://github.com/pilosa/pilosa/pull/1135), [#1154](https://github.com/pilosa/pilosa/pull/1154), [#1091](https://github.com/pilosa/pilosa/pull/1091), [#1108](https://github.com/pilosa/pilosa/pull/1108), [#1087](https://github.com/pilosa/pilosa/pull/1087), [#1086](https://github.com/pilosa/pilosa/pull/1086), [#1026](https://github.com/pilosa/pilosa/pull/1026), [#1022](https://github.com/pilosa/pilosa/pull/1022), [#1007](https://github.com/pilosa/pilosa/pull/1007), [#981](https://github.com/pilosa/pilosa/pull/981), [#901](https://github.com/pilosa/pilosa/pull/901), [#972](https://github.com/pilosa/pilosa/pull/972), [#1215](https://github.com/pilosa/pilosa/pull/1215), [#1213](https://github.com/pilosa/pilosa/pull/1213), [#1224](https://github.com/pilosa/pilosa/pull/1224), [#1250](https://github.com/pilosa/pilosa/pull/1250))
### Changed
- Put Statik behind an interface ([#1163](https://github.com/pilosa/pilosa/pull/1163))
- Refactor diagnostics, inject gopsutil dependency ([#1166](https://github.com/pilosa/pilosa/pull/1166))
- Use boolean instead of address to configure coordinator ([#1158](https://github.com/pilosa/pilosa/pull/1158))
- Put GCNotify behind an interface ([#1148](https://github.com/pilosa/pilosa/pull/1148))
- Replace custom assembly bit functions with standard go ([#797](https://github.com/pilosa/pilosa/pull/797))
- Improve roaring tests ([#1115](https://github.com/pilosa/pilosa/pull/1115))
- Change configuration cluster.type (string) to cluster.disabled (bool) ([#1099](https://github.com/pilosa/pilosa/pull/1099))
- Use NodeID instead of URI for node identification ([#1077](https://github.com/pilosa/pilosa/pull/1077))
- Change gossip config from DefaultLocalConfig to DefaultWANConfig ([#1032](https://github.com/pilosa/pilosa/pull/1032))
- Use binary search in runAdd ([#1027](https://github.com/pilosa/pilosa/pull/1027))
- Use HTTP handler for gossip SendSync ([#1001](https://github.com/pilosa/pilosa/pull/1001))
- Group the write operations in syncBlock by MaxWritesPerRequest ([#950](https://github.com/pilosa/pilosa/pull/950))
- Refactor HTTPClient handling ([#991](https://github.com/pilosa/pilosa/pull/991))
- Remove FrameSchema. Move Fields to the Frame struct ([#907](https://github.com/pilosa/pilosa/pull/907))
- Refactor pilosa/server ([#1220](https://github.com/pilosa/pilosa/pull/1220))
- Clean up flipBitmap and add tests ([#1223](https://github.com/pilosa/pilosa/pull/1223))
- Move pilosa.Config to pilosa/server.Config ([#1216](https://github.com/pilosa/pilosa/pull/1216))
- Vendor github.com/golang/groupcache/lru ([#1221](https://github.com/pilosa/pilosa/pull/1221))
### Removed
- Remove the Gossip stutter from memberlist-related config options ([#1171](https://github.com/pilosa/pilosa/pull/1171))
- Remove old GossipPort and GossipSeed config options ([#1142](https://github.com/pilosa/pilosa/pull/1142))
- Remove cluster type `http` from docs ([#1130](https://github.com/pilosa/pilosa/pull/1130))
- Remove holder.Peek, combine with HasData, move server logic ([#1226](https://github.com/pilosa/pilosa/pull/1226))
- Remove PATCH frame endpoint ([#1222](https://github.com/pilosa/pilosa/pull/1222))
- Remove Index.MergeSchemas() method ([#1219](https://github.com/pilosa/pilosa/pull/1219))
- Remove references to Input Definition from the docs ([#1212](https://github.com/pilosa/pilosa/pull/1212))
- Remove Index.TimeQuantum ([#1209](https://github.com/pilosa/pilosa/pull/1209))
- Remove SecurityManager. Implement api restrictions in api package. ([#1207](https://github.com/pilosa/pilosa/pull/1207))
### Fixed
- Handle the scheme correctly in config.Bind ([#1143](https://github.com/pilosa/pilosa/pull/1143))
- Prevent excessive sendSync (createView) messages. ([#1139](https://github.com/pilosa/pilosa/pull/1139))
- Fix a shift logic bug in bitmapZeroRange ([#1110](https://github.com/pilosa/pilosa/pull/1110))
- Fix node id validation on set-coordinator ([#1102](https://github.com/pilosa/pilosa/pull/1102))
- Avoid overflow bug in differenceRunArray ([#1105](https://github.com/pilosa/pilosa/pull/1105))
- Fix bug in NewServerCluster where each host was its own coordinator ([#1101](https://github.com/pilosa/pilosa/pull/1101))
- Fix count/bitmap mismatch bug ([#1084](https://github.com/pilosa/pilosa/pull/1084))
- Fix edge case with Range() calls outside field Min/Max. Fixes #876. ([#979](https://github.com/pilosa/pilosa/pull/979))
- Bind the handler to all interfaces (0.0.0.0) in Dockerfile. Fixes #977. ([#980](https://github.com/pilosa/pilosa/pull/980))
- Fix nil client bug in monitorAntiEntropy (and test) ([#1233](https://github.com/pilosa/pilosa/pull/1233))
- Fix crash due to server.diagnostics.server not set ([#1229](https://github.com/pilosa/pilosa/pull/1229))
- Fix some cluster race conditions ([#1228](https://github.com/pilosa/pilosa/pull/1228))
### Deprecated
- Deprecate RangeEnabled option ([#1205](https://github.com/pilosa/pilosa/pull/1205))
### Performance
- Add benchmark for various container usage patterns ([#1017](https://github.com/pilosa/pilosa/pull/1017))
## [0.8.8] - 2018-02-19
This version contains 1 contribution from 2 contributors. There are 4 files changed; 1,153 insertions; and 618 deletions.
### Fixed
- Bug fixes and improved test coverage in roaring ([#1118](https://github.com/pilosa/pilosa/pull/1118))
## [0.8.7] - 2018-02-12
This version contains 1 contribution from 1 contributors. There are 2 files changed; 84 insertions; and 4 deletions.
### Fixed
- Fix a shift logic bug in bitmapZeroRange ([#1111](https://github.com/pilosa/pilosa/pull/1111))
## [0.8.6] - 2018-02-09
This version contains 2 contributions from 2 contributors. There are 3 files changed; 171 insertions; and 6 deletions.
### Fixed
- Fix overflow bug in differenceRunArray [#1106](https://github.com/pilosa/pilosa/pull/1106)
- Fix bug where count and bitmap queries could return different numbers [#1083](https://github.com/pilosa/pilosa/pull/1083)
## [0.8.5] - 2018-01-18
This version contains 1 contribution from 1 contributor. There is 1 file changed; 1 insertion, and 0 deletions.
### Fixed
- Bind Docker container on all interfaces ([#1061](https://github.com/pilosa/pilosa/pull/1061))
## [0.8.4] - 2018-01-10
This version contains 4 contributions from 3 contributors. There are 17 files changed; 974 insertions; and 221 deletions.
### Fixed
- Group the write operations in syncBlock by MaxWritesPerRequest ([#1038](https://github.com/pilosa/pilosa/pull/1038))
- Change gossip config from memberlist.DefaultLocalConfig to memberlist.DefaultWANConfig ([#1033](https://github.com/pilosa/pilosa/pull/1033))
### Performance
- Change AttrBlock handler calls to support protobuf instead of json ([#1046](https://github.com/pilosa/pilosa/pull/1046))
- Use RLock instead of Lock in a few places ([#1042](https://github.com/pilosa/pilosa/pull/1042))
## [0.8.3] - 2017-12-12
This version contains 1 contribution from 1 contributor. There are 2 files changed; 59 insertions; and 42 deletions.
### Fixed
- Protect against accessing pointers to memory which was unmapped ([#1000](https://github.com/pilosa/pilosa/pull/1000))
## [0.8.2] - 2017-12-05
This version contains 1 contribution from 1 contributor. There are 15 files changed; 127 insertions; and 98 deletions.
### Fixed
- Modify initialization of HTTP client so only one instance is created ([#994](https://github.com/pilosa/pilosa/pull/994))
## [0.8.1] - 2017-11-15
This version contains 2 contributions from 2 contributors. There are 4 files changed; 27 insertions; and 14 deletions.
### Fixed
- Fix CountOpenFiles() fatal crash ([#969](https://github.com/pilosa/pilosa/pull/969))
- Fix version check when local is greater than pilosa.com ([#968](https://github.com/pilosa/pilosa/pull/968))
## [0.8.0] - 2017-11-15
This version contains 31 contributions from 8 contributors. There are 84 files changed; 3,732 insertions; and 1,428 deletions.
### Added
- Diagnostics ([#895](https://github.com/pilosa/pilosa/pull/895))
- Add docker-build make target for repeatable Docker-based builds ([#933](https://github.com/pilosa/pilosa/pull/933))
- Add documentation on importing field values; fixes #924 ([#938](https://github.com/pilosa/pilosa/pull/938))
- Add flag documentation and tests, remove "plugins.path" ([#942](https://github.com/pilosa/pilosa/pull/942))
- Add TLS support ([#867](https://github.com/pilosa/pilosa/pull/867))
- Add TLS cluster how to ([#898](https://github.com/pilosa/pilosa/pull/898))
- Add support for gossip encryption ([#889](https://github.com/pilosa/pilosa/pull/889))
- Add Recalculate Caches endpoint ([#881](https://github.com/pilosa/pilosa/pull/881))
- Add search-friendly documentation for BSI range query syntax ([#955](https://github.com/pilosa/pilosa/pull/955))
### Changed
- Remove unneeded Gopkg.toml constraints and update all dependencies ([#943](https://github.com/pilosa/pilosa/pull/943))
- Remove row and column labels in webUI ([#884](https://github.com/pilosa/pilosa/pull/884))
- Internal Client refactoring ([#892](https://github.com/pilosa/pilosa/pull/892))
- Remove column/row labels for input definition ([#945](https://github.com/pilosa/pilosa/pull/945))
- Update dependencies and Go version ([#878](https://github.com/pilosa/pilosa/pull/878))
### Fixed
- Skip permissions test when run as root. Fixes #940 ([#941](https://github.com/pilosa/pilosa/pull/941))
- Address "connection reset" issues in client ([#934](https://github.com/pilosa/pilosa/pull/934))
- Fix field value import: Use signed int and respect field minimum ([#919](https://github.com/pilosa/pilosa/pull/919))
- Constrain BoltDB to version rather than specific revision ([#887](https://github.com/pilosa/pilosa/pull/887))
- Fix bug in environment variable format ([#882](https://github.com/pilosa/pilosa/pull/882))
- Fix overflow in differenceRunBitmap ([#949](https://github.com/pilosa/pilosa/pull/949))
### Performance
- Use FieldNotNull to improve efficiency of BETWEEN queries ([#874](https://github.com/pilosa/pilosa/pull/874))
## [0.7.2] - 2017-11-15
This version contains 1 contribution from 1 contributor. There is 1 file changed; 16 insertions; and 1 deletion.
### Changed
- Bump HTTP client's MaxIdleConns and MaxIdleConnsPerHost ([#920](https://github.com/pilosa/pilosa/pull/920))
## [0.7.1] - 2017-10-09
This version contains 3 contributions from 3 contributors. There are 14 files changed; 221 insertions; and 52 deletions.
### Changed
- Update dependencies and Go version ([#878](https://github.com/pilosa/pilosa/pull/878))
### Performance
- Leverage not-null field to make BETWEEN queries more efficient ([#874](https://github.com/pilosa/pilosa/pull/874))
## [0.7.0] - 2017-10-03
This version contains 59 contributions from 9 contributors. There are 61 files changed; 5207 insertions; and 1054 deletions.
### Added
- Add HTTP API for fields ([#811](https://github.com/pilosa/pilosa/pull/811), [#856](https://github.com/pilosa/pilosa/pull/856))
- Add HTTP API for delete views ([#785](https://github.com/pilosa/pilosa/pull/785))
- Modify import endpoint to handle BSI field values ([#840](https://github.com/pilosa/pilosa/pull/840))
- Add field Range() support to Executor ([#791](https://github.com/pilosa/pilosa/pull/791))
- Support PQL Range() queries for fields ([#755](https://github.com/pilosa/pilosa/pull/755))
- Add Sum() field query ([#778](https://github.com/pilosa/pilosa/pull/778))
- Add documentation for BSI ([#861](https://github.com/pilosa/pilosa/pull/861))
- Add BETWEEN for Range queries ([#847](https://github.com/pilosa/pilosa/pull/847))
- Add Xor support for PQL ([#789](https://github.com/pilosa/pilosa/pull/789))
- Enable auto-creating the schema on imports ([#837](https://github.com/pilosa/pilosa/pull/837))
- Update client library docs ([#831](https://github.com/pilosa/pilosa/pull/831))
- Handle SIGTERM signal ([#830](https://github.com/pilosa/pilosa/pull/830))
- Add cluster config example to docs ([#806](https://github.com/pilosa/pilosa/pull/806))
- Add ability to exclude attributes and bits in Bitmap queries ([#783](https://github.com/pilosa/pilosa/pull/783))
### Fixed
- Fix panic when iterating over an empty run container ([#860](https://github.com/pilosa/pilosa/pull/860))
- Fix row id zero bug ([#814](https://github.com/pilosa/pilosa/pull/814))
- Fix cache invalidation bug ([#795](https://github.com/pilosa/pilosa/pull/795))
- Set container.n in differenceRunRun ([#794](https://github.com/pilosa/pilosa/pull/794))
- Fix infinite loop in bitmap-to-array conversion ([#779](https://github.com/pilosa/pilosa/pull/779))
- Fix CountRange bug ([#773](https://github.com/pilosa/pilosa/pull/773))
### Deprecated
- Remove support for row/column labels ([#839](https://github.com/pilosa/pilosa/pull/839))
### Performance
- Refactor differenceRunArray ([#859](https://github.com/pilosa/pilosa/pull/859))
- Update fragment.FieldSum to use roaring IntersectionCount() ([#841](https://github.com/pilosa/pilosa/pull/841))
- Add roaring optimizations ([#842](https://github.com/pilosa/pilosa/pull/842))
- Convert lock to read lock ([#848](https://github.com/pilosa/pilosa/pull/848))
- Reduce Lock calls in executor ([#846](https://github.com/pilosa/pilosa/pull/846))
- Implement container.flipBitmap() to improve differenceRunBitmap() ([#849](https://github.com/pilosa/pilosa/pull/849))
- Reuse container storage on UnmarshalBinary to improve memory utilization ([#820](https://github.com/pilosa/pilosa/pull/820))
- Improve WriteTo performance ([#812](https://github.com/pilosa/pilosa/pull/812))
## [0.6.0] - 2017-08-11
This version contains 14 contributions from 5 contributors. There are 28 files changed; 4,936 insertions; and 692 deletions.
### Added
- Add Run-length Encoding ([#758](https://github.com/pilosa/pilosa/pull/758))
### Changed
- Make gossip the default broadcast type ([#750](https://github.com/pilosa/pilosa/pull/750))
### Fixed
- Fix CountRange ([#759](https://github.com/pilosa/pilosa/pull/759))
- Fix `differenceArrayRun` logic ([#674](https://github.com/pilosa/pilosa/pull/674))
## [0.5.0] - 2017-08-02
This version contains 65 contributions from 8 contributors (including 1 volunteer contributor). There are 79 files changed; 7,972 insertions; and 2,800 deletions.
### Added
- Set open file limit during Pilosa startup ([#748](https://github.com/pilosa/pilosa/pull/748))
- Add Input Definition ([#646](https://github.com/pilosa/pilosa/pull/646))
- Add cache type: None ([#745](https://github.com/pilosa/pilosa/pull/745))
- Add panic recovery in top level HTTP handler ([#741](https://github.com/pilosa/pilosa/pull/741))
- Count open file handles as a StatsD metric ([#636](https://github.com/pilosa/pilosa/pull/636))
- Add coverage tools to Makefile ([#635](https://github.com/pilosa/pilosa/pull/635))
- Add Holder test coverage ([#629](https://github.com/pilosa/pilosa/pull/629))
- Add runtime memory metrics ([#600](https://github.com/pilosa/pilosa/pull/600))
- Add sorting flag to import command ([#606](https://github.com/pilosa/pilosa/pull/606))
- Add PQL support for field values (WIP) ([#721](https://github.com/pilosa/pilosa/pull/721))
- Set and retrieve field values (WIP) ([#702](https://github.com/pilosa/pilosa/pull/702))
- Add BSI range-encoding schema support (WIP) ([#670](https://github.com/pilosa/pilosa/pull/670))
### Changed
- Move InternalPort config option to top-level ([#747](https://github.com/pilosa/pilosa/pull/747))
- Switch from glide to dep for dependency management ([#744](https://github.com/pilosa/pilosa/pull/744))
- Remove QueryRequest.Quantum since it is no longer used ([#699](https://github.com/pilosa/pilosa/pull/699))
- Refactor test utilities into importable package ([#675](https://github.com/pilosa/pilosa/pull/675))
### Fixed
- Add mutex for attribute cache ([#729](https://github.com/pilosa/pilosa/pull/729))
- Use log-path flag to specify log file ([#678](https://github.com/pilosa/pilosa/pull/678))
## [0.4.0] - 2017-06-08
This version contains 53 contributions from 13 contributors (including 4 volunteer contributors). There are 96 files changed; 6373 insertions; and 770 deletions.
*Note that data files created in Pilosa < 0.4.0 are not compatible with Pilosa 0.4.0 as a result of [#520](https://github.com/pilosa/pilosa/pull/520).*
### Added
- Support metric reporting through StatsD protocol ([#468](https://github.com/pilosa/pilosa/pull/468), [#568](https://github.com/pilosa/pilosa/pull/568), [#580](https://github.com/pilosa/pilosa/pull/580))
- Improve test coverage for ctl package ([#586](https://github.com/pilosa/pilosa/pull/586))
- Add support for bit flip (negate) in roaring ([#592](https://github.com/pilosa/pilosa/pull/592))
- Add xor support to roaring ([#571](https://github.com/pilosa/pilosa/pull/571))
- Improve WebUI autocomplete ([#560](https://github.com/pilosa/pilosa/pull/560))
- Add syntax hints tooltip to WebUI ([#537](https://github.com/pilosa/pilosa/pull/537))
- Implement 'config' CLI command ([#541](https://github.com/pilosa/pilosa/pull/541))
- Move docs into repo ([#563](https://github.com/pilosa/pilosa/pull/563))
- Add inverse TopN() support ([#551](https://github.com/pilosa/pilosa/pull/551))
- Add various Makefile updates ([#540](https://github.com/pilosa/pilosa/pull/540))
- Provide details on Glide checksum mismatch ([#546](https://github.com/pilosa/pilosa/pull/546))
- Add Docker multi-stage build ([#535](https://github.com/pilosa/pilosa/pull/535))
- Support inverse Range() queries ([#533](https://github.com/pilosa/pilosa/pull/533))
- Support colon commands in WebUI ([#529](https://github.com/pilosa/pilosa/pull/529), [#510](https://github.com/pilosa/pilosa/pull/510))
### Changed
- Increase default partition count from 16 to 256 (BREAKING CHANGE) ([#520](https://github.com/pilosa/pilosa/pull/520))
- Validate unknown query params ([#578](https://github.com/pilosa/pilosa/pull/578))
- Validate configuration file ([#573](https://github.com/pilosa/pilosa/pull/573))
- Change default cache type to ranked ([#524](https://github.com/pilosa/pilosa/pull/524))
- Add max-writes-per-requests limit ([#525](https://github.com/pilosa/pilosa/pull/525))
### Fixed
- Add "make test" to PHONY section of Makefile ([#605](https://github.com/pilosa/pilosa/pull/605))
- Fix failing tests when IPv6 is disabled ([#594](https://github.com/pilosa/pilosa/pull/594))
- Add minor docs fix, indent in JSON ([#599](https://github.com/pilosa/pilosa/pull/599))
- Fix BroadcastHandler handle missing index error ([#597](https://github.com/pilosa/pilosa/pull/597))
- Add WebUI fixes ([#589](https://github.com/pilosa/pilosa/pull/589))
- Fix support for 32-bit Linux ([#549](https://github.com/pilosa/pilosa/pull/549), [#565](https://github.com/pilosa/pilosa/pull/565))
- Fix 3 separate bugs in bitmapCountRange ([#559](https://github.com/pilosa/pilosa/pull/559))
- Add client support for MaxInverseSliceByIndex ([#555](https://github.com/pilosa/pilosa/pull/555))
- Fix bug in `handleGetSliceMax` ([#554](https://github.com/pilosa/pilosa/pull/554))
- Default to `standard` view in export command ([#548](https://github.com/pilosa/pilosa/pull/548))
- Fix vet issues with the assembly code in Roaring ([#528](https://github.com/pilosa/pilosa/pull/528))
- Prevent row labels that match the column label ([#503](https://github.com/pilosa/pilosa/pull/503))
- Fix roaring test: TestBitmap_Quick_Array1 ([#507](https://github.com/pilosa/pilosa/pull/507))
- Don't try to create inverse views on Import() when inverseEnabled is false ([#462](https://github.com/pilosa/pilosa/pull/462))
### Performance
- Set n based on array length instead of incrementing repeatedly ([#590](https://github.com/pilosa/pilosa/pull/590))
- Rewrite intersectCountArrayBitmap for perf test ([#577](https://github.com/pilosa/pilosa/pull/577))
- Check for duplicate attributes under read lock on insert ([#562](https://github.com/pilosa/pilosa/pull/562))
[Unreleased]: https://github.com/pilosa/pilosa/compare/v1.2...HEAD
[0.4.0]: https://github.com/pilosa/pilosa/compare/v0.3...v0.4
[0.5.0]: https://github.com/pilosa/pilosa/compare/v0.4...v0.5
[0.6.0]: https://github.com/pilosa/pilosa/compare/v0.5...v0.6
[0.7.0]: https://github.com/pilosa/pilosa/compare/v0.6...v0.7
[0.8.0]: https://github.com/pilosa/pilosa/compare/v0.7...v0.8
[0.9.0]: https://github.com/pilosa/pilosa/compare/v0.8...v0.9
[0.10.0]: https://github.com/pilosa/pilosa/compare/v0.9...v0.10
[1.0.0]: https://github.com/pilosa/pilosa/compare/v0.10...v1.0
[1.1.0]: https://github.com/pilosa/pilosa/compare/v1.0...v1.1
[1.2.0]: https://github.com/pilosa/pilosa/compare/v1.1...v1.2

View file

@ -1,133 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
community@featurebase.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

177
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,177 @@
# Contributing to Pilosa
The workflow components of these instructions apply to all Pilosa repositories.
## Reporting a bug
If you have discovered a bug and don't see it in the [github issue tracker][5], [open a new issue][1].
## Submitting a feature request
Feature requests are managed in Github issues, organized with [Zenhub](https://www.zenhub.com/), which is publicly available as a browser extension. New features typically go through a [Proposal Process][4]
which starts by [opening a new issue][1] that describes the new feature proposal.
## Making code contributions
Before you start working on new features, you should [open a new issue][1] to let others know what
you're doing, otherwise you run the risk of duplicating effort. This also
gives others an opportunity to provide input for your feature.
If you want to help but you aren't sure where to start, check out our [github label for low-effort issues][6].
### Development Environment
- Ensure you have a recent version of [Go](https://golang.org/doc/install) installed. Pilosa generally supports the current and previous minor versions; check our [CircleCI config file](../master/.circleci/config.yml) for the most up-to-date information.
- Make sure `$GOPATH` environment variable points to your Go working directory and `$PATH` incudes `$GOPATH/bin`, as described [here](https://golang.org/doc/code.html#GOPATH).
- Fork the [Pilosa repository][2] to your own account.
- It will be easier to follow these instructions if you:
```sh
export GH_USERNAME=<your github username>
```
- Create a directory (note that we use `github.com/pilosa`, NOT `github.com/USER`) and clone Pilosa:
```sh
mkdir -p ${GOPATH}/src/github.com/pilosa && cd $_
git clone https://github.com/pilosa/pilosa.git
```
- `cd` to your pilosa directory:
```sh
cd ${GOPATH}/src/github.com/pilosa/pilosa
```
- Install Pilosa command line tools:
```sh
make install
```
Running `pilosa` should now run a Pilosa instance.
- The official Pilosa repository is your "origin" remote in git. Add your fork as your github username
```sh
cd ${GOPATH}/src/github.com/pilosa/pilosa
git remote add ${GH_USERNAME} git@github.com:${GH_USERNAME}/pilosa.git
```
### Makefile
Pilosa includes a Makefile that automates several tasks:
- Install Pilosa:
```sh
make install
```
- Install build dependencies:
```sh
make install-build-deps
```
- Create the vendor directory:
```sh
make vendor
```
- Run the test suite:
```sh
make test
```
- View the coverage report:
```sh
make cover-viz
```
- Clear the `vendor/` and `build/` directories:
```sh
make clean
```
- Create release tarballs:
```sh
make release
```
- Regenerate protocol buffer files in `internal/`:
```sh
make generate-protoc
```
- Create tagged Docker image:
```sh
make docker
```
- Run tests inside Docker container:
```sh
make docker-test
```
Additional commands are available in the `Makefile`.
### Submitting code changes
- Before starting to work on a task, sync your branch with the upstream:
```sh
git checkout master
git pull
```
- Create a local feature branch:
```sh
git checkout -b something-amazing
```
- Commit your changes locally using `git add` and `git commit`. Please use [appropriate commit messages](https://chris.beams.io/posts/git-commit/).
- Make sure that you've written tests for your new feature, and then run the tests:
```sh
make test
```
- Verify that your pull request is applied to the latest version of code on github:
```sh
git checkout master
git pull
git checkout something-amazing
git rebase master
```
- Push to your fork:
```sh
git push -u $GH_USERNAME something-amazing:something-amazing
```
- Submit a [pull request][3]
[1]: https://github.com/pilosa/pilosa/issues/new
[2]: https://github.com/pilosa/pilosa
[3]: https://github.com/pilosa/pilosa/compare/
[4]: https://github.com/pilosa/general/blob/master/proposal.md
[5]: https://github.com/pilosa/pilosa/issues
[6]: https://github.com/pilosa/pilosa/issues?q=is%3Aopen+is%3Aissue+label%3Anewcomer

View file

@ -4,7 +4,7 @@ ARG GO_VERSION=latest
### Lattice builder ###
#######################
FROM ghcr.io/featurebasedb/nodejs:0.0.1 as lattice-builder
FROM moleculacorp/nodejs:latest as lattice-builder
WORKDIR /lattice
COPY lattice/package.json ./
@ -20,18 +20,15 @@ RUN yarn build
FROM golang:${GO_VERSION} as pilosa-builder
ARG MAKE_FLAGS
ARG SOURCE_DATE_EPOCH
WORKDIR /pilosa
RUN go install github.com/rakyll/statik@v0.1.7
RUN go get github.com/rakyll/statik
COPY . ./
COPY --from=lattice-builder /lattice/build /lattice
RUN /go/bin/statik -src=/lattice -dest=/pilosa
ENV SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}
RUN make build FLAGS="-o build/featurebase" ${MAKE_FLAGS}
RUN make build FLAGS="-o build/pilosa" ${MAKE_FLAGS}
#####################
### Pilosa runner ###
@ -41,10 +38,11 @@ FROM alpine:3.13.2 as runner
LABEL maintainer "dev@molecula.com"
RUN apk add --no-cache curl jq tree
RUN apk add --no-cache curl jq
COPY --from=pilosa-builder /pilosa/build/featurebase /
COPY --from=pilosa-builder /pilosa/build/pilosa /
COPY LICENSE /LICENSE
COPY NOTICE /NOTICE
EXPOSE 10101
@ -54,5 +52,5 @@ ENV PILOSA_DATA_DIR /data
ENV PILOSA_BIND 0.0.0.0:10101
ENV PILOSA_BIND_GRPC 0.0.0.0:20101
ENTRYPOINT ["/featurebase"]
ENTRYPOINT ["/pilosa"]
CMD ["server"]

View file

@ -1,38 +1,26 @@
# This Dockerfile is used for cluster testing - it produces a much larger image
# and includes all of Go as well as some utilities.
FROM golang:1.19
FROM golang:1.13
LABEL maintainer "dev@pilosa.com"
COPY . /go/src/github.com/featurebasedb/featurebase/
COPY . /go/src/github.com/pilosa/pilosa/
RUN cd /go/src/github.com/pilosa/pilosa \
&& make install FLAGS="-a -mod=vendor"
# download pumba for fault injection
ADD https://github.com/alexei-led/pumba/releases/download/0.6.0/pumba_linux_amd64 /pumba
RUN chmod +x /pumba
# add docker client to pause/unpause nodes
RUN apt update
RUN apt install -y docker.io
# add docker-compose so tests can use it for stuff
ADD https://github.com/docker/compose/releases/latest/download/docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
RUN chmod +x /usr/local/bin/docker-compose
WORKDIR /go/src/github.com/featurebasedb/featurebase/cmd/featurebase
# generate an instrumented binary to allow for calculating code coverage for clustertests
# the entrypoint for the binary is TestRunMain, which is wrapper for main
RUN go test -covermode=atomic -coverpkg=../../... -c -tags testrunmain -o featurebase
RUN cp /go/src/github.com/featurebasedb/featurebase/cmd/featurebase/featurebase /featurebase
RUN cp /go/bin/pilosa /pilosa
COPY LICENSE /LICENSE
COPY NOTICE /NOTICE
EXPOSE 10101
VOLUME /data
# use e.g. "-test.coverprofile=/results/coverage.out"
CMD ["/featurebase", "-test.run=TestRunMain", "server"]
ENTRYPOINT ["bash", "-c"]
CMD ["/pilosa", "server", "--data-dir", "/data", "--bind", "http://0.0.0.0:10101"]

View file

@ -1,37 +0,0 @@
# This Dockerfile is used for cluster testing - it produces a much larger image
# and includes all of Go as well as some utilities.
FROM golang:1.19
LABEL maintainer "dev@pilosa.com"
COPY . /go/src/github.com/featurebasedb/featurebase/
# download pumba for fault injection
ADD https://github.com/alexei-led/pumba/releases/download/0.6.0/pumba_linux_amd64 /pumba
RUN chmod +x /pumba
# add docker client to pause/unpause nodes
RUN apt update
RUN apt install -y docker.io
# add docker-compose so tests can use it for stuff
ADD https://github.com/docker/compose/releases/latest/download/docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
RUN chmod +x /usr/local/bin/docker-compose
WORKDIR /go/src/github.com/featurebasedb/featurebase/cmd/featurebase
RUN go test -covermode=atomic -coverpkg=../../... -c -tags testrunmain -o featurebase
RUN cp /go/src/github.com/featurebasedb/featurebase/cmd/featurebase/featurebase /featurebase
COPY NOTICE /NOTICE
COPY ./internal/clustertests /go/src/github.com/featurebasedb/featurebase/internal/clustertests
EXPOSE 10101
VOLUME /data
WORKDIR /go/src/github.com/featurebasedb/featurebase
CMD ["/featurebase", "-test.run=TestRunMain", "-test.coverprofile=/results/coverage.out", "server", "--data-dir", "/data", "--bind", "http://0.0.0.0:10101"]

View file

@ -1,47 +0,0 @@
# syntax=docker/dockerfile:1
##########################
### datagen builder ###
##########################
FROM golang:alpine as builder
WORKDIR /featurebase
COPY . ./
RUN apk add --no-cache build-base bash git make librdkafka pkgconfig
# install librdkafka
RUN git clone https://github.com/edenhill/librdkafka.git
RUN cd librdkafka && ./configure --prefix /usr && make && make install
ENV PKG_CONFIG_PATH=/usr/lib/pkgconfig/
RUN cd idk && make build-datagen
# ENTRYPOINT ["tail", "-f", "/dev/null"]
#########################
### datagen runner ###
#########################
FROM alpine:3.15.3 as runner
WORKDIR /
LABEL maintainer "dev@molecula.com"
RUN apk add --no-cache curl jq
COPY --from=builder /featurebase/idk/build/datagen /bin/
COPY --from=builder /usr/lib/librdkafka* /usr/lib/
COPY idk/datagen/testdata/* /testdata/
EXPOSE 8080
# VOLUME /data
# ENV ADDR 0.0.0.0:8080
#ENTRYPOINT ["sleep", "infinity"]
ENTRYPOINT ["datagen"]

View file

@ -1,32 +0,0 @@
ARG GO_VERSION=latest
###########################
### FeatureBase Builder ###
###########################
FROM golang:${GO_VERSION} as featurebase-builder
ARG MAKE_FLAGS
WORKDIR /fb
COPY . ./
RUN make build FLAGS="-o build/featurebase" ${MAKE_FLAGS}
##########################
### FeatureBase runner ###
##########################
FROM golang:alpine as runner
LABEL maintainer "dev@featurebase.com"
RUN apk add --no-cache curl jq tree
COPY --from=featurebase-builder /fb/build/featurebase /
COPY NOTICE /NOTICE
EXPOSE 8080
ENTRYPOINT ["/featurebase"]
CMD ["dax"]

View file

@ -1,18 +0,0 @@
ARG GO_VERSION=latest
##########################
### FeatureBase runner ###
##########################
FROM alpine:3.13.2 as runner
LABEL maintainer "dev@featurebase.com"
RUN apk add --no-cache curl jq tree
COPY ./fb_linux /featurebase
EXPOSE 8080
ENTRYPOINT ["/featurebase"]
CMD ["dax"]

View file

@ -1,48 +0,0 @@
ARG GO_VERSION=1.19
FROM golang:1.19-buster as builder
WORKDIR /
RUN apt-get update -y -qq && apt-get install -y -qq \
build-essential \
git \
musl-tools \
netcat \
unixodbc \
unixodbc-dev \
&& rm -rf /var/lib/apt/lists/*
RUN ["git", "clone", "https://github.com/edenhill/librdkafka.git"]
WORKDIR /librdkafka
RUN ./configure --prefix /usr && \
make && \
make install
WORKDIR /featurebase
COPY . .
ARG MAKE_FLAGS
ARG GO_BUILD_FLAGS
ARG SOURCE_DATE_EPOCH
WORKDIR /featurebase/
ENV SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH}
RUN make build-fbsql GO_BUILD_FLAGS="-mod=vendor ${GO_BUILD_FLAGS}" ${MAKE_FLAGS}
FROM ubuntu:20.04 as runner
RUN apt-get update -y -qq && apt-get install -y -qq \
ca-certificates \
musl-tools \
netcat \
unixodbc-dev \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /featurebase/fbsql /usr/local/bin/
# Verify that the linker can find everything.
FROM runner as linkcheck
RUN if [ -e /usr/local/bin/fbsql ] ; then ldd /usr/local/bin/fbsql; fi
FROM runner

View file

@ -1,3 +1,4 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
@ -186,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2023 Molecula Corp. All rights reserved.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View file

@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

428
Makefile
View file

@ -1,38 +1,37 @@
.PHONY: build clean build-lattice cover cover-viz default docker docker-build docker-build-fbsql docker-tag-push generate generate-protoc generate-pql generate-statik generate-stringer install install-protoc-gen-gofast install-protoc install-statik install-peg test docker-login
.PHONY: build check-clean clean build-lattice cover cover-viz default docker docker-build docker-test docker-tag-push generate generate-protoc generate-pql generate-statik gometalinter install install-build-deps install-golangci-lint install-gometalinter install-protoc install-protoc-gen-gofast install-peg install-statik release release-build test testv testv-race testvsub testvsub-race test-txstore-rbf
SHELL := /bin/bash
CLONE_URL=github.com/pilosa/pilosa
MOD_VERSION=v2
VERSION := $(shell git describe --tags 2> /dev/null || echo unknown)
VARIANT = Molecula
GO=go
GOOS=$(shell $(GO) env GOOS)
GOARCH=$(shell $(GO) env GOARCH)
VERSION_ID=$(if $(TRIAL_DEADLINE),trial-$(TRIAL_DEADLINE)-,)$(VERSION)-$(GOOS)-$(GOARCH)
DATE_FMT="+%FT%T%z"
# set SOURCE_DATE_EPOCH like this to use the last git commit timestamp
# export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) instead of the current time from running `date`
ifdef SOURCE_DATE_EPOCH
BUILD_TIME ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u "$(DATE_FMT)")
else
BUILD_TIME ?= $(shell date -u "$(DATE_FMT)")
endif
BRANCH := $(if $(CIRCLE_BRANCH),$(CIRCLE_BRANCH),$(shell git rev-parse --abbrev-ref HEAD))
BRANCH_ID := $(BRANCH)-$(GOOS)-$(GOARCH)
BUILD_TIME := $(shell date -u +%FT%T%z)
SHARD_WIDTH = 20
COMMIT := $(shell git describe --exact-match >/dev/null 2>&1 || git rev-parse --short HEAD)
LDFLAGS="-X github.com/featurebasedb/featurebase/v3.Version=$(VERSION) -X github.com/featurebasedb/featurebase/v3.BuildTime=$(BUILD_TIME) -X github.com/featurebasedb/featurebase/v3.Variant=$(VARIANT) -X github.com/featurebasedb/featurebase/v3.Commit=$(COMMIT) -X github.com/featurebasedb/featurebase/v3.TrialDeadline=$(TRIAL_DEADLINE)"
GO_VERSION=1.19
GO_BUILD_FLAGS=
LDFLAGS="-X github.com/pilosa/pilosa/v2.Version=$(VERSION) -X github.com/pilosa/pilosa/v2.BuildTime=$(BUILD_TIME) -X github.com/pilosa/pilosa/v2.Variant=$(VARIANT) -X github.com/pilosa/pilosa/v2.Commit=$(COMMIT) -X github.com/pilosa/pilosa/v2.TrialDeadline=$(TRIAL_DEADLINE)"
GO_VERSION=1.16.3
DOCKER_BUILD= # set to 1 to use `docker-build` instead of `build` when creating a release
BUILD_TAGS +=
BUILD_TAGS += shardwidth$(SHARD_WIDTH)
TEST_TAGS = roaringparanoia
TEST_TIMEOUT=10m
RACE_TEST_TIMEOUT=10m
# size in GB to use for ramdisk, ?= so you can override it with env
# 4GB is not enough for `make test`, 8GB usually is.
RAMDISK_SIZE ?= 8
define LICENSE_HASH_CODE
head -13 $1 | sed -e 's/Copyright 20[0-9][0-9]/Copyright 20XX/g' | shasum | cut -f 1 -d " "
endef
LICENSE_HASH=$(shell $(call LICENSE_HASH_CODE, pilosa.go))
UNAME := $(shell uname -s)
ifeq ($(UNAME), Darwin)
IS_MACOS:=1
else
IS_MACOS:=0
endif
export GO111MODULE=on
export GOPRIVATE=github.com/molecula
export CGO_ENABLED=0
AWS_ACCOUNTID ?= undefined
# Run tests and compile Pilosa
default: test build
@ -40,30 +39,22 @@ default: test build
# Remove build directories
clean:
rm -rf vendor build
rm -f *.rpm *.deb
# Set up vendor directory using `go mod vendor`
vendor: go.mod
$(GO) mod vendor
version:
@echo $(VERSION)
# We build a list of packages that omits the IDK and batch packages because
# those packages require fancy environment setup.
GOPACKAGES := $(shell $(GO) list ./... | grep -v "/v3/idk" | grep -v "/v3/batch")
# Run test suite
test:
$(GO) test $(GOPACKAGES) -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -v -timeout $(TEST_TIMEOUT) -count=1
$(GO) test ./... -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -v
# Run test suite with race flag
test-race:
CGO_ENABLED=1 $(GO) test $(GOPACKAGES) -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -race -timeout $(RACE_TEST_TIMEOUT) -v
CGO_ENABLED=1 $(GO) test ./... -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -race -timeout 60m -v
testv: testvsub
testv: topt testvsub
testv-race: testvsub-race
testv-race: topt-race testvsub-race
# testvsub: run go test -v in sub-directories in "local mode" with incremental output,
# avoiding go -test ./... "package list mode" which doesn't give output
@ -71,42 +62,28 @@ testv-race: testvsub-race
# find which test is hung/deadlocked.
#
testvsub:
@set -e; for pkg in $(GOPACKAGES); do \
if [ $${pkg:0:38} == "github.com/featurebasedb/featurebase/v3/idk" ]; then \
echo; echo "___ skipping subpkg $$pkg"; \
continue; \
fi; \
echo; echo "___ testing subpkg $$pkg"; \
$(GO) test -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -v -timeout $(RACE_TEST_TIMEOUT) $$pkg || break; \
echo; echo "999 done testing subpkg $$pkg"; \
done
# make a $(RAMDISK_SIZE)GB RAMDisk. Speed up tests by running
# them with TMPDIR=/mnt/ramdisk.
ramdisk-linux:
mount -o size=$(RAMDISK__SIZE)G -t tmpfs none /mnt/ramdisk
# make a $(RAMDISK_SIZE)GB RAMDisk. Speed up tests by running
# them with TMPDIR=/Volumes/RAMDisk. This is more important on
# OS X than it is on Linux, because there's performance issues
# with fsync on OS X that can make the SSD slow down to moving-platters
# drive speeds. Oops.
ramdisk-osx:
diskutil erasevolume HFS+ 'RAMDisk' $$(hdiutil attach -nobrowse -nomount ram://$$(expr 2097152 \* $(RAMDISK_SIZE)))
detach-ramdisk-osx:
hdiutil detach /Volumes/RAMDisk
testvsub-race:
@set -e; for pkg in $(GOPACKAGES); do \
echo; echo "___ testing subpkg $$pkg"; \
CGO_ENABLED=1 $(GO) test -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -v -race -timeout $(RACE_TEST_TIMEOUT) $$pkg || break; \
echo; echo "999 done testing subpkg $$pkg"; \
set -e; for i in boltdb client ctl http pg pql rbf roaring server sql txkey; do \
echo; echo "___ testing subpkg $$i"; \
cd $$i; pwd; \
$(GO) test -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -v -timeout 60m || break; \
echo; echo "999 done testing subpkg $$i"; \
cd ..; \
done
testvsub-race:
set -e; for i in boltdb client ctl http pg pql rbf roaring server sql txkey; do \
echo; echo "___ testing subpkg $$i -race"; \
cd $$i; pwd; \
CGO_ENABLED=1 $(GO) test -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -v -race -timeout 60m || break; \
echo; echo "999 done testing subpkg $$i -race"; \
cd ..; \
done
tour:
./tournament.sh
bench:
$(GO) test $(GOPACKAGES) -bench=. -run=NoneZ -timeout=127m $(TESTFLAGS)
$(GO) test ./... -bench=. -run=NoneZ -timeout=127m $(TESTFLAGS)
# Run test suite with coverage enabled
cover:
@ -117,53 +94,60 @@ cover:
cover-viz: cover
$(GO) tool cover -html=build/coverage.out
# Build featurebase
# Compile Pilosa
build:
$(GO) build -tags='$(BUILD_TAGS)' -ldflags $(LDFLAGS) $(FLAGS) ./cmd/featurebase
$(GO) build -tags='$(BUILD_TAGS)' -ldflags $(LDFLAGS) $(FLAGS) ./cmd/pilosa
package:
GOOS=$(GOOS) GOARCH=$(GOARCH) $(MAKE) build
GOOS=$(GOOS) GOARCH=$(GOARCH) $(MAKE) build-fbsql
GOARCH=$(GOARCH) VERSION=$(VERSION) nfpm package --packager deb --target featurebase.$(VERSION).$(GOARCH).deb
GOARCH=$(GOARCH) VERSION=$(VERSION) nfpm package --packager rpm --target featurebase.$(VERSION).$(GOARCH).rpm
# Create a single release build under the build directory
release-build:
$(MAKE) $(if $(DOCKER_BUILD),docker-)build FLAGS="-o build/pilosa-$(VERSION_ID)/pilosa"
cp NOTICE README.md LICENSE build/pilosa$(VERSION_ID)
tar -cvz -C build -f build/pilosa-$(VERSION_ID).tar.gz pilosa-$(VERSION_ID)/
@echo Created release build: build/pilosa-$(VERSION_ID).tar.gz
# We allow setting a custom docker-compose "project". Multiple of the
# same docker-compose environment can exist simultaneously as long as
# they use different projects (the project name is prepended to
# container names and such). This is useful in a CI environment where
# we might be running multiple instances of the tests concurrently.
PROJECT ?= clustertests
DOCKER_COMPOSE = docker-compose -p $(PROJECT)
# Error out if there are untracked changes in Git
check-clean:
ifndef SKIP_CHECK_CLEAN
$(if $(shell git status --porcelain),$(error Git status is not clean! Please commit or checkout/reset changes.))
endif
# Create release build tarballs for all supported platforms. DEPRECATED: Use `docker-release`
release: check-clean generate-statik-docker
$(MAKE) release-build GOOS=darwin GOARCH=amd64
$(MAKE) release-build GOOS=darwin GOARCH=arm64
$(MAKE) release-build GOOS=linux GOARCH=amd64
# Create release build tarballs for all supported platforms. Same as `release`, but without embedded Lattice UI.
release-sans-ui: check-clean
rm -f statik/statik.go
$(MAKE) release-build GOOS=darwin GOARCH=amd64
$(MAKE) release-build GOOS=darwin GOARCH=arm64
$(MAKE) release-build GOOS=linux GOARCH=amd64
# try (e.g.) internal/clustertests/docker-compose-replication2.yml
DOCKER_COMPOSE=internal/clustertests/docker-compose.yml
# Run cluster integration tests using docker. Requires docker daemon to be
# running and docker-compose to be installed.
# running. This will catch changes to internal/clustertests/*.go, but if you
# make changes to Pilosa, you'll want to run clustertests-build to rebuild the
# pilosa image.
clustertests: vendor
$(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml down
$(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml build
$(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml up -d pilosa1 pilosa2 pilosa3
PROJECT=$(PROJECT) $(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml run client1
$(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml down
docker-compose -f $(DOCKER_COMPOSE) down
docker-compose -f $(DOCKER_COMPOSE) build client1
docker-compose -f $(DOCKER_COMPOSE) up --exit-code-from=client1
# Run the cluster tests with authentication enabled
AUTH_ARGS="-c /go/src/github.com/featurebasedb/featurebase/internal/clustertests/testdata/featurebase.conf"
authclustertests: vendor
CLUSTERTESTS_FB_ARGS=$(AUTH_ARGS) $(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml down
CLUSTERTESTS_FB_ARGS=$(AUTH_ARGS) $(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml build
CLUSTERTESTS_FB_ARGS=$(AUTH_ARGS) $(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml up -d pilosa1 pilosa2 pilosa3
PROJECT=$(PROJECT) ENABLE_AUTH=1 $(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml run client1
CLUSTERTESTS_FB_ARGS=$(AUTH_ARGS) $(DOCKER_COMPOSE) -f internal/clustertests/docker-compose.yml down
# Install FeatureBase and IDK
install: install-featurebase install-idk install-fbsql
# Like clustertests, but rebuilds all images.
clustertests-build: vendor
docker-compose -f $(DOCKER_COMPOSE) down -v
docker-compose -f $(DOCKER_COMPOSE) up --exit-code-from=client1 --build
install-featurebase:
$(GO) install -tags='$(BUILD_TAGS)' -ldflags $(LDFLAGS) $(FLAGS) ./cmd/featurebase
# Install Pilosa
install:
$(GO) install -tags='$(BUILD_TAGS)' -ldflags $(LDFLAGS) $(FLAGS) ./cmd/pilosa
install-idk:
$(MAKE) -C ./idk install
install-fbsql:
CGO_ENABLED=1 $(GO) install ./cmd/fbsql
install-bench:
$(GO) install -tags='$(BUILD_TAGS)' -ldflags $(LDFLAGS) $(FLAGS) ./cmd/pilosa-bench
# Build the lattice assets
build-lattice:
@ -172,11 +156,11 @@ build-lattice:
# `go generate` protocol buffers
generate-protoc: require-protoc require-protoc-gen-gofast
$(GO) generate github.com/featurebasedb/featurebase/v3/pb
$(GO) generate github.com/pilosa/pilosa/v2/pb
# `go generate` statik assets (lattice UI)
generate-statik: build-lattice require-statik
$(GO) generate github.com/featurebasedb/featurebase/v3/statik
$(GO) generate github.com/pilosa/pilosa/v2/statik
# `go generate` statik assets (lattice UI) in Docker
generate-statik-docker: build-lattice
@ -184,15 +168,19 @@ generate-statik-docker: build-lattice
# `go generate` stringers
generate-stringer:
$(GO) generate github.com/featurebasedb/featurebase/v3
$(GO) generate github.com/pilosa/pilosa/v2
generate-pql: require-peg
cd pql && peg -inline pql.peg && cd ..
generate-proto-grpc: require-protoc require-protoc-gen-go
protoc -I proto proto/pilosa.proto --go_out=plugins=grpc:proto
# address re-generation here only if we need to
# protoc -I proto proto/vdsm.proto --go_out=plugins=grpc:proto
protoc -I proto proto/vdsm/vdsm.proto --go_out=plugins=grpc:proto
# TODO: Modify above commands and remove the below mv if possible.
# See https://go-review.googlesource.com/c/protobuf/+/219298/ for info on --go-opt
# I couldn't get it to work during development - Cody
cp -r proto/github.com/pilosa/pilosa/v2/proto/ proto/
rm -rf proto/github.com
# `go generate` all needed packages
generate: generate-protoc generate-statik generate-stringer generate-pql
@ -200,7 +188,6 @@ generate: generate-protoc generate-statik generate-stringer generate-pql
# Create release using Docker
docker-release:
$(MAKE) docker-build GOOS=linux GOARCH=amd64
$(MAKE) docker-build GOOS=linux GOARCH=arm64
$(MAKE) docker-build GOOS=darwin GOARCH=amd64
$(MAKE) docker-build GOOS=darwin GOARCH=arm64
@ -209,103 +196,61 @@ docker-build: vendor
docker build \
--build-arg GO_VERSION=$(GO_VERSION) \
--build-arg MAKE_FLAGS="TRIAL_DEADLINE=$(TRIAL_DEADLINE) GOOS=$(GOOS) GOARCH=$(GOARCH)" \
--build-arg SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH) \
--target pilosa-builder \
--tag featurebase:build .
docker create --name featurebase-build featurebase:build
mkdir -p build/featurebase-$(VERSION_ID)
docker cp featurebase-build:/pilosa/build/. ./build/featurebase-$(VERSION_ID)
cp NOTICE install/featurebase.conf install/featurebase*.service ./build/featurebase-$(VERSION_ID)
docker rm featurebase-build
tar -cvz -C build -f build/featurebase-$(VERSION_ID).tar.gz featurebase-$(VERSION_ID)/
--tag pilosa:build .
docker create --name pilosa-build pilosa:build
mkdir -p build/pilosa-$(VERSION_ID)
docker cp pilosa-build:/pilosa/build/. ./build/pilosa-$(VERSION_ID)
cp NOTICE LICENSE ./build/pilosa-$(VERSION_ID)
docker rm pilosa-build
tar -cvz -C build -f build/pilosa-$(VERSION_ID).tar.gz pilosa-$(VERSION_ID)/
# Create Docker image from Dockerfile
docker-image: vendor
docker build \
--build-arg GO_VERSION=$(GO_VERSION) \
--build-arg MAKE_FLAGS="TRIAL_DEADLINE=$(TRIAL_DEADLINE)" \
--tag featurebase:$(VERSION) .
@echo Created docker image: featurebase:$(VERSION)
docker-image-featurebase: vendor
docker build \
--build-arg GO_VERSION=$(GO_VERSION) \
--file Dockerfile-dax \
--tag dax/featurebase .
docker-image-featurebase-linux-amd64: vendor
docker build \
--build-arg GO_VERSION=$(GO_VERSION) \
--platform linux/amd64 \
--file Dockerfile-dax \
--tag dax/featurebase .
docker-image-featurebase-test: vendor
docker build \
--build-arg GO_VERSION=$(GO_VERSION) \
--file Dockerfile-clustertests \
--tag dax/featurebase-test .
# build-for-quick builds a linux featurebase binary outside of docker
# (which is much faster for some reason), and places it in the .quick
# subdirectory.
build-for-quick:
GOOS=linux $(MAKE) build FLAGS="-o .quick/fb_linux"
# docker-image-featurebase-quick uses a pre-built featurebase binary
# to quickly create a fresh docker image without needing to send the
# context of the featurebase top level directory.
docker-image-featurebase-quick: build-for-quick
docker build \
--build-arg GO_VERSION=$(GO_VERSION) \
--file Dockerfile-dax-quick \
--tag dax/featurebase ./.quick/
docker-image-datagen: vendor
docker build --tag dax/datagen --file Dockerfile-datagen .
get-account-id:
$(eval AWS_ACCOUNTID := $(shell aws sts get-caller-identity --output=json | jq -r .Account))
ecr-push-featurebase: docker-login
echo "Pushing to account $(AWS_ACCOUNTID), profile $(AWS_PROFILE)"
docker tag dax/featurebase:latest $(AWS_ACCOUNTID).dkr.ecr.us-east-2.amazonaws.com/dax/featurebase:latest
docker push $(AWS_ACCOUNTID).dkr.ecr.us-east-2.amazonaws.com/dax/featurebase:latest
ecr-push-datagen: docker-login
docker tag dax/datagen:latest $(AWS_ACCOUNTID).dkr.ecr.us-east-2.amazonaws.com/dax/datagen:latest
docker push $(AWS_ACCOUNTID).dkr.ecr.us-east-2.amazonaws.com/dax/datagen:latest
docker-login: get-account-id
aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin $(AWS_ACCOUNTID).dkr.ecr.us-east-2.amazonaws.com
--tag pilosa:$(VERSION) .
@echo Created docker image: pilosa:$(VERSION)
# Create docker image (alias)
docker: docker-image # alias
# Tag and push a Docker image
docker-tag-push: vendor
docker tag "featurebase:$(VERSION)" $(DOCKER_TARGET)
docker tag "pilosa:$(VERSION)" $(DOCKER_TARGET)
docker push $(DOCKER_TARGET)
@echo Pushed docker image: $(DOCKER_TARGET)
# These commands (docker-idk and docker-idk-tag-push)
# are designed to be used in CI.
# docker-idk builds idk docker images and tags them - intended for use in CI.
docker-idk: vendor
docker build \
-f idk/Dockerfile \
--build-arg GO_VERSION=$(GO_VERSION) \
--build-arg MAKE_FLAGS="GOOS=$(GOOS) GOARCH=$(GOARCH) BUILD_CGO=$(BUILD_CGO)" \
--tag registry.gitlab.com/molecula/featurebase/idk:$(VERSION_ID) .
@echo Created docker image: registry.gitlab.com/molecula/featurebase/idk:$(VERSION_ID)
# docker-idk-tag-push pushes tagged docker images to the GitLab container
# registry - intended for use in CI.
docker-idk-tag-push:
docker push registry.gitlab.com/molecula/featurebase/idk:$(VERSION_ID)
@echo Pushed docker image: registry.gitlab.com/molecula/featurebase/idk:$(VERSION_ID)
# Install diagnostic pilosa-keydump tool. Allows viewing the keys in a transaction-engine directory.
pilosa-keydump:
$(GO) install -tags='$(BUILD_TAGS)' -ldflags $(LDFLAGS) $(FLAGS) ./cmd/pilosa-keydump
# Install diagnostic pilosa-chk tool for string translations and fragment checksums.
pilosa-chk:
$(GO) install -tags='$(BUILD_TAGS)' -ldflags $(LDFLAGS) $(FLAGS) ./cmd/pilosa-chk
pilosa-fsck:
cd ./cmd/pilosa-fsck && make install && make release
# Run Pilosa tests inside Docker container
docker-test:
docker run --rm -v $(PWD):/go/src/$(CLONE_URL) -w /go/src/$(CLONE_URL) golang:$(GO_VERSION) go test -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) ./...
# Must use bash in order to -o pipefail; otherwise the tee will hide red tests.
# run top tests, not subdirs. print summary red/green after.
# The \-\-\- FAIL avoids counting the extra two FAIL strings at then bottom of log.topt.
topt:
mv log.topt.roar log.topt.roar.prev || true
$(eval SHELL:=/bin/bash) set -o pipefail; $(GO) test -v -timeout 60m -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) 2>&1 | tee log.topt.roar
@echo " log.topt.roar green: \c"; cat log.topt.roar | grep PASS |wc -l
@echo " log.topt.roar red: \c"; cat log.topt.roar | grep '\-\-\- FAIL' | wc -l
topt-race:
mv log.topt.race log.topt.race.prev || true
$(eval SHELL:=/bin/bash) set -o pipefail; CGO_ENABLED=1 $(GO) test -race -timeout 60m -v -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) 2>&1 | tee log.topt.race
@echo " log.topt.race green: \c"; cat log.topt.race | grep PASS |wc -l
@echo " log.topt.race red: \c"; cat log.topt.race | grep '\-\-\- FAIL' | wc -l
# Run golangci-lint
golangci-lint: require-golangci-lint
@ -317,6 +262,35 @@ linter: golangci-lint
# Better alias
ocd: golangci-lint
# Run gometalinter with custom flags
gometalinter: require-gometalinter vendor
GO111MODULE=off gometalinter --vendor --disable-all \
--deadline=300s \
--enable=deadcode \
--enable=gochecknoinits \
--enable=gofmt \
--enable=goimports \
--enable=gotype \
--enable=gotypex \
--enable=ineffassign \
--enable=interfacer \
--enable=maligned \
--enable=misspell \
--enable=nakedret \
--enable=staticcheck \
--enable=unconvert \
--enable=unparam \
--enable=vet \
--exclude "^internal/.*\.pb\.go" \
--exclude "^pql/pql.peg.go" \
./...
# Verify that all Go files have license header
check-license-headers: SHELL:=/bin/bash
check-license-headers:
@! find . -path ./vendor -prune -o -name '*.go' -print | grep -v -F -f license.exceptions | while read fn;\
do [[ `$(call LICENSE_HASH_CODE, $$fn)` == $(LICENSE_HASH) ]] || echo $$fn; done | grep '.'
######################
# Build dependencies #
######################
@ -327,20 +301,22 @@ require-%:
$(info Verified build dependency "$*" is installed.),\
$(error Build dependency "$*" not installed. To install, try `make install-$*`))
install-build-deps: install-protoc-gen-gofast install-protoc install-statik install-peg
install-build-deps: install-protoc-gen-gofast install-protoc install-statik install-stringer install-peg
install-statik:
go install github.com/rakyll/statik@latest
go get -u github.com/rakyll/statik
install-stringer:
GO111MODULE=off $(GO) get -u golang.org/x/tools/cmd/stringer
install-protoc-gen-gofast:
GO111MODULE=off $(GO) get -u github.com/gogo/protobuf/protoc-gen-gofast
install-protoc-gen-go:
GO111MODULE=off $(GO) get -u github.com/golang/protobuf/protoc-gen-go
install-protoc:
@echo This tool cannot automatically install protoc. Please download and install protoc from https://google.github.io/proto-lens/installing-protoc.html
@echo On mac, brew install protobuf seems to work.
@echo As of the commit that added this line, protoc-gen-gofast was at 226206f39bd7, and the protoc version in use was:
@echo $$ protoc --version
@echo libprotoc 3.19.4
install-peg:
GO111MODULE=off $(GO) get github.com/pointlander/peg
@ -348,58 +324,16 @@ install-peg:
install-golangci-lint:
GO111MODULE=off $(GO) get github.com/golangci/golangci-lint/cmd/golangci-lint
install-gometalinter:
GO111MODULE=off $(GO) get -u github.com/alecthomas/gometalinter
GO111MODULE=off gometalinter --install
GO111MODULE=off $(GO) get github.com/remyoudompheng/go-misc/deadcode
test-txstore-rbf:
PILOSA_STORAGE_BACKEND=rbf $(MAKE) testv-race
test-txstore-rbf_bolt:
PILOSA_STORAGE_BACKEND=rbf_bolt $(MAKE) testv-race
test-external-lookup:
$(GO) test . -tags='$(BUILD_TAGS) $(TEST_TAGS)' $(TESTFLAGS) -run ^TestExternalLookup$$ -externalLookupDSN $(EXTERNAL_LOOKUP_DSN)
bnf:
ebnf2railroad --no-overview-diagram --no-optimizations ./sql3/sql3.ebnf
#################################
# fbsql builds in docker
#################################
# This allows multiple concurrent builds to happen in CI without
# creating container name conflicts and such. (different BUILD_NAMEs
# are passed in from gitlab-ci.yml)
BUILD_NAME ?= fbsql-build
LDFLAGS_STATIC="-linkmode external -extldflags \"-static\" -X 'github.com/featurebasedb/featurebase/v3/fbsql.Version=$(VERSION)' -X 'github.com/featurebasedb/featurebase/v3/fbsql.BuildTime=$(BUILD_TIME)' "
UNAME_P := $(shell uname -p)
BUILD_CGO ?= 0
# Build fbsql
build-fbsql:
@echo GOOS=$(GOOS) GOARCH=$(GOARCH) uname -p=$(UNAME_P) build_cgo=$(BUILD_CGO)
ifeq ($(BUILD_CGO), 0)
make build-fbsql-non-cgo
endif
ifeq ($(BUILD_CGO), 1)
make build-fbsql-cgo
endif
build-fbsql-non-cgo:
CGO_ENABLED=0 $(GO) build -ldflags $(LDFLAGS) $(GO_BUILD_FLAGS) -o fbsql ./cmd/fbsql
build-fbsql-cgo:
ifeq ($(GOARCH), arm64)
CGO_ENABLED=1 $(GO) build -tags dynamic $(GO_BUILD_FLAGS) -o fbsql ./cmd/fbsql
endif
ifeq ($(GOARCH), amd64)
CC=/usr/bin/musl-gcc CGO_ENABLED=1 $(GO) build -tags "musl static" -ldflags $(LDFLAGS_STATIC) $(GO_BUILD_FLAGS) -o fbsql ./cmd/fbsql
endif
docker-build-fbsql: vendor
DOCKER_BUILDKIT=0 docker build \
--file Dockerfile-fbsql \
--build-arg GO_VERSION=$(GO_VERSION) \
--build-arg MAKE_FLAGS="GOOS=$(GOOS) GOARCH=$(GOARCH) BUILD_CGO=$(BUILD_CGO)" \
--build-arg GO_BUILD_FLAGS=$(GO_BUILD_FLAGS) \
--build-arg SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH) \
--target builder \
--tag fbsql:$(BUILD_NAME) .
mkdir -p build
docker create --name $(BUILD_NAME) fbsql:$(BUILD_NAME)
docker cp $(BUILD_NAME):/featurebase/fbsql ./build/fbsql_$(GOOS)_$(GOARCH)
docker rm $(BUILD_NAME)

26
NOTES Normal file
View file

@ -0,0 +1,26 @@
Index Column
┌───────────▼────────────────────────────┐
│0000000000000000000000000000000000000000│
│0000000000000000000000000000000000000000│
│0000000000000000000000000000000000000000│
Row──▶0000000000000000000000000000000000000000│
│0000000000000000000000000000000000000000│
│────────────────────────────────────────┤
│0000000000000000000000000000000000000000│
│0000000000000000000000000000000000000000│
│0000000000000000000000000000000000000000│
│0000000000000000000000000000000000000000│
│0000000000000000000000000000000000000000│
│────────────────────────────────────────┤
F ▶│0000000000000000000000000000000000000000│
i ││0000000000000000000000000000000000000000│
e ││0000000000000000000000000000000000000000│
l ││0000000000000000000000000000000000000000│
d ▶│0000000000000000000000000000000000000000│
└────────────────────────────────────────┘
▲───────────▲
Shard
Fragment=intersection of field & shard

15
NOTICE
View file

@ -1,12 +1,23 @@
Software license
================
Copyright (C) 2017-2021 Molecula Corp. All rights reserved.
Copyright (C) 2017-2018 Pilosa Corp. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License").
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Third-party software licenses
=============================
The file /lru/lru.go contains a redistribution of lru
The file /pilosa/lru/lru.go contains a redistribution of lru
(github.com/golang/groupcache/lru); the license follows:
Copyright 2013 Google Inc.

View file

@ -1,45 +0,0 @@
## User Contribution Guidelines for FeatureBase
Thank you for your interest in contributing to FeatureBase! We appreciate your support in making this open-source project even better. Here are some guidelines to help you get started with contributing to FeatureBase:
1. Familiarize Yourself with the Project:
- Visit the FeatureBase website at www.featurebase.com to understand the project's goals, capabilities, and features.
- Read the documentation available on the website, including the installation guide, configuration options, and data modeling concepts.
- Explore the codebase by cloning the repository and reviewing the source code.
2. Join the Community:
- Visit the FeatureBase community page at https://www.featurebase.com/community to learn more about the project's community and how to get involved.
- Join the Discord server at https://discord.gg/FBn2vEp7Na to chat with other contributors and users, ask questions, and share your ideas.
3. Set Up Your Development Environment:
- Ensure you have Go installed on your machine. Make sure your shell's search path includes the go/bin directory.
- Clone the FeatureBase repository or download it as a zip file from the repository's page.
- Follow the "Build FeatureBase Server from source" instructions in the README file to compile the server binary and the ingester binaries.
4. Choose a Contribution Area:
- Identify the area you'd like to contribute to, such as bug fixes, new features, performance improvements, documentation updates, or community support.
- Check the issue tracker on the repository or the FeatureBase community for open issues or feature requests that align with your interests and skills. Alternatively, propose your own idea by creating a new issue.
5. Create a New Branch:
- Before making any changes, create a new branch in the repository's Git repository. This branch will contain your contributions.
- Give your branch a descriptive name that reflects the nature of your contribution.
6. Make Your Changes:
- Follow the coding style and conventions used in the existing codebase.
- Write clear and concise commit messages for each logical change.
- If you're introducing new features or modifying existing behavior, make sure to update the documentation to reflect the changes.
7. Test Your Changes:
- Run the existing test suite to ensure that your modifications do not introduce any regressions.
- If applicable, write additional tests to cover the changes you made.
- Document any new testing procedures required for your contribution.
8. Submitting Your Contribution:
- Push your branch to the main repository or create a fork and submit a pull request to the main repository.
- Provide a detailed description of your changes, including the problem you solved and the approach you took.
- Be responsive to any feedback or suggestions provided by the project maintainers or other contributors.
- Once your contribution is approved, it will be reviewed and merged into the main codebase.
Please note that by contributing to FeatureBase, you agree that your contributions will be licensed under the Apache 2.0 license, which governs the project.
Thank you for considering contributing to FeatureBase! Your contributions are valuable and help improve the project for everyone.

View file

@ -1,72 +1,63 @@
# FeatureBase Community
FeatureBase Community is now archived and no longer maintained.
* [FeatureBase Community Help](https://github.com/FeatureBaseDB/FB-community-help)
<p>
<a href="https://www.pilosa.com">
<img src="https://www.pilosa.com/img/logo.svg" width="50%">
</a>
</p>
## Our private fork of [Pilosa](https://github.com/pilosa/pilosa), a distributed bitmap index
- [Docs](#docs)
- [Getting Started](#getting-started)
- [Data Model](#data-model)
- [Query Language](#query-language)
- [Client Libraries](#client-libraries)
- [Get Support](#get-support)
- [Contributing](#contributing)
## Pilosa is now FeatureBase
## Docs
As of September 7, 2022, the Pilosa project is now FeatureBase. The core of the project remains the same: FeatureBase is the first real-time distributed database built entirely on bitmaps. (More information about updated capabilities and improvements below.)
See our [internal documentation](https://internal-docs.molecula.cloud), which includes all [external documentation](https://docs.molecula.cloud), plus many internal-only pages, listed under the "Internal" heading in the main navigation bar.
FeatureBase delivers low-latency query results, regardless of throughput or query volumes, on fresh data with extreme efficiency. It works because bitmaps are faster, simpler, and far more I/O efficient than traditional column-oriented data formats. With FeatureBase, you can ingest data from batch data sources (e.g. S3, CSV, Snowflake, BigQuery, etc.) and/or streaming data sources (e.g. Kafka/Confluent, Kinesis, Pulsar).
For more information about FeatureBase, please visit [www.featurebase.com][HomePage].
The [documentation](https://www.pilosa.com/docs/) for the open source fork is also available, but is outdated for most technical details. Conceptual explanations and [technical blog posts](https://www.pilosa.com/blog/) may still be informative.
## Getting Started
* [Learn how to install FeatureBase Community](https://github.com/FeatureBaseDB/FB-community-help/blob/main/docs/community/com-getstart/com-getstart-home.md)
1. [Install Pilosa](https://www.pilosa.com/docs/latest/installation/#build-from-source).
### Build FeatureBase Server from source
Optionally, to include Lattice, the in-browser UI, follow the "Build from source" instructions, and run `make generate-statik` before `make install`. When you run a local Pilosa server on the default host, for example, you can access Lattice at [localhost:10101](http://localhost:10101).
0. Install go. Ensure that your shell's search path includes the go/bin directory.
1. Clone the FeatureBase repository (or download as zip).
2. In the featurebase directory, run `make install` to compile the FeatureBase server binary. By default, it will be installed in the go/bin directory.
3. In the idk directory, run `make install` to compile the ingester binaries. By default, they will be installed in the go/bin directory.
4. Run `featurebase server --handler.allowed-origins=http://localhost:3000` to run FeatureBase server with default settings (learn more about configuring FeatureBase at the link below). The `--handler.allowed-origins` parameter allows the standalone web UI to talk to the server; this can be omitted if the web UI is not needed.
5. Run `curl localhost:10101/status` to verify the server is running and accessible.
2. [Start Pilosa](https://www.pilosa.com/docs/getting-started/#starting-pilosa) with the default configuration:
### Data Model
```shell
pilosa server
```
and verify that it's running:
```shell
curl localhost:10101/status
```
Because FeatureBase is built on bitmaps, there is bit of a learning curve to grasp how your data is represented.
* [Learn about Data Modeling](https://github.com/FeatureBaseDB/FB-community-help/blob/main/docs/concepts/concepts-home.md)
3. Follow along with the [Sample Project](https://internal-docs.molecula.cloud/tutorials/getting-started) to get a better understanding of Pilosa's capabilities.
### Ingest Data and Query
## Data Model
* [Learn how to ingest data from multiple data sources](https://github.com/FeatureBaseDB/FB-community-help/blob/main/docs/community/com-ingest/com-ingest-manage.md)
Check out how the Pilosa [Data Model](https://www.pilosa.com/docs/data-model/) works.
## Community
You can email us at community@featurebase.com and [learn more about contributing](https://github.com/FeatureBaseDB/featurebase/blob/master/OPENSOURCE.md).
## Query Language
Chat with us: [https://discord.gg/FBn2vEp7Na][Discord]
You can interact with Pilosa directly in the console using the [Pilosa Query Language](https://internal-docs.molecula.cloud/explanations/pql-intro) (PQL).
## What's Changed Since the Pilosa Days?
A lot has changed since the days of Pilosa. This list highlights some new capabilites included in FeatureBase. We have also made signficant improvements to the performance, scalability, and stability of the FeatureBase product.
## Client Libraries
* Query Languages: FeatureBase supports Pilosa Query Language (PQL), as well as SQL
* Stream and Batch Ingest: Combine real-time data streams with batch historical data and act on it within milliseconds.
* Mutable: Perform inserts, updates, and deletes at scale, in real time and on-the-fly. This is key for meeting data compliance requirements, and for reflecting the constantly-changing nature of high-volume data.
* Multi-Valued Set Fields: Store multiple comma-delimited values within a single field while *increasing* query performance of counts, TopKs, etc.
* Time Quantums: Setting a time quantum on a field creates extra views which allow ranged Row queries down to the time interval specified. For example, if the time quantum is set to YMD, ranged Row queries down to the granularity of a day are supported.
* RBF storage backend: this is a new compressed bitmap format which improves performance in a number of ways: ACID support on a per shard basis, prevents issues with the number of open files, reduces memory allocation and lock contention for reads, provides more consistent garbage collection, and allows backups to run concurrently with writes. However, because of this change, Pilosa backup files cannot be restored into FeatureBase.
Three client libraries were supported for the open source fork: [Go](https://www.pilosa.com/docs/client-libraries/#go), (https://www.pilosa.com/docs/client-libraries/#java), (https://www.pilosa.com/docs/client-libraries/#python). Of these, only the Go client has seen significant use and development in the private fork, and it has now been incorporated into this repository, in [the `client` directory](https://github.com/molecula/pilosa/tree/master/client)
## License
FeatureBase is licensed under the [Apache License, Version 2.0][License]
Pilosa is licensed under the Apache License, Version 2.0.
[Community]: https://github.com/FeatureBaseDB/FB-community-help/tree/main
[Install]:https://github.com/FeatureBaseDB/FB-community-help/blob/main/docs/community/com-getstart/com-getstart-home.md
[Config]: https://github.com/FeatureBaseDB/FB-community-help/tree/main/docs/community/com-config
[DataModel]: https://github.com/FeatureBaseDB/FB-community-help/blob/main/docs/concepts/concepts-home.md
[Discord]: https://discord.gg/FBn2vEp7Na
[HomePage]: http://featurebase.com?utm_campaign=Open%20Source&utm_source=GitHub
[Ingest]: https://github.com/FeatureBaseDB/FB-community-help/blob/main/docs/community/com-ingest/com-ingest-manage.md
[License]: http://www.apache.org/licenses/LICENSE-2.0
[PQL]: https://docs.featurebase.com/docs/pql-guide/pql-home/?utm_campaign=Open%20Source&utm_source=GitHub
[SQL]: https://docs.featurebase.com/docs/sql-guide/sql-guide-home/?utm_campaign=Open%20Source&utm_source=GitHub
A copy of the license is located in [github.com/molecula/pilosa/LICENSE](https://github.com/pilosa/molecula/blob/master/LICENSE).
More details about licensing are found in [github.com/molecula/pilosa/NOTICE](https://github.com/molecula/pilosa/blob/master/NOTICE).

2114
api.go

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,17 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package client
import (
@ -7,13 +19,12 @@ import (
"crypto/tls"
"sync"
"github.com/featurebasedb/featurebase/v3/logger"
pb "github.com/featurebasedb/featurebase/v3/proto"
"github.com/pilosa/pilosa/v2/logger"
pb "github.com/pilosa/pilosa/v2/proto"
"github.com/pkg/errors"
"google.golang.org/grpc"
"google.golang.org/grpc/connectivity"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
)
const maxMsgSize = 1024 * 1024 * 100 // 100 megs ought to be enough for anybody!
@ -65,7 +76,7 @@ func (c *GRPCClient) resetConn() error {
creds := credentials.NewTLS(c.tlsConfig)
opts = append(opts, grpc.WithTransportCredentials(creds))
} else {
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
opts = append(opts, grpc.WithInsecure())
}
opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxMsgSize)))

View file

@ -1,987 +0,0 @@
// Copyright 2021 Molecula Corp. All rights reserved.
package pilosa
import (
"context"
"io"
"log"
"sync"
"github.com/featurebasedb/featurebase/v3/dax"
"github.com/featurebasedb/featurebase/v3/dax/computer"
"github.com/featurebasedb/featurebase/v3/dax/storage"
"github.com/featurebasedb/featurebase/v3/disco"
"github.com/pkg/errors"
)
// ApplyDirective applies a Directive received, from the Controller, at the
// /directive endpoint.
func (api *API) ApplyDirective(ctx context.Context, d *dax.Directive) error {
// Get the current directive for comparison.
previousDirective := api.holder.Directive()
// Check that incoming version is newer.
// Note: 0 is an invalid Directive version. This decision was made because
// previousDirective is not a pointer to a directive, but a concrete
// Directive. Which means we can't check for nil, and by default it has a
// version of 0. So in order to ensure the version has increased, we need to
// require that incoming directive versions are greater than 0.
if d.Version == 0 {
return errors.Errorf("directive version cannot be 0")
} else if previousDirective.Version >= d.Version {
return errors.Errorf("directive version mismatch, got %d, but already have %d", d.Version, previousDirective.Version)
}
// Handle the operations based on the directive method.
switch d.Method {
case dax.DirectiveMethodDiff:
// In order to prevent adding too much code specific to handling a diff
// directive (e.g. adding something like an `enactDirectiveDiff()`
// method), we are instead going to build a full Directive based on the
// diff, and then proceed normally as if we had received a full
// Directive. We do that by copying the previous Directive and then
// applying the diffs to the copy.
newD := previousDirective.Copy()
// Apply the diffs from the incoming Directive to the new, copied
// Directive.
newD.ApplyDiff(d)
// Now proceed with the new diff as if we had received it as a full diff.
d = newD
case dax.DirectiveMethodFull:
// pass: normal operation
case dax.DirectiveMethodReset:
// Delete all tables.
if err := api.deleteAllIndexes(ctx); err != nil {
return errors.Wrap(err, "deleting all indexes")
}
// Set previousDirective to empty so the diff handles everything as new.
previousDirective = dax.Directive{}
case dax.DirectiveMethodSnapshot:
// TODO(tlt): this was the existing logic, but we should really diff the
// directive and ensure that overwriting the value in the cache doesn't
// have a negative effect.
api.holder.SetDirective(d)
return nil
default:
return errors.Errorf("invalid directive method: %s", d.Method)
}
// Cache this directive as the latest applied. There is functionality within
// the "enactDirective" stage of ApplyDirective which validates against this
// cached Directive, so it's important that it be set before calling
// enactDirective(). An example: when loading partition data from the
// Writelogger, there are validations to ensure that the partition being
// loaded is meant to be handled by this node; that validation is done
// against the cached Directive.
// TODO(tlt): despite what this comment says, this logic is not sound; we
// shouldn't be setting the directive until enactiveDirective() succeeds.
api.holder.SetDirective(d)
defer api.holder.SetDirectiveApplied(true)
return api.enactDirective(ctx, &previousDirective, d)
}
// deleteAllIndexes deletes all indexes handled by this node.
func (api *API) deleteAllIndexes(ctx context.Context) error {
indexes, err := api.Schema(ctx, false)
if err != nil {
return errors.Wrap(err, "getting schema")
}
for i := range indexes {
if err := api.DeleteIndex(ctx, indexes[i].Name); err != nil {
return errors.Wrapf(err, "deleting index: %s", indexes[i].Name)
}
}
return nil
}
// directiveJobType allows us to switch on jobType in the directiveWorker in
// order to use a single worker pool for all job types (as opposed to having a
// separate worker pool for each job type).
type directiveJobType interface {
// We have this method just to prevent *any* struct from implementing this
// interface automatically. But, interestingly enough, we don't actually
// have to have this method on the implementation because we embed the
// interface.
isJobType() bool
}
type directiveJobTableKeys struct {
directiveJobType
idx *Index
tkey dax.TableKey
partition dax.PartitionNum
}
type directiveJobFieldKeys struct {
directiveJobType
tkey dax.TableKey
field dax.FieldName
}
type directiveJobShards struct {
directiveJobType
tkey dax.TableKey
shard dax.ShardNum
}
// directiveWorker is a worker in a worker pool which handles portions of a
// directive. Multiple instances of directiveWorker run in goroutines in order
// to load data from snapshotter and writelogger concurrently. Note: unlike the
// api.ingestWorkerPool, of which one pool is always running, the
// directiveWorker pool is only running during the life of the
// api.ApplyDirective call. Technically, this means that multiple
// directiveWorker pools could be active at the same time, but we should never
// be running more than once instance of ApplyDirective concurrently.
func (api *API) directiveWorker(ctx context.Context, jobs <-chan directiveJobType, errs chan<- error) {
for j := range jobs {
switch job := j.(type) {
case directiveJobTableKeys:
if err := api.loadTableKeys(ctx, job.idx, job.tkey, job.partition); err != nil {
errs <- errors.Wrapf(err, "loading table keys: %s, %s", job.tkey, job.partition)
}
case directiveJobFieldKeys:
if err := api.loadFieldKeys(ctx, job.tkey, job.field); err != nil {
errs <- errors.Wrapf(err, "loading field keys: %s, %s", job.tkey, job.field)
}
case directiveJobShards:
if err := api.loadShard(ctx, job.tkey, job.shard); err != nil {
errs <- errors.Wrapf(err, "loading shard: %s, %s", job.tkey, job.shard)
}
default:
errs <- errors.Errorf("unsupported job type: %T %[1]v", job)
}
select {
case <-ctx.Done():
return
default:
// continue pulling jobs off the channel
}
}
}
func (api *API) enactDirective(ctx context.Context, fromD, toD *dax.Directive) error {
// enactTables is called before the jobs that run in the worker pool because
// it probably makes sense to apply the schema before trying to load data
// concurrently.
if err := api.enactTables(ctx, fromD, toD); err != nil {
return errors.Wrap(err, "enactTables")
}
// The following types use a shared pool of workers to run each
// directiveJobType.
var wg sync.WaitGroup
// open job channel
jobs := make(chan directiveJobType, api.directiveWorkerPoolSize)
errs := make(chan error)
done := make(chan struct{})
// Spin up n workers in goroutines that pull jobs from the jobs channel.
for i := 0; i < api.directiveWorkerPoolSize; i++ {
wg.Add(1)
go func() {
api.directiveWorker(ctx, jobs, errs)
defer wg.Done()
}()
}
// Wait for the WaitGroup counter to reach 0. When it has, indicate that
// we're done processing all jobs by closing the done channel.
go func() {
wg.Wait()
close(done)
}()
// Run through all the "enact" methods. These push jobs onto the jobs
// channel. Once all the jobs have been queued to the channel, we close the
// jobs channel. This allows the directiveWorkers to exit out of the
// function, which will then decrement the WaitGroup counter.
go func() {
api.pushJobsTableKeys(ctx, jobs, fromD, toD)
api.pushJobsFieldKeys(ctx, jobs, fromD, toD)
api.pushJobsShards(ctx, jobs, fromD, toD)
close(jobs)
}()
// Keep running until we get an error or until the done channel is closed.
// Note: the code is written such that only non-nil errors are pushed to the
// errs channel.
for {
select {
case err := <-errs:
return err
case <-done:
return nil
}
}
}
func (api *API) enactTables(ctx context.Context, fromD, toD *dax.Directive) error {
currentIndexes := api.holder.Indexes()
// Make a list of indexes that currently exist (from).
from := make(dax.TableKeys, 0, len(currentIndexes))
for _, idx := range currentIndexes {
qtid, err := dax.QualifiedTableIDFromKey(idx.Name())
if err != nil {
return errors.Wrap(err, "converting index name to qualified table id")
}
from = append(from, qtid.Key())
}
// TODO sanity check holder against fromD. We're getting existing
// indexes from holder, but in theory fromD should be
// identical. If we have an error in our directive-caching logic
// (it has happened before (just now, in fact!) and we'd be
// foolish to think it won't happen again), or we have schema
// mutations that are not going through the directive path, we
// could potentially catch them here.
// Make a list of tables that are in the directive (to) along with a map of
// tableKey to table (m).
m := make(map[dax.TableKey]*dax.QualifiedTable, len(toD.Tables))
to := make(dax.TableKeys, 0, len(toD.Tables))
for _, t := range toD.Tables {
m[t.Key()] = t
to = append(to, t.Key())
}
sc := newSliceComparer(from, to)
// Remove all indexes that are no longer part of the directive.
for _, tkey := range sc.removed() {
idx := string(tkey)
if err := api.DeleteIndex(ctx, idx); err != nil {
return errors.Wrapf(err, "deleting index: %s", tkey)
}
}
// Put partitions into a map by table.
partitionMap := toD.TranslatePartitionsMap()
// Add all indexes that weren't previously (but now are) a part of the
// directive.
for _, tkey := range sc.added() {
if qtbl, found := m[tkey]; !found {
return errors.Errorf("table '%s' was not in map", tkey)
} else if err := api.createTableAndFields(qtbl, partitionMap[tkey]); err != nil {
return err
}
}
// Check fields on all indexes present in both from and to.
for _, tkey := range sc.same() {
if err := api.enactFieldsForTable(ctx, tkey, fromD, toD); err != nil {
return errors.Wrapf(err, "enacting fields for table: '%s'", tkey)
}
}
return nil
}
func (api *API) enactFieldsForTable(ctx context.Context, tkey dax.TableKey, fromD, toD *dax.Directive) error {
qtid := tkey.QualifiedTableID()
fromT, err := fromD.Table(qtid)
if err != nil {
return errors.Wrap(err, "getting from table")
}
toT, err := toD.Table(qtid)
if err != nil {
return errors.Wrap(err, "getting to table")
}
// Get the index for tkey.
idx := api.holder.Index(string(tkey))
if idx == nil {
return errors.Errorf("index not found: %s", tkey)
}
sc := newSliceComparer(fromT.FieldNames(), toT.FieldNames())
// Add fields new to toT.
for _, fldName := range sc.added() {
if field, found := toT.Field(fldName); !found {
return dax.NewErrFieldDoesNotExist(fldName)
} else if err := createField(idx, field); err != nil {
return errors.Wrapf(err, "creating field: %s/%s", tkey, fldName)
}
}
// Remove fields which don't exist in toT.
for _, fldName := range sc.removed() {
if err := api.DeleteField(ctx, string(tkey), string(fldName)); err != nil {
return errors.Wrapf(err, "deleting field: %s/%s", tkey, fldName)
}
}
// // Update any field options which have changed for existing fields.
// for _, fldName := range sc.same() {
// // handle changed field options??
// }
return nil
}
func (api *API) pushJobsTableKeys(ctx context.Context, jobs chan<- directiveJobType, fromD, toD *dax.Directive) {
toPartitionsMap := toD.TranslatePartitionsMap()
// Get the diff between from/to directive.partitions.
partComp := newPartitionsComparer(fromD.TranslatePartitionsMap(), toPartitionsMap)
// Remove any partitions which are no longer assigned to this worker.
// TODO(tlt): currently, this is just removing the file lock on the
// resource; it's not actually removing the resource from the local
// computer. We should do that.
for tkey, partitions := range partComp.removed() {
qtid := tkey.QualifiedTableID()
for _, partition := range partitions {
api.serverlessStorage.RemoveTableKeyResource(qtid, partition)
}
}
// Loop over the partition map and load from Writelogger.
for tkey, partitions := range partComp.added() {
// Get index in order to find the translate stores (by partition) for
// the table.
idx := api.holder.Index(string(tkey))
if idx == nil {
log.Printf("index not found in holder: %s", tkey)
continue
}
// Update the cached version of translate partitions that we keep on the
// Index.
idx.SetTranslatePartitions(toPartitionsMap[tkey])
for _, partition := range partitions {
jobs <- directiveJobTableKeys{
idx: idx,
tkey: tkey,
partition: partition,
}
}
}
}
func (api *API) loadTableKeys(ctx context.Context, idx *Index, tkey dax.TableKey, partition dax.PartitionNum) error {
qtid := tkey.QualifiedTableID()
resource := api.serverlessStorage.GetTableKeyResource(qtid, partition)
if resource.IsLocked() {
api.logger().Warnf("skipping loadTableKeys (already held) %s %d", tkey, partition)
return nil
}
// load latest snapshot
if rc, err := resource.LoadLatestSnapshot(); err != nil {
return errors.Wrap(err, "loading table key snapshot")
} else if rc != nil {
defer rc.Close()
if err := api.TranslateIndexDB(ctx, string(tkey), int(partition), rc); err != nil {
return errors.Wrap(err, "restoring table keys")
}
}
// define write log loading in a function since we have to do it
// before and after locking
loadWriteLog := func() error {
writelog, err := resource.LoadWriteLog()
if err != nil {
return errors.Wrap(err, "getting write log reader for table keys")
}
if writelog == nil {
return nil
}
reader := storage.NewTableKeyReader(qtid, partition, writelog)
defer reader.Close()
store := idx.TranslateStore(int(partition))
for msg, err := reader.Read(); err != io.EOF; msg, err = reader.Read() {
if err != nil {
return errors.Wrap(err, "reading from log reader")
}
for key, id := range msg.StringToID {
if err := store.ForceSet(id, key); err != nil {
return errors.Wrapf(err, "forcing set id, key: %d, %s", id, key)
}
}
}
return nil
}
// 1st write log load
if err := loadWriteLog(); err != nil {
return err
}
// acquire lock on this partition's keys
if err := resource.Lock(); err != nil {
return errors.Wrap(err, "locking table key partition")
}
// reload writelog in case of changes between last load and
// lock. The resource object takes care of only loading new data.
return loadWriteLog()
}
func (api *API) pushJobsFieldKeys(ctx context.Context, jobs chan<- directiveJobType, fromD, toD *dax.Directive) {
// Get the diff between from/to directive.fields.
fieldComp := newFieldsComparer(fromD.TranslateFieldsMap(), toD.TranslateFieldsMap())
// Remove any field keys which are no longer assigned to this worker.
// TODO(tlt): currently, this is just removing the file lock on the
// resource; it's not actually removing the resource from the local
// computer. We should do that.
for tkey, fields := range fieldComp.removed() {
qtid := tkey.QualifiedTableID()
for _, field := range fields {
api.serverlessStorage.RemoveFieldKeyResource(qtid, field)
}
}
// Loop over the field map and load from Writelogger.
for tkey, fields := range fieldComp.added() {
for _, field := range fields {
jobs <- directiveJobFieldKeys{
tkey: tkey,
field: field,
}
}
}
}
func (api *API) loadFieldKeys(ctx context.Context, tkey dax.TableKey, field dax.FieldName) error {
qtid := tkey.QualifiedTableID()
resource := api.serverlessStorage.GetFieldKeyResource(qtid, field)
if resource.IsLocked() {
api.logger().Warnf("skipping loadFieldKeys (already held) %s %s", tkey, field)
return nil
}
// load latest snapshot
if rc, err := resource.LoadLatestSnapshot(); err != nil {
return errors.Wrap(err, "loading field key snapshot")
} else if rc != nil {
defer rc.Close()
if err := api.TranslateFieldDB(ctx, string(tkey), string(field), rc); err != nil {
return errors.Wrap(err, "restoring field keys")
}
}
// define write log loading in a function since we have to do it
// before and after locking
loadWriteLog := func() error {
writelog, err := resource.LoadWriteLog()
if err != nil {
return errors.Wrap(err, "getting write log reader for field keys")
}
if writelog == nil {
return nil
}
reader := storage.NewFieldKeyReader(qtid, field, writelog)
defer reader.Close()
// Get field in order to find the translate store.
fld := api.holder.Field(string(tkey), string(field))
if fld == nil {
log.Printf("field not found in holder: %s", field)
return nil
}
store := fld.TranslateStore()
for msg, err := reader.Read(); err != io.EOF; msg, err = reader.Read() {
if err != nil {
return errors.Wrap(err, "reading from log reader")
}
for key, id := range msg.StringToID {
if err := store.ForceSet(id, key); err != nil {
return errors.Wrapf(err, "forcing set id, key: %d, %s", id, key)
}
}
}
return nil
}
// 1st write log load
if err := loadWriteLog(); err != nil {
return err
}
// acquire lock on this partition's keys
if err := resource.Lock(); err != nil {
return errors.Wrap(err, "locking field key partition")
}
// reload writelog in case of changes between last load and
// lock. The resource object takes care of only loading new data.
return loadWriteLog()
}
func (api *API) pushJobsShards(ctx context.Context, jobs chan<- directiveJobType, fromD, toD *dax.Directive) {
// Put shards into a map by table.
shardMap := toD.ComputeShardsMap()
// Get the diff between from/to directive shards.
shardComp := newShardsComparer(fromD.ComputeShardsMap(), shardMap)
// Remove any shards which are no longer assigned to this worker.
// TODO(tlt): currently, this is just removing the file lock on the
// resource; it's not actually removing the resource from the local
// computer. We should do that.
for tkey, shards := range shardComp.removed() {
qtid := tkey.QualifiedTableID()
for _, shard := range shards {
partition := dax.PartitionNum(disco.ShardToShardPartition(string(tkey), uint64(shard), disco.DefaultPartitionN))
api.serverlessStorage.RemoveShardResource(qtid, partition, shard)
}
}
// Loop over the shard map and load from Writelogger.
for tkey, shards := range shardComp.added() {
for _, shard := range shards {
jobs <- directiveJobShards{
tkey: tkey,
shard: shard,
}
}
}
}
func (api *API) loadShard(ctx context.Context, tkey dax.TableKey, shard dax.ShardNum) error {
qtid := tkey.QualifiedTableID()
partition := dax.PartitionNum(disco.ShardToShardPartition(string(tkey), uint64(shard), disco.DefaultPartitionN))
resource := api.serverlessStorage.GetShardResource(qtid, partition, shard)
if resource.IsLocked() {
api.logger().Warnf("skipping loadShard (already held) %s %d", tkey, shard)
return nil
}
if rc, err := resource.LoadLatestSnapshot(); err != nil {
return errors.Wrap(err, "reading latest snapshot for shard")
} else if rc != nil {
defer rc.Close()
if err := api.RestoreShard(ctx, string(tkey), uint64(shard), rc); err != nil {
return errors.Wrap(err, "restoring shard data")
}
}
// define write log loading in a func because we do it twice.
loadWriteLog := func() error {
writelog, err := resource.LoadWriteLog()
if err != nil {
return errors.Wrap(err, "")
}
if writelog == nil {
return nil
}
reader := storage.NewShardReader(qtid, partition, shard, writelog)
defer reader.Close()
for logMsg, err := reader.Read(); err != io.EOF; logMsg, err = reader.Read() {
if err != nil {
return errors.Wrap(err, "reading from log reader")
}
switch msg := logMsg.(type) {
case *computer.ImportRoaringMessage:
req := &ImportRoaringRequest{
Clear: msg.Clear,
Action: msg.Action,
Block: msg.Block,
Views: msg.Views,
UpdateExistence: msg.UpdateExistence,
SuppressLog: true,
}
if err := api.ImportRoaring(ctx, msg.Table, msg.Field, msg.Shard, true, req); err != nil {
return errors.Wrapf(err, "import roaring, table: %s, field: %s, shard: %d", msg.Table, msg.Field, msg.Shard)
}
case *computer.ImportMessage:
req := &ImportRequest{
Index: msg.Table,
Field: msg.Field,
Shard: msg.Shard,
RowIDs: msg.RowIDs,
ColumnIDs: msg.ColumnIDs,
RowKeys: msg.RowKeys,
ColumnKeys: msg.ColumnKeys,
Timestamps: msg.Timestamps,
Clear: msg.Clear,
}
qcx := api.Txf().NewQcx()
defer qcx.Abort()
opts := []ImportOption{
OptImportOptionsClear(msg.Clear),
OptImportOptionsIgnoreKeyCheck(msg.IgnoreKeyCheck),
OptImportOptionsPresorted(msg.Presorted),
OptImportOptionsSuppressLog(true),
}
if err := api.Import(ctx, qcx, req, opts...); err != nil {
return errors.Wrapf(err, "import, table: %s, field: %s, shard: %d", msg.Table, msg.Field, msg.Shard)
}
case *computer.ImportValueMessage:
req := &ImportValueRequest{
Index: msg.Table,
Field: msg.Field,
Shard: msg.Shard,
ColumnIDs: msg.ColumnIDs,
ColumnKeys: msg.ColumnKeys,
Values: msg.Values,
FloatValues: msg.FloatValues,
TimestampValues: msg.TimestampValues,
StringValues: msg.StringValues,
Clear: msg.Clear,
}
qcx := api.Txf().NewQcx()
defer qcx.Abort()
opts := []ImportOption{
OptImportOptionsClear(msg.Clear),
OptImportOptionsIgnoreKeyCheck(msg.IgnoreKeyCheck),
OptImportOptionsPresorted(msg.Presorted),
OptImportOptionsSuppressLog(true),
}
if err := api.ImportValue(ctx, qcx, req, opts...); err != nil {
return errors.Wrapf(err, "import value, table: %s, field: %s, shard: %d", msg.Table, msg.Field, msg.Shard)
}
case *computer.ImportRoaringShardMessage:
req := &ImportRoaringShardRequest{
Remote: true,
Views: make([]RoaringUpdate, len(msg.Views)),
SuppressLog: true,
}
for i, view := range msg.Views {
req.Views[i] = RoaringUpdate{
Field: view.Field,
View: view.View,
Clear: view.Clear,
Set: view.Set,
ClearRecords: view.ClearRecords,
}
}
if err := api.ImportRoaringShard(ctx, msg.Table, msg.Shard, req); err != nil {
return errors.Wrapf(err, "import roaring shard table: %s, shard: %d", msg.Table, msg.Shard)
}
}
}
return nil
}
// 1st write log load
if err := loadWriteLog(); err != nil {
return err
}
// acquire lock on this partition's keys
if err := resource.Lock(); err != nil {
return errors.Wrap(err, "locking field key partition")
}
// reload writelog in case of changes between last load and
// lock. The resource object takes care of only loading new data.
return loadWriteLog()
}
//////////////////////////////////////////////////////////////
// sliceComparer is used to compare the differences between two slices of comparables.
type sliceComparer[K comparable] struct {
from []K
to []K
}
func newSliceComparer[K comparable](from []K, to []K) *sliceComparer[K] {
return &sliceComparer[K]{
from: from,
to: to,
}
}
// added returns the items which are present in `to` but not in `from`.
func (s *sliceComparer[K]) added() []K {
return thingsAdded(s.from, s.to)
}
// removed returns the items which are present in `from` but not in `to`.
func (s *sliceComparer[K]) removed() []K {
return thingsAdded(s.to, s.from)
}
// same returns the items which are in both `to` and `from`.
func (s *sliceComparer[K]) same() []K {
var same []K
for _, fromThing := range s.from {
for _, toThing := range s.to {
if fromThing == toThing {
same = append(same, fromThing)
break
}
}
}
return same
}
// thingsAdded returns the comparable things which are present in `to` but not
// in `from`.
func thingsAdded[K comparable](from []K, to []K) []K {
var added []K
for i := range to {
var found bool
for j := range from {
if from[j] == to[i] {
found = true
break
}
}
if !found {
added = append(added, to[i])
}
}
return added
}
// partitionsComparer is used to compare the differences between two maps of
// table:[]partition.
type partitionsComparer struct {
from map[dax.TableKey]dax.PartitionNums
to map[dax.TableKey]dax.PartitionNums
}
func newPartitionsComparer(from map[dax.TableKey]dax.PartitionNums, to map[dax.TableKey]dax.PartitionNums) *partitionsComparer {
return &partitionsComparer{
from: from,
to: to,
}
}
// added returns the partitions which are present in `to` but not in `from`. The
// results remain in the format of a map of table:[]partition.
func (p *partitionsComparer) added() map[dax.TableKey]dax.PartitionNums {
return partitionsAdded(p.from, p.to)
}
// removed returns the partitions which are present in `from` but not in `to`.
// The results remain in the format of a map of table:[]partition.
func (p *partitionsComparer) removed() map[dax.TableKey]dax.PartitionNums {
return partitionsAdded(p.to, p.from)
}
// partitionsAdded returns the partitions which are present in `to` but not in `from`.
func partitionsAdded(from map[dax.TableKey]dax.PartitionNums, to map[dax.TableKey]dax.PartitionNums) map[dax.TableKey]dax.PartitionNums {
if from == nil {
return to
}
added := make(map[dax.TableKey]dax.PartitionNums)
for tt, tps := range to {
fps, found := from[tt]
if !found {
added[tt] = tps
continue
}
addedPartitions := dax.PartitionNums{}
for i := range tps {
var found bool
for j := range fps {
if fps[j] == tps[i] {
found = true
break
}
}
if !found {
addedPartitions = append(addedPartitions, tps[i])
}
}
if len(addedPartitions) > 0 {
added[tt] = addedPartitions
}
}
return added
}
// fieldsComparer is used to compare the differences between two maps of
// table:[]fieldVersion.
type fieldsComparer struct {
from map[dax.TableKey][]dax.FieldName
to map[dax.TableKey][]dax.FieldName
}
func newFieldsComparer(from map[dax.TableKey][]dax.FieldName, to map[dax.TableKey][]dax.FieldName) *fieldsComparer {
return &fieldsComparer{
from: from,
to: to,
}
}
// added returns the fields which are present in `to` but not in `from`. The
// results remain in the format of a map of table:[]field.
func (f *fieldsComparer) added() map[dax.TableKey][]dax.FieldName {
return fieldsAdded(f.from, f.to)
}
// removed returns the fields which are present in `from` but not in `to`.
// The results remain in the format of a map of table:[]field.
func (f *fieldsComparer) removed() map[dax.TableKey][]dax.FieldName {
return fieldsAdded(f.to, f.from)
}
// fieldsAdded returns the fields which are present in `to` but not in `from`.
func fieldsAdded(from map[dax.TableKey][]dax.FieldName, to map[dax.TableKey][]dax.FieldName) map[dax.TableKey][]dax.FieldName {
if from == nil {
return to
}
added := make(map[dax.TableKey][]dax.FieldName)
for tt, tps := range to {
fps, found := from[tt]
if !found {
added[tt] = tps
continue
}
addedFieldVersions := []dax.FieldName{}
for i := range tps {
var found bool
for j := range fps {
if fps[j] == tps[i] {
found = true
break
}
}
if !found {
addedFieldVersions = append(addedFieldVersions, tps[i])
}
}
if len(addedFieldVersions) > 0 {
added[tt] = addedFieldVersions
}
}
return added
}
// shardsComparer is used to compare the differences between two maps of
// table:[]shardV.
type shardsComparer struct {
from map[dax.TableKey]dax.ShardNums
to map[dax.TableKey]dax.ShardNums
}
func newShardsComparer(from map[dax.TableKey]dax.ShardNums, to map[dax.TableKey]dax.ShardNums) *shardsComparer {
return &shardsComparer{
from: from,
to: to,
}
}
// added returns the shards which are present in `to` but not in `from`. The
// results remain in the format of a map of table:[]shard.
func (s *shardsComparer) added() map[dax.TableKey]dax.ShardNums {
return shardsAdded(s.from, s.to)
}
// removed returns the shards which are present in `from` but not in `to`. The
// results remain in the format of a map of table:[]shard.
func (s *shardsComparer) removed() map[dax.TableKey]dax.ShardNums {
return shardsAdded(s.to, s.from)
}
// shardsAdded returns the shards which are present in `to` but not in `from`.
func shardsAdded(from map[dax.TableKey]dax.ShardNums, to map[dax.TableKey]dax.ShardNums) map[dax.TableKey]dax.ShardNums {
if from == nil {
return to
}
added := make(map[dax.TableKey]dax.ShardNums)
for tt, tss := range to {
fss, found := from[tt]
if !found {
added[tt] = tss
continue
}
addedShards := dax.ShardNums{}
for i := range tss {
var found bool
for j := range fss {
if fss[j] == tss[i] {
found = true
break
}
}
if !found {
addedShards = append(addedShards, tss[i])
}
}
if len(addedShards) > 0 {
added[tt] = addedShards
}
}
return added
}
// createTableAndFields creates the FeatureBase Tables and Fields provided in
// the dax.Directive format.
func (api *API) createTableAndFields(tbl *dax.QualifiedTable, partitions dax.PartitionNums) error {
cim := &CreateIndexMessage{
Index: string(tbl.Key()),
CreatedAt: 0,
Meta: IndexOptions{
Keys: tbl.StringKeys(),
TrackExistence: true,
},
}
// Create the index in etcd as the system of record.
if err := api.holder.persistIndex(context.Background(), cim); err != nil {
return errors.Wrap(err, "persisting index")
}
idx, err := api.holder.createIndexWithPartitions(cim, partitions)
if err != nil {
return errors.Wrapf(err, "adding index: %s", tbl.Name)
}
// Add the fields
for _, fld := range tbl.Fields {
if fld.IsPrimaryKey() {
continue
}
if err := createField(idx, fld); err != nil {
return errors.Wrapf(err, "creating field: %s", fld.Name)
}
}
return nil
}
// createField creates a FeatureBase Field in the provided FeatureBase Index
// based on the provided field's type.
func createField(idx *Index, fld *dax.Field) error {
opts, err := FieldOptionsFromField(fld)
if err != nil {
return errors.Wrapf(err, "creating field options from field: %s", fld.Name)
}
if _, err := idx.createNullableField(string(fld.Name), "", opts...); err != nil {
return errors.Wrapf(err, "creating field on index: %s", fld.Name)
}
return nil
}

View file

@ -1,25 +0,0 @@
package pilosa
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestThingsAddedGeneric(t *testing.T) {
from := []string{"a", "b", "c"}
to := []string{"b", "c", "d"}
added := thingsAdded(from, to)
assert.Equal(t, added, []string{"d"})
}
func TestSliceComparer(t *testing.T) {
from := []string{"a", "b", "c"}
to := []string{"b", "c", "d"}
sc := newSliceComparer(from, to)
added := sc.added()
assert.Equal(t, added, []string{"d"})
}

View file

@ -1,97 +0,0 @@
package pilosa_test
import (
"context"
"testing"
pilosa "github.com/featurebasedb/featurebase/v3"
"github.com/featurebasedb/featurebase/v3/dax"
daxtest "github.com/featurebasedb/featurebase/v3/dax/test"
"github.com/featurebasedb/featurebase/v3/test"
"github.com/stretchr/testify/assert"
)
// Ensure holder can handle an incoming directive.
func TestAPI_Directive(t *testing.T) {
c := test.MustRunCluster(t, 1)
defer c.Close()
api := c.GetPrimary().API
ctx := context.Background()
qdbid := dax.NewQualifiedDatabaseID("acme", "db1")
tbl1 := daxtest.TestQualifiedTableWithID(t, qdbid, "1", "tbl1", 12, false)
tbl2 := daxtest.TestQualifiedTableWithID(t, qdbid, "2", "tbl2", 12, false)
tbl3 := daxtest.TestQualifiedTableWithID(t, qdbid, "3", "tbl3", 12, false)
t.Run("Schema", func(t *testing.T) {
// Empty directive (and empty holder).
{
d := &dax.Directive{
Method: dax.DirectiveMethodFull,
Version: 1,
}
err := api.ApplyDirective(ctx, d)
assert.NoError(t, err)
assertTablesMatch(t, []string{}, api.Holder().Indexes())
}
// Add a new table.
{
d := &dax.Directive{
Method: dax.DirectiveMethodFull,
Tables: []*dax.QualifiedTable{
tbl1,
},
Version: 2,
}
err := api.ApplyDirective(ctx, d)
assert.NoError(t, err)
assertTablesMatch(t, []string{"tbl__acme__db1__1"}, api.Holder().Indexes())
}
// Add a new table, and keep the existing table.
{
d := &dax.Directive{
Method: dax.DirectiveMethodFull,
Tables: []*dax.QualifiedTable{
tbl1,
tbl2,
},
Version: 3,
}
err := api.ApplyDirective(ctx, d)
assert.NoError(t, err)
assertTablesMatch(t, []string{"tbl__acme__db1__1", "tbl__acme__db1__2"}, api.Holder().Indexes())
}
// Add a new table and remove one of the existing tables.
{
d := &dax.Directive{
Method: dax.DirectiveMethodFull,
Tables: []*dax.QualifiedTable{
tbl2,
tbl3,
},
Version: 4,
}
err := api.ApplyDirective(ctx, d)
assert.NoError(t, err)
assertTablesMatch(t, []string{"tbl__acme__db1__2", "tbl__acme__db1__3"}, api.Holder().Indexes())
}
})
}
// assertTablesMatch is a helper function which asserts that the list of index
// names in `actual` match those provided in `expected`.
func assertTablesMatch(t *testing.T, expected []string, actual []*pilosa.Index) {
t.Helper()
act := make([]string, len(actual))
for i := range actual {
act[i] = actual[i].Name()
}
assert.ElementsMatch(t, expected, act)
}

File diff suppressed because it is too large Load diff

View file

@ -27,27 +27,27 @@ func _() {
_ = x[apiIndex-16]
_ = x[apiQuery-17]
_ = x[apiRecalculateCaches-18]
_ = x[apiSchema-19]
_ = x[apiShardNodes-20]
_ = x[apiState-21]
_ = x[apiViews-22]
_ = x[apiApplySchema-23]
_ = x[apiStartTransaction-24]
_ = x[apiFinishTransaction-25]
_ = x[apiTransactions-26]
_ = x[apiGetTransaction-27]
_ = x[apiActiveQueries-28]
_ = x[apiPastQueries-29]
_ = x[apiIDReserve-30]
_ = x[apiIDCommit-31]
_ = x[apiIDReset-32]
_ = x[apiPartitionNodes-33]
_ = x[apiMutexCheck-34]
_ = x[apiRemoveNode-19]
_ = x[apiResizeAbort-20]
_ = x[apiSchema-21]
_ = x[apiShardNodes-22]
_ = x[apiState-23]
_ = x[apiViews-24]
_ = x[apiApplySchema-25]
_ = x[apiStartTransaction-26]
_ = x[apiFinishTransaction-27]
_ = x[apiTransactions-28]
_ = x[apiGetTransaction-29]
_ = x[apiActiveQueries-30]
_ = x[apiPastQueries-31]
_ = x[apiIDReserve-32]
_ = x[apiIDCommit-33]
_ = x[apiIDReset-34]
}
const _apiMethod_name = "apiClusterMessageapiCreateFieldapiCreateIndexapiDeleteFieldapiDeleteAvailableShardapiDeleteIndexapiDeleteViewapiExportCSVapiFragmentBlockDataapiFragmentBlocksapiFragmentDataapiTranslateDataapiFieldTranslateDataapiFieldapiImportapiImportValueapiIndexapiQueryapiRecalculateCachesapiSchemaapiShardNodesapiStateapiViewsapiApplySchemaapiStartTransactionapiFinishTransactionapiTransactionsapiGetTransactionapiActiveQueriesapiPastQueriesapiIDReserveapiIDCommitapiIDResetapiPartitionNodesapiMutexCheck"
const _apiMethod_name = "apiClusterMessageapiCreateFieldapiCreateIndexapiDeleteFieldapiDeleteAvailableShardapiDeleteIndexapiDeleteViewapiExportCSVapiFragmentBlockDataapiFragmentBlocksapiFragmentDataapiTranslateDataapiFieldTranslateDataapiFieldapiImportapiImportValueapiIndexapiQueryapiRecalculateCachesapiRemoveNodeapiResizeAbortapiSchemaapiShardNodesapiStateapiViewsapiApplySchemaapiStartTransactionapiFinishTransactionapiTransactionsapiGetTransactionapiActiveQueriesapiPastQueriesapiIDReserveapiIDCommitapiIDReset"
var _apiMethod_index = [...]uint16{0, 17, 31, 45, 59, 82, 96, 109, 121, 141, 158, 173, 189, 210, 218, 227, 241, 249, 257, 277, 286, 299, 307, 315, 329, 348, 368, 383, 400, 416, 430, 442, 453, 463, 480, 493}
var _apiMethod_index = [...]uint16{0, 17, 31, 45, 59, 82, 96, 109, 121, 141, 158, 173, 189, 210, 218, 227, 241, 249, 257, 277, 290, 304, 313, 326, 334, 342, 356, 375, 395, 410, 427, 443, 457, 469, 480, 490}
func (i apiMethod) String() string {
if i < 0 || i >= apiMethod(len(_apiMethod_index)-1) {

686
apply.go
View file

@ -1,686 +0,0 @@
// Copyright 2021 Molecula Corp. All rights reserved.
package pilosa
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strings"
"sync"
"github.com/apache/arrow/go/v10/arrow"
"github.com/apache/arrow/go/v10/arrow/array"
"github.com/apache/arrow/go/v10/arrow/memory"
"github.com/featurebasedb/featurebase/v3/pql"
"github.com/featurebasedb/featurebase/v3/tracing"
"github.com/featurebasedb/featurebase/v3/vprint"
"github.com/gomem/gomem/pkg/dataframe"
"github.com/pkg/errors"
ivy "robpike.io/ivy/arrow"
config "robpike.io/ivy/config"
"robpike.io/ivy/exec"
"robpike.io/ivy/parse"
"robpike.io/ivy/run"
"robpike.io/ivy/scan"
"robpike.io/ivy/value"
)
type (
ApplyResult *arrow.Column
)
func runIvyString(context value.Context, str string) (ok bool, err error) {
defer func() {
if r := recover(); r != nil {
err = r.(value.Error)
}
}()
scanner := scan.New(context, "<args>", strings.NewReader(str))
parser := parse.NewParser("<args>", scanner, context)
ok = run.Run(parser, context, false)
return
}
// Possibly combine all arrays together then apply some interesting
// computation at the end?
func IvyReduce(reduceCode string, opCode string, opt *ExecOptions) (func(ctx context.Context, prev, v interface{}) interface{}, func() (*dataframe.DataFrame, error)) {
var accumulator value.Value
mu := &sync.Mutex{}
concat := value.BinaryOps[opCode]
conf := getDefaultConfig()
ctxIvy := exec.NewContext(&conf)
// concat returned results at coordinating node.
reduceFn := func(ctx context.Context, prev, v interface{}) interface{} {
if v == nil {
return prev
}
if accumulator == nil {
switch val := v.(type) {
case *dataframe.DataFrame:
col := val.ColumnAt(0)
resolver := dataframe.NewChunkResolver(col)
accumulator = value.NewArrowVector(col, &conf, &resolver)
case value.Value:
accumulator = v.(value.Value)
default:
return errors.New(fmt.Sprintf("ivy reduction failed first unexpected type %T", v))
}
return nil
}
switch val := v.(type) {
case *dataframe.DataFrame:
col := val.ColumnAt(0)
resolver := dataframe.NewChunkResolver(col)
x := value.NewArrowVector(col, &conf, &resolver)
mu.Lock() // i'm being overyerly cautious..need to confirm this can be concurrent
accumulator = concat.EvalBinary(ctxIvy, accumulator, x)
mu.Unlock()
case value.Value:
mu.Lock()
accumulator = concat.EvalBinary(ctxIvy, accumulator, val)
mu.Unlock()
default:
return errors.New(fmt.Sprintf("ivy reduction failed unexpected type %T", v))
}
return nil
}
tablerFn := func() (*dataframe.DataFrame, error) {
pool := memory.NewGoAllocator() // TODO(twg) 2022/09/01 singledton?
if opt.Remote {
col := value.ToArrowColumn(accumulator, pool)
return dataframe.NewDataFrameFromColumns(pool, []arrow.Column{*col})
}
// only actually reduce on the initiating node i hate the network
// over head but oh well
ctxIvy.AssignGlobal("_", accumulator)
ok, err := runIvyString(ctxIvy, reduceCode)
if err != nil {
return nil, err
}
if ok {
v := ctxIvy.Global("_")
if v == nil {
return nil, errors.New("ivy reduction no result ")
}
col := value.ToArrowColumn(ctxIvy.Global("_"), pool)
return dataframe.NewDataFrameFromColumns(pool, []arrow.Column{*col})
}
return nil, errors.New("ivy reduction failed ")
}
return reduceFn, tablerFn
}
// executeApply executes a Apply() call.
func (e *executor) executeApply(ctx context.Context, qcx *Qcx, index string, c *pql.Call, shards []uint64, opt *ExecOptions) (*dataframe.DataFrame, error) {
if !e.dataframeEnabled {
return nil, errors.New("Dataframe support not enabled")
}
span, ctx := tracing.StartSpanFromContext(ctx, "Executor.executeMax")
defer span.Finish()
if _, err := c.FirstStringArg("_ivy"); err != nil {
return nil, errors.Wrap(err, " no ivy program supplied")
}
if len(c.Children) > 1 {
return nil, errors.New("Apply() only accepts a single bitmap input filter")
}
// Execute calls in bulk on each remote node and merge.
mapFn := func(ctx context.Context, shard uint64, mopt *mapOptions) (_ interface{}, err error) {
return e.executeApplyShard(ctx, qcx, index, c, shard)
}
ivyReduce, ok, err := c.StringArg("_ivyReduce")
if err != nil {
return nil, err
}
reduceFn, tablerFn := IvyReduce("_", ",", opt)
if ok {
reduceFn, tablerFn = IvyReduce(ivyReduce, ",", opt)
}
_, err = e.mapReduce(ctx, index, shards, c, opt, mapFn, reduceFn)
if err != nil {
return nil, err
}
return tablerFn()
}
func getDefaultConfig() config.Config {
maxbits := uint(1e9) // "maximum size of an integer, in bits; 0 means no limit")
maxdigits := uint(1e4) // "above this many `digits`, integers print as floating point; 0 disables")
maxstack := uint(100000)
origin := 1 // "set index origin to `n` (must be 0 or 1)")
prompt := "" // flag.String("prompt", "", "command `prompt`")
format := ""
// debugFlag := "" // flag.String("debug", "", "comma-separated `names` of debug settings to enable")
conf := config.Config{}
conf.SetFormat(format)
conf.SetMaxBits(maxbits)
conf.SetMaxDigits(maxdigits)
conf.SetMaxStack(maxstack)
conf.SetOrigin(origin)
conf.SetPrompt(prompt)
conf.SetOutput(io.Discard)
conf.SetErrOutput(io.Discard)
conf.SetEmbedded(true) // needed to propagate panic
return conf
}
func filterDataframe(resolver dataframe.Resolver, pool memory.Allocator, filter []int64) (*dataframe.IndexResolver, error) {
if resolver.NumRows() == 0 {
return nil, errors.New("No data")
}
indexResolver := dataframe.NewIndexResolver(len(filter), uint32(ShardWidth-1))
for i, id := range filter {
if int(id) >= resolver.NumRows() {
continue
}
c, o := resolver.Resolve(int(id))
indexResolver.Set(i, c, o)
}
return indexResolver, nil
}
func (e *executor) executeApplyShard(ctx context.Context, qcx *Qcx, index string, c *pql.Call, shard uint64) (value.Value, error) {
span, _ := tracing.StartSpanFromContext(ctx, "Executor.executeApplyShard")
defer span.Finish()
ivyProgram, ok, err := c.StringArg("_ivy")
if err != nil || !ok {
return nil, errors.Wrap(err, "finding ivy program")
}
var filter *Row
if len(c.Children) == 1 {
row, err := e.executeBitmapCallShard(ctx, qcx, index, c.Children[0], shard)
if err != nil {
return nil, err
}
filter = row
if !filter.Any() {
// no need to actuall run the query for its not operating against any values
return value.NewVector([]value.Value{}), nil
}
}
//
pool := memory.NewGoAllocator() // TODO(twg) 2022/09/01 singledton?
ids := filter.ShardColumns() // needs to be shard columns
// Fetch index.
idx := e.Holder.Index(index)
if idx == nil {
return nil, newNotFoundError(ErrIndexNotFound, index)
}
fname := idx.GetDataFramePath(shard)
if !e.dataFrameExists(fname) {
return value.NewVector([]value.Value{}), nil
}
table, err := e.getDataTable(ctx, fname, pool)
if err != nil {
return nil, err
}
defer table.Release()
df, err := dataframe.NewDataFrameFromTable(pool, table)
if err != nil {
return nil, err
}
p := dataframe.NewChunkResolver(df.ColumnAt(0))
var resolver dataframe.Resolver
resolver = &p
if filter != nil {
if len(ids) == 0 {
return value.NewVector([]value.Value{}), nil
}
resolver, err = filterDataframe(resolver, pool, ids)
if err != nil {
return nil, err
}
}
conf := getDefaultConfig()
context, err := ivy.RunArrow(dataframe.NewTableFacade(df), ivyProgram, conf, resolver)
if err != nil {
return nil, fmt.Errorf("ivy map error: %w", err)
}
return context.Global("_"), nil
}
// ///////////////////////////////////////////////////////
// all the ingest supporting functions
// ///////////////////////////////////////////////////////
func NewShardFile(ctx context.Context, name string, mem memory.Allocator, e *executor) (*ShardFile, error) {
if !e.dataFrameExists(name) {
return &ShardFile{dest: name, executor: e, strings: make(map[key][]string)}, nil
}
// else read in existing
table, err := e.getDataTable(ctx, name, mem)
if err != nil {
return nil, err
}
return &ShardFile{table: table, schema: table.Schema(), dest: name, executor: e, strings: make(map[key][]string)}, nil
}
type NameType struct {
Name string
DataType arrow.DataType
}
type ChangesetRequest struct {
ShardIds []int64 // only shardwidth bits to provide 0 indexing inside shard file
Columns []interface{}
SimpleSchema []NameType
}
// TODO(twg) 2022/09/30 Needs a refactor
func cast(v interface{}) arrow.DataType {
switch v.(type) {
case *arrow.Int64Type:
return arrow.PrimitiveTypes.Int64
case int64:
return arrow.PrimitiveTypes.Int64
case *arrow.Float64Type:
return arrow.PrimitiveTypes.Float64
case float64:
return arrow.PrimitiveTypes.Float64
case *arrow.StringType:
return arrow.BinaryTypes.String
default:
vprint.VV("%T .... %v", v, v)
}
return arrow.PrimitiveTypes.Int64
}
func (cr *ChangesetRequest) ArrowSchema() *arrow.Schema {
fields := make([]arrow.Field, len(cr.SimpleSchema))
for i := range cr.SimpleSchema {
fields[i] = arrow.Field{Name: cr.SimpleSchema[i].Name, Type: cast(cr.SimpleSchema[i].DataType)}
}
return arrow.NewSchema(fields, nil)
}
type key struct {
col int
chunk int
}
type ShardFile struct {
table arrow.Table
schema *arrow.Schema
beforeRows int64
added int64
columns []interface{}
dest string
executor *executor
strings map[key][]string
}
func compareSchema(s1, s2 *arrow.Schema) bool {
if s1 == nil || s2 == nil {
return false
}
if len(s1.Fields()) != len(s2.Fields()) {
return false
}
for i := 0; i < len(s1.Fields()); i++ {
f1 := s1.Field(i)
f2 := s2.Field(i)
if f1.Name != f2.Name {
return false
}
if f1.Type != f2.Type {
return false
}
}
return true
}
func (sf *ShardFile) EnsureSchema(cs *ChangesetRequest) error {
schema := cs.ArrowSchema()
if sf.schema == nil {
sf.schema = schema
} else {
if !compareSchema(sf.schema, schema) {
vprint.VV("incomeing schema", schema)
vprint.VV("existing schema", sf.schema)
return errors.New("dataframe schema's don't match")
}
}
sf.columns = make([]interface{}, len(sf.schema.Fields()))
return nil
}
func (sf *ShardFile) buildAppenders(maxid int64) {
if sf.table != nil {
sf.beforeRows = sf.table.NumRows()
}
if maxid < sf.beforeRows {
// no need to add new rows
return
}
newSize := maxid - sf.beforeRows + 1
for i := 0; i < len(sf.schema.Fields()); i++ {
switch sf.schema.Field(i).Type {
case arrow.PrimitiveTypes.Int64:
sf.columns[i] = make([]int64, newSize)
case arrow.PrimitiveTypes.Float64:
sf.columns[i] = make([]float64, newSize)
case arrow.BinaryTypes.String:
sf.columns[i] = make([]string, newSize)
}
}
sf.added = newSize
}
// the row offset must be reset to 0 for the slices being appended
func (sf *ShardFile) SetIntValue(col int, row int64, val int64) {
v := sf.columns[col].([]int64)
v[row-sf.beforeRows] = val
}
func (sf *ShardFile) SetFloatValue(col int, row int64, val float64) {
v := sf.columns[col].([]float64)
v[row-sf.beforeRows] = val
}
func (sf *ShardFile) SetStringValue(col int, row int64, val string) {
v := sf.columns[col].([]string)
v[row-sf.beforeRows] = val
}
func (sf *ShardFile) Process(cs *ChangesetRequest) error {
err := sf.process(cs)
if err != nil {
return err
}
rtemp := sf.dest + ".temp"
err = sf.Save(rtemp)
if err != nil {
return err
}
return os.Rename(rtemp+sf.executor.TableExtension(), sf.dest+sf.executor.TableExtension())
}
func (sf *ShardFile) LoadBlobs() error {
for col := 0; col < len(sf.schema.Fields()); col++ {
column := sf.table.Column(col)
switch column.DataType() {
case arrow.BinaryTypes.String:
for i, chunk := range column.Data().Chunks() {
stringData := chunk.(*array.String)
k := key{col: col, chunk: i}
for j := 0; j < stringData.Len(); j++ {
v := stringData.Value(j)
sf.strings[k] = append(sf.strings[k], v)
}
}
}
}
return nil
}
func (sf *ShardFile) ReplaceString(col, chunk, l int, s string) {
sf.strings[key{col: col, chunk: chunk}][l] = s
}
func (sf *ShardFile) process(cs *ChangesetRequest) error {
offset := 0
if sf.table != nil {
// need to load blobs prior
sf.LoadBlobs()
column := sf.table.Column(0)
resolver := dataframe.NewChunkResolver(column)
for i, rowid := range cs.ShardIds {
offset = i
if rowid >= sf.table.NumRows() {
break
}
chunk, l := resolver.Resolve(int(rowid))
for col := 0; col < len(sf.schema.Fields()); col++ {
column := sf.table.Column(col)
switch column.DataType() {
case arrow.PrimitiveTypes.Int64:
v := column.Data().Chunk(chunk).(*array.Int64).Int64Values()
v[l] = cs.Columns[col].([]int64)[i]
case arrow.PrimitiveTypes.Float64:
v := column.Data().Chunk(chunk).(*array.Float64).Float64Values()
v[l] = cs.Columns[col].([]float64)[i]
case arrow.BinaryTypes.String:
// TODO(twg) 2023/01/09 How to update existing?
new := cs.Columns[col].([]string)[i]
sf.ReplaceString(col, chunk, l, new)
default:
panic(fmt.Sprintf("Unknown Type %v", column.DataType()))
}
}
}
}
max := cs.ShardIds[len(cs.ShardIds)-1]
sf.buildAppenders(max)
// need to check if only replace and no apend
if sf.added > 0 {
for i, rowid := range cs.ShardIds[offset:] {
i += offset
for col := 0; col < len(sf.schema.Fields()); col++ {
switch sf.schema.Field(col).Type {
case arrow.PrimitiveTypes.Int64:
sf.SetIntValue(col, rowid, cs.Columns[col].([]int64)[i])
case arrow.PrimitiveTypes.Float64:
sf.SetFloatValue(col, rowid, cs.Columns[col].([]float64)[i])
case arrow.BinaryTypes.String:
sf.SetStringValue(col, rowid, cs.Columns[col].([]string)[i])
default:
panic(fmt.Sprintf("2 Unknown Type %v", sf.schema.Field(col).Type))
}
}
}
}
return nil
}
type twoSlices struct {
id_slice []int
lists_slice [][]string
}
type SortByOther twoSlices
func (sbo SortByOther) Len() int {
return len(sbo.id_slice)
}
func (sbo SortByOther) Swap(i, j int) {
sbo.id_slice[i], sbo.id_slice[j] = sbo.id_slice[j], sbo.id_slice[i]
sbo.lists_slice[i], sbo.lists_slice[j] = sbo.lists_slice[j], sbo.lists_slice[i]
}
func (sbo SortByOther) Less(i, j int) bool {
return sbo.id_slice[i] < sbo.id_slice[j]
}
func (sf *ShardFile) buildFromStrings(idx int, mem memory.Allocator) []arrow.Array {
ids := make([]int, 0)
lists := make([][]string, 0)
for k, v := range sf.strings {
if k.col == idx { // ugh not ordered :(
ids = append(ids, k.chunk)
lists = append(lists, v)
}
}
// sort ids/lists
parts := twoSlices{id_slice: ids, lists_slice: lists}
sort.Sort(SortByOther(parts))
builder := array.NewStringBuilder(mem)
chunks := make([]arrow.Array, 0)
for _, v := range parts.lists_slice {
builder.AppendValues(v, nil)
newChunk := builder.NewArray()
chunks = append(chunks, newChunk)
}
return chunks
}
func (sf *ShardFile) Save(name string) error {
parts := make([]arrow.Array, 0)
mem := memory.NewGoAllocator()
for col := 0; col < len(sf.schema.Fields()); col++ {
chunks := make([]arrow.Array, 0)
if sf.table != nil {
// we append if there was existing file
column := sf.table.Column(col)
// if primitive type
switch column.DataType() {
case arrow.BinaryTypes.String:
chunks = sf.buildFromStrings(col, mem)
default:
chunks = append(chunks, column.Data().Chunks()...)
}
// else binary type
}
switch sf.schema.Field(col).Type {
case arrow.PrimitiveTypes.Int64:
// case *arrow.Int64Type:
if sf.added > 0 {
ibuild := array.NewInt64Builder(mem)
ibuild.AppendValues(sf.columns[col].([]int64), nil) // TODO(twg) 2022/09/28 need to handle null
newChunk := ibuild.NewArray()
chunks = append(chunks, newChunk)
}
record, err := array.Concatenate(chunks, mem)
if err != nil {
return err
}
parts = append(parts, record)
case arrow.PrimitiveTypes.Float64:
// case *arrow.Float64Type:
if sf.added > 0 {
fbuild := array.NewFloat64Builder(mem)
fbuild.AppendValues(sf.columns[col].([]float64), nil) // TODO(twg) 2022/09/28 need to handle null
newChunk := fbuild.NewArray()
chunks = append(chunks, newChunk)
}
record, err := array.Concatenate(chunks, mem)
if err != nil {
return err
}
parts = append(parts, record)
case arrow.BinaryTypes.String:
if sf.added > 0 {
fbuild := array.NewStringBuilder(mem)
fbuild.AppendValues(sf.columns[col].([]string), nil) // TODO(twg) 2022/09/28 need to handle null
newChunk := fbuild.NewArray()
chunks = append(chunks, newChunk)
}
record, err := array.Concatenate(chunks, mem)
if err != nil {
return err
}
parts = append(parts, record)
default:
vprint.VV("UNKNOWN %T", sf.schema.Field(col).Type)
}
}
rec := array.NewRecord(sf.schema, parts, sf.beforeRows+sf.added)
table := array.NewTableFromRecords(sf.schema, []arrow.Record{rec})
return sf.executor.SaveTable(name, table, mem)
}
// TODO(twg) 2022/10/03 Not a huge fan of the global variable will look at adding to executor structure
// when dataframe is fully integrated
var (
dataframeShardLocks map[uint64]*sync.Mutex
muWriteDataframe sync.Mutex
)
func init() {
dataframeShardLocks = make(map[uint64]*sync.Mutex)
}
func getDataframeWritelock(shard uint64) *sync.Mutex {
muWriteDataframe.Lock()
defer muWriteDataframe.Unlock()
lock, ok := dataframeShardLocks[shard]
if ok {
return lock
}
newLock := sync.Mutex{}
dataframeShardLocks[shard] = &newLock
return &newLock
}
func (api *API) ApplyDataframeChangeset(ctx context.Context, index string, cs *ChangesetRequest, shard uint64) error {
// TODO(twg) 2022/09/29 need to validate api call
idx := api.Holder().Index(index)
// check if dataframe exists
fname := idx.GetDataFramePath(shard)
// only 1 shard writer allowed at at time so wait for it to be available
mu := getDataframeWritelock(shard)
mu.Lock()
defer mu.Unlock()
mem := memory.NewGoAllocator()
shardFile, err := NewShardFile(ctx, fname, mem, api.server.executor)
if err != nil {
return err
}
err = shardFile.EnsureSchema(cs)
if err != nil {
return err
}
return shardFile.Process(cs)
}
type column struct {
Name string
Type string
}
func (api *API) GetDataframeSchema(ctx context.Context, indexName string) (interface{}, error) {
idx, err := api.Index(ctx, indexName)
if err != nil {
return nil, err
}
base := idx.DataframesPath()
dir, _ := os.Open(base)
files, _ := dir.Readdir(0)
parts := make([]column, 0)
mem := memory.NewGoAllocator()
for i := range files {
file := files[i]
name := file.Name()
if api.server.executor.IsDataframeFile(name) {
// strip off the parquet extenison
name = strings.TrimSuffix(name, filepath.Ext(name))
// read the parquet file and extract the schema
fname := filepath.Join(base, name)
table, err := api.server.executor.getDataTable(ctx, fname, mem)
if err != nil {
return nil, err
}
for i := 0; i < int(table.NumCols()); i++ {
col := table.Column(i)
part := column{Name: col.Name(), Type: col.DataType().String()}
parts = append(parts, part)
}
break // only go on first file
}
}
return parts, nil
}

562
arrow.go
View file

@ -1,562 +0,0 @@
// Copyright 2021 Molecula Corp. All rights reserved.
package pilosa
import (
"context"
"encoding/json"
"fmt"
"io"
"os"
"strings"
"sync"
"github.com/apache/arrow/go/v10/arrow"
"github.com/apache/arrow/go/v10/arrow/array"
"github.com/apache/arrow/go/v10/arrow/ipc"
"github.com/apache/arrow/go/v10/arrow/memory"
"github.com/apache/arrow/go/v10/parquet"
"github.com/apache/arrow/go/v10/parquet/file"
"github.com/apache/arrow/go/v10/parquet/pqarrow"
"github.com/featurebasedb/featurebase/v3/pql"
"github.com/featurebasedb/featurebase/v3/tracing"
"github.com/gomem/gomem/pkg/dataframe"
"github.com/pkg/errors"
)
/*
The function Arrow provides filtered access to the raw values stored in the dataframe.
If Arrow is just provided a bitmap filter, such as ConstRow or any Bitmap Operation,
all the values associated with each column are returned. This set can be limited with
the addition of the header parameter
Example:
Arrow(ConstRow(columns=[2,4,6]),header=["fval"])
*/
// executeApply executes a Arrow() call.
func (e *executor) executeArrow(ctx context.Context, qcx *Qcx, index string, c *pql.Call, shards []uint64, opt *ExecOptions) (arrow.Table, error) {
if !e.dataframeEnabled {
return nil, errors.New("Dataframe support not enabled")
}
span, ctx := tracing.StartSpanFromContext(ctx, "Executor.executeArrow")
defer span.Finish()
if len(c.Children) > 1 {
return nil, errors.New("Apply() only accepts a single bitmap input filter")
}
var columnFilter []string
if cols, ok := c.Args["header"].([]interface{}); ok {
columnFilter = make([]string, 0, len(cols))
for _, v := range cols {
columnFilter = append(columnFilter, v.(string))
}
}
mapcounter := 0
reducecounter := 0
pool := memory.NewGoAllocator() // TODO(twg) 2022/09/01 singledton?
// Execute calls in bulk on each remote node and merge.
mu := &sync.Mutex{}
mapFn := func(ctx context.Context, shard uint64, mopt *mapOptions) (_ interface{}, err error) {
mu.Lock()
mapcounter++
mu.Unlock()
return e.executeArrowShard(ctx, qcx, index, c, shard, pool, columnFilter)
}
tables := make([]*BasicTable, 0)
reduceFn := func(ctx context.Context, prev, v interface{}) interface{} {
mu.Lock()
reducecounter++
mu.Unlock()
if v == nil {
return prev
}
switch t := v.(type) {
case *BasicTable:
if t.resolver != nil {
mu.Lock()
tables = append(tables, t)
mu.Unlock()
}
case arrow.Table:
if t.NumRows() > 0 {
bt := BasicTableFromArrow(t, pool)
mu.Lock()
tables = append(tables, bt)
mu.Unlock()
}
}
return nil
}
_, err := e.mapReduce(ctx, index, shards, c, opt, mapFn, reduceFn)
if err != nil {
return nil, err
}
if len(tables) == 0 {
return &BasicTable{name: "empty"}, nil
}
tbl := Concat(tables[0].Schema(), tables, pool)
r := dataframe.NewChunkResolver(tbl.Column(0))
return &BasicTable{resolver: &r, table: tbl}, nil
}
type BasicTable struct {
resolver dataframe.Resolver
table arrow.Table
filtered bool
name string
}
func (st *BasicTable) Name() string {
return st.name
}
func (st *BasicTable) Schema() *arrow.Schema {
if st.table != nil {
return st.table.Schema()
}
return &arrow.Schema{}
}
func (st *BasicTable) IsFiltered() bool {
return st.filtered
}
func (st *BasicTable) NumRows() int64 {
if st.resolver == nil {
return 0
}
return int64(st.resolver.NumRows())
}
func (st *BasicTable) NumCols() int64 {
if st.table != nil {
return st.table.NumCols()
}
return 0
}
func (st *BasicTable) Column(i int) *arrow.Column {
if st.table != nil {
return st.table.Column(i)
}
return nil
}
func (st *BasicTable) Retain() {
if st.table != nil {
st.table.Retain()
}
}
func (st *BasicTable) Release() {
if st.table != nil {
st.table.Retain()
}
}
func (st *BasicTable) Get(column, row int) interface{} {
field := st.Schema().Field(column)
c, i := st.resolver.Resolve(row)
nullable := field.Nullable
chunk := st.Column(column).Data().Chunk(c)
// TODO(twg) 2023/01/26 potential NULL support?
if nullable && chunk.IsNull(i) {
return nil
}
switch field.Type.(type) {
case *arrow.BooleanType:
return chunk.(*array.Boolean).Value(i)
case *arrow.Int8Type:
v := chunk.(*array.Int8).Int8Values()
return int64(v[i])
case *arrow.Int16Type:
v := chunk.(*array.Int16).Int16Values()
return int64(v[i])
case *arrow.Int32Type:
v := chunk.(*array.Int32).Int32Values()
return int64(v[i])
case *arrow.Int64Type:
v := chunk.(*array.Int64).Int64Values()
return int64(v[i])
case *arrow.Uint8Type:
v := chunk.(*array.Uint8).Uint8Values()
return uint64(v[i])
case *arrow.Uint16Type:
v := chunk.(*array.Uint16).Uint16Values()
return uint64(v[i])
case *arrow.Uint32Type:
v := chunk.(*array.Uint32).Uint32Values()
return uint64(v[i])
case *arrow.Uint64Type:
v := chunk.(*array.Uint64).Uint64Values()
return v[i]
case *arrow.Float32Type:
v := chunk.(*array.Float32).Float32Values()
return float64(v[i])
case *arrow.Float64Type:
v := chunk.(*array.Float64).Float64Values()
return v[i]
case *arrow.StringType:
return chunk.(*array.String).Value(i)
}
return 0
}
func builderFrom(mem memory.Allocator, dt arrow.DataType, size int64) array.Builder {
var bldr array.Builder
switch dt := dt.(type) {
case *arrow.BooleanType:
bldr = array.NewBooleanBuilder(mem)
case *arrow.Int8Type:
bldr = array.NewInt8Builder(mem)
case *arrow.Int16Type:
bldr = array.NewInt16Builder(mem)
case *arrow.Int32Type:
bldr = array.NewInt32Builder(mem)
case *arrow.Int64Type:
bldr = array.NewInt64Builder(mem)
case *arrow.Uint8Type:
bldr = array.NewUint8Builder(mem)
case *arrow.Uint16Type:
bldr = array.NewUint16Builder(mem)
case *arrow.Uint32Type:
bldr = array.NewUint32Builder(mem)
case *arrow.Uint64Type:
bldr = array.NewUint64Builder(mem)
case *arrow.Float32Type:
bldr = array.NewFloat32Builder(mem)
case *arrow.Float64Type:
bldr = array.NewFloat64Builder(mem)
case *arrow.StringType:
bldr = array.NewStringBuilder(mem)
default:
panic(fmt.Errorf("builderFrom: invalid Arrow type %v", dt))
}
bldr.Reserve(int(size))
return bldr
}
func appendData(bldr array.Builder, v interface{}) {
switch bldr := bldr.(type) {
case *array.BooleanBuilder:
bldr.Append(v.(bool))
case *array.Int8Builder:
bldr.Append(v.(int8))
case *array.Int16Builder:
bldr.Append(v.(int16))
case *array.Int32Builder:
bldr.Append(v.(int32))
case *array.Int64Builder:
bldr.Append(v.(int64))
case *array.Uint8Builder:
bldr.Append(v.(uint8))
case *array.Uint16Builder:
bldr.Append(v.(uint16))
case *array.Uint32Builder:
bldr.Append(v.(uint32))
case *array.Uint64Builder:
bldr.Append(v.(uint64))
case *array.Float32Builder:
bldr.Append(v.(float32))
case *array.Float64Builder:
bldr.Append(v.(float64))
case *array.StringBuilder:
bldr.Append(v.(string))
default:
panic(fmt.Errorf("appendData: invalid Arrow builder type %T", bldr))
}
}
func Concat(schema *arrow.Schema, tables []*BasicTable, mem memory.Allocator) arrow.Table {
if len(tables) == 1 {
if !tables[0].IsFiltered() {
return tables[0]
}
}
cols := make([]arrow.Column, len(schema.Fields()))
defer func(cols []arrow.Column) {
for i := range cols {
cols[i].Release()
}
}(cols)
sz := 0
for i := range tables {
sz += int(tables[i].NumRows())
}
for i := range cols {
field := schema.Field(i)
arrs := make([]arrow.Array, 0)
builder := builderFrom(mem, field.Type, int64(sz))
for t := range tables {
table := tables[t]
if table.IsFiltered() {
for row := 0; row < int(table.NumRows()); row++ {
v := table.Get(i, row)
appendData(builder, v)
}
arrs = append(arrs, builder.NewArray())
} else {
parts := table.Column(i).Data()
arrs = append(arrs, parts.Chunks()...)
}
}
chunk := arrow.NewChunked(field.Type, arrs)
cols[i] = *arrow.NewColumn(field, chunk)
chunk.Release()
}
return array.NewTable(schema, cols, -1)
}
func (st *BasicTable) MarshalJSON() ([]byte, error) {
results := make(map[string]interface{})
n := 0
if st.table != nil {
n = int(st.table.NumCols())
}
for b := 0; b < n; b++ {
col := st.table.Column(b)
result := make([]interface{}, st.resolver.NumRows())
for n := st.resolver.NumRows() - 1; n >= 0; n-- {
v := st.Get(b, n)
result[n] = v
}
results[col.Name()] = result
}
return json.Marshal(results)
}
func BasicTableFromArrow(table arrow.Table, mem memory.Allocator) *BasicTable {
col := table.Column(0)
r := dataframe.NewChunkResolver(col)
return &BasicTable{resolver: &r, table: table}
}
func filterColumns(filters []string, table arrow.Table) arrow.Table {
filters = append(filters, "_ID")
schema := table.Schema()
// TODO(twg) 2022/11/09 add glob support
allFields := schema.Fields()
in := func(key string) bool {
for _, v := range filters {
if v == key {
return true
}
}
return false
}
cols := make([]arrow.Column, 0)
fields := make([]arrow.Field, 0)
for i := range allFields {
field := allFields[i]
if in(field.Name) {
cols = append(cols, *table.Column(i))
fields = append(fields, field)
}
}
filterdSchema := arrow.NewSchema(fields, nil) // TODO(twg) 2022/11/09 handle meta:w
return array.NewTable(filterdSchema, cols, table.NumRows())
}
func (e *executor) executeArrowShard(ctx context.Context, qcx *Qcx, index string, c *pql.Call, shard uint64, pool memory.Allocator, columnFilter []string) (*BasicTable, error) {
name := fmt.Sprintf("a. %v", shard)
span, _ := tracing.StartSpanFromContext(ctx, "Executor.executeArrowShard")
defer span.Finish()
var filter *Row
if len(c.Children) == 1 {
row, err := e.executeBitmapCallShard(ctx, qcx, index, c.Children[0], shard)
if err != nil {
return nil, err
}
filter = row
if !filter.Any() {
// no need to actuall run the query for its not operating against any values
return &BasicTable{name: name}, nil
}
}
//
ids := filter.ShardColumns() // needs to be shard columns
// Fetch index.
idx := e.Holder.Index(index)
if idx == nil {
return nil, newNotFoundError(ErrIndexNotFound, index)
}
fname := idx.GetDataFramePath(shard)
if !e.dataFrameExists(fname) {
return &BasicTable{name: name}, nil
}
table, err := e.getDataTable(ctx, fname, pool)
if err != nil {
return nil, errors.Wrap(err, "arrow readTableParquet")
}
defer table.Release()
if len(columnFilter) > 0 {
table = filterColumns(columnFilter, table)
}
df, err := dataframe.NewDataFrameFromTable(pool, table)
if err != nil {
return nil, errors.Wrap(err, "arrow NewDataFromTable")
}
p := dataframe.NewChunkResolver(df.ColumnAt(0))
var resolver dataframe.Resolver
resolver = &p
if filter != nil {
if len(ids) == 0 {
return &BasicTable{name: name}, nil
}
resolver, err = filterDataframe(resolver, pool, ids)
if err != nil {
return nil, errors.Wrap(err, "filtering dataframe")
}
}
table.Retain()
return &BasicTable{resolver: resolver, table: table, filtered: filter != nil, name: name}, nil
}
func (e *executor) dataFrameExists(fname string) bool {
if e.typeIsParquet() {
if _, err := os.Stat(fname + ".parquet"); os.IsNotExist(err) {
return false
}
return true
}
if _, err := os.Stat(fname + ".arrow"); os.IsNotExist(err) {
return false
}
return true
}
func (e *executor) getDataTable(ctx context.Context, fname string, mem memory.Allocator) (arrow.Table, error) {
if e.typeIsParquet() {
table, err := readTableParquetCtx(ctx, fname, mem)
return table, err
}
return readTableArrow(fname, mem)
}
func (e *executor) typeIsParquet() bool {
return e.datafameUseParquet
}
func (e *executor) IsDataframeFile(name string) bool {
if e.typeIsParquet() {
return strings.HasSuffix(name, ".parquet")
}
return strings.HasSuffix(name, ".arrow")
}
func (e *executor) SaveTable(name string, table arrow.Table, mem memory.Allocator) error {
if e.typeIsParquet() {
return writeTableParquet(table, name)
}
return writeTableArrow(table, name, mem)
}
func (e *executor) TableExtension() string {
if e.typeIsParquet() {
return ".parquet"
}
return ".arrow"
}
func readTableArrow(filename string, mem memory.Allocator) (arrow.Table, error) {
r, err := os.Open(filename + ".arrow")
if err != nil {
return nil, err
}
rr, err := ipc.NewFileReader(r, ipc.WithAllocator(mem))
if err != nil {
return nil, err
}
defer rr.Close()
records := make([]arrow.Record, rr.NumRecords())
i := 0
for {
rec, err := rr.Read()
if err == io.EOF {
break
} else if err != nil {
return nil, err
}
records[i] = rec
i++
}
records = records[:i]
table := array.NewTableFromRecords(rr.Schema(), records)
return table, nil
}
func readTableParquetCtx(ctx context.Context, filename string, mem memory.Allocator) (arrow.Table, error) {
r, err := os.Open(filename + ".parquet")
if err != nil {
return nil, err
}
defer r.Close()
pf, err := file.NewParquetReader(r)
if err != nil {
return nil, err
}
reader, err := pqarrow.NewFileReader(pf, pqarrow.ArrowReadProperties{}, mem)
if err != nil {
return nil, err
}
return reader.ReadTable(ctx)
}
func writeTableParquet(table arrow.Table, filename string) error {
f, err := os.Create(filename + ".parquet")
if err != nil {
return err
}
defer f.Close()
props := parquet.NewWriterProperties(parquet.WithDictionaryDefault(false))
arrProps := pqarrow.DefaultWriterProps()
chunkSize := 10 * 1024 * 1024
err = pqarrow.WriteTable(table, f, int64(chunkSize), props, arrProps)
if err != nil {
return err
}
f.Sync()
return nil
}
func writeTableArrow(table arrow.Table, filename string, mem memory.Allocator) error {
f, err := os.Create(filename + ".arrow")
if err != nil {
return err
}
defer f.Close()
writer, err := ipc.NewFileWriter(f, ipc.WithAllocator(mem), ipc.WithSchema(table.Schema()))
if err != nil {
panic(err)
}
chunkSize := int64(0)
tr := array.NewTableReader(table, chunkSize)
defer tr.Release()
n := 0
for tr.Next() {
arec := tr.Record()
err = writer.Write(arec)
if err != nil {
panic(err)
}
n++
}
err = writer.Close()
if err != nil {
panic(err)
}
f.Sync()
return nil
}

View file

@ -1,53 +0,0 @@
// Copyright 2021 Molecula Corp. All rights reserved.
package pilosa
import (
"context"
"encoding/hex"
"math/rand"
"os"
"path/filepath"
"testing"
"github.com/apache/arrow/go/v10/arrow"
"github.com/apache/arrow/go/v10/arrow/array"
"github.com/apache/arrow/go/v10/arrow/memory"
)
func TempFileName(prefix string) string {
randBytes := make([]byte, 16)
rand.Read(randBytes)
return filepath.Join(os.TempDir(), prefix+hex.EncodeToString(randBytes))
}
func Test_TableParquet(t *testing.T) {
// create a arrow table
schema := arrow.NewSchema(
[]arrow.Field{
{Name: "num", Type: arrow.PrimitiveTypes.Float64},
},
nil, // no metadata
)
mem := memory.NewGoAllocator()
b := array.NewRecordBuilder(mem, schema)
defer b.Release()
b.Field(0).(*array.Float64Builder).AppendValues([]float64{1.0, 1.5, 2.0}, nil)
table := array.NewTableFromRecords(schema, []arrow.Record{b.NewRecord()})
defer table.Release()
fileName := TempFileName("pq-")
// save it as a parquet file
err := writeTableParquet(table, fileName)
if err != nil {
t.Fatal(err)
}
defer os.Remove(fileName)
// read it back in and compare the result
got, err := readTableParquetCtx(context.Background(), fileName, mem)
if err != nil {
t.Fatalf("readTableParquetCtx() error = %v", err)
}
if got.NumCols() != table.NumCols() {
t.Errorf("got:%v expected:%v", got.NumCols(), table.NumCols())
}
}

View file

@ -1,9 +1,21 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa
import (
"github.com/featurebasedb/featurebase/v3/testhook"
"github.com/pilosa/pilosa/v2/testhook"
)
var NewAuditor func() testhook.Auditor = NewNopAuditor

View file

@ -1,12 +1,24 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa
import (
"fmt"
"reflect"
"github.com/featurebasedb/featurebase/v3/testhook"
"github.com/pilosa/pilosa/v2/testhook"
)
// These audit hooks are desireable during testing, but not in

View file

@ -1,5 +1,17 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa_test
import (
@ -7,8 +19,8 @@ import (
"os"
"reflect"
"github.com/featurebasedb/featurebase/v3"
"github.com/featurebasedb/featurebase/v3/testhook"
"github.com/pilosa/pilosa/v2"
"github.com/pilosa/pilosa/v2/testhook"
)
// AuditLeaksOn is a global switch to turn on resource

View file

@ -1,445 +0,0 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Package authn handles authentication
package authn
import (
"context"
"encoding/hex"
"encoding/json"
"fmt"
"net"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/golang-jwt/jwt"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
"github.com/featurebasedb/featurebase/v3/logger"
"github.com/pkg/errors"
"golang.org/x/oauth2"
)
// AuthContextKey is a unique type to prevent collisions when using context.WithValue()
type AuthContextKey string
const (
// AccessCookieName is the name of the cookie that holds the access token.
AccessCookieName = "molecula-chip"
// RefreshCookieName is the name of the cookie that holds the refresh token.
RefreshCookieName = "refresh-molecula-chip"
// RefreshHeaderName is the name of the header that holds the refresh token.
RefreshHeaderName = "X-Molecula-Refresh-Token"
// ContextValueAccessToken is the key used to set AccessTokens in a ctx.
ContextValueAccessToken = AuthContextKey("Access")
// ContextValueRefreshToken is the key used to set RefreshTokens in a ctx.
ContextValueRefreshToken = AuthContextKey("Refresh")
)
// cachedGroups is used to hold groups and when they were last cached
type cachedGroups struct {
cacheTime time.Time
groups []Group
}
// UserInfo holds the information about the user from the token
type UserInfo struct {
UserID string `json:"userid"`
UserName string `json:"username"`
Groups []Group `json:"groups"`
Expiry time.Time `json:"expiry"`
Token string `json:"token"`
RefreshToken string `json:"refreshtoken"`
}
// Group holds group information for an authenticated user
type Group struct {
GroupID string `json:"id"`
GroupName string `json:"displayName"`
}
// Groups holds a slice of Group for marshalling from JSON
type Groups struct {
NextLink string `json:"@odata.nextLink"`
Groups []Group `json:"value"`
}
// Auth holds state, configuration, and utilities needed for authentication.
type Auth struct {
logger logger.Logger
accessCookieName string
refreshCookieName string
secretKey []byte
groupEndpoint string
logoutEndpoint string
fbURL string // fbURL is the domain featurebase is hosted on, used for post logout redirection
oAuthConfig *oauth2.Config
cacheTTL time.Duration // cacheTTL is used to determine if a cached item should be refreshed or not
groupsCache map[string]cachedGroups // groupsCache is a map of accessToken -> group memberships
lastCacheClean time.Time // last cache clean is the time that the cache was last cleaned
allowedNetworks []net.IPNet // list of allowed networks for ingest
}
// NewAuth instantiates and returns a new Auth struct
func NewAuth(logger logger.Logger, url string, scopes []string, authURL, tokenURL, groupEndpoint, logout, clientID, clientSecret, secretKey string, configuredIPs []string) (auth *Auth, err error) {
auth = &Auth{
logger: logger,
accessCookieName: AccessCookieName,
refreshCookieName: RefreshCookieName,
groupEndpoint: groupEndpoint,
logoutEndpoint: logout,
fbURL: url,
oAuthConfig: &oauth2.Config{
RedirectURL: fmt.Sprintf("%s/redirect", url),
ClientID: clientID,
ClientSecret: clientSecret,
Scopes: scopes,
Endpoint: oauth2.Endpoint{
AuthURL: authURL,
TokenURL: tokenURL,
},
},
groupsCache: map[string]cachedGroups{},
cacheTTL: 10 * time.Minute,
lastCacheClean: time.Now(),
}
if auth.secretKey, err = decodeHex(secretKey); err != nil {
return nil, errors.Wrap(err, "decoding secret key")
}
// convert IPs and add them to allowed networks
err = auth.convertIP(configuredIPs)
if err != nil {
return nil, err
}
return auth, nil
}
// CleanOAuthConfig returns a's oauthConfig without the client secret
func (a Auth) CleanOAuthConfig() oauth2.Config {
b := *a.oAuthConfig
b.ClientSecret = ""
return b
}
// SecretKey is a convenient function to get the SecretKey from an Auth struct
func (a Auth) SecretKey() []byte {
return a.secretKey
}
// refreshToken refreshes a given access/refresh token pair
func (a *Auth) refreshToken(access, refresh string) (string, string, error) {
resp, err := http.PostForm(a.oAuthConfig.Endpoint.TokenURL,
url.Values{
"grant_type": {"refresh_token"},
"refresh_token": {refresh},
"client_id": {a.oAuthConfig.ClientID},
"client_secret": {a.oAuthConfig.ClientSecret},
},
)
if err != nil {
return "", "", errors.Wrap(err, "refreshing token")
}
if resp.StatusCode != http.StatusOK {
return "", "", fmt.Errorf("refreshing token: %s", resp.Status)
}
defer resp.Body.Close()
var t oauth2.Token
if err := json.NewDecoder(resp.Body).Decode(&t); err != nil {
return "", "", errors.Wrap(err, "decoding refreshed token")
}
// remove the old groups from the groups cache
delete(a.groupsCache, access)
return t.AccessToken, t.RefreshToken, nil
}
// Authenticate takes in a auth token `access` and returns UserInfo from that token
// it is caller's responsibility to inform the user that the access token has been refreshed
func (a *Auth) Authenticate(access, refresh string) (*UserInfo, error) {
// clean up the cache every 30 minutes or so
if time.Since(a.lastCacheClean) >= 30*time.Minute {
a.cleanCache()
}
if len(access) == 0 {
return nil, fmt.Errorf("auth token is empty")
}
// NOTE: we are using ParseUnverified here because the IDP validates the
// token's signature when we get the user's groups, we just need to make
// sure it's not expired and is well-formed
token, _, err := new(jwt.Parser).ParseUnverified(access, &jwt.MapClaims{})
// well-formed-ness check
if token == nil || token.Claims == nil || err != nil {
return nil, fmt.Errorf("parsing auth token: %v", err)
}
claims := *token.Claims.(*jwt.MapClaims)
// expiry check
if exp, ok := claims["exp"]; ok {
var expiry int64
switch v := exp.(type) {
case string:
expiry, err = strconv.ParseInt(v, 10, 64)
if err != nil {
return nil, fmt.Errorf("parsing exp string: %v", err)
}
case float64:
expiry = int64(v)
case int64:
expiry = v
}
if expiry < time.Now().UTC().Unix() {
access, refresh, err = a.refreshToken(access, refresh)
if err != nil {
return nil, fmt.Errorf("token is expired: %w", err)
}
}
}
userInfo := UserInfo{
Token: access,
RefreshToken: refresh,
Groups: []Group{},
}
if uid, ok := claims["oid"].(string); ok {
userInfo.UserID = uid
}
if name, ok := claims["name"].(string); ok {
userInfo.UserName = name
}
if userInfo.Groups, err = a.getGroups(access); err != nil {
return nil, errors.Wrap(err, "getting groups")
}
return &userInfo, nil
}
// cleanCache removes old items from our cache
func (a *Auth) cleanCache() {
for access, tkn := range a.groupsCache {
// if it's been more than 24 hours since the groups were cached
if time.Since(tkn.cacheTime) >= 24*time.Hour {
// remove it from our cache
delete(a.groupsCache, access)
}
}
a.lastCacheClean = time.Now()
}
// Login redirects a user to login to their configured oAuth authorize endpoint
func (a *Auth) Login(w http.ResponseWriter, r *http.Request) {
authURL := a.oAuthConfig.AuthCodeURL(a.oAuthConfig.Endpoint.AuthURL)
http.Redirect(w, r, authURL, http.StatusTemporaryRedirect)
}
// Logout clears out the user's cookie, removes the token from our cache, and
// redirects user to IdP's logout endpoint
func (a *Auth) Logout(w http.ResponseWriter, r *http.Request) {
// remove the access token from a.groupsCache
if access, err := r.Cookie(a.accessCookieName); err == nil {
delete(a.groupsCache, access.Value)
}
// clear cookie
http.SetCookie(w, &http.Cookie{
Name: a.accessCookieName,
Value: "",
Path: "/",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Expires: time.Unix(0, 0),
})
http.SetCookie(w, &http.Cookie{
Name: a.refreshCookieName,
Value: "",
Path: "/",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Expires: time.Unix(0, 0),
})
http.Redirect(w, r, fmt.Sprintf("%s?post_logout_redirect_uri=%s/", a.logoutEndpoint, a.fbURL), http.StatusTemporaryRedirect)
}
// Redirect handles the oAuth /redirect endpoint. It gets an access token and
// returns it to the user in the form of a cookie
func (a *Auth) Redirect(w http.ResponseWriter, r *http.Request) {
token, err := a.oAuthConfig.Exchange(r.Context(), r.FormValue("code"), oauth2.AccessTypeOffline)
if err != nil {
a.logger.Warnf("getting token from IdP: %+v", err)
http.Error(w, "Bad Request", http.StatusBadRequest)
return
}
a.SetCookie(w, token.AccessToken, token.RefreshToken, token.Expiry)
http.Redirect(w, r, "/", http.StatusTemporaryRedirect)
}
// getGroups gets the group membership for a given token from configured IdP
func (a *Auth) getGroups(token string) ([]Group, error) {
var groups Groups
gc, ok := a.groupsCache[token]
if ok && (time.Since(gc.cacheTime) < a.cacheTTL) && len(gc.groups) > 0 {
return gc.groups, nil
}
nextLink := a.groupEndpoint
for nextLink != "" {
req, err := http.NewRequest("GET", nextLink, nil)
if err != nil {
return nil, errors.Wrap(err, "creating new request to group endpoint")
}
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
response, err := http.DefaultClient.Do(req)
if err != nil {
return nil, errors.Wrap(err, "getting group membership info")
}
if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("getting group membership info: %s", response.Status)
}
var g Groups
if err = json.NewDecoder(response.Body).Decode(&g); err != nil {
return groups.Groups, errors.Wrap(err, "failed unmarshalling group membership response")
}
response.Body.Close()
groups.Groups = append(groups.Groups, g.Groups...)
nextLink = g.NextLink
}
if len(groups.Groups) == 0 {
return nil, fmt.Errorf("no groups found")
}
a.groupsCache[token] = cachedGroups{
cacheTime: time.Now(),
groups: groups.Groups,
}
return groups.Groups, nil
}
func (a *Auth) SetCookie(w http.ResponseWriter, access, refresh string, expiry time.Time) error {
http.SetCookie(w, &http.Cookie{
Name: a.refreshCookieName,
Value: refresh,
Path: "/",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Expires: expiry,
})
http.SetCookie(w, &http.Cookie{
Name: a.accessCookieName,
Value: access,
Path: "/",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Expires: expiry,
})
return nil
}
func (a *Auth) SetGRPCMetadata(ctx context.Context, md metadata.MD, access, refresh string) (context.Context, error) {
mCookies := map[string]string{}
if c, ok := md["cookie"]; ok {
for _, cookie := range c {
name, val := parseCookie(cookie)
mCookies[name] = val
}
}
mCookies[a.accessCookieName] = access
mCookies[a.refreshCookieName] = refresh
cookies := []string{}
for name, val := range mCookies {
cookies = append(cookies, name+"="+val)
}
md["cookie"] = cookies
return metadata.NewIncomingContext(ctx, md), grpc.SetHeader(ctx, md)
}
func decodeHex(hexstr string) ([]byte, error) {
data, err := hex.DecodeString(hexstr)
if err != nil {
return nil, errors.Wrap(err, "decoding hex string to byte slice")
}
if len(data) != 32 {
return nil, fmt.Errorf("invalid key length")
}
return data, nil
}
func (a *Auth) convertIP(configuredIPs []string) error {
sz := len(configuredIPs)
nets := make([]net.IPNet, sz)
for i, ip := range configuredIPs {
// skip empty strings
if ip == "" {
sz--
continue
}
// for IPs passed without a subnet, append /32 to only allow 1 IP
// this step is needed because ParseCIDR method assumes a CIDR address
if !strings.Contains(ip, "/") {
ip = ip + "/32"
}
_, subnet, err := net.ParseCIDR(ip)
if err != nil {
return errors.Wrapf(err, "parsing CIDR for %v", ip)
}
nets[i] = *subnet
}
a.allowedNetworks = nets[:sz]
return nil
}
// if IP is in allowed networks, then return true to grant admin permissions
func (a *Auth) CheckAllowedNetworks(clientIP string) bool {
clientIP = strings.Split(clientIP, ":")[0]
convertedIP := net.ParseIP(clientIP)
for _, network := range a.allowedNetworks {
if network.Contains(convertedIP) {
return true
}
}
return false
}
func parseCookie(cookie string) (name, data string) {
vals := strings.Split(cookie, "=")
if len(vals) == 0 {
vals = []string{"", ""}
} else if len(vals) < 2 {
vals = append(vals, "")
}
return vals[0], vals[1]
}

View file

@ -1,760 +0,0 @@
package authn
import (
"bytes"
"context"
"encoding/hex"
"encoding/json"
"fmt"
"net"
"net/http"
"net/http/httptest"
"os"
"reflect"
"strconv"
"strings"
"testing"
"time"
"github.com/featurebasedb/featurebase/v3/logger"
"github.com/golang-jwt/jwt"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)
func NewTestAuth(t *testing.T) *Auth {
t.Helper()
var (
ClientID = "e9088663-eb08-41d7-8f65-efb5f54bbb71"
ClientSecret = "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
AuthorizeURL = "https://login.microsoftonline.com/4a137d66-d161-4ae4-b1e6-07e9920874b8/oauth2/v2.0/authorize"
TokenURL = "https://login.microsoftonline.com/4a137d66-d161-4ae4-b1e6-07e9920874b8/oauth2/v2.0/token"
GroupEndpointURL = "https://graph.microsoft.com/v1.0/me/transitiveMemberOf/microsoft.graph.group?$count=true"
LogoutURL = "https://login.microsoftonline.com/common/oauth2/v2.0/logout"
Scopes = []string{"https://graph.microsoft.com/.default", "offline_access"}
Key = "DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"
configuredIPs = []string{}
)
a, err := NewAuth(
logger.NewStandardLogger(os.Stdout),
"http://localhost:10101/",
Scopes,
AuthorizeURL,
TokenURL,
GroupEndpointURL,
LogoutURL,
ClientID,
ClientSecret,
Key,
configuredIPs,
)
if err != nil {
t.Fatalf("building auth object%s", err)
}
return a
}
func TestSetGRPCMetadata(t *testing.T) {
a := NewTestAuth(t)
for name, md := range map[string]metadata.MD{
"empty": {},
"something": {"cookie": []string{a.accessCookieName + "=something"}},
"somethingElse": {"cookie": []string{
a.accessCookieName + "=something",
a.refreshCookieName + "=something",
}},
"otherCookies": {"cookie": []string{a.accessCookieName + "=something", "blah=blah"}},
} {
t.Run(name, func(t *testing.T) {
ogCookies := md["cookie"]
ctx := grpc.NewContextWithServerTransportStream(
metadata.NewIncomingContext(context.TODO(),
md,
),
NewServerTransportStream(),
)
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
t.Fatalf("expected ok, got: %v", ok)
}
ctx, err := a.SetGRPCMetadata(ctx, md, "accesstoken!", "refreshtoken!")
if err != nil {
t.Fatalf("expected no errors, got: %v", err)
}
if err := grpc.SendHeader(ctx, md); err != nil {
t.Fatalf("expected no errors, got: %v", err)
}
md, ok = metadata.FromIncomingContext(ctx)
if !ok {
t.Fatalf("expected ok, got: %v", ok)
}
c, ok := md["cookie"]
if !ok {
t.Fatalf("expected ok, got: %v", ok)
}
var accessCookie, refreshCookie string
for _, cookie := range c {
if strings.HasPrefix(cookie, a.accessCookieName) {
accessCookie = cookie
} else if strings.HasPrefix(cookie, a.refreshCookieName) {
refreshCookie = cookie
}
if refreshCookie != "" && accessCookie != "" {
break
}
}
exp := a.accessCookieName + "=accesstoken!"
if accessCookie != exp {
t.Fatalf("expected '%v', got '%v'", exp, accessCookie)
}
exp = a.refreshCookieName + "=refreshtoken!"
if refreshCookie != exp {
t.Fatalf("expected '%v', got '%v'", exp, refreshCookie)
}
for _, cookie := range c {
if strings.HasPrefix(cookie, a.accessCookieName) || strings.HasPrefix(cookie, a.refreshCookieName) {
continue
}
found := false
for _, ogCookie := range ogCookies {
if cookie == ogCookie {
found = true
break
}
}
if !found {
t.Fatal("SetGRPCMetadata did not maintain the previous cookie list")
}
}
})
}
}
func TestAuth(t *testing.T) {
a := NewTestAuth(t)
t.Run("SetCookie", func(t *testing.T) {
w := httptest.NewRecorder()
err := a.SetCookie(w, "access", "refresh", time.Now().Add(time.Hour))
if err != nil {
t.Fatalf("expected no errors, got: %v", err)
}
if w.Result().Cookies()[0].Value == "" {
t.Errorf("expected something, got empty string")
}
if got, want := w.Result().Cookies()[0].Path, "/"; got != want {
t.Fatalf("path=%s, want %s", got, want)
}
})
t.Run("KeyLength", func(t *testing.T) {
_, err := NewAuth(
logger.NewStandardLogger(os.Stdout),
"http://localhost:10101/",
[]string{"https://graph.microsoft.com/.default", "offline_access"},
"https://login.microsoftonline.com/4a137d66-d161-4ae4-b1e6-07e9920874b8/oauth2/v2.0/authorize",
"https://login.microsoftonline.com/4a137d66-d161-4ae4-b1e6-07e9920874b8/oauth2/v2.0/token",
"https://graph.microsoft.com/v1.0/me/transitiveMemberOf/microsoft.graph.group?$count=true",
"https://login.microsoftonline.com/common/oauth2/v2.0/logout",
"e9088663-eb08-41d7-8f65-efb5f54bbb71",
"DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF",
"DEADBEEFD",
[]string{},
)
if err == nil || !strings.Contains(err.Error(), "decoding secret key") {
t.Fatalf("expected error decoding secret key got: %v", err)
}
})
t.Run("GetSecretKey", func(t *testing.T) {
want, _ := hex.DecodeString("DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF")
if got := a.SecretKey(); !bytes.Equal(got, want) {
t.Fatalf("expected %v, got %v", got, want)
}
})
}
func TestAuthenticate(t *testing.T) {
cases := []struct {
name string
uid string
uname string
exp int64
refresh bool
refreshToken string
malformed bool
empty bool
groups []Group
err error
}{
{
name: "GoodToken",
uid: "42",
uname: "A. Token",
groups: []Group{
{
GroupID: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe",
GroupName: "adminGroup",
},
},
},
{
name: "Malformed",
malformed: true,
err: fmt.Errorf("parsing auth token: token contains an invalid number of segments"),
},
{
name: "Empty",
empty: true,
err: fmt.Errorf("auth token is empty"),
},
{
name: "ExpiredTokenNoRefresh",
uid: "42",
uname: "A. Token",
groups: []Group{
{
GroupID: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe",
GroupName: "adminGroup",
},
},
exp: -17764800,
err: fmt.Errorf("token is expired: refreshing token: 400 Bad Request"),
},
{
name: "ExpiredTokenYesRefresh",
uid: "42",
uname: "A. Token",
groups: []Group{
{
GroupID: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe",
GroupName: "adminGroup",
},
},
refresh: true,
refreshToken: "refreshToken",
exp: -17764800,
},
{
name: "ExpiredTokenYesRefreshButError",
uid: "42",
uname: "A. Token",
groups: []Group{
{
GroupID: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe",
GroupName: "adminGroup",
},
},
refresh: true,
refreshToken: "blah!!",
exp: -17764800,
err: fmt.Errorf("token is expired: refreshing token: 403 Forbidden"),
},
}
for _, test := range cases {
t.Run(test.name, func(t *testing.T) {
// setup the test
a := NewTestAuth(t)
token := ""
var err error
if !test.malformed && !test.empty {
tkn := jwt.New(jwt.SigningMethodHS256)
claims := tkn.Claims.(jwt.MapClaims)
claims["oid"] = test.uid
claims["name"] = test.uname
if test.exp != 0 {
claims["exp"] = float64(test.exp)
}
token, err = tkn.SignedString(a.SecretKey())
if err != nil {
t.Fatalf("unexpected error when signing token %v", err)
}
} else if !test.empty {
token = "asdfasdfasdfasdF"
}
if len(test.groups) > 0 {
a.groupsCache[token] = cachedGroups{time.Now(), test.groups}
}
if test.refresh {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
refresh := r.Form.Get("refresh_token")
if refresh != test.refreshToken {
t.Fatalf("refresh token not passed properly, expected %v, got %v", test.refreshToken, refresh)
return
}
if refresh != "refreshToken" {
http.Error(w, "bad token", http.StatusForbidden)
}
tkn := jwt.New(jwt.SigningMethodHS256)
claims := tkn.Claims.(jwt.MapClaims)
claims["oid"] = test.uid
claims["name"] = test.uname
expiry := float64(time.Now().Add(2 * time.Hour).Unix())
claims["exp"] = expiry
fresh, err := tkn.SignedString(a.SecretKey())
if err != nil {
t.Fatalf("unexpected error when signing token %v", err)
}
a.groupsCache[fresh] = cachedGroups{time.Now(), test.groups}
fmt.Fprintf(w, `{"access_token": "`+fresh+`", "refresh_token": "blah", "token_type": "bearer", "expires": `+strconv.FormatFloat(expiry, 'f', 0, 64)+` }`)
}))
defer srv.Close()
a.oAuthConfig.Endpoint.TokenURL = srv.URL
}
// do the actual testing
uinfo, err := a.Authenticate(token, test.refreshToken)
// okay this part kind of sucks bc we need to check errors and i
// dont want to write a whole new test for things that should have
// errors just to avoid this mess. errors.Is doesn't work either
if (test.err == nil && err != nil) || (test.err != nil && err == nil) {
t.Fatalf("expected %v, but got %v", test.err, err)
} else if test.err != nil && err != nil {
if test.err.Error() != err.Error() {
t.Fatalf("expected %v, but got %v", test.err, err)
} else {
return
}
}
if !reflect.DeepEqual(uinfo.Groups, test.groups) {
t.Fatalf("expected %v, got %v", test.groups, uinfo.Groups)
}
if !reflect.DeepEqual(uinfo.UserID, test.uid) {
t.Fatalf("expected %v, got %v", test.uid, uinfo.UserID)
}
if !reflect.DeepEqual(uinfo.UserName, test.uname) {
t.Fatalf("expected %v, got %v", test.uname, uinfo.UserName)
}
})
}
}
func TestAuthenticate_CleanCache(t *testing.T) {
// this deserves its own test bc it has gross setup required
t.Run("should clean", func(t *testing.T) {
a := NewTestAuth(t)
now := time.Now()
a.groupsCache["oldy"] = cachedGroups{now.Add(-24 * time.Hour), []Group{}}
a.groupsCache["goldy"] = cachedGroups{now.Add(-4 * time.Hour), []Group{}}
a.lastCacheClean = now.Add(-45 * time.Minute)
_, _ = a.Authenticate("this doesn't matter", "this doesn't matter?")
if a.lastCacheClean.Sub(now) <= time.Nanosecond {
t.Fatalf("cache should have been cleaned")
}
if _, ok := a.groupsCache["oldy"]; ok {
t.Errorf("oldy should have been deleted")
}
if _, ok := a.groupsCache["goldy"]; !ok {
t.Errorf("goldy should not have been deleted")
}
})
t.Run("shouldn't clean", func(t *testing.T) {
a := NewTestAuth(t)
now := time.Now()
a.groupsCache["oldy"] = cachedGroups{now.Add(-24 * time.Hour), []Group{}}
a.groupsCache["goldy"] = cachedGroups{now.Add(-4 * time.Hour), []Group{}}
a.lastCacheClean = now
_, _ = a.Authenticate("this doesn't matter", "this doesn't matter?")
if a.lastCacheClean.Sub(now) >= time.Nanosecond {
t.Fatalf("cache should not have been cleaned")
}
if _, ok := a.groupsCache["oldy"]; !ok {
t.Errorf("oldy should not have been deleted")
}
if _, ok := a.groupsCache["goldy"]; !ok {
t.Errorf("goldy should not have been deleted")
}
})
}
func TestGetGroups(t *testing.T) {
a := NewTestAuth(t)
a.groupsCache = map[string]cachedGroups{
"the world is changed": {
cacheTime: time.Now(),
groups: []Group{
{
GroupID: "a han noston ned wilith",
GroupName: "I smell it in the air",
},
},
},
}
srvNext := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, err := json.Marshal(
Groups{
Groups: []Group{
{
GroupID: "han mathon ne chae",
GroupName: "I feel it in the earth",
},
},
},
)
if err != nil {
t.Fatalf("unexpected error marshalling groups response: %v", err)
}
fmt.Fprintf(w, "%s", body)
}))
defer srvNext.Close()
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body, err := json.Marshal(
Groups{
NextLink: srvNext.URL,
Groups: []Group{
{
GroupID: "han mathon ne nen",
GroupName: "i feel it in the water",
},
},
},
)
if err != nil {
t.Fatalf("unexpected error marshalling groups response: %v", err)
}
fmt.Fprintf(w, "%s", body)
}))
defer srv.Close()
a.groupEndpoint = srv.URL
for name, test := range map[string]struct {
token string
groups []Group
}{
"InCache": {
token: "the world is changed",
groups: []Group{
{
GroupID: "a han noston ned wilith",
GroupName: "I smell it in the air",
},
},
},
"NotInCache": {
token: "i smell it in the air",
groups: []Group{
{
GroupID: "han mathon ne nen",
GroupName: "i feel it in the water",
},
{
GroupID: "han mathon ne chae",
GroupName: "I feel it in the earth",
},
},
},
} {
t.Run(name, func(t *testing.T) {
if got, err := a.getGroups(test.token); err != nil || !reflect.DeepEqual(got, test.groups) {
t.Errorf("expected %v, nil, got %v, %v", test.groups, got, err)
}
})
}
}
func TestDecodeHex(t *testing.T) {
t.Run("cantDecode", func(t *testing.T) {
_, err := decodeHex("gggg")
if err == nil {
t.Fatalf("expected err cannot decode slice, got nil")
}
})
t.Run("tooSmall", func(t *testing.T) {
_, err := decodeHex("DEADBEEF")
if err == nil {
t.Fatalf("expected err wrong length, got nil")
}
})
t.Run("tooBig", func(t *testing.T) {
_, err := decodeHex("DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF")
if err == nil {
t.Fatalf("expected err wrong length, got nil")
}
})
t.Run("justRight", func(t *testing.T) {
_, err := decodeHex("DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF")
if err != nil {
t.Fatalf("expected nil, got %v", err)
}
})
}
func TestHandlers(t *testing.T) {
a := NewTestAuth(t)
t.Run("login", func(t *testing.T) {
req := httptest.NewRequest("GET", "/login", nil)
w := httptest.NewRecorder()
a.Login(w, req)
resp := w.Result()
if resp.StatusCode != http.StatusTemporaryRedirect {
t.Fatalf("expected redirect, got %v", resp.StatusCode)
}
redirect := a.oAuthConfig.AuthCodeURL(a.oAuthConfig.Endpoint.AuthURL)
if got, err := resp.Location(); err != nil || got.String() != redirect {
t.Fatalf("expected %v, got %v", redirect, got.Path)
}
})
t.Run("logout", func(t *testing.T) {
req := httptest.NewRequest("GET", "/logout", nil)
w := httptest.NewRecorder()
req.AddCookie(
&http.Cookie{
Name: a.accessCookieName,
Value: "test",
Path: "/",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Expires: time.Unix(3000000, 0),
},
)
req.AddCookie(
&http.Cookie{
Name: a.refreshCookieName,
Value: "test",
Path: "/",
Secure: true,
HttpOnly: true,
SameSite: http.SameSiteStrictMode,
Expires: time.Unix(3000000, 0),
},
)
a.groupsCache["test"] = cachedGroups{}
a.Logout(w, req)
resp := w.Result()
if resp.StatusCode != http.StatusTemporaryRedirect {
t.Fatalf("expected redirect, got %v", resp.StatusCode)
}
redirect := fmt.Sprintf("%s?post_logout_redirect_uri=%s/", a.logoutEndpoint, a.fbURL)
if got, err := resp.Location(); err != nil || got.String() != redirect {
t.Fatalf("expected %v, got %v", redirect, got.Path)
}
for _, c := range resp.Cookies() {
if c.Name == a.accessCookieName || c.Name == a.refreshCookieName {
if c.Value != "" {
t.Fatalf("cookie not set to empty value!")
}
want := time.Unix(0, 0).Unix()
got := c.Expires.Unix()
if want != got {
t.Fatalf("expected %v, got %v", want, got)
}
}
}
if _, ok := a.groupsCache["test"]; ok {
t.Fatalf("groups not deleted!")
}
})
t.Run("redirectGood", func(t *testing.T) {
req := httptest.NewRequest("GET", "/redirect", nil)
w := httptest.NewRecorder()
tkn := jwt.New(jwt.SigningMethodHS256)
claims := tkn.Claims.(jwt.MapClaims)
claims["oid"] = "user id"
claims["name"] = "user name"
expiresIn := 2 * time.Hour
exp := time.Now().Add(expiresIn)
expiry := float64(exp.Unix())
claims["exp"] = expiry
fresh, err := tkn.SignedString(a.SecretKey())
if err != nil {
t.Fatalf("unexpected error when signing token %v", err)
}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
body := `{"access_token": "` + fresh + `", "refresh_token": "blah", "expires_in": "` + strconv.Itoa(int(expiresIn.Seconds())) + `"}`
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
w.Write([]byte(body))
}))
a.oAuthConfig.Endpoint.TokenURL = srv.URL
a.Redirect(w, req)
resp := w.Result()
if resp.StatusCode != http.StatusTemporaryRedirect {
t.Fatalf("expected redirect, got %v", resp.StatusCode)
}
if got, err := resp.Location(); err != nil || got.String() != "/" {
t.Fatalf("expected %v, got %v", "/", got.Path)
}
cookies := resp.Cookies()
for _, c := range cookies {
if c.Name == a.accessCookieName && c.Value != fresh {
t.Fatalf("expected %v, got %v", exp, c.Value)
} else if c.Name == a.refreshCookieName && c.Value != "blah" {
t.Fatalf("expected %v, got %v", "blah", c.Value)
}
}
})
t.Run("redirectBad", func(t *testing.T) {
req := httptest.NewRequest("GET", "/redirect", nil)
w := httptest.NewRecorder()
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "Server Error", http.StatusInternalServerError)
}))
a.oAuthConfig.Endpoint.TokenURL = srv.URL
a.Redirect(w, req)
resp := w.Result()
if resp.StatusCode != http.StatusBadRequest {
t.Fatalf("expected BadRequest, got %v", resp.StatusCode)
}
})
}
// This type is used for mocking ServerTransportStreams in tests
type ServerTransportStream struct {
md metadata.MD
method string
}
func NewServerTransportStream() *ServerTransportStream {
return &ServerTransportStream{
md: metadata.MD{},
method: "test",
}
}
func (s *ServerTransportStream) Method() string {
return s.method
}
func (s *ServerTransportStream) SetHeader(md metadata.MD) error {
s.md = md
return nil
}
func (s *ServerTransportStream) SendHeader(md metadata.MD) error {
_ = md
return nil
}
func (s *ServerTransportStream) SetTrailer(md metadata.MD) error {
_ = md
return nil
}
func TestCleanOAuthConfig(t *testing.T) {
a := NewTestAuth(t)
res := a.CleanOAuthConfig()
assertEqual("", res.ClientSecret, t)
assertEqual(a.oAuthConfig.ClientID, res.ClientID, t)
assertEqual(a.oAuthConfig.RedirectURL, res.RedirectURL, t)
assertEqual(a.oAuthConfig.Scopes, res.Scopes, t)
assertEqual(a.oAuthConfig.Endpoint, res.Endpoint, t)
}
func assertEqual(exp, got interface{}, t *testing.T) {
if !reflect.DeepEqual(exp, got) {
t.Fatalf("expected %v, got %v", exp, got)
}
}
func TestCheckAllowedNetworks(t *testing.T) {
tests := []struct {
requestIP string
configuredIPs []string
isAdmin bool
}{
{
requestIP: "10.0.0.1",
configuredIPs: []string{"10.0.0.1"},
isAdmin: true,
},
{
requestIP: "10.0.0.3",
configuredIPs: []string{"10.0.0.1", "10.0.0.2"},
isAdmin: false,
},
{
requestIP: "10.0.0.2",
configuredIPs: []string{"10.0.0.1/30"},
isAdmin: true,
},
// it is possible for the client IP to have a port
{
requestIP: "10.0.0.2:22",
configuredIPs: []string{"10.0.0.1/30"},
isAdmin: true,
},
{
requestIP: "10.1.0.3",
configuredIPs: []string{"10.0.0.1/32"},
isAdmin: false,
},
{
requestIP: "10.0.0.254",
configuredIPs: []string{"10.0.0.1/24"},
isAdmin: true,
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("network-%d", i), func(t *testing.T) {
a := NewTestAuth(t)
if err := a.convertIP(test.configuredIPs); err != nil {
t.Fatalf("failed to convert IPs from strings to net.IP: %v", err)
}
got := a.CheckAllowedNetworks(test.requestIP)
if got != test.isAdmin {
t.Fatalf("expected %v, got %v", test.isAdmin, got)
}
})
}
}
func TestConvertIP(t *testing.T) {
tests := []struct {
configuredIPs []string
convertedIPs []net.IPNet
}{
{
configuredIPs: []string{"10.0.0.1"},
convertedIPs: []net.IPNet{
{IP: net.ParseIP("10.0.0.1"), Mask: net.CIDRMask(32, 32)},
},
},
{
configuredIPs: []string{"10.0.0.1/30"},
convertedIPs: []net.IPNet{
{IP: net.ParseIP("10.0.0.0"), Mask: net.CIDRMask(30, 32)},
},
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("network-%d", i), func(t *testing.T) {
a := NewTestAuth(t)
if err := a.convertIP(test.configuredIPs); err != nil {
t.Fatalf("failed to convert IPs from strings to net.IP: %v", err)
}
if len(a.allowedNetworks) != len(test.convertedIPs) {
t.Fatalf("expected len of %v networks, got %v", len(test.convertedIPs), len(a.allowedNetworks))
}
for i := range a.allowedNetworks {
expected, got := test.convertedIPs[i], a.allowedNetworks[i]
if got.IP.String() != expected.IP.String() {
t.Fatalf("for IP, expected %v, got %v", expected.IP, got.IP)
}
if got.Mask.String() != expected.Mask.String() {
t.Fatalf("for mask, expected %v, got %v", expected.Mask.String(), got.Mask.String())
}
}
})
}
}

View file

@ -1,54 +0,0 @@
// Copyright 2022 Molecula Corp (DBA FeatureBase). All rights reserved.
package authn
import "context"
// Empty struct to avoid allocations
type contextKeyAccessToken struct{}
type contextKeyRefreshToken struct{}
type contextKeyUserInfo struct{}
type contextKeyIndexes struct{}
// GetAccessToken gets the access token from a context.
func GetAccessToken(ctx context.Context) (token string, ok bool) {
token, ok = ctx.Value(contextKeyAccessToken{}).(string)
return
}
// WithAccessToken makes a new Context with an access token.
func WithAccessToken(ctx context.Context, token string) context.Context {
return context.WithValue(ctx, contextKeyAccessToken{}, token)
}
// GetRefreshToken gets the refresh token from a context.
func GetRefreshToken(ctx context.Context) (token string, ok bool) {
token, ok = ctx.Value(contextKeyRefreshToken{}).(string)
return
}
// WithRefreshToken makes a new Context with a refresh token.
func WithRefreshToken(ctx context.Context, token string) context.Context {
return context.WithValue(ctx, contextKeyRefreshToken{}, token)
}
// GetUserInfo gets the UserInfo from a context.
func GetUserInfo(ctx context.Context) (userInfo *UserInfo, ok bool) {
userInfo, ok = ctx.Value(contextKeyUserInfo{}).(*UserInfo)
return
}
// WithUserInfo makes a new Context with UserInfo.
func WithUserInfo(ctx context.Context, userInfo *UserInfo) context.Context {
return context.WithValue(ctx, contextKeyUserInfo{}, userInfo)
}
// GetIndexes get the indices from a context.
func GetIndexes(ctx context.Context) (indexes []string, ok bool) {
indexes, ok = ctx.Value(contextKeyIndexes{}).([]string)
return
}
// WithIndexes makes a new Context with a []string containing the indicies.
func WithIndexes(ctx context.Context, indexes []string) context.Context {
return context.WithValue(ctx, contextKeyUserInfo{}, indexes)
}

View file

@ -1,130 +0,0 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
package authz
import (
"fmt"
"io"
"github.com/featurebasedb/featurebase/v3/authn"
"gopkg.in/yaml.v2"
)
type GroupPermissions struct {
Permissions map[string]map[string]Permission `yaml:"user-groups"`
Admin string `yaml:"admin"`
}
type Permission string
const (
None Permission = ""
Read Permission = "read"
Write Permission = "write"
Admin Permission = "admin"
)
// Satisfies returns whether `p` satisfies the permissions required by `b`
func (p Permission) Satisfies(b Permission) bool {
switch p {
case "":
return b == ""
case "read":
return b == "" || b == "read"
case "write":
return b == "" || b == "read" || b == "write"
case "admin":
return b == "" || b == "read" || b == "write" || b == "admin"
}
return false
}
func (p *GroupPermissions) ReadPermissionsFile(permsFile io.Reader) (err error) {
permsData, err := io.ReadAll(permsFile)
if err != nil {
return fmt.Errorf("reading permissions failed with error: %s", err)
}
err = yaml.UnmarshalStrict(permsData, &p)
if err != nil {
return fmt.Errorf("unmarshalling permissions failed with error: %s", err)
}
return
}
func (p *GroupPermissions) GetPermissions(user *authn.UserInfo, index string) (permission Permission, errors error) {
groups := user.Groups
if admin := p.IsAdmin(groups); admin {
return Admin, nil
}
allPermissions := map[Permission]bool{
Write: false,
Read: false,
}
if len(groups) == 0 {
return None, fmt.Errorf("user is not part of any groups in identity provider")
}
var groupsDenied []string
for _, group := range groups {
if _, ok := p.Permissions[group.GroupID]; ok {
if perm, ok := p.Permissions[group.GroupID][index]; ok {
allPermissions[perm] = true
} else {
return None, fmt.Errorf("user %s does not have permission to index %s", user.UserID, index)
}
} else {
groupsDenied = append(groupsDenied, group.GroupID)
}
}
if len(groupsDenied) == len(groups) {
return None, fmt.Errorf("group(s) %s does not have permission to FeatureBase", groupsDenied)
}
if allPermissions[Write] {
return Write, nil
} else if allPermissions[Read] {
return Read, nil
} else {
return None, fmt.Errorf("no permissions found")
}
}
func (p *GroupPermissions) IsAdmin(groups []authn.Group) bool {
for _, group := range groups {
if p.Admin == group.GroupID {
return true
}
}
return false
}
func (p *GroupPermissions) GetAuthorizedIndexList(groups []authn.Group, desiredPermission Permission) (indexList []string) {
// if user is admin, find all indexes in permissions file and return them
if p.IsAdmin(groups) {
for groupId := range p.Permissions {
for index := range p.Permissions[groupId] {
indexList = append(indexList, index)
}
}
return indexList
}
for _, group := range groups {
if _, ok := p.Permissions[group.GroupID]; ok {
for index, permission := range p.Permissions[group.GroupID] {
if permission.Satisfies(desiredPermission) {
indexList = append(indexList, index)
}
}
}
}
return indexList
}

View file

@ -1,305 +0,0 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
package authz_test
import (
"fmt"
"reflect"
"sort"
"strings"
"testing"
"github.com/featurebasedb/featurebase/v3/authn"
"github.com/featurebasedb/featurebase/v3/authz"
)
func TestAuth_ReadPermissionsFile(t *testing.T) {
singleInput := `user-groups:
"dca35310-ecda-4f23-86cd-876aee55906b":
"test": "read"
admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe"`
multiInput := `user-groups:
"dca35310-ecda-4f23-86cd-876aee55906b":
"test": "read"
"test2": "write"
"dca35310-ecda-4f23-86cd-876aee559900":
"test": "write"
admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe"`
singlePermission := authz.GroupPermissions{
Permissions: map[string]map[string]authz.Permission{
"dca35310-ecda-4f23-86cd-876aee55906b": {"test": authz.Read},
},
Admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe",
}
multiPermission := authz.GroupPermissions{
Permissions: map[string]map[string]authz.Permission{
"dca35310-ecda-4f23-86cd-876aee55906b": {"test": authz.Read, "test2": authz.Write},
"dca35310-ecda-4f23-86cd-876aee559900": {"test": authz.Write}},
Admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe",
}
tests := []struct {
input string
output authz.GroupPermissions
}{
{singleInput, singlePermission},
{multiInput, multiPermission},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
permFile := strings.NewReader(test.input)
var p authz.GroupPermissions
err := p.ReadPermissionsFile(permFile)
if err != nil {
t.Fatalf("readPermissionsFile error: %s", err)
}
if !reflect.DeepEqual(p, test.output) {
t.Fatalf("expected output %s, but got %s", test.output, p)
}
},
)
}
}
func TestAuth_GetPermissions(t *testing.T) {
// initializes different example of permissions file in yaml
permissions1 := `"user-groups":
"dca35310-ecda-4f23-86cd-876aee55906b":
"test": "read"
admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe"`
permissions2 := `"user-groups":
"dca35310-ecda-4f23-86cd-876aee559900":
"test": "write"
admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe"`
permissions3 := `"user-groups":
"dca35310-ecda-4f23-86cd-876aee55906b":
"test": "write"
"test2": "read"
"dca35310-ecda-4f23-86cd-876aee559900":
"test": "read"
admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe"`
permissions4 := `"user-groups":
"dca35310-ecda-4f23-86cd-876aee559900":
"test": ""
admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe"`
// initializes groups that are returned from identity provider
groupName := "name"
groupsList1 := []authn.Group{}
groupsList2 := []authn.Group{{
GroupID: "fake-group",
GroupName: groupName}}
groupsList3 := []authn.Group{
{GroupID: "dca35310-ecda-4f23-86cd-876aee55906b", GroupName: groupName},
{GroupID: "dca35310-ecda-4f23-86cd-876aee559900", GroupName: groupName},
}
groupsList4 := []authn.Group{{GroupID: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe", GroupName: groupName}}
tests := []struct {
yamlData string
groups []authn.Group
index string
userAccess authz.Permission
err string
}{
{
permissions1,
groupsList1,
"test",
authz.None,
"user is not part of any groups in identity provider",
},
{
permissions1,
groupsList3,
"test1",
authz.None,
"does not have permission to index",
},
{
permissions2,
groupsList2,
"test",
authz.None,
"does not have permission to FeatureBase",
},
{
permissions1,
groupsList3,
"test",
authz.Read,
"",
},
{
permissions2,
groupsList3,
"test",
authz.Write,
"",
},
{
permissions3,
groupsList4,
"test",
authz.Admin,
"",
},
{
permissions4,
groupsList3,
"test",
authz.None,
"no permissions found",
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
permFile := strings.NewReader(test.yamlData)
var p authz.GroupPermissions
if err := p.ReadPermissionsFile(permFile); err != nil {
t.Errorf("Error: %s", err)
}
p1, err := p.GetPermissions(&authn.UserInfo{Groups: test.groups}, test.index)
if p1 != test.userAccess {
t.Errorf("expected permission to be %s, but got %s", test.userAccess, p1)
}
if err != nil {
if !strings.Contains(err.Error(), test.err) {
t.Errorf("expected error to contain %s, but got %s", test.err, err.Error())
}
}
})
}
}
func TestAuth_IsAdmin(t *testing.T) {
group1 := []authn.Group{
{GroupID: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe", GroupName: "admin-group"},
}
group2 := []authn.Group{
{GroupID: "dca35310-ecda-4f23-86cd-876aee55906b", GroupName: "group-name"},
}
groupPermissions := authz.GroupPermissions{
Permissions: map[string]map[string]authz.Permission{
"dca35310-ecda-4f23-86cd-876aee55906b": {"test": authz.Write},
},
Admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe",
}
tests := []struct {
groups []authn.Group
groupPermissions authz.GroupPermissions
output bool
}{
{
group1, groupPermissions, true,
},
{
group2, groupPermissions, false,
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
p := test.groupPermissions
resp := p.IsAdmin(test.groups)
if resp != test.output {
t.Errorf("expected %t, but got %t", test.output, resp)
}
})
}
}
func TestAuth_GetAuthorizedIndexList(t *testing.T) {
group1 := []authn.Group{
{GroupID: "dca35310-ecda-4f23-86cd-876aee55906b", GroupName: "group-name"},
}
group2 := []authn.Group{
{GroupID: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe", GroupName: "admin-group"},
}
group3 := []authn.Group{
{GroupID: "dca35310-ecda-4f23-86cd-876aee559900", GroupName: "group-name"},
}
p := authz.GroupPermissions{
Permissions: map[string]map[string]authz.Permission{
"dca35310-ecda-4f23-86cd-876aee55906b": {
"test1": authz.Read,
"test2": authz.Write,
},
"dca35310-ecda-4f23-86cd-876aee559900": {
"test3": authz.Read,
},
},
Admin: "ac97c9e2-346b-42a2-b6da-18bcb61a32fe",
}
tests := []struct {
groups []authn.Group
permission authz.Permission
output []string
}{
{
group1,
authz.Read,
[]string{"test1", "test2"},
},
{
group1,
authz.Write,
[]string{"test2"},
},
{
group3,
authz.Write,
nil,
},
{
group2,
authz.Read,
[]string{"test1", "test2", "test3"},
},
{
group2,
authz.Write,
[]string{"test1", "test2", "test3"},
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
indexList := p.GetAuthorizedIndexList(test.groups, test.permission)
sort.Strings(indexList)
if !reflect.DeepEqual(indexList, test.output) {
t.Errorf("expected %s, but got %s", test.output, indexList)
}
})
}
}

219
barrier.go Normal file
View file

@ -0,0 +1,219 @@
// home https://github.com/glycerine/lmdb-go
// Copyright (c) 2020, the lmdb-go authors
// Copyright (c) 2015, Bryan Matsuo
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// Neither the name of the author nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package pilosa
import (
"github.com/glycerine/idem"
)
// Barrier allows us to temporarily halt all readers, so that
// a writer can commit alone and thus compact the db.
// The Barrier starts unblocked, alllowing passage to any
// caller of WaitAtGate().
type Barrier struct {
wait chan *appointment // send upon entering the waiting room.
halt *idem.Halter
blockReqCh chan *blockReq
unblockCh chan *unblock
}
type blockReq struct {
count int
done chan struct{}
}
func newBlockReq(count int) *blockReq {
return &blockReq{
count: count,
done: make(chan struct{}),
}
}
type appointment struct {
id int
done chan struct{}
}
func newAppointment(id int) *appointment {
return &appointment{
id: id,
done: make(chan struct{}),
}
}
// NewBarrier is either open, allowing immediate passage,
// or blocked, halting all callers at WaitAtGate()
// until the barrier is opened. By default it is open.
//
// Barrier.Close() must be called when the barrier
// is no longer needed to avoid a goroutine leak.
func NewBarrier() (b *Barrier) {
b = &Barrier{
wait: make(chan *appointment), // waiters indicate they are waiting for the gate by sending here.
halt: idem.NewHalter(),
blockReqCh: make(chan *blockReq),
unblockCh: make(chan *unblock),
}
go func() {
defer b.halt.Done.Close()
var waitlist []*appointment
var curBlockReq *blockReq
for {
select {
case br := <-b.blockReqCh:
if br.count == 0 {
close(br.done)
continue
}
if curBlockReq == nil {
// good, changing state from open to closed barrier.
} else {
panic("got 2nd block request atop of first")
}
curBlockReq = br
//vv("barrier: request to block for %v waiters", br.count)
if len(waitlist) != 0 {
panic("had waiters when we were open, internal/client bug")
}
case appt := <-b.wait:
//vv("barrier.wait sees appt = '%#v' and curBlockReq = '%#v'", appt, curBlockReq)
if curBlockReq == nil {
close(appt.done)
continue
}
waitlist = append(waitlist, appt)
n := len(waitlist)
th := curBlockReq.count
if th < 0 {
// infinite waiters. we block everybody until we
// see an unblock request.
continue
}
if n >= th {
close(curBlockReq.done)
curBlockReq = nil
}
case ub := <-b.unblockCh:
for _, appt := range waitlist {
close(appt.done)
}
waitlist = nil
curBlockReq = nil
close(ub.done)
case <-b.halt.ReqStop.Chan:
return
}
}
}()
return
}
// WaitAtGate will return immediately
// if the barrier is unblocked. Otherwise
// it will not return until another
// goroutine unblocks the barrier.
func (b *Barrier) WaitAtGate(id int) {
appt := newAppointment(id)
select {
case b.wait <- appt:
select {
case <-appt.done:
case <-b.halt.ReqStop.Chan:
}
case <-b.halt.ReqStop.Chan:
}
}
// Close should be called to stop the
// barrier's background goroutine when
// you are done using the barrier.
func (b *Barrier) Close() {
b.halt.ReqStop.Close()
<-b.halt.Done.Chan
}
type unblock struct {
done chan struct{}
}
func newUnblock() *unblock {
return &unblock{
done: make(chan struct{}),
}
}
// Unblock lets all waiting goroutines resume execution.
func (b *Barrier) UnblockReaders() {
ub := newUnblock()
select {
case b.unblockCh <- ub:
select {
case <-ub.done:
case <-b.halt.ReqStop.Chan:
}
case <-b.halt.ReqStop.Chan:
}
}
// BlockUntil is called with a count, the
// number of waiters required to be present and waiting
// at the gate before call returns.
// A count of < 0 will return immediately and raise
// the barrier to any number of arriving readers.
// A count of 0 is a no-op.
//
// Otherwise we raise the barrier
// and wait until we have seen count other goroutines waiting
// on it.
//
// We return without releasing the waiters. Call
// Open when you want them to resume.
func (b *Barrier) BlockUntil(count int) {
if count == 0 {
return
}
req := newBlockReq(count)
b.blockReqCh <- req
if count > 0 {
<-req.done
}
}
// BlockAllReadersNoWait raises the barrier to
// an infinite number of waiters and returns immediately
// to the caller.
func (b *Barrier) BlockAllReadersNoWait() {
req := newBlockReq(-1) // -1 means block any number of readers.
b.blockReqCh <- req
// don't wait. <-req.done
}

90
barrier_test.go Normal file
View file

@ -0,0 +1,90 @@
// home https://github.com/glycerine/lmdb-go
// Copyright (c) 2020, the lmdb-go authors
// Copyright (c) 2015, Bryan Matsuo
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// Neither the name of the author nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package pilosa
import (
"fmt"
"sync/atomic"
"testing"
"time"
)
func TestBarrierHolds(t *testing.T) {
b := NewBarrier()
defer b.Close()
released := int64(0)
waiter := func(i int) {
b.WaitAtGate(i)
//vv("goro %v is released", i)
atomic.AddInt64(&released, 1)
}
for i := 0; i < 3; i++ {
go waiter(i)
}
time.Sleep(time.Second)
r := atomic.SwapInt64(&released, 0)
if r != 3 {
panic("open barrier held back goro")
}
//vv("good: barrier started open")
//seenAll := make(chan bool)
b.BlockAllReadersNoWait()
for i := 0; i < 3; i++ {
go waiter(i)
}
time.Sleep(time.Second)
r = atomic.SwapInt64(&released, 0)
if r != 0 {
panic("bad: barrier did not hold back goro")
}
//vv("good: barrier of 4 did not release on 3")
go waiter(4)
time.Sleep(time.Second)
r = atomic.SwapInt64(&released, 0)
if r != 0 {
panic(fmt.Sprintf("bad: barrier did not hold back goro, should wait for unblock. r = %v", r))
}
b.UnblockReaders()
time.Sleep(time.Second)
r = atomic.SwapInt64(&released, 0)
if r != 4 {
panic("bad: unblock should have released 4 goro")
}
}

View file

@ -1,11 +0,0 @@
ARG GO_VERSION=1.19
FROM golang:${GO_VERSION}
WORKDIR /go/src/github.com/featurebasedb/featurebase/
COPY . .
WORKDIR /go/src/github.com/featurebasedb/featurebase/batch/
CMD ["go","test","-v","-mod=vendor","-tags=odbc,dynamic","./..."]

View file

@ -1,8 +0,0 @@
FROM ubuntu:18.04
RUN ["apt-get", "update", "-y"]
RUN ["apt-get", "install", "-y", "curl", "netcat"]
ADD wait.sh /wait
ENTRYPOINT ["/wait"]

View file

@ -1,44 +0,0 @@
GO ?= go
# We allow setting a custom docker-compose "project". Multiple of the
# same docker-compose environment can exist simultaneously as long as
# they use different projects (the project name is prepended to
# container names and such). This is useful in a CI environment where
# we might be running multiple instances of the tests concurrently.
PROJECT ?= batch
DOCKER_COMPOSE = docker-compose -p $(PROJECT)
vendor: ../go.mod
$(GO) mod vendor
build-%:
$(DOCKER_COMPOSE) build $*
test-all:
$(MAKE) startup
$(MAKE) test-run
$(MAKE) shutdown
start-all: build-wait
$(DOCKER_COMPOSE) up -d featurebase
$(DOCKER_COMPOSE) run -T wait featurebase curl --silent --fail http://featurebase:10101/status
startup: start-all
shutdown:
$(DOCKER_COMPOSE) down -v --remove-orphans
save-%-logs:
$(DOCKER_COMPOSE) logs $* > ./testdata/$(PROJECT)_$*_logs.txt
TCMD ?= ./...
# do "make startup", then e.g. "make test-run-local TCMD='-run=MyFavTest ./kafka'"
test-run-local: vendor
pwd
$(DOCKER_COMPOSE) build batch-test
$(DOCKER_COMPOSE) run -T batch-test go test -mod=vendor -tags=odbc,dynamic $(TCMD)
TPKG ?= ../...
test-run: vendor
$(DOCKER_COMPOSE) build batch-test
$(DOCKER_COMPOSE) run -T batch-test bash -c "set -o pipefail; go test -v -mod=vendor -tags=odbc,dynamic ./... -covermode=atomic -coverpkg=$(TPKG) -coverprofile=/testdata/$(PROJECT)_base_coverage.out"

View file

@ -1,46 +0,0 @@
# batch
The `batch` package provides a standard tool set for batching records in a way
that is most performant for ingesting those records into FeatureBase. The main
implementation is `Batch` (which can be initated with the `NewBatch()`
function). The `NewBatch()` function takes an `Importer` which contains all of
the methods required to interact with FeatureBase; these include methods for
doing string/id translation as well as for importing shards of data.
IDK uses the `batch` package internally. Another example where the `batch`
package is used in the `sql3` package. When an "INSERT INTO" statement is
executed, the SQL engine uses a `Batch` to do key translation and build import
batches prior to doing the final import.
## Integration tests
To run the tests, you will need to install the following dependencies:
1. [Docker](https://docs.docker.com/install/)
2. [Docker Compose](https://docs.docker.com/compose/install/)
In addition to these dependancies, you will need to be added to the molecula [Gitlab](https://registry.gitlab.com/molecula) account.
First start the test environment. This is a docker-compose environment that includes featurebase.
make startup
To build and run the integration tests, run:
make test-run-local
Then to shut down the test environment, run:
make shutdown
The previous command is equivalent to running the following:
make startup
sleep 30 # wait for services to come up
make test-run
make shutdown
To run an individual test, you can run the command directly using docker-compose. Note that you must run `docker-compose build batch-test` for docker to run the latest code. Modify the following as needed:
make startup
docker-compose build batch-test
docker-compose run batch-test /usr/local/go/bin/go test -count=1 -mod=vendor -run=TestCmdMainOne .

File diff suppressed because it is too large Load diff

View file

@ -1,20 +0,0 @@
package batch
import (
"time"
"github.com/featurebasedb/featurebase/v3/dax"
)
// Batcher is an interface implemented by anything which can allocate new
// batches.
type Batcher interface {
NewBatch(cfg Config, tbl *dax.Table, fields []*dax.Field) (RecordBatch, error)
}
// Config is the configuration options passed to NewBatch for any implementation
// of the Batcher interface.
type Config struct {
Size int
MaxStaleness time.Duration
}

View file

@ -1,145 +0,0 @@
package batch
import (
"time"
featurebase "github.com/featurebasedb/featurebase/v3"
"github.com/featurebasedb/featurebase/v3/errors"
)
var (
MinTimestampNano = time.Unix(-1<<32, 0).UTC() // 1833-11-24T17:31:44Z
MaxTimestampNano = time.Unix(1<<32, 0).UTC() // 2106-02-07T06:28:16Z
MinTimestamp = time.Unix(-62135596799, 0).UTC() // 0001-01-01T00:00:01Z
MaxTimestamp = time.Unix(253402300799, 0).UTC() // 9999-12-31T23:59:59Z
ErrTimestampOutOfRange = errors.New("", "value provided for timestamp field is out of range")
)
type TimeUnit string
const (
TimeUnitSeconds = TimeUnit(featurebase.TimeUnitSeconds)
TimeUnitMilliseconds = TimeUnit(featurebase.TimeUnitMilliseconds)
TimeUnitMicroseconds = TimeUnit(featurebase.TimeUnitMicroseconds)
TimeUnitUSeconds = TimeUnit(featurebase.TimeUnitUSeconds)
TimeUnitNanoseconds = TimeUnit(featurebase.TimeUnitNanoseconds)
)
// TimestampToInt64 converts the provided timestamp to an int64 as the number of
// units past the epoch.
func TimestampToInt64(unit TimeUnit, epoch time.Time, ts time.Time) (int64, error) {
var err error
unit, err = validateTimeUnit(unit)
if err != nil {
return 0, errors.Wrap(err, "validating time unit")
}
epoch, err = validateEpoch(epoch)
if err != nil {
return 0, errors.Wrap(err, "validating epoch")
}
// Check if the epoch alone is out-of-range. If so, ingest should halt,
// regardless of state of the timestamp out-of-range CLI option.
if err := validateTimestamp(unit, epoch); err != nil {
return 0, errors.Wrap(err, "validating epoch")
}
epochAsInt64 := timestampToInt(unit, epoch)
// Check if the timestamp is out-of-range.
if err := validateTimestamp(unit, ts); err != nil {
return 0, errors.Wrapf(ErrTimestampOutOfRange, "validating timestamp: %s", ts)
}
tsAsInt64 := timestampToInt(unit, ts)
return tsAsInt64 - epochAsInt64, nil
}
// validateTimeUnit checks if the time unit is supported. If the provided unit
// is blank, validateTimeUnit returns the default TimeUnit.
func validateTimeUnit(unit TimeUnit) (TimeUnit, error) {
switch unit {
case "":
return TimeUnitSeconds, nil
case TimeUnitSeconds,
TimeUnitMilliseconds,
TimeUnitMicroseconds,
TimeUnitUSeconds,
TimeUnitNanoseconds:
return unit, nil
}
return "", errors.Errorf("unsupported time unit: %s", unit)
}
// validateEpoch checks if the epoch is supported. If the provided epoch
// is "zero", validateEpoch returns the default epoch value.
func validateEpoch(epoch time.Time) (time.Time, error) {
if epoch.IsZero() {
return time.Unix(0, 0), nil
}
return epoch, nil
}
// validateTimestamp checks if the timestamp is within the range of what FB accepts.
func validateTimestamp(unit TimeUnit, ts time.Time) error {
// Min and Max timestamps that Featurebase accepts
var minStamp, maxStamp time.Time
switch unit {
case TimeUnitNanoseconds:
minStamp = MinTimestampNano
maxStamp = MaxTimestampNano
default:
minStamp = MinTimestamp
maxStamp = MaxTimestamp
}
if ts.Before(minStamp) || ts.After(maxStamp) {
return errors.Errorf("timestamp value (%v) must be within min: %v and max: %v", ts, minStamp, maxStamp)
}
return nil
}
// timestampToInt takes a time unit and a time.Time and converts it to an
// integer value.
func timestampToInt(unit TimeUnit, ts time.Time) int64 {
switch unit {
case TimeUnitSeconds:
return ts.Unix()
case TimeUnitMilliseconds:
return ts.UnixMilli()
case TimeUnitMicroseconds, TimeUnitUSeconds:
return ts.UnixMicro()
case TimeUnitNanoseconds:
return ts.UnixNano()
}
return 0
}
// intToTimestamp takes a timeunit and an integer value and converts it to
// time.Time.
func intToTimestamp(unit TimeUnit, val int64) (time.Time, error) {
switch unit {
case TimeUnitSeconds:
return time.Unix(val, 0).UTC(), nil
case TimeUnitMilliseconds:
return time.UnixMilli(val).UTC(), nil
case TimeUnitMicroseconds, TimeUnitUSeconds:
return time.UnixMicro(val).UTC(), nil
case TimeUnitNanoseconds:
return time.Unix(0, val).UTC(), nil
default:
return time.Time{}, errors.Errorf("Unknown time unit: '%v'", unit)
}
}
// Int64ToTimestamp converts the provided int64 to a timestamp based on the time unit
// and epoch.
func Int64ToTimestamp(unit TimeUnit, epoch time.Time, val int64) (time.Time, error) {
return intToTimestamp(unit, timestampToInt(unit, epoch)+val)
}

View file

@ -1,29 +0,0 @@
version: '3'
services:
featurebase:
build:
context: ../.
dockerfile: ./Dockerfile-clustertests
environment:
PILOSA_DATA_DIR: /data
PILOSA_BIND: 0.0.0.0:10101
PILOSA_BIND_GRPC: 0.0.0.0:20101
PILOSA_ADVERTISE: featurebase:10101
command: /featurebase -test.run=TestRunMain -test.coverprofile=/testdata/batch_coverage.out server
volumes:
- ./testdata:/testdata
batch-test:
build:
context: ../.
dockerfile: ./batch/Dockerfile-test
volumes:
- ./testdata:/testdata
wait:
depends_on:
- "featurebase"
build:
context: .
dockerfile: Dockerfile-wait

View file

@ -1,38 +0,0 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
package egpool_test
import (
"errors"
"testing"
"github.com/featurebasedb/featurebase/v3/batch/egpool"
)
func TestEGPool(t *testing.T) {
eg := egpool.Group{}
a := make([]int, 10)
for i := 0; i < 10; i++ {
i := i
eg.Go(func() error {
a[i] = i
if i == 7 {
return errors.New("blah")
}
return nil
})
}
err := eg.Wait()
if err == nil || err.Error() != "blah" {
t.Errorf("expected err blah, got: %v", err)
}
for i := 0; i < 10; i++ {
if a[i] != i {
t.Errorf("expected a[%d] to be %d, but is %d", i, i, a[i])
}
}
}

View file

@ -1,8 +0,0 @@
package batch
import "github.com/pkg/errors"
// Predefined batch-related errors.
var (
ErrPreconditionFailed = errors.New("Precondition failed")
)

View file

@ -1,3 +0,0 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
package batch

View file

@ -1,3 +0,0 @@
# testdata
This directory is used in CI tests. I think.

View file

@ -1,26 +0,0 @@
#!/bin/sh
name=$1
shift
_start_ts=$(date +%s)
elapsed=0
timeout=120
while :
do
$@ > /dev/null
_ret=$?
_end_ts=$(date +%s)
if [ $_ret -eq 0 ]; then
echo "$name is available after $((_end_ts - _start_ts)) seconds."
break
else
echo "Waiting for $name after $((_end_ts - _start_ts)) seconds."
fi
sleep 1s
elapsed=$((elapsed+1))
if [ $elapsed -ge $timeout ]; then
exit 110
fi
done
set -ex

1028
bluegreentx.go Normal file

File diff suppressed because it is too large Load diff

100
bluegreentx_test.go Normal file
View file

@ -0,0 +1,100 @@
// Copyright 2020 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa
import (
"bytes"
"context"
"io"
"io/ioutil"
"os"
"strings"
"testing"
cryrand "crypto/rand"
. "github.com/pilosa/pilosa/v2/vprint" // nolint:staticcheck
)
var _ = context.Background
var _ = os.Open
var _ = strings.Split
func TestMultiReaderB(t *testing.T) {
// MultiReaderB should read identical chunks of bytes from both its "a" and "b"
// member io.Readers, else it should panic. This should hold for
// varying sizes of inputs.
for n := 1 << 5; n < (1 << 18); n = n*2 - 13 {
src := io.LimitReader(cryrand.Reader, int64(n))
a := make([]byte, n)
nr := 0
for nr < n {
na, err := src.Read(a)
PanicOn(err)
nr += na
}
if nr != n {
panic("short read")
}
b := make([]byte, n)
copy(b, a)
if !bytes.Equal(a, b) {
panic("test prep failed")
}
m := &MultiReaderB{
a: ioutil.NopCloser(bytes.NewBuffer(a)),
b: ioutil.NopCloser(bytes.NewBuffer(b)),
}
// should not trigger the internal panic of MultiReadB
ncp, err := io.Copy(ioutil.Discard, m)
PanicOn(err)
if ncp != int64(n) {
panic("short copy")
}
for victim := 0; victim < n; victim += 7 {
copy(b, a)
if victim%2 == 0 {
// corrupt b
b[victim] = (b[victim] + 1) % 255
} else {
// corrupt a
a[victim] = (a[victim] + 1) % 255
}
m = &MultiReaderB{
a: ioutil.NopCloser(bytes.NewBuffer(a)),
b: ioutil.NopCloser(bytes.NewBuffer(b)),
}
helperShouldPanicOnCopy(m)
}
}
}
func helperShouldPanicOnCopy(m *MultiReaderB) {
// differences in bytes read should be noticed
defer func() {
r := recover()
if r == nil {
panic("expected panic on byte difference but didn't see it")
}
}()
_, _ = io.Copy(ioutil.Discard, m)
}

1606
bolt.go Normal file

File diff suppressed because it is too large Load diff

1269
bolt_test.go Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,18 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
package pilosa
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package boltdb
import (
"bytes"
@ -10,13 +22,14 @@ import (
"io"
"os"
"path/filepath"
"runtime/pprof"
"sync"
"time"
"github.com/featurebasedb/featurebase/v3/roaring"
"github.com/pilosa/pilosa/v2"
"github.com/pkg/errors"
bolt "go.etcd.io/bbolt"
"runtime/pprof"
)
var _ = pprof.StartCPUProfile
@ -24,7 +37,7 @@ var _ = pprof.StartCPUProfile
var (
// ErrTranslateStoreClosed is returned when reading from an TranslateEntryReader
// and the underlying store is closed.
ErrBoltTranslateStoreClosed = errors.New("boltdb: translate store closing")
ErrTranslateStoreClosed = errors.New("boltdb: translate store closing")
// ErrTranslateKeyNotFound is returned when translating key
// and the underlying store returns an empty set
@ -32,8 +45,6 @@ var (
bucketKeys = []byte("keys")
bucketIDs = []byte("ids")
bucketFree = []byte("free")
freeKey = []byte("free")
)
const (
@ -44,8 +55,8 @@ const (
)
// OpenTranslateStore opens and initializes a boltdb translation store.
func OpenTranslateStore(path, index, field string, partitionID, partitionN int, fsyncEnabled bool) (TranslateStore, error) {
s := NewBoltTranslateStore(index, field, partitionID, partitionN, fsyncEnabled)
func OpenTranslateStore(path, index, field string, partitionID, partitionN int) (pilosa.TranslateStore, error) {
s := NewTranslateStore(index, field, partitionID, partitionN)
s.Path = path
if err := s.Open(); err != nil {
return nil, err
@ -54,19 +65,18 @@ func OpenTranslateStore(path, index, field string, partitionID, partitionN int,
}
// Ensure type implements interface.
var _ TranslateStore = &BoltTranslateStore{}
var _ pilosa.TranslateStore = &TranslateStore{}
// BoltTranslateStore is an on-disk storage engine for translating string-to-uint64 values.
// TranslateStore is an on-disk storage engine for translating string-to-uint64 values.
// An empty string will be converted into the sentinel byte slice:
//
// var emptyKey = []byte{
// 0x00, 0x00, 0x00,
// 0x4d, 0x54, 0x4d, 0x54, // MTMT
// 0x00,
// 0xc2, 0xa0, // NO-BREAK SPACE
// 0x00,
// }
type BoltTranslateStore struct {
// var emptyKey = []byte{
// 0x00, 0x00, 0x00,
// 0x4d, 0x54, 0x4d, 0x54, // MTMT
// 0x00,
// 0xc2, 0xa0, // NO-BREAK SPACE
// 0x00,
// }
type TranslateStore struct {
mu sync.RWMutex
db *bolt.DB
@ -78,29 +88,28 @@ type BoltTranslateStore struct {
once sync.Once
closing chan struct{}
readOnly bool
fsyncEnabled bool
writeNotify chan struct{}
readOnly bool
writeNotify chan struct{}
// File path to database file.
Path string
}
// NewBoltTranslateStore returns a new instance of TranslateStore.
func NewBoltTranslateStore(index, field string, partitionID, partitionN int, fsyncEnabled bool) *BoltTranslateStore {
return &BoltTranslateStore{
index: index,
field: field,
partitionID: partitionID,
partitionN: partitionN,
closing: make(chan struct{}),
writeNotify: make(chan struct{}),
fsyncEnabled: fsyncEnabled,
// NewTranslateStore returns a new instance of TranslateStore.
func NewTranslateStore(index, field string, partitionID, partitionN int) *TranslateStore {
return &TranslateStore{
index: index,
field: field,
partitionID: partitionID,
partitionN: partitionN,
closing: make(chan struct{}),
writeNotify: make(chan struct{}),
}
}
// Open opens the translate file.
func (s *BoltTranslateStore) Open() (err error) {
func (s *TranslateStore) Open() (err error) {
// add the path to the problem database if we panic handling it.
defer func() {
r := recover()
@ -109,9 +118,9 @@ func (s *BoltTranslateStore) Open() (err error) {
}
}()
if err := os.MkdirAll(filepath.Dir(s.Path), 0o750); err != nil {
if err := os.MkdirAll(filepath.Dir(s.Path), 0777); err != nil {
return errors.Wrapf(err, "mkdir %s", filepath.Dir(s.Path))
} else if s.db, err = bolt.Open(s.Path, 0o600, &bolt.Options{Timeout: 1 * time.Second, NoSync: !s.fsyncEnabled, InitialMmapSize: 0}); err != nil {
} else if s.db, err = bolt.Open(s.Path, 0666, &bolt.Options{Timeout: 1 * time.Second}); err != nil {
return errors.Wrapf(err, "open file: %s", err)
}
@ -121,8 +130,6 @@ func (s *BoltTranslateStore) Open() (err error) {
return err
} else if _, err := tx.CreateBucketIfNotExists(bucketIDs); err != nil {
return err
} else if _, err := tx.CreateBucketIfNotExists(bucketFree); err != nil {
return err
}
return nil
}); err != nil {
@ -134,7 +141,7 @@ func (s *BoltTranslateStore) Open() (err error) {
}
// Close closes the underlying database.
func (s *BoltTranslateStore) Close() (err error) {
func (s *TranslateStore) Close() (err error) {
s.once.Do(func() { close(s.closing) })
if s.db != nil {
@ -146,26 +153,26 @@ func (s *BoltTranslateStore) Close() (err error) {
}
// PartitionID returns the partition id the store was initialized with.
func (s *BoltTranslateStore) PartitionID() int {
func (s *TranslateStore) PartitionID() int {
return s.partitionID
}
// ReadOnly returns true if the store is in read-only mode.
func (s *BoltTranslateStore) ReadOnly() bool {
func (s *TranslateStore) ReadOnly() bool {
s.mu.RLock()
defer s.mu.RUnlock()
return s.readOnly
}
// SetReadOnly toggles whether store is in read-only mode.
func (s *BoltTranslateStore) SetReadOnly(v bool) {
func (s *TranslateStore) SetReadOnly(v bool) {
s.mu.Lock()
defer s.mu.Unlock()
s.readOnly = v
}
// Size returns the number of bytes in the data file.
func (s *BoltTranslateStore) Size() int64 {
func (s *TranslateStore) Size() int64 {
if s.db == nil {
return 0
}
@ -180,7 +187,7 @@ func (s *BoltTranslateStore) Size() int64 {
// FindKeys looks up the ID for each key.
// Keys are not created if they do not exist.
// Missing keys are not considered errors, so the length of the result may be less than that of the input.
func (s *BoltTranslateStore) FindKeys(keys ...string) (map[string]uint64, error) {
func (s *TranslateStore) FindKeys(keys ...string) (map[string]uint64, error) {
result := make(map[string]uint64, len(keys))
err := s.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(bucketKeys)
@ -214,9 +221,9 @@ const translateTransactionSize = 16384
// CreateKeys maps all keys to IDs, creating the IDs if they do not exist.
// If the translator is read-only, this will return an error.
func (s *BoltTranslateStore) CreateKeys(keys ...string) (map[string]uint64, error) {
func (s *TranslateStore) CreateKeys(keys ...string) (map[string]uint64, error) {
if s.ReadOnly() {
return nil, ErrTranslateStoreReadOnly
return nil, pilosa.ErrTranslateStoreReadOnly
}
written := false
@ -234,26 +241,14 @@ func (s *BoltTranslateStore) CreateKeys(keys ...string) (map[string]uint64, erro
if idBucket == nil {
return errors.Errorf(errFmtTranslateBucketNotFound, bucketIDs)
}
freeBucket := tx.Bucket(bucketFree)
if freeBucket == nil {
return errors.Errorf(errFmtTranslateBucketNotFound, bucketFree)
}
puts := 0
// we create a freeIDGetter to reduce marshalling
getter := newFreeIDGetter(freeBucket)
defer getter.Close()
for idx, key := range keys {
id, boltKey := findIDByKey(keyBucket, key)
if id != 0 {
result[key] = id
continue
}
// see if we can re-use any IDs first
if id = getter.GetFreeID(); id == 0 {
id = GenerateNextPartitionedID(s.index, maxID(tx), s.partitionID, s.partitionN)
}
id = pilosa.GenerateNextPartitionedID(s.index, maxID(tx), s.partitionID, s.partitionN)
idBytes := idScratch[puts*8 : puts*8+8]
binary.BigEndian.PutUint64(idBytes, id)
puts++
@ -284,7 +279,7 @@ func (s *BoltTranslateStore) CreateKeys(keys ...string) (map[string]uint64, erro
}
// Match finds the IDs of all keys matching a filter.
func (s *BoltTranslateStore) Match(filter func([]byte) bool) ([]uint64, error) {
func (s *TranslateStore) Match(filter func([]byte) bool) ([]uint64, error) {
var matches []uint64
err := s.db.View(func(tx *bolt.Tx) error {
// This uses the id bucket instead of the key bucket so that matches are produced in sorted order.
@ -314,7 +309,7 @@ func (s *BoltTranslateStore) Match(filter func([]byte) bool) ([]uint64, error) {
// TranslateID converts an integer ID to a string key.
// Returns a blank string if ID does not exist.
func (s *BoltTranslateStore) TranslateID(id uint64) (string, error) {
func (s *TranslateStore) TranslateID(id uint64) (string, error) {
tx, err := s.db.Begin(false)
if err != nil {
return "", err
@ -324,7 +319,7 @@ func (s *BoltTranslateStore) TranslateID(id uint64) (string, error) {
}
// TranslateIDs converts a list of integer IDs to a list of string keys.
func (s *BoltTranslateStore) TranslateIDs(ids []uint64) ([]string, error) {
func (s *TranslateStore) TranslateIDs(ids []uint64) ([]string, error) {
if len(ids) == 0 {
return nil, nil
}
@ -345,7 +340,7 @@ func (s *BoltTranslateStore) TranslateIDs(ids []uint64) ([]string, error) {
}
// ForceSet writes the id/key pair to the store even if read only. Used by replication.
func (s *BoltTranslateStore) ForceSet(id uint64, key string) error {
func (s *TranslateStore) ForceSet(id uint64, key string) error {
if err := s.db.Update(func(tx *bolt.Tx) (err error) {
if err := tx.Bucket(bucketKeys).Put([]byte(key), u64tob(id)); err != nil {
return err
@ -361,13 +356,13 @@ func (s *BoltTranslateStore) ForceSet(id uint64, key string) error {
}
// EntryReader returns a reader that streams the underlying data file.
func (s *BoltTranslateStore) EntryReader(ctx context.Context, offset uint64) (TranslateEntryReader, error) {
func (s *TranslateStore) EntryReader(ctx context.Context, offset uint64) (pilosa.TranslateEntryReader, error) {
ctx, cancel := context.WithCancel(ctx)
return &BoltTranslateEntryReader{ctx: ctx, cancel: cancel, store: s, offset: offset}, nil
return &TranslateEntryReader{ctx: ctx, cancel: cancel, store: s, offset: offset}, nil
}
// WriteNotify returns a channel that is closed when a new entry is written.
func (s *BoltTranslateStore) WriteNotify() <-chan struct{} {
func (s *TranslateStore) WriteNotify() <-chan struct{} {
s.mu.RLock()
ch := s.writeNotify
s.mu.RUnlock()
@ -375,7 +370,7 @@ func (s *BoltTranslateStore) WriteNotify() <-chan struct{} {
}
// notifyWrite sends a write notification under write lock.
func (s *BoltTranslateStore) notifyWrite() {
func (s *TranslateStore) notifyWrite() {
s.mu.Lock()
defer s.mu.Unlock()
close(s.writeNotify)
@ -383,7 +378,7 @@ func (s *BoltTranslateStore) notifyWrite() {
}
// MaxID returns the highest id in the store.
func (s *BoltTranslateStore) MaxID() (max uint64, err error) {
func (s *TranslateStore) MaxID() (max uint64, err error) {
if err := s.db.View(func(tx *bolt.Tx) error {
max = maxID(tx)
return nil
@ -393,13 +388,18 @@ func (s *BoltTranslateStore) MaxID() (max uint64, err error) {
return max, nil
}
// Begin starts and returns a transaction on the underlying store.
func (s *BoltTranslateStore) Begin(write bool) (TranslatorTx, error) {
return s.db.Begin(write)
// WriteTo writes the contents of the store to the writer.
func (s *TranslateStore) WriteTo(w io.Writer) (int64, error) {
tx, err := s.db.Begin(false)
if err != nil {
return 0, err
}
defer func() { _ = tx.Rollback() }()
return tx.WriteTo(w)
}
// ReadFrom reads the content and overwrites the existing store.
func (s *BoltTranslateStore) ReadFrom(r io.Reader) (n int64, err error) {
func (s *TranslateStore) ReadFrom(r io.Reader) (n int64, err error) {
// Close store.
if err := s.Close(); err != nil {
return 0, errors.Wrap(err, "closing store")
@ -443,27 +443,27 @@ func maxID(tx *bolt.Tx) uint64 {
return 0
}
type BoltTranslateEntryReader struct {
type TranslateEntryReader struct {
ctx context.Context
store *BoltTranslateStore
store *TranslateStore
offset uint64
cancel func()
}
// Close closes the reader.
func (r *BoltTranslateEntryReader) Close() error {
func (r *TranslateEntryReader) Close() error {
r.cancel()
return nil
}
// ReadEntry reads the next entry from the underlying translate store.
func (r *BoltTranslateEntryReader) ReadEntry(entry *TranslateEntry) error {
func (r *TranslateEntryReader) ReadEntry(entry *pilosa.TranslateEntry) error {
// Ensure reader has not been closed before read.
select {
case <-r.ctx.Done():
return r.ctx.Err()
case <-r.store.closing:
return ErrBoltTranslateStoreClosed
return ErrTranslateStoreClosed
default:
}
@ -503,95 +503,12 @@ func (r *BoltTranslateEntryReader) ReadEntry(entry *TranslateEntry) error {
case <-r.ctx.Done():
return r.ctx.Err()
case <-r.store.closing:
return ErrBoltTranslateStoreClosed
return ErrTranslateStoreClosed
case <-writeNotify:
}
}
}
type boltWrapper struct {
tx *bolt.Tx
}
func (w *boltWrapper) Commit() error {
if w.tx != nil {
return w.tx.Commit()
}
return nil
}
func (w *boltWrapper) Rollback() {
if w.tx != nil {
w.tx.Rollback()
}
}
func (s *BoltTranslateStore) FreeIDs() (*roaring.Bitmap, error) {
result := roaring.NewBitmap()
err := s.db.View(func(tx *bolt.Tx) error {
bkt := tx.Bucket(bucketFree)
if bkt == nil {
return errors.Errorf(errFmtTranslateBucketNotFound, bucketKeys)
}
b := bkt.Get(freeKey)
err := result.UnmarshalBinary(b)
if err != nil {
return err
}
return nil
})
return result, err
}
func (s *BoltTranslateStore) MergeFree(tx *bolt.Tx, newIDs *roaring.Bitmap) error {
bkt := tx.Bucket(bucketFree)
b := bkt.Get(freeKey)
buf := new(bytes.Buffer)
if b != nil { // if existing combine with newIDs
before := roaring.NewBitmap()
err := before.UnmarshalBinary(b)
if err != nil {
return err
}
final := newIDs.Union(before)
_, err = final.WriteTo(buf)
if err != nil {
return err
}
} else {
newIDs.WriteTo(buf)
}
return bkt.Put(freeKey, buf.Bytes())
}
// Delete removes the lookeup pairs in order to make avialble for reuse but doesn't commit the
// transaction for that is tied to the associated rbf transaction being successful
func (s *BoltTranslateStore) Delete(records *roaring.Bitmap) (Commitor, error) {
tx, err := s.db.Begin(true)
if err != nil {
return nil, err
}
keyBucket := tx.Bucket(bucketKeys)
idBucket := tx.Bucket(bucketIDs)
ids := records.Slice()
for i := range ids {
id := u64tob(ids[i])
boltKey := idBucket.Get(id)
err = keyBucket.Delete(boltKey)
if err != nil {
tx.Rollback()
return &boltWrapper{}, err
}
err = idBucket.Delete(id)
if err != nil {
tx.Rollback()
return &boltWrapper{}, err
}
}
return &boltWrapper{tx: tx}, s.MergeFree(tx, records)
}
// emptyKey is a sentinel byte slice which stands for "" as a key.
var emptyKey = []byte{
0x00, 0x00, 0x00,
@ -615,84 +532,6 @@ func findIDByKey(bkt *bolt.Bucket, key string) (uint64, []byte) {
return 0, boltKey
}
// freeIDGetter reduces the amount of marshaling required to get multiple ids
type freeIDGetter struct {
freeBucket *bolt.Bucket
b *roaring.Bitmap
changed bool
}
// newFreeIDGetter initializes a new freeIDGetter. If at any point there is a
// failure, it returns an error.
//
// NOTE: For changes to be persisted to the bucket, you must call
// (*freeIDGetter).Close()
func newFreeIDGetter(freeBucket *bolt.Bucket) *freeIDGetter {
g := &freeIDGetter{
freeBucket: freeBucket,
}
// we ignore this value because it's okay if we dont have a bitmap just yet
_ = g.getBitmap()
return g
}
func (g *freeIDGetter) getBitmap() bool {
if g.b == nil {
// get the bitmap from freeBucket
value := g.freeBucket.Get(freeKey)
if value == nil {
return false
}
// turn the value into a bitmap
b := roaring.NewBitmap()
if err := b.UnmarshalBinary(value); err != nil {
return false
}
g.b = b
}
return true
}
// GetFreeID tries to get a free ID from the free id bucket. If at any point it
// fails to do so, it returns a 0. Otherwise, it returns the first free ID in the
// bucket
func (g *freeIDGetter) GetFreeID() (id uint64) {
if !g.getBitmap() {
return 0
}
// get the first free id
id, ok := g.b.Min()
if !ok {
return 0
}
// remove that id from the free id bitmap
if changed, err := g.b.RemoveN(id); changed == 0 || err != nil {
return 0
} else {
g.changed = true
}
return id
}
// Close persists any changes to the bitmap back to the bucket and then nils the
// references for safety.
func (g *freeIDGetter) Close() error {
if g.changed {
// convert bitmap to binary
buf, err := g.b.MarshalBinary()
if err != nil {
return errors.Wrap(err, "closing free ID Getter")
}
// put updated bitmap back into the freeBucket
if err := g.freeBucket.Put(freeKey, buf); err != nil {
return errors.Wrap(err, "closing free ID Getter")
}
}
g.b = nil
g.freeBucket = nil
return nil
}
func findKeyByID(bkt *bolt.Bucket, id uint64) string {
boltKey := bkt.Get(u64tob(id))
if bytes.Equal(boltKey, emptyKey) {

View file

@ -1,6 +1,17 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
package pilosa_test
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package boltdb_test
import (
"bytes"
@ -11,11 +22,10 @@ import (
"testing"
"time"
pilosa "github.com/featurebasedb/featurebase/v3"
"github.com/featurebasedb/featurebase/v3/disco"
"github.com/featurebasedb/featurebase/v3/roaring"
"github.com/featurebasedb/featurebase/v3/testhook"
"github.com/stretchr/testify/require"
"github.com/pilosa/pilosa/v2"
"github.com/pilosa/pilosa/v2/boltdb"
"github.com/pilosa/pilosa/v2/testhook"
"github.com/pilosa/pilosa/v2/topology"
)
//var vv = pilosa.VV
@ -204,7 +214,7 @@ func TestTranslateStore_MaxID(t *testing.T) {
}
}
func TestBoltTranslateStore_EntryReader(t *testing.T) {
func TestTranslateStore_EntryReader(t *testing.T) {
t.Run("OK", func(t *testing.T) {
s := MustOpenNewTranslateStore(t)
defer MustCloseTranslateStore(s)
@ -362,7 +372,7 @@ func TestBoltTranslateStore_EntryReader(t *testing.T) {
}()
var entry pilosa.TranslateEntry
if err := r.ReadEntry(&entry); err != pilosa.ErrBoltTranslateStoreClosed {
if err := r.ReadEntry(&entry); err != boltdb.ErrTranslateStoreClosed {
t.Fatalf("unexpected error: %#v", err)
}
@ -375,7 +385,7 @@ func TestBoltTranslateStore_EntryReader(t *testing.T) {
}
// MustNewTranslateStore returns a new TranslateStore with a temporary path.
func MustNewTranslateStore(tb testing.TB) *pilosa.BoltTranslateStore {
func MustNewTranslateStore(tb testing.TB) *boltdb.TranslateStore {
f, err := testhook.TempFile(tb, "translate-store")
if err != nil {
panic(err)
@ -383,57 +393,11 @@ func MustNewTranslateStore(tb testing.TB) *pilosa.BoltTranslateStore {
panic(err)
}
s := pilosa.NewBoltTranslateStore("I", "F", 0, disco.DefaultPartitionN, false)
s := boltdb.NewTranslateStore("I", "F", 0, topology.DefaultPartitionN)
s.Path = f.Name()
return s
}
func TestTranslateStore_Delete(t *testing.T) {
s := MustOpenNewTranslateStore(t)
defer MustCloseTranslateStore(s)
// Setup initial keys.
ids, err := s.CreateKeys("foo", "bar", "deleteme")
if err != nil {
t.Fatal(err)
}
records := roaring.NewBitmap(ids["deleteme"])
c, err := s.Delete(records)
if err != nil {
t.Fatal(err)
}
if err = c.Commit(); err != nil {
t.Fatal(err)
}
r, e := s.FreeIDs()
if e != nil {
t.Fatal(err)
}
freeids := r.Slice()
if len(freeids) == 0 {
t.Fatalf("expected to have free id")
}
if freeids[0] != ids["deleteme"] {
t.Fatalf("expected [%v] and got %v", ids["deleteme"], freeids[0])
}
records2 := roaring.NewBitmap(ids["foo"])
c, err = s.Delete(records2)
if err != nil {
t.Fatal(err)
}
if err = c.Commit(); err != nil {
t.Fatal(err)
}
r, e = s.FreeIDs()
if e != nil {
t.Fatal(err)
}
freeids = r.Slice()
if len(freeids) != 2 {
t.Fatalf("expected to have 2 free ids")
}
}
func TestTranslateStore_ReadWrite(t *testing.T) {
t.Run("WriteTo_ReadFrom", func(t *testing.T) {
s := MustOpenNewTranslateStore(t)
@ -456,21 +420,14 @@ func TestTranslateStore_ReadWrite(t *testing.T) {
// Put the contents of the store into a buffer.
buf := bytes.NewBuffer(nil)
expN := s.Size()
expN := int64(32768)
// wrap in a func so we can defer rollback. Need rollback to
// happen before the end of the test. I'm not entirely sure
// why, but it hangs if you don't.
func() {
tx, err := s.Begin(false)
require.NoError(t, err)
defer tx.Rollback()
// After this, the buffer should contain batch0.
n, err := tx.WriteTo(buf)
require.NoError(t, err)
require.Equal(t, expN, n)
}()
// After this, the buffer should contain batch0.
if n, err := s.WriteTo(buf); err != nil {
t.Fatalf("writing to buffer: %s", err)
} else if n != expN {
t.Fatalf("expected buffer size: %d, but got: %d", expN, n)
}
// Populate the store with the keys in batch1.
batch1IDs, err := s.CreateKeys(batch1...)
@ -510,16 +467,16 @@ func TestTranslateStore_ReadWrite(t *testing.T) {
}
// MustOpenNewTranslateStore returns a new, opened TranslateStore.
func MustOpenNewTranslateStore(tb testing.TB) *pilosa.BoltTranslateStore {
func MustOpenNewTranslateStore(tb testing.TB) *boltdb.TranslateStore {
s := MustNewTranslateStore(tb)
if err := s.Open(); err != nil {
tb.Fatalf("opening s: %v", err)
panic(err)
}
return s
}
// MustCloseTranslateStore closes s and removes the underlying data file.
func MustCloseTranslateStore(s *pilosa.BoltTranslateStore) {
func MustCloseTranslateStore(s *boltdb.TranslateStore) {
if err := s.Close(); err != nil {
panic(err)
}

View file

@ -1,11 +1,23 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa
import (
"fmt"
"github.com/featurebasedb/featurebase/v3/disco"
"github.com/pilosa/pilosa/v2/topology"
"github.com/pkg/errors"
)
@ -30,7 +42,7 @@ func (*nopSerializer) Unmarshal([]byte, Message) error { return nil }
type broadcaster interface {
SendSync(Message) error
SendAsync(Message) error
SendTo(*disco.Node, Message) error
SendTo(*topology.Node, Message) error
}
// Message is the interface implemented by all core pilosa types which can be serialized to messages.
@ -49,7 +61,7 @@ func (nopBroadcaster) SendSync(Message) error { return nil }
func (nopBroadcaster) SendAsync(Message) error { return nil }
// SendTo is a no-op implementation of Broadcaster SendTo method.
func (nopBroadcaster) SendTo(*disco.Node, Message) error { return nil }
func (nopBroadcaster) SendTo(*topology.Node, Message) error { return nil }
// Broadcast message types.
const (
@ -61,18 +73,16 @@ const (
messageTypeCreateView
messageTypeDeleteView
messageTypeClusterStatus
messageTypeUNUSED0 // used to be ResizeInstruction
messageTypeUNUSED1 // used to be ResizeInstructionComplete
messageTypeResizeInstruction
messageTypeResizeInstructionComplete
messageTypeNodeState
messageTypeRecalculateCaches
messageTypeLoadSchemaMessage
messageTypeNodeEvent
messageTypeNodeStatus
messageTypeTransaction
messageTypeUNUSED2 // used to be ResizeNodeMessage
messageTypeUNUSED3 // used to be ResizeAbortMessage
messageTypeUpdateField
messageTypeDeleteDataframe
messageTypeResizeNodeMessage
messageTypeResizeAbortMessage
)
// MarshalInternalMessage serializes the pilosa message and adds pilosa internal
@ -104,6 +114,10 @@ func getMessage(typ byte) Message {
return &DeleteViewMessage{}
case messageTypeClusterStatus:
return &ClusterStatus{}
case messageTypeResizeInstruction:
return &ResizeInstruction{}
case messageTypeResizeInstructionComplete:
return &ResizeInstructionComplete{}
case messageTypeNodeState:
return &NodeStateMessage{}
case messageTypeRecalculateCaches:
@ -116,10 +130,10 @@ func getMessage(typ byte) Message {
return &NodeStatus{}
case messageTypeTransaction:
return &TransactionMessage{}
case messageTypeUpdateField:
return &UpdateFieldMessage{}
case messageTypeDeleteDataframe:
return &DeleteDataframeMessage{}
case messageTypeResizeNodeMessage:
return &ResizeNodeMessage{}
case messageTypeResizeAbortMessage:
return &ResizeAbortMessage{}
default:
panic(fmt.Sprintf("unknown message type %d", typ))
}
@ -143,6 +157,10 @@ func getMessageType(m Message) byte {
return messageTypeDeleteView
case *ClusterStatus:
return messageTypeClusterStatus
case *ResizeInstruction:
return messageTypeResizeInstruction
case *ResizeInstructionComplete:
return messageTypeResizeInstructionComplete
case *NodeStateMessage:
return messageTypeNodeState
case *RecalculateCaches:
@ -155,10 +173,10 @@ func getMessageType(m Message) byte {
return messageTypeNodeStatus
case *TransactionMessage:
return messageTypeTransaction
case *UpdateFieldMessage:
return messageTypeUpdateField
case *DeleteDataframeMessage:
return messageTypeDeleteDataframe
case *ResizeNodeMessage:
return messageTypeResizeNodeMessage
case *ResizeAbortMessage:
return messageTypeResizeAbortMessage
default:
panic(fmt.Sprintf("don't have type for message %#v", m))
}

50
bsi.go
View file

@ -1,21 +1,33 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa
import (
"math/bits"
"github.com/featurebasedb/featurebase/v3/roaring"
"github.com/pilosa/pilosa/v2/roaring"
)
// BSIData contains BSI-structured data.
type BSIData []*Row
// bsiData contains BSI-structured data.
type bsiData []*Row
// PivotDescending loops over nonzero BSI values in descending order.
// pivotDescending loops over nonzero BSI values in descending order.
// For each value, the provided function is called with the value and a slice of the associated columns.
// If limit or offset are not-nil, they will be applied.
// Applying a limit or offset may modify the pointed-to value.
func (bsi BSIData) PivotDescending(filter *Row, branch uint64, limit, offset *uint64, fn func(uint64, ...uint64)) {
func (bsi bsiData) pivotDescending(filter *Row, branch uint64, limit, offset *uint64, fn func(uint64, ...uint64)) {
// This "pivot" algorithm works by treating the BSI data as a tree.
// Each branch of this tree corresponds to a power-of-2-sized range of BSI values.
// Each range is subdivided into 2 ranges of half size, which form lower branches.
@ -56,8 +68,8 @@ func (bsi BSIData) PivotDescending(filter *Row, branch uint64, limit, offset *ui
upperBranch, lowerBranch := branch|(1<<uint(len(bsi)-1)), branch
splitBit := bsi[len(bsi)-1]
lowerBits := bsi[:len(bsi)-1]
lowerBits.PivotDescending(filter.Intersect(splitBit), upperBranch, limit, offset, fn)
lowerBits.PivotDescending(filter.Difference(splitBit), lowerBranch, limit, offset, fn)
lowerBits.pivotDescending(filter.Intersect(splitBit), upperBranch, limit, offset, fn)
lowerBits.pivotDescending(filter.Difference(splitBit), lowerBranch, limit, offset, fn)
}
}
@ -69,7 +81,7 @@ func (bsi BSIData) PivotDescending(filter *Row, branch uint64, limit, offset *ui
// - TopN on int
func (bsi bsiData) distribution(filter *Row) bsiData {
var dist bsiData
bsi.PivotDescending(filter, 0, nil, nil, func(count uint64, values ...uint64) {
bsi.pivotDescending(filter, 0, nil, nil, func(count uint64, values ...uint64) {
dist.insert(count, uint64(len(values)))
})
return dist
@ -78,20 +90,20 @@ func (bsi bsiData) distribution(filter *Row) bsiData {
var placeholderBitmap = roaring.NewBitmap()
// AddBSI adds two BSI bitmaps together.
// addBSI adds two BSI bitmaps together.
// It does not handle sign and has no concept of overflow.
func AddBSI(x, y BSIData) BSIData {
func addBSI(x, y bsiData) bsiData {
// Accumulate row segments.
segments := make([][]RowSegment, len(x)+len(y))
segments := make([][]rowSegment, len(x)+len(y))
xsegs, ysegs := segments[:len(x)], segments[len(x):]
for i, r := range x {
xsegs[i] = r.Segments
xsegs[i] = r.segments
}
for i, r := range y {
ysegs[i] = r.Segments
ysegs[i] = r.segments
}
var dst BSIData
var dst bsiData
var xbitmaps, ybitmaps []*roaring.Bitmap
for {
// Find the next shard.
@ -162,7 +174,7 @@ func AddBSI(x, y BSIData) BSIData {
for len(dst) <= i {
dst = append(dst, NewRow())
}
dst[i].Segments = append(dst[i].Segments, RowSegment{
dst[i].segments = append(dst[i].segments, rowSegment{
shard: next,
writable: true,
data: b,
@ -273,10 +285,10 @@ func (b *bsiBuilder) Insert(col, val uint64) {
// Build BSI data.
// This resets the builder.
func (b *bsiBuilder) Build() BSIData {
func (b *bsiBuilder) Build() bsiData {
builders := *b
*b = builders[:0]
rows := make(BSIData, len(builders))
rows := make(bsiData, len(builders))
for i := range builders {
rows[i] = builders[i].Build()
}

View file

@ -1,5 +1,17 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa
import (
@ -69,11 +81,11 @@ func TestBSIAdd(t *testing.T) {
builderB.Insert(uint64(id), vb)
}
dataA, dataB := builderA.Build(), builderB.Build()
dataC := AddBSI(dataA, dataB)
dataC := addBSI(dataA, dataB)
// build results from added bsiData; results[i] should hold a[i]+b[i]
results := make([]uint64, len(a))
dataC.PivotDescending(NewRow().Union(dataC...), 0, nil, nil, func(count uint64, ids ...uint64) {
dataC.pivotDescending(NewRow().Union(dataC...), 0, nil, nil, func(count uint64, ids ...uint64) {
for _, id := range ids {
results[idToIndex[int(id)]] = count
}
@ -141,10 +153,10 @@ func TestBSIAddCases(t *testing.T) {
}
dataA, dataB := builderA.Build(), builderB.Build()
dataC := AddBSI(dataA, dataB)
dataC := addBSI(dataA, dataB)
// maps id to count
results := make(map[uint64]uint64)
dataC.PivotDescending(NewRow().Union(dataC...), 0, nil, nil, func(count uint64, ids ...uint64) {
dataC.pivotDescending(NewRow().Union(dataC...), 0, nil, nil, func(count uint64, ids ...uint64) {
for _, id := range ids {
results[id] = count
}

View file

@ -1,110 +0,0 @@
package buffer
import (
"bytes"
"io"
"io/ioutil"
"os"
"sync"
)
// NewFileBuffer returns a file buffer which will use an in-memory buffer, until `max` bytes have been written, at which point it will write the contents of memory to a file, and continue writing future data to the file.
// The file will be written to `temp` directory. The buffer fulfills the io.Reader and io.Writer interface
func NewFileBuffer(max int, temp string) *FileBuffer {
return &FileBuffer{max: max, tempDir: temp}
}
type FileBuffer struct {
max int
buf bytes.Buffer
file *os.File
tempDir string
reading bool
files []*os.File
mu sync.Mutex
}
func (fb *FileBuffer) Write(p []byte) (n int, err error) {
if fb.reading {
panic("cannot write after read")
}
if fb.file != nil {
return fb.file.Write(p)
}
n, err = fb.buf.Write(p)
if err != nil {
return
}
if fb.buf.Len() > fb.max {
fb.file, err = ioutil.TempFile(fb.tempDir, "filebuffer-")
if err != nil {
return
}
_, err = io.Copy(fb.file, &fb.buf)
fb.buf.Reset()
}
return
}
func (fb *FileBuffer) Len() (int64, error) {
if fb.file == nil {
return int64(fb.buf.Len()), nil
}
fi, err := fb.file.Stat()
if err != nil {
return 0, err
}
return fi.Size(), nil
}
func (fb *FileBuffer) Read(p []byte) (n int, err error) {
if fb.file != nil {
if !fb.reading {
fb.reading = true
_, err = fb.file.Seek(0, 0)
if err != nil {
return
}
}
return fb.file.Read(p)
}
fb.reading = true
return fb.buf.Read(p)
}
func (fb *FileBuffer) Close() error {
if fb.file != nil {
name := fb.file.Name()
if err := fb.file.Close(); err != nil {
return err
}
for _, f := range fb.files {
f.Close()
}
fb.files = fb.files[:0]
fb.file = nil
return os.Remove(name)
}
return nil
}
func (fb *FileBuffer) Reset() error {
fb.mu.Lock()
defer fb.mu.Unlock()
fb.reading = false
fb.buf.Reset()
return fb.Close()
}
func (fb *FileBuffer) NewReader() (io.Reader, error) {
fb.mu.Lock()
defer fb.mu.Unlock()
fb.reading = true
if fb.file == nil {
return bytes.NewReader(fb.buf.Bytes()), nil
}
f, err := os.OpenFile(fb.file.Name(), os.O_RDONLY, 0)
fb.files = append(fb.files, f)
return f, err
}

View file

@ -1,262 +0,0 @@
package bufferpool
import (
"errors"
"fmt"
"sync"
)
// FrameID is the type for frame id
type FrameID int
// PageID is the type for page id
type PageID int
var pageSyncPool = sync.Pool{
New: func() any {
pg := new(Page)
pg.id = PageID(INVALID_PAGE)
pg.isDirty = false
pg.pinCount = 0
return pg
},
}
// BufferPool represents a buffer pool of pages
type BufferPool struct {
// the underlying storage
diskManager DiskManager
// the actual pages in the buffer pool
pages []*Page
// the replacer that will elect replacements when buffer pool is full
replacer *ClockReplacer
// the list of free frames
freeList []FrameID
// the map of frames to page ids to frame ids
// frame ids are the offset into pages
// if you ask the pool for page 673, this will know at
// what offset in pages page 673 will exist
pageTable map[PageID]FrameID
}
// TODO(pok) implement a lazy writer
// * if free list is 'low' then
// * increase size of cache if there is physical memory available
// * write out old pages and boot them from the cache to increase free list
// TODO(pok) implement a checkpoint that scans the pool and writes out dirty pages every
// minute or so
// NewBufferPool returns a buffer pool
func NewBufferPool(maxSize int, diskManager DiskManager) *BufferPool {
freeList := make([]FrameID, 0)
pages := make([]*Page, maxSize)
for i := 0; i < maxSize; i++ {
frameNumber := FrameID(i)
freeList = append(freeList, frameNumber)
}
clockReplacer := NewClockReplacer(maxSize)
return &BufferPool{
diskManager: diskManager,
pages: pages,
replacer: clockReplacer,
freeList: freeList,
pageTable: make(map[PageID]FrameID),
}
}
// Dumps all the pages in the buffer pool
func (b *BufferPool) Dump() {
fmt.Println()
fmt.Printf("------------------------------------------------------------------------------------------\n")
fmt.Printf("BUFFER POOL\n")
for _, p := range b.pages {
if p != nil {
p.Dump("")
}
}
fmt.Printf("------------------------------------------------------------------------------------------\n")
fmt.Println()
}
// FetchPage fetches the requested page from the buffer pool.
func (b *BufferPool) FetchPage(pageID PageID) (*Page, error) {
// if it is in buffer pool already then just return it
if frameID, ok := b.pageTable[pageID]; ok {
page := b.pages[frameID]
page.pinCount++
b.replacer.Pin(frameID)
return page, nil
}
// not in the buffer pool so try the free list or
// the replacer will vote a page off the island
frameID, isFromFreeList, err := b.getFrameID()
if err != nil {
return nil, err
}
if !isFromFreeList {
// if it didn't come from the freelist then
// remove page from current frame, writing it out if dirty
currentPage := b.pages[frameID]
if currentPage != nil {
if currentPage.isDirty {
b.diskManager.WritePage(currentPage)
}
delete(b.pageTable, currentPage.id)
}
}
// if we got to here, sorry, have to do an I/O
page, err := b.diskManager.ReadPage(pageID)
if err != nil {
return nil, err
}
page.pinCount = 1
b.pageTable[pageID] = frameID
pageSyncPool.Put(b.pages[frameID])
b.pages[frameID] = page
b.replacer.Pin(frameID)
return page, nil
}
// UnpinPage unpins the target page from the buffer pool
func (b *BufferPool) UnpinPage(pageID PageID) error {
if frameID, ok := b.pageTable[pageID]; ok {
page := b.pages[frameID]
page.DecPinCount()
if page.pinCount <= 0 {
b.replacer.Unpin(frameID)
}
return nil
}
return errors.New("could not find page")
}
// FlushPage Flushes the target page to disk
func (b *BufferPool) FlushPage(pageID PageID) bool {
if frameID, ok := b.pageTable[pageID]; ok {
page := b.pages[frameID]
page.DecPinCount()
b.diskManager.WritePage(page)
page.isDirty = false
return true
}
return false
}
// NewPage allocates a new page in the buffer pool with the disk manager help
func (b *BufferPool) NewPage() (*Page, error) {
// get a free frame
frameID, isFromFreeList, err := b.getFrameID()
if err != nil {
return nil, err
}
if !isFromFreeList {
// remove page from current frame
currentPage := b.pages[frameID]
if currentPage != nil {
if currentPage.isDirty {
b.diskManager.WritePage(currentPage)
}
delete(b.pageTable, currentPage.id)
}
}
// allocates new page
pageID, err := b.diskManager.AllocatePage()
if err != nil {
return nil, err
}
page := &Page{pageID, 1, false, [PAGE_SIZE]byte{}}
page.WritePageNumber(int32(pageID))
page.WriteFreeSpaceOffset(int16(PAGE_SIZE))
page.WriteNextPointer(int32(INVALID_PAGE))
page.WritePrevPointer(int32(INVALID_PAGE))
// update the frame table
b.pageTable[pageID] = frameID
pageSyncPool.Put(b.pages[frameID])
b.pages[frameID] = page
return page, nil
}
// ScratchPage returns a page outside the buffer pool - do not use if you intend the page
// to be in the buffer pool (use NewPage() for that)
// ScratchPage is intended to be used in cases where you need the Page primitives
// and will copy the scratch page back over a real page later
func (b *BufferPool) ScratchPage() *Page {
page := &Page{
id: PageID(INVALID_PAGE),
pinCount: 0,
isDirty: false,
data: [PAGE_SIZE]byte{},
}
page.WritePageNumber(int32(INVALID_PAGE))
page.WriteFreeSpaceOffset(int16(PAGE_SIZE))
page.WriteNextPointer(int32(INVALID_PAGE))
page.WritePrevPointer(int32(INVALID_PAGE))
return page
}
// DeletePage deletes a page from the buffer pool
func (b *BufferPool) DeletePage(pageID PageID) error {
var frameID FrameID
var ok bool
if frameID, ok = b.pageTable[pageID]; !ok {
return nil
}
page := b.pages[frameID]
if page.pinCount > 0 {
return errors.New("pin count greater than 0")
}
delete(b.pageTable, page.id)
b.replacer.Pin(frameID)
b.diskManager.DeallocatePage(pageID)
b.freeList = append(b.freeList, frameID)
return nil
}
// FlushAllpages flushes all the pages in the buffer pool to disk
// Yeah, never call this unless you know what you are doing
func (b *BufferPool) FlushAllpages() {
for pageID := range b.pageTable {
b.FlushPage(pageID)
}
}
func (b *BufferPool) getFrameID() (FrameID, bool, error) {
if len(b.freeList) > 0 {
frameID, newFreeList := b.freeList[0], b.freeList[1:]
b.freeList = newFreeList
return frameID, true, nil
}
victim, err := b.replacer.Victim()
return victim, false, err
}
// OnDiskSize exposes the on disk size of the backing store
// behind this buffer pool
func (b *BufferPool) OnDiskSize() int64 {
return b.diskManager.FileSize()
}
// Close closes the buffer pool
func (b *BufferPool) Close() {
b.diskManager.Close()
}

View file

@ -1,93 +0,0 @@
package bufferpool
import (
"errors"
)
type circularListNode struct {
key interface{}
value interface{}
next *circularListNode
prev *circularListNode
}
type circularList struct {
head *circularListNode
tail *circularListNode
size int
capacity int
}
func newCircularList(maxSize int) *circularList {
return &circularList{nil, nil, 0, maxSize}
}
func (c *circularList) find(key interface{}) *circularListNode {
ptr := c.head
for i := 0; i < c.size; i++ {
if ptr.key == key {
return ptr
}
ptr = ptr.next
}
return nil
}
func (c *circularList) hasKey(key interface{}) bool {
return c.find(key) != nil
}
func (c *circularList) insert(key interface{}, value interface{}) error {
if c.size == c.capacity {
return errors.New("list is full")
}
newNode := &circularListNode{key, value, nil, nil}
if c.size == 0 {
newNode.next = newNode
newNode.prev = newNode
c.head = newNode
c.tail = newNode
c.size++
return nil
}
node := c.find(key)
if node != nil {
node.value = value
return nil
}
newNode.next = c.head
newNode.prev = c.tail
c.tail.next = newNode
if c.head == c.tail {
c.head.next = newNode
}
c.tail = newNode
c.head.prev = c.tail
c.size++
return nil
}
func (c *circularList) remove(key interface{}) {
node := c.find(key)
if node == nil {
return
}
if c.size == 1 {
c.head = nil
c.tail = nil
c.size--
return
}
if node == c.head {
c.head = c.head.next
}
if node == c.tail {
c.tail = c.tail.prev
}
node.next.prev = node.prev
node.prev.next = node.next
c.size--
}

View file

@ -1,64 +0,0 @@
package bufferpool
import "errors"
// ClockReplacer implements a clock replacer algorithm
type ClockReplacer struct {
cList *circularList
clockHand **circularListNode
}
// NewClockReplacer instantiates a new clock replacer
func NewClockReplacer(poolSize int) *ClockReplacer {
cList := newCircularList(poolSize)
return &ClockReplacer{cList, &cList.head}
}
// Victim removes the victim frame as defined by the replacement policy
func (c *ClockReplacer) Victim() (FrameID, error) {
if c.cList.size == 0 {
return FrameID(INVALID_PAGE), errors.New("no victims available")
}
var victimFrameID FrameID
currentNode := (*c.clockHand)
for {
if currentNode.value.(bool) {
currentNode.value = false
c.clockHand = &currentNode.next
} else {
frameID := currentNode.key.(FrameID)
victimFrameID = frameID
c.clockHand = &currentNode.next
c.cList.remove(currentNode.key)
return victimFrameID, nil
}
}
}
// Unpin unpins a frame, indicating that it can now be victimized
func (c *ClockReplacer) Unpin(id FrameID) {
if !c.cList.hasKey(id) {
c.cList.insert(id, true)
if c.cList.size == 1 {
c.clockHand = &c.cList.head
}
}
}
// Pin pins a frame, indicating that it should not be victimized until it is unpinned
func (c *ClockReplacer) Pin(id FrameID) {
node := c.cList.find(id)
if node == nil {
return
}
if (*c.clockHand) == node {
c.clockHand = &(*c.clockHand).next
}
c.cList.remove(id)
}
// Size returns the size of the clock
func (c *ClockReplacer) Size() int {
return c.cList.size
}

View file

@ -1,21 +0,0 @@
package bufferpool
// DiskManager is responsible for interacting with disk
type DiskManager interface {
// reads a page from the disk
ReadPage(PageID) (*Page, error)
// writes a page to the disk
WritePage(*Page) error
// allocates a page
AllocatePage() (PageID, error)
// deallocates a page
DeallocatePage(PageID) error
// returns on disk file size
FileSize() int64
// closes and does any clean up
Close()
}

View file

@ -1,162 +0,0 @@
package bufferpool
import (
"errors"
"fmt"
"os"
uuid "github.com/satori/go.uuid"
)
// InMemDiskSpillingDiskManager is a memory implementation for a DiskManager interface
// that can spill to disk when a threshold is reached
type InMemDiskSpillingDiskManager struct {
// tracks the number of pages
numPages int
onDiskPages int
// tracks the number of pages we can consume before spilling
thresholdPages int
hasSpilled *struct{}
fd *os.File
// the data buffer
data []byte
}
// NewInMemDiskSpillingDiskManager returns a in-memory version of disk manager
func NewInMemDiskSpillingDiskManager(thresholdPages int) *InMemDiskSpillingDiskManager {
dm := &InMemDiskSpillingDiskManager{
numPages: 0,
thresholdPages: thresholdPages,
data: make([]byte, 0),
}
return dm
}
// ReadPage reads a page from pages
func (d *InMemDiskSpillingDiskManager) ReadPage(pageID PageID) (*Page, error) {
// check we're not asking for page out of range
if pageID < 0 || int(pageID) >= d.numPages {
return nil, errors.New("page not found")
}
// check that the offset is within range
offset := int(pageID) * PAGE_SIZE
var page = pageSyncPool.Get().(*Page)
// we have to do this stupid check because if -cpuprofile is set for go test, this
// the previous line return a weird nil-ish thing...
if page == (*Page)(nil) {
page = pageSyncPool.New().(*Page)
}
page.id = pageID
// do the read
if d.hasSpilled == nil {
if offset+PAGE_SIZE > len(d.data) {
return nil, errors.New("offset out of range")
}
b := copy(page.data[:], d.data[offset:offset+PAGE_SIZE])
fmt.Printf("bytes read: %d", b)
} else {
var err error
if offset+PAGE_SIZE > d.numPages*PAGE_SIZE {
return nil, errors.New("offset out of range")
}
_, err = d.fd.ReadAt(page.data[:], int64(offset))
if err != nil {
return nil, err
}
}
return page, nil
}
// WritePage writes a page in memory to pages
func (d *InMemDiskSpillingDiskManager) WritePage(page *Page) error {
// make sure the offset is sensible
offset := int(page.ID()) * PAGE_SIZE
// do the write
if d.hasSpilled == nil {
if offset+PAGE_SIZE > len(d.data) {
return errors.New("offset out of range")
}
copy(d.data[offset:], page.data[:])
} else {
var err error
if offset+PAGE_SIZE > d.numPages*PAGE_SIZE {
return errors.New("offset out of range")
}
_, err = d.fd.WriteAt(page.data[:], int64(offset))
if err != nil {
return err
}
// err = d.fd.Sync()
// if err != nil {
// return err
// }
}
return nil
}
// AllocatePage allocates a page and returns the page number
func (d *InMemDiskSpillingDiskManager) AllocatePage() (PageID, error) {
d.numPages = d.numPages + 1
pageID := PageID(d.numPages - 1)
if d.hasSpilled == nil {
// we have not spilled (yet), so make storage bigger
newData := make([]byte, PAGE_SIZE)
d.data = append(d.data, newData...)
// check to see if we need to spill
if d.numPages > d.thresholdPages {
fileUUID, err := uuid.NewV4()
if err != nil {
return PageID(INVALID_PAGE), err
}
// TODO(pok) we should try to tell the OS not to cache this file
d.fd, err = os.CreateTemp("", fmt.Sprintf("fb-ehash-%s", fileUUID.String()))
if err != nil {
return PageID(INVALID_PAGE), err
}
_, err = d.fd.WriteAt(d.data, 0)
if err != nil {
return PageID(INVALID_PAGE), err
}
d.data = []byte{}
d.hasSpilled = &struct{}{}
}
} else {
if d.numPages >= d.onDiskPages {
// grow the file by a chunk - 512 pages
d.onDiskPages += 512
var err error
size := int64(d.onDiskPages * PAGE_SIZE)
_, err = d.fd.WriteAt([]byte{0}, size-1)
if err != nil {
return PageID(INVALID_PAGE), err
}
}
}
return pageID, nil
}
// DeallocatePage removes page from disk
func (d *InMemDiskSpillingDiskManager) DeallocatePage(pageID PageID) error {
// nothing to do right now
return nil
}
func (d *InMemDiskSpillingDiskManager) FileSize() int64 {
return int64(len(d.data))
}
func (d *InMemDiskSpillingDiskManager) Close() {
// close and delete the file if we spilled
if d.fd != nil {
_ = d.fd.Close()
os.Remove(d.fd.Name())
}
}

View file

@ -1,371 +0,0 @@
package bufferpool
import (
"encoding/binary"
"errors"
"fmt"
)
const PAGE_SIZE int = 8192
const INVALID_PAGE int = -1
const PAGE_TYPE_BTREE_INTERNAL = 10
const PAGE_TYPE_BTREE_LEAF = 11
const PAGE_TYPE_HASH_TABLE = 12
// PAGE
// page size 8192 bytes
// byte aligned, big endian
// |====================================================|
// | offset | length | |
// |----------------------------------------------------|
// | header |
// |====================================================|
// | 0 | 4 | pageNumber (int32) |
// | 4 | 2 | pageType (int16) |
// | 6 | 2 | slotCount (int16) |
// | 8 | 2 | localDepth (int16) |
// | 10 | 2 | freeSpaceOffset (int16) |
// | 12 | 4 | prevPointer (int32) |
// | 16 | 4 | nextPointer (int32) |
// |====================================================|
// | <start of slot array 1..slotCount> |
// |----------------------------------------------------|
// | 20 | slotcount | slot entry is 2 int16 |
// | | * slotwidth | values (payloadOffset, |
// | | * #slots | payloadLength) |
// |----------------------------------------------------|
// | <free space> |
// |----------------------------------------------------|
// | <payload starting at freeSpaceOffset> |
// | payload entries are keylength (int16), key bytes, |
// | payload length (int32), payload bytes |
// |====================================================|
const PAGE_NUMBER_OFFSET = 0 // offset 0, length 4, end 4
const PAGE_TYPE_OFFSET = 4 // offset 4, length 2, end 6
const PAGE_SLOT_COUNT_OFFSET = 6 // offset 6, length 2, end 8
const PAGE_LOCAL_DEPTH_OFFSET = 8 // offset 8, length 2, end 10
const PAGE_FREE_SPACE_OFFSET = 10 // offset 10, length 2, end 12
const PAGE_PREV_POINTER_OFFSET = 12 // offset 12, length 4, end 16
const PAGE_NEXT_POINTER_OFFSET = 16 // offset 16, length 4, end 20
const PAGE_SLOTS_START_OFFSET = 20 // offset 20
// PAGE_SLOT_LENGTH is the size of the page slot key/value.
//
// key offset int16 //offset 0, length 2, end 2
// value offset int16 //offset 2, length 2, end 4
const PAGE_SLOT_LENGTH = 4
// Page represents a page on disk
type Page struct {
id PageID
pinCount int
isDirty bool
data [PAGE_SIZE]byte
}
type PageSlot struct {
KeyOffset int16
ValueOffset int16
}
func (s *PageSlot) KeyBytes(page *Page) []byte {
offset := s.KeyOffset
keyLen := int16(binary.BigEndian.Uint16(page.data[offset:]))
offset += 2
result := make([]byte, keyLen)
copy(result, page.data[offset:offset+keyLen])
return result
}
func (s *PageSlot) KeyAsInt(page *Page) int32 {
return int32(binary.BigEndian.Uint32(page.data[s.KeyOffset+2:]))
}
func (s *PageSlot) ValueBytes(page *Page) []byte {
offset := s.ValueOffset
valueLen := int32(binary.BigEndian.Uint32(page.data[offset:]))
offset += 4
result := make([]byte, valueLen)
copy(result, page.data[offset:int32(offset)+valueLen])
return result
}
func (s *PageSlot) ValueAsPagePointer(page *Page) int32 {
return int32(binary.BigEndian.Uint32(page.data[s.ValueOffset+4:]))
}
type PageChunk struct {
KeyLength int16
KeyBytes []byte
// TODO(pok) ValueBytes can be up to int32 long
// this requires an overflow page mechanism, that is not implemented
// yet, so be aware of this when storing stuff...
ValueLength int32
ValueBytes []byte
}
func (pc *PageChunk) Length() int {
return 2 + len(pc.KeyBytes) + 4 + len(pc.ValueBytes)
}
func (pc *PageChunk) ComputeKeyOffset(pageOffset int) int {
return pageOffset
}
func (pc *PageChunk) ComputeValueOffset(pageOffset int) int {
return pageOffset + 2 + len(pc.KeyBytes)
}
func (p *Page) WritePageNumber(pageNumber int32) {
p.id = PageID(pageNumber)
binary.BigEndian.PutUint32(p.data[PAGE_NUMBER_OFFSET:], uint32(pageNumber))
p.isDirty = true
}
func (p *Page) ReadPageNumber() int {
return int(binary.BigEndian.Uint32(p.data[PAGE_NUMBER_OFFSET:]))
}
func (p *Page) WritePageType(pageType int16) {
binary.BigEndian.PutUint16(p.data[PAGE_TYPE_OFFSET:], uint16(pageType))
p.isDirty = true
}
func (p *Page) ReadPageType() int16 {
return int16(binary.BigEndian.Uint16(p.data[PAGE_TYPE_OFFSET:]))
}
func (p *Page) WriteSlotCount(slotCount int16) {
binary.BigEndian.PutUint16(p.data[PAGE_SLOT_COUNT_OFFSET:], uint16(slotCount))
p.isDirty = true
}
func (p *Page) ReadSlotCount() int16 {
return int16(binary.BigEndian.Uint16(p.data[PAGE_SLOT_COUNT_OFFSET:]))
}
func (p *Page) WriteLocalDepth(localDepth int16) {
binary.BigEndian.PutUint16(p.data[PAGE_LOCAL_DEPTH_OFFSET:], uint16(localDepth))
p.isDirty = true
}
func (p *Page) ReadLocalDepth() int16 {
return int16(binary.BigEndian.Uint16(p.data[PAGE_LOCAL_DEPTH_OFFSET:]))
}
func (p *Page) ReadSlot(slot int16) PageSlot {
offset := PAGE_SLOTS_START_OFFSET + PAGE_SLOT_LENGTH*slot
keyOffset := int16(binary.BigEndian.Uint16(p.data[offset:]))
offset += 2
valueOffset := int16(binary.BigEndian.Uint16(p.data[offset:]))
return PageSlot{
KeyOffset: keyOffset,
ValueOffset: valueOffset,
}
}
func (p *Page) WriteSlot(slot int16, value PageSlot) {
offset := PAGE_SLOTS_START_OFFSET + PAGE_SLOT_LENGTH*slot
binary.BigEndian.PutUint16(p.data[offset:], uint16(value.KeyOffset))
offset += 2
binary.BigEndian.PutUint16(p.data[offset:], uint16(value.ValueOffset))
}
func (p *Page) WriteFreeSpaceOffset(offset int16) {
binary.BigEndian.PutUint16(p.data[PAGE_FREE_SPACE_OFFSET:], uint16(offset))
p.isDirty = true
}
func (p *Page) ReadFreeSpaceOffset() int16 {
return int16(binary.BigEndian.Uint16(p.data[PAGE_FREE_SPACE_OFFSET:]))
}
func (p *Page) WritePrevPointer(prevPointer int32) {
binary.BigEndian.PutUint32(p.data[PAGE_PREV_POINTER_OFFSET:], uint32(prevPointer))
p.isDirty = true
}
func (p *Page) ReadPrevPointer() int {
return int(binary.BigEndian.Uint32(p.data[PAGE_PREV_POINTER_OFFSET:]))
}
func (p *Page) WriteNextPointer(nextPointer int32) {
binary.BigEndian.PutUint32(p.data[PAGE_NEXT_POINTER_OFFSET:], uint32(nextPointer))
p.isDirty = true
}
func (p *Page) ReadNextPointer() int {
return int(binary.BigEndian.Uint32(p.data[PAGE_NEXT_POINTER_OFFSET:]))
}
func (p *Page) WriteChunk(offset int16, chunk PageChunk) {
binary.BigEndian.PutUint16(p.data[offset:], uint16(chunk.KeyLength))
offset += 2
copy(p.data[offset:], chunk.KeyBytes)
offset += int16(len(chunk.KeyBytes))
binary.BigEndian.PutUint32(p.data[offset:], uint32(chunk.ValueLength))
offset += 4
copy(p.data[offset:], chunk.ValueBytes)
p.isDirty = true
}
func (p *Page) ReadChunk(offset int16) PageChunk {
keyLen := int16(binary.BigEndian.Uint16(p.data[offset:]))
offset += 2
keyBytes := make([]byte, keyLen)
copy(keyBytes, p.data[offset:offset+keyLen])
offset += keyLen
valueLen := int32(binary.BigEndian.Uint32(p.data[offset:]))
offset += 4
valueBytes := make([]byte, valueLen)
copy(valueBytes, p.data[offset:int32(offset)+valueLen])
return PageChunk{
KeyLength: keyLen,
KeyBytes: keyBytes,
ValueLength: valueLen,
ValueBytes: valueBytes,
}
}
func (p *Page) FreeSpace() int16 {
freeSpaceOffset := p.ReadFreeSpaceOffset()
freespace := freeSpaceOffset - (p.ReadSlotCount()*PAGE_SLOT_LENGTH + PAGE_SLOT_LENGTH + PAGE_SLOTS_START_OFFSET)
return freespace
}
func (p *Page) WriteKeyValueInSlot(slotNumber int16, key []byte, value []byte) error {
freeSpaceOffset := p.ReadFreeSpaceOffset()
// build a chunk
chunk := PageChunk{
KeyLength: int16(len(key)),
KeyBytes: key,
ValueLength: int32(len(value)),
ValueBytes: value,
}
// compute the new free space offset
freeSpaceOffset -= int16(chunk.Length())
// check we won't blow free space on page
slotCount := p.ReadSlotCount()
slotEndOffset := slotCount*PAGE_SLOT_LENGTH + PAGE_SLOT_LENGTH + PAGE_SLOTS_START_OFFSET
// DEBUG!!
//fmt.Printf("freeSpaceOffset: %d, slotCount: %d, slotCount*4 + 4 + 20: %d, freeSpace: %d\n", freeSpaceOffset, slotCount, slotEndOffset, freeSpaceOffset-slotEndOffset)
if freeSpaceOffset-slotEndOffset <= 0 {
return errors.New("page is full")
}
keyOffset := chunk.ComputeKeyOffset(int(freeSpaceOffset))
valueOffset := chunk.ComputeValueOffset(int(freeSpaceOffset))
p.WriteChunk(freeSpaceOffset, chunk)
// update the free space offset
p.WriteFreeSpaceOffset(int16(freeSpaceOffset))
// make a slot
slot := PageSlot{
KeyOffset: int16(keyOffset),
ValueOffset: int16(valueOffset),
}
// write the slot
p.WriteSlot(slotNumber, slot)
return nil
}
func (p *Page) WritePage(page *Page) {
// copy everything but pageNumber & pageType
offset := PAGE_SLOT_COUNT_OFFSET
copy(page.data[offset:], p.data[offset:offset+PAGE_SIZE-offset])
}
func (p *Page) PinCount() int {
return p.pinCount
}
func (p *Page) ID() PageID {
return p.id
}
func (p *Page) DecPinCount() {
if p.pinCount > 0 {
p.pinCount--
}
}
type PageSlotIterator struct {
page *Page
slotCount int16
cursor int16
}
func NewPageSlotIterator(page *Page, fromSlot int16) *PageSlotIterator {
i := &PageSlotIterator{
page: page,
slotCount: page.ReadSlotCount(),
cursor: fromSlot,
}
return i
}
func (i *PageSlotIterator) Next() *PageSlot {
if i.cursor < i.slotCount {
s := i.page.ReadSlot(i.cursor)
i.cursor++
return &s
}
return nil
}
func (i *PageSlotIterator) Cursor() int16 {
return i.cursor
}
func (pg *Page) Dump(label string) {
indent := 0
if len(label) > 0 {
fmt.Printf("%s%s:\n", fmt.Sprintf("%*s", indent, ""), label)
indent += 4
}
pageType := pg.ReadPageType()
fmt.Printf("%sPAGE(%d) pageType: %d slotCount: %d, prevPtr: %d, nextPtr: %d\n", fmt.Sprintf("%*s", indent, ""), pg.ID(), pageType, pg.ReadSlotCount(), pg.ReadPrevPointer(), pg.ReadNextPointer())
fmt.Printf("%sKEYS: -->\n", fmt.Sprintf("%*s", indent, ""))
indent += 4
// get the keys off the page
keys := make([]int, 0)
pointers := make([]int, 0)
iter := NewPageSlotIterator(pg, 0)
for {
ps := iter.Next()
if ps == nil {
break
}
keys = append(keys, int(ps.KeyAsInt(pg)))
if pageType == /*nodeTypeInternal*/ 10 {
pointers = append(pointers, int(ps.ValueAsPagePointer(pg)))
}
}
if pageType == /*nodeTypeLeaf*/ 11 {
for _, key := range keys {
fmt.Printf("%s(%d)\n", fmt.Sprintf("%*s", indent, ""), key)
}
} else {
for idx, key := range keys {
ptr := pointers[idx]
fmt.Printf("%s(%d, %d)\n", fmt.Sprintf("%*s", indent, ""), key, ptr)
}
ptr := pg.ReadNextPointer()
fmt.Printf("%s(-->, %d)\n", fmt.Sprintf("%*s", indent, ""), ptr)
}
}

150
cache.go
View file

@ -1,5 +1,17 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa
import (
@ -11,8 +23,9 @@ import (
"sync"
"time"
"github.com/featurebasedb/featurebase/v3/lru"
pb "github.com/featurebasedb/featurebase/v3/proto"
"github.com/pilosa/pilosa/v2/lru"
pb "github.com/pilosa/pilosa/v2/proto"
"github.com/pilosa/pilosa/v2/stats"
"github.com/pkg/errors"
)
@ -40,24 +53,23 @@ type cache interface {
// Returns an ordered list of the top ranked bitmaps.
Top() []bitmapPair
// Clear removes everything from the cache. If possible it should leave allocated structures in place to be reused.
Clear()
// SetStats defines the stats client used in the cache.
SetStats(s stats.StatsClient)
}
// lruCache represents a least recently used Cache implementation.
type lruCache struct {
cache *lru.Cache
counts map[uint64]uint64
// maxEntries is saved to support Clear which recreates the cache.
maxEntries uint32
stats stats.StatsClient
}
// newLRUCache returns a new instance of LRUCache.
func newLRUCache(maxEntries uint32) *lruCache {
c := &lruCache{
cache: lru.New(int(maxEntries)),
counts: make(map[uint64]uint64),
maxEntries: maxEntries,
cache: lru.New(int(maxEntries)),
counts: make(map[uint64]uint64),
stats: stats.NopStatsClient,
}
c.cache.OnEvicted = c.onEvicted
return c
@ -114,11 +126,9 @@ func (c *lruCache) Top() []bitmapPair {
return a
}
func (c *lruCache) Clear() {
for k := range c.counts {
delete(c.counts, k)
}
c.cache = lru.New(int(c.maxEntries))
// SetStats defines the stats client used in the cache.
func (c *lruCache) SetStats(s stats.StatsClient) {
c.stats = s
}
func (c *lruCache) onEvicted(key lru.Key, _ interface{}) { delete(c.counts, key.(uint64)) }
@ -128,7 +138,6 @@ var _ cache = &lruCache{}
// rankCache represents a cache with sorted entries.
type rankCache struct {
// TODO why does this have a lock and lruCache doesn't?
mu sync.Mutex
entries map[uint64]uint64
rankings bitmapPairs // cached, ordered list
@ -147,6 +156,8 @@ type rankCache struct {
// thresholdValue is the value of the last item in the cache
thresholdValue uint64
stats stats.StatsClient
}
// NewRankCache returns a new instance of RankCache.
@ -155,24 +166,10 @@ func NewRankCache(maxEntries uint32) *rankCache {
maxEntries: maxEntries,
thresholdBuffer: int(thresholdFactor * float64(maxEntries)),
entries: make(map[uint64]uint64),
stats: stats.NopStatsClient,
}
}
func (c *rankCache) Clear() {
c.mu.Lock()
defer c.mu.Unlock()
for k := range c.entries {
delete(c.entries, k)
}
c.rankings = c.rankings[:0]
c.rankingsRead = false
c.dirty = false
c.updateN = 0
c.updateTime = time.Time{}
c.thresholdValue = 0
}
// Add adds a count to the cache.
func (c *rankCache) Add(id uint64, n uint64) {
c.mu.Lock()
@ -210,14 +207,6 @@ func (c *rankCache) BulkAdd(id uint64, n uint64) {
}
c.entries[id] = n
// FB-1206: Periodically invalidate the cache when we are bulk loading
// as this can take up an upbounded amount of memory. This is especially
// true when restoring shards as all rows will be added.
if len(c.entries) > int(2*c.maxEntries) {
CounterRecalculateCache.Inc()
c.recalculate()
}
}
// Get returns a count for a given id.
@ -260,7 +249,7 @@ func (c *rankCache) Invalidate() {
func (c *rankCache) Recalculate() {
c.mu.Lock()
defer c.mu.Unlock()
CounterRecalculateCache.Inc()
c.stats.Count(MetricRecalculateCache, 1, 1.0)
c.recalculate()
}
@ -272,12 +261,12 @@ func (c *rankCache) invalidate() {
// This is somewhat necessary for now since recalculation is not cheap.
// The cache will remain flagged as dirty and will be recalculated if Top is called.
// This may cause unexpected memory growth, so record it in metrics for debugging purposes.
CounterInvalidateCacheSkipped.Inc()
c.stats.Count(MetricInvalidateCacheSkipped, 1, 1.0)
// Ensure that we're marked as dirty even if we weren't otherwise.
c.dirty = true
return
}
CounterInvalidateCache.Inc()
c.stats.Count(MetricInvalidateCache, 1, 1.0)
c.recalculate()
}
@ -303,7 +292,7 @@ func (c *rankCache) recalculate() {
// Store the count of the item at the threshold index.
length := len(c.rankings)
GaugeRankCacheLength.Set(float64(length))
c.stats.Gauge(MetricRankCacheLength, float64(length), 1.0)
var removeItems []bitmapPair // cached, ordered list
if length > int(c.maxEntries) {
@ -319,7 +308,7 @@ func (c *rankCache) recalculate() {
// If size is larger than the threshold then trim it.
if len(c.entries) > c.thresholdBuffer {
CounterCacheThresholdReached.Inc()
c.stats.Count(MetricCacheThresholdReached, 1, 1.0)
for _, pair := range removeItems {
delete(c.entries, pair.ID)
}
@ -329,6 +318,11 @@ func (c *rankCache) recalculate() {
c.dirty = false
}
// SetStats defines the stats client used in the cache.
func (c *rankCache) SetStats(s stats.StatsClient) {
c.stats = s
}
// Top returns an ordered list of pairs.
func (c *rankCache) Top() []bitmapPair {
c.mu.Lock()
@ -336,7 +330,7 @@ func (c *rankCache) Top() []bitmapPair {
if c.dirty {
// The cache is dirty, so we need to recalculate it to get a consistent view.
CounterReadDirtyCache.Inc()
c.stats.Count(MetricReadDirtyCache, 1, 1.0)
c.recalculate()
}
@ -404,8 +398,8 @@ func (p PairField) ToRows(callback func(*pb.RowResponse) error) error {
{Name: "count", Datatype: "uint64"},
},
Columns: []*pb.ColumnResponse{
{ColumnVal: &pb.ColumnResponse_StringVal{StringVal: p.Pair.Key}},
{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: p.Pair.Count}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_StringVal{StringVal: p.Pair.Key}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: p.Pair.Count}},
},
})
} else {
@ -415,8 +409,8 @@ func (p PairField) ToRows(callback func(*pb.RowResponse) error) error {
{Name: "count", Datatype: "uint64"},
},
Columns: []*pb.ColumnResponse{
{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: p.Pair.ID}},
{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: p.Pair.Count}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: p.Pair.ID}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: p.Pair.Count}},
},
})
}
@ -546,8 +540,8 @@ func (p *PairsField) ToRows(callback func(*pb.RowResponse) error) error {
if err := callback(&pb.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{
{ColumnVal: &pb.ColumnResponse_StringVal{StringVal: pair.Key}},
{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: uint64(pair.Count)}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_StringVal{StringVal: pair.Key}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: uint64(pair.Count)}},
}}); err != nil {
return errors.Wrap(err, "calling callback")
}
@ -555,8 +549,8 @@ func (p *PairsField) ToRows(callback func(*pb.RowResponse) error) error {
if err := callback(&pb.RowResponse{
Headers: ci,
Columns: []*pb.ColumnResponse{
{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: uint64(pair.ID)}},
{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: uint64(pair.Count)}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: uint64(pair.ID)}},
&pb.ColumnResponse{ColumnVal: &pb.ColumnResponse_Uint64Val{Uint64Val: uint64(pair.Count)}},
}}); err != nil {
return errors.Wrap(err, "calling callback")
}
@ -586,22 +580,56 @@ func (p uint64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p uint64Slice) Len() int { return len(p) }
func (p uint64Slice) Less(i, j int) bool { return p[i] < p[j] }
// simpleCache implements a bitmap Rowcache.
// it is meant to be a short-lived cache for cases where writes are continuing to access
// the same row within a short time frame (i.e. good for write-heavy loads)
// A read-heavy use case would cause the cache to get bigger, potentially causing the
// node to run out of memory.
type simpleCache struct {
cache map[uint64]*Row
}
// Fetch retrieves the bitmap at the id in the cache.
func (s *simpleCache) Fetch(id uint64) (*Row, bool) {
m, ok := s.cache[id]
return m, ok
}
func newSimpleCache() *simpleCache {
return &simpleCache{
cache: make(map[uint64]*Row),
}
}
// Add adds the bitmap to the cache, keyed on the id. A nil row means
// deleting the row from the cache.
func (s *simpleCache) Add(id uint64, b *Row) {
if b != nil {
s.cache[id] = b
} else {
delete(s.cache, id)
}
}
// nopCache represents a no-op Cache implementation.
type nopCache struct{}
type nopCache struct {
stats stats.StatsClient
}
// Ensure NopCache implements Cache.
var globalNopCache cache = nopCache{}
var globalNopCache cache = nopCache{
stats: stats.NopStatsClient,
}
func (c nopCache) Add(uint64, uint64) {}
func (c nopCache) BulkAdd(uint64, uint64) {}
func (c nopCache) Get(uint64) uint64 { return 0 }
func (c nopCache) IDs() []uint64 { return []uint64{} }
func (c nopCache) Invalidate() {}
func (c nopCache) Len() int { return 0 }
func (c nopCache) Recalculate() {}
func (c nopCache) Clear() {}
func (c nopCache) Invalidate() {}
func (c nopCache) Len() int { return 0 }
func (c nopCache) Recalculate() {}
func (c nopCache) SetStats(stats.StatsClient) {}
func (c nopCache) Top() []bitmapPair {
return []bitmapPair{}

View file

@ -1,12 +1,24 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa_test
import (
"reflect"
"testing"
pilosa "github.com/featurebasedb/featurebase/v3"
"github.com/pilosa/pilosa/v2"
)
// Ensure cache stays constrained to its configured size.
@ -62,7 +74,7 @@ func TestCache_Rank_Dirty(t *testing.T) {
cache.Add(v.ID, v.Count)
}
var got []pair //nolint:prealloc
var got []pair
for _, p := range cache.Top() {
got = append(got, pair(p))
}
@ -71,15 +83,3 @@ func TestCache_Rank_Dirty(t *testing.T) {
t.Fatalf("wrote %v but got %v", expect, got)
}
}
func TestCache_Rank_BulkAdd(t *testing.T) {
const cacheSize = 10
cache := pilosa.NewRankCache(uint32(cacheSize))
for i := uint64(0); i < 1000; i++ {
cache.BulkAdd(i, i)
if n := cache.Len(); n > cacheSize*2 {
t.Fatalf("entry count exceed 2x cache size: %d", n)
}
}
}

View file

@ -1,11 +1,26 @@
// Copyright 2022 Molecula Corp. (DBA FeatureBase).
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 Pilosa Corp.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package pilosa
import (
"github.com/featurebasedb/featurebase/v3/roaring"
txkey "github.com/featurebasedb/featurebase/v3/short_txkey"
"github.com/featurebasedb/featurebase/v3/vprint"
"fmt"
"io"
"github.com/pilosa/pilosa/v2/roaring"
txkey "github.com/pilosa/pilosa/v2/short_txkey"
. "github.com/pilosa/pilosa/v2/vprint"
)
// catcher is useful to report error locations with a
@ -27,21 +42,47 @@ func init() {
var _ Tx = (*catcherTx)(nil)
func (c *catcherTx) ImportRoaringBits(index, field, view string, shard uint64, rit roaring.RoaringIterator, clear bool, log bool, rowSize uint64) (changed int, rowSet map[uint64]int, err error) {
func (c *catcherTx) IncrementOpN(index, field, view string, shard uint64, changedN int) {
c.b.IncrementOpN(index, field, view, shard, changedN)
}
func (c *catcherTx) NewTxIterator(index, field, view string, shard uint64) *roaring.Iterator {
return c.b.NewTxIterator(index, field, view, shard)
}
func (c *catcherTx) ImportRoaringBits(index, field, view string, shard uint64, rit roaring.RoaringIterator, clear bool, log bool, rowSize uint64, data []byte) (changed int, rowSet map[uint64]int, err error) {
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see ImportRoaringBits() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see ImportRoaringBits() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ImportRoaringBits(index, field, view, shard, rit, clear, log, rowSize)
return c.b.ImportRoaringBits(index, field, view, shard, rit, clear, log, rowSize, data)
}
func (c *catcherTx) Dump(short bool, shard uint64) {
c.b.Dump(short, shard)
}
func (c *catcherTx) Readonly() bool {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see Readonly() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Readonly()
}
func (tx *catcherTx) Pointer() string {
return fmt.Sprintf("%p", tx)
}
func (c *catcherTx) Rollback() {
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Rollback() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see Rollback() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
c.b.Rollback()
@ -51,8 +92,8 @@ func (c *catcherTx) Commit() error {
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Commit() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see Commit() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Commit()
@ -62,8 +103,8 @@ func (c *catcherTx) RoaringBitmap(index, field, view string, shard uint64) (*roa
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see RoaringBitmap() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see RoaringBitmap() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.RoaringBitmap(index, field, view, shard)
@ -73,8 +114,8 @@ func (c *catcherTx) Container(index, field, view string, shard uint64, key uint6
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Container() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see Container() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Container(index, field, view, shard, key)
@ -84,8 +125,8 @@ func (c *catcherTx) PutContainer(index, field, view string, shard uint64, key ui
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see PutContainer() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see PutContainer() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.PutContainer(index, field, view, shard, key, rc)
@ -95,19 +136,27 @@ func (c *catcherTx) RemoveContainer(index, field, view string, shard uint64, key
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see RemoveContainer() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see RemoveContainer() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.RemoveContainer(index, field, view, shard, key)
}
func (c *catcherTx) UseRowCache() bool {
return c.b.UseRowCache()
}
func (c *catcherTx) IsDone() bool {
return c.b.IsDone()
}
func (c *catcherTx) Add(index, field, view string, shard uint64, a ...uint64) (changeCount int, err error) {
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Add() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see Add() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Add(index, field, view, shard, a...)
@ -117,30 +166,19 @@ func (c *catcherTx) Remove(index, field, view string, shard uint64, a ...uint64)
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Remove() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see Remove() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Remove(index, field, view, shard, a...)
}
func (c *catcherTx) Removed(index, field, view string, shard uint64, a ...uint64) (changed []uint64, err error) {
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Removed() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
}
}()
return c.b.Removed(index, field, view, shard, a...)
}
func (c *catcherTx) Contains(index, field, view string, shard uint64, key uint64) (exists bool, err error) {
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Contains() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see Contains() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Contains(index, field, view, shard, key)
@ -150,19 +188,41 @@ func (c *catcherTx) ContainerIterator(index, field, view string, shard uint64, f
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see ContainerIterator() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see ContainerIterator() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ContainerIterator(index, field, view, shard, firstRoaringContainerKey)
}
func (c *catcherTx) ForEach(index, field, view string, shard uint64, fn func(i uint64) error) error {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ForEach() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ForEach(index, field, view, shard, fn)
}
func (c *catcherTx) ForEachRange(index, field, view string, shard uint64, start, end uint64, fn func(uint64) error) error {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see ForEachRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.ForEachRange(index, field, view, shard, start, end, fn)
}
func (c *catcherTx) Count(index, field, view string, shard uint64) (uint64, error) {
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Count() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see Count() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Count(index, field, view, shard)
@ -172,8 +232,8 @@ func (c *catcherTx) Max(index, field, view string, shard uint64) (uint64, error)
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Max() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see Max() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Max(index, field, view, shard)
@ -183,19 +243,30 @@ func (c *catcherTx) Min(index, field, view string, shard uint64) (uint64, bool,
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see Min() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see Min() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.Min(index, field, view, shard)
}
func (c *catcherTx) UnionInPlace(index, field, view string, shard uint64, others ...*roaring.Bitmap) error {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see UnionInPlace() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.UnionInPlace(index, field, view, shard, others...)
}
func (c *catcherTx) CountRange(index, field, view string, shard uint64, start, end uint64) (n uint64, err error) {
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see CountRange() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see CountRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.CountRange(index, field, view, shard, start, end)
@ -205,29 +276,48 @@ func (c *catcherTx) OffsetRange(index, field, view string, shard, offset, start,
defer func() {
if r := recover(); r != nil {
vprint.AlwaysPrintf("see OffsetRange() PanicOn '%v' at '%v'", r, vprint.Stack())
vprint.PanicOn(r)
AlwaysPrintf("see OffsetRange() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.OffsetRange(index, field, view, shard, offset, start, end)
}
func (c *catcherTx) RoaringBitmapReader(index, field, view string, shard uint64, fragmentPathForRoaring string) (r io.ReadCloser, sz int64, err error) {
defer func() {
if r := recover(); r != nil {
AlwaysPrintf("see RoaringBitmapReader() PanicOn '%v' at '%v'", r, Stack())
PanicOn(r)
}
}()
return c.b.RoaringBitmapReader(index, field, view, shard, fragmentPathForRoaring)
}
func (c *catcherTx) Type() string {
return c.b.Type()
}
func (c *catcherTx) ApplyFilter(index, field, view string, shard uint64, ckey uint64, filter roaring.BitmapFilter) (err error) {
return GenericApplyFilter(c, index, field, view, shard, ckey, filter)
func (c *catcherTx) Group() *TxGroup {
return c.b.Group()
}
func (c *catcherTx) ApplyRewriter(index, field, view string, shard uint64, ckey uint64, filter roaring.BitmapRewriter) (err error) {
return c.b.ApplyRewriter(index, field, view, shard, ckey, filter)
func (c *catcherTx) Options() Txo {
return c.b.Options()
}
// Sn retreives the serial number of the Tx.
func (c *catcherTx) Sn() int64 {
return c.b.Sn()
}
func (c *catcherTx) ApplyFilter(index, field, view string, shard uint64, ckey uint64, filter roaring.BitmapFilter) (err error) {
return GenericApplyFilter(c, index, field, view, shard, ckey, filter)
}
func (c *catcherTx) GetSortedFieldViewList(idx *Index, shard uint64) (fvs []txkey.FieldView, err error) {
return c.b.GetSortedFieldViewList(idx, shard)
}
func (c *catcherTx) GetFieldSizeBytes(index, field string) (uint64, error) {
func (tx *catcherTx) GetFieldSizeBytes(index, field string) (uint64, error) {
return 0, nil
}

View file

@ -1,15 +0,0 @@
.PHONY: test testv test-integration testv-integration
GO=go
test:
$(GO) test ./... -short
testv:
$(GO) test -v ./... -short
test-integration:
$(GO) test . -count 1 -timeout 20m -run TestCLIIntegration/$(RUN)
testv-integration:
$(GO) test -v . -count 1 -timeout 20m -run TestCLIIntegration/$(RUN)

View file

@ -1,8 +0,0 @@
package batch
// Inserter can be implemented by anything which can handle a SQL statement
// representing a write operation. An example is `BULK INSERT`. The Insert()
// method on this interface does not return any results other than an error.
type Inserter interface {
Insert(sql string) error
}

View file

@ -1,215 +0,0 @@
package batch
import (
"encoding/json"
"fmt"
"strings"
"time"
fbbatch "github.com/featurebasedb/featurebase/v3/batch"
"github.com/featurebasedb/featurebase/v3/dax"
"github.com/featurebasedb/featurebase/v3/errors"
"github.com/featurebasedb/featurebase/v3/pql"
)
// Ensure type implements interface.
var _ fbbatch.Batcher = (*sqlBatcher)(nil)
type sqlBatcher struct {
inserter Inserter
fields []*dax.Field
}
func NewSQLBatcher(i Inserter, flds []*dax.Field) *sqlBatcher {
return &sqlBatcher{
inserter: i,
fields: flds,
}
}
func (b *sqlBatcher) NewBatch(cfg fbbatch.Config, tbl *dax.Table, flds []*dax.Field) (fbbatch.RecordBatch, error) {
fields := flds
if b.fields != nil {
fields = b.fields
}
return &sqlBatch{
table: tbl,
fields: fields,
size: cfg.Size,
maxStaleness: cfg.MaxStaleness,
ids: make([]interface{}, 0, cfg.Size),
rows: make([][]interface{}, 0, cfg.Size),
inserter: b.inserter,
}, nil
}
// Ensure type implements interface.
var _ fbbatch.RecordBatch = (*sqlBatch)(nil)
type sqlBatch struct {
table *dax.Table
fields []*dax.Field
size int
ids []interface{}
rows [][]interface{}
// staleTime tracks the time the first record of the batch was inserted
// plus the maxStaleness, in order to raise ErrBatchNowStale if the
// maxStaleness has elapsed
staleTime time.Time
maxStaleness time.Duration
// inserter handles SQL INSERT statements generated for each batch.
inserter Inserter
}
func (b *sqlBatch) Add(rec fbbatch.Row) error {
// Clear rec.Values and rec.Clears upon return.
defer func() {
for i := range rec.Values {
rec.Values[i] = nil
}
for k := range rec.Clears {
delete(rec.Clears, k)
}
}()
if len(b.ids) == cap(b.ids) {
return fbbatch.ErrBatchAlreadyFull
}
if len(rec.Values) != len(b.fields) {
return errors.Errorf("record needs to match up with batch fields, got %d fields and %d record", len(b.fields), len(rec.Values))
}
// Append the ID to b.ids.
b.ids = append(b.ids, rec.ID)
// Convert decimal fields (which come in as int64, along with the scale in
// field) to pql.Decimal.
for i, fld := range b.fields {
switch b.fields[i].Type {
case dax.BaseTypeDecimal:
if val, ok := rec.Values[i].(int64); ok {
rec.Values[i] = pql.NewDecimal(val, fld.Options.Scale)
}
case dax.BaseTypeTimestamp:
if val, ok := rec.Values[i].(int64); ok {
ts := time.Unix(val, 0)
rec.Values[i] = ts.Format(time.RFC3339)
}
}
}
// Append the record to b.rows.
vals := make([]interface{}, 0, len(rec.Values))
vals = append(vals, rec.Values...)
b.rows = append(b.rows, vals)
// Check for batch full or stale.
if len(b.ids) == cap(b.ids) {
return fbbatch.ErrBatchNowFull
}
if b.maxStaleness != time.Duration(0) { // set maxStaleness to 0 to disable staleness checking
if len(b.ids) == 1 {
b.staleTime = time.Now().Add(b.maxStaleness)
} else if time.Now().After(b.staleTime) {
return fbbatch.ErrBatchNowStale
}
}
return nil
}
func (b *sqlBatch) Import() error {
if len(b.rows) == 0 {
return nil
}
// Construct the BULK INSERT statement based on the table and fields.
sql, err := buildBulkInsert(b.table, b.fields, b.ids, b.rows)
if err != nil {
return errors.Wrap(err, "building bulk insert statement")
}
// Reset batch data.
b.reset()
// Submit the SQL statement.
return b.inserter.Insert(sql)
}
func (b *sqlBatch) reset() {
b.ids = b.ids[:0]
b.rows = b.rows[:0]
}
func (b *sqlBatch) Len() int {
return len(b.rows)
}
func (b *sqlBatch) Flush() error {
return nil
}
func buildBulkInsert(tbl *dax.Table, fields []*dax.Field, ids []interface{}, rows [][]interface{}) (string, error) {
// Validation.
if tbl.Name == "" {
return "", errors.New(errors.ErrUncoded, "table name is required")
} else if len(fields) == 0 {
return "", errors.New(errors.ErrUncoded, "at least one field is required")
}
var sb strings.Builder
sb.WriteString(`BULK INSERT INTO `)
sb.WriteString(string(tbl.Name))
sb.WriteString(` (_id,`)
flds := make([]string, 0, len(fields))
maps := make([]string, 0, len(fields))
for i := range fields {
flds = append(flds, string(fields[i].Name))
maps = append(maps, fmt.Sprintf("'$.col_%d' %s", i, fields[i].FullType()))
}
// Fields
sb.WriteString(strings.Join(flds, ","))
// MAP
keyType := dax.BaseTypeID
if tbl.StringKeys() {
keyType = dax.BaseTypeString
}
sb.WriteString(`) MAP ('$._id' `)
sb.WriteString(keyType)
sb.WriteString(`,`)
sb.WriteString(strings.Join(maps, ","))
sb.WriteString(`) FROM x'`)
// Row values.
// m is a map representing a single row to be marshalled and added to the
// bulk insert as one line in the NDJSON payload. We re-use the map for each
// row.
m := make(map[string]interface{})
for i := range rows {
// Write the ID value.
m[string(dax.PrimaryKeyFieldName)] = ids[i]
// Write the rest of the data values.
for col := range rows[i] {
m[fmt.Sprintf("col_%d", col)] = rows[i][col]
}
// Marshal the map to json and add to the sql statement.
if j, err := json.Marshal(m); err != nil {
return "", errors.Wrap(err, "marshalling row to json")
} else {
sb.Write(j)
sb.WriteString("\n")
}
}
// WITH
sb.WriteString(fmt.Sprintf(`' WITH BATCHSIZE %d FORMAT 'NDJSON' INPUT 'STREAM'`, len(rows)))
return sb.String(), nil
}

View file

@ -1,47 +0,0 @@
package batch
import (
"testing"
"github.com/featurebasedb/featurebase/v3/dax"
"github.com/stretchr/testify/assert"
)
func TestBatchSQL(t *testing.T) {
tbl := &dax.Table{
Name: "foo",
}
fields := []*dax.Field{
{
Name: "name",
Type: dax.BaseTypeString,
},
{
Name: "age",
Type: dax.BaseTypeInt,
},
}
ids := []interface{}{
0, 1, 2,
}
rows := [][]interface{}{
{
[]interface{}{"Alice", int64(11)},
},
{
[]interface{}{"Bob", int64(22)},
},
{
[]interface{}{"Carl,Comma", int64(33)},
},
}
s, err := buildBulkInsert(tbl, fields, ids, rows)
assert.NoError(t, err)
exp := `BULK INSERT INTO foo (_id,name,age) MAP ('$._id' id,'$.col_0' string,'$.col_1' int) FROM x'{"_id":0,"col_0":["Alice",11]}
{"_id":1,"col_0":["Bob",22]}
{"_id":2,"col_0":["Carl,Comma",33]}
' WITH BATCHSIZE 3 FORMAT 'NDJSON' INPUT 'STREAM'`
assert.Equal(t, exp, s)
}

View file

@ -1,91 +0,0 @@
package cli
import (
"io"
"strings"
"github.com/featurebasedb/featurebase/v3/errors"
)
// buffer is a query buffer for SQL statements. Note that this is not a query
// buffer as you would find on a database server (buffering query results).
// Rather, this buffers the working SQL statement. The buffer has two
// components: the buffer of query parts making up the working, incomplete SQL
// statement, and the last completed SQL statement submitted to the Queryer.
type buffer struct {
parts []queryPart
lastQuery query
hasBatchFile bool
}
func newBuffer() *buffer {
return &buffer{}
}
// addPart adds the given queryPart to the buffer. If the part is of type
// `partTerminator` (which is generally singified in the CLI by a ";"), the
// buffer will finalize the query and return it. In all other cases, the
// returned query is nil.
func (b *buffer) addPart(part queryPart) (query, error) {
// Check for part type compatibility. For example, multiple batchFile parts
// are not allowed in the same query.
switch part.(type) {
case *partBatchFile:
if b.hasBatchFile {
return nil, errors.Errorf("multiple batch files in one query is not supported")
}
b.hasBatchFile = true
case *partTerminator:
return b.finalize(), nil
}
b.parts = append(b.parts, part)
return nil, nil
}
// finalize copies the contents (queryParts) of buffer to lastQuery and then
// resets the buffer. It returns the query that was finalized.
func (b *buffer) finalize() query {
q := make(query, len(b.parts))
copy(q, b.parts)
b.lastQuery = q
b.reset()
return q
}
// print returns the contents of the buffer as a string. This is generally used
// to visually inspect the state of the buffer (for example, when a user issues
// a `\p` meta-command in the CLI).
func (b *buffer) print() string {
if len(b.parts) > 0 {
return query(b.parts).String()
} else if b.lastQuery != nil {
return b.lastQuery.String() + ";"
}
return "Query buffer is empty."
}
// reset clears the buffer. It returns a message which may optionally be used to
// display to a user.
func (b *buffer) reset() string {
b.parts = b.parts[:0]
b.hasBatchFile = false
return "Query buffer reset (cleared)."
}
func (b *buffer) Reader() io.Reader {
if len(b.parts) > 0 {
return query(b.parts).Reader()
} else if b.lastQuery != nil {
r := b.lastQuery.Reader()
// TODO(tlt): terminating the query here results in a line feed just
// before the semi-colon (for example, when you print out the query
// buffer using `\w [FILE]`). The removal and re-introduction of line
// feeds is kind of a mess.
term := strings.NewReader(";")
return io.MultiReader(r, term)
}
return strings.NewReader("")
}

View file

@ -1,816 +0,0 @@
// Package cli contains a FeatureBase command line interface.
package cli
import (
"context"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/chzyer/readline"
featurebase "github.com/featurebasedb/featurebase/v3"
"github.com/featurebasedb/featurebase/v3/cli/batch"
"github.com/featurebasedb/featurebase/v3/cli/fbcloud"
"github.com/featurebasedb/featurebase/v3/errors"
"github.com/featurebasedb/featurebase/v3/logger"
)
const (
defaultHost string = "localhost"
defaultClientID string = "6i2gs7mu215ab23cnvmshdoq6t" // production Cognito client ID
defaultRegion string = "us-east-2"
terminationChar string = ";"
nullValue string = "NULL"
)
var (
Stdin io.ReadCloser = os.Stdin
Stdout io.Writer = os.Stdout
Stderr io.Writer = os.Stderr
)
var splash string = fmt.Sprintf(`FeatureBase CLI (%s)
Type "\q" to quit.
`, featurebase.Version)
// Ensure type implments interfaces.
var _ printer = (*Command)(nil)
var _ batch.Inserter = (*Command)(nil)
type Command struct {
host string
port string
splitter *splitter
buffer *buffer
workingDir *workingDir
organizationID string
database string
databaseID string
databaseName string
Queryer Queryer `json:"-"`
stdin io.ReadCloser `json:"-"`
stdout io.Writer `json:"-"`
stderr io.Writer `json:"-"`
// output is where actual results are written. This might point to stdout,
// or to a file, based on the current configuration.
output io.Writer `json:"-"`
writeOptions *writeOptions
Config *Config `json:"config"`
historyPath string
// Commands contains optional commands provided via one or more `-c` (or
// `--command`) flags. If this is non-empty, the cli will run in
// non-interactive mode; i.e. it will quit after the command is complete.
Commands []string `json:"commands"`
// Files contains optional files provided via one or more `-f` (or `--file`)
// flags. If this is non-empty, the cli will run in non-interactive mode;
// i.e. it will quit after the command is complete.
Files []string `json:"files"`
// variables holds the variables created with the \set meta-command.
variables map[string]string
// nonInteractiveMode is set to true when fbsql is running in
// non-ineracative mode. And example of this is when the user has provided a
// `-c` flag in the command line.
nonInteractiveMode bool
// quit gets closed when Run should stop listening for input.
quit chan struct{}
}
func NewCommand(logdest logger.Logger) *Command {
variables := make(map[string]string)
return &Command{
Config: &Config{
Host: defaultHost,
Port: "",
OrganizationID: "",
Database: "",
CloudAuth: CloudAuthConfig{
ClientID: defaultClientID,
Region: defaultRegion,
Email: "",
Password: "",
},
HistoryPath: "",
CSV: false,
},
buffer: newBuffer(),
splitter: newSplitter(newReplacer(variables)),
workingDir: newWorkingDir(),
stdin: Stdin,
stdout: Stdout,
stderr: Stderr,
output: Stdout,
writeOptions: defaultWriteOptions(),
variables: variables,
quit: make(chan struct{}),
}
}
// SetStdin sets stdin. This is useful for initial configuration in tests.
func (cmd *Command) SetStdin(rc io.ReadCloser) {
cmd.stdin = rc
}
// SetStdout sets both stdout and output to the value provided. This is useful
// for initial configuration in tests.
func (cmd *Command) SetStdout(w io.Writer) {
cmd.stdout = w
cmd.output = w
}
// SetStderr sets stderr. This is useful for initial configuration in tests.
func (cmd *Command) SetStderr(w io.Writer) {
cmd.stderr = w
}
// Run is the main entry-point to the CLI.
func (cmd *Command) Run(ctx context.Context) error {
if err := cmd.run(ctx); err != nil {
cmd.Errorf(err.Error() + "\n")
return err
}
return nil
}
// run is effectively wrapped by the Run() method, but it's split out this way
// so that run() can simply return errors, rather than worrying about how errors
// should be printed; printing errors returned by run() is left up to the Run()
// method.
func (cmd *Command) run(ctx context.Context) error {
if err := cmd.setupConfig(); err != nil {
return errors.Wrap(err, "setting up config")
}
// Check to see if Command needs to run in non-interactive mode.
if len(cmd.Commands) > 0 ||
len(cmd.Files) > 0 ||
cmd.Config.KafkaConfig != "" ||
cmd.Config.CSV {
cmd.nonInteractiveMode = true
}
// Print the splash message.
if !cmd.nonInteractiveMode {
cmd.Printf(splash)
}
if err := cmd.setupClient(); err != nil {
return errors.Wrap(err, "setting up client")
}
// Print the connection info.
if !cmd.nonInteractiveMode {
cmd.printConnInfo()
}
if err := cmd.connectToDatabase(cmd.database); err != nil {
cmd.Errorf(errors.Wrap(err, "connecting to database").Error() + "\n")
// We intentionally do not return err here.
}
// Run in non-interactive mode based on flags and configuration.
// This includes either handling `-c` and/or `-f` flags, or handling a
// `--kafka-config` flag.
if len(cmd.Commands) > 0 || len(cmd.Files) > 0 {
// Run Commands.
for _, line := range cmd.Commands {
if err := cmd.handleLine(line); err != nil {
return errors.Wrapf(err, "handling line: %s", line)
}
}
// Run Files.
for _, fname := range cmd.Files {
if _, err := executeFile(cmd, fname); err != nil {
return errors.Wrapf(err, "executing file: %s", fname)
}
}
return nil
} else if cmd.Config.KafkaConfig != "" {
runner, err := cmd.newKafkaRunner(cmd.Config.KafkaConfig)
if err != nil {
return errors.Wrap(err, "getting new kafka runner")
}
if err := runner.Main.Run(); err != nil {
return errors.Wrap(err, "running kafka")
}
return nil
}
// From this point on, we should be in interactive mode.
// Set up history for saving user input.
cmd.setupHistory()
rl, err := readline.NewEx(&readline.Config{
Prompt: cmd.prompt(false),
HistoryFile: cmd.historyPath,
HistoryLimit: 100000,
DisableAutoSaveHistory: true,
Stdin: cmd.stdin,
Stdout: cmd.stdout,
Stderr: cmd.stderr,
})
if err != nil {
return errors.Wrap(err, "getting readline")
}
defer rl.Close()
// inMidCommand indicates whether a partial command has been received and
// we're still waiting for a termination character.
var inMidCommand bool
for {
rl.SetPrompt(cmd.prompt(inMidCommand))
// Read user provided input.
line, err := rl.Readline()
if err == readline.ErrInterrupt {
inMidCommand = false
cmd.buffer.reset()
continue
} else if err != nil {
return errors.Wrap(err, "reading line")
}
// We append a line feed at the end of each line because at this point
// we have effectively stripped any intentional line feeds (since we are
// reading a line at a time), and we don't want to do that. An example
// of an intentional line feed is in a BULK INSERT CSV STREAM like this
// example:
//
// bulk replace
// into foo (_id, age)
// map (0 id, 1 int)
// from
// x'3,33
// 4,44
// 5,55'
// with
// format 'CSV'
// input 'STREAM';
//
// We want to preserve the line feeds that are contained in the x''
// block; those are intentional as they demarc records within the csv.
qps, mcs, err := cmd.splitter.split(line + "\n")
if err != nil {
cmd.Errorf("error splitting line: %s\n", err)
continue
}
// Save line in the history.
if err := rl.SaveHistory(line); err != nil {
cmd.Errorf("Couldn't save history: %v\n", err)
}
// This is wrapped in an anonymous function so we can capture any
// errors, ignore the rest of the line, and return back to a prompt.
if err := func() error {
for i := range qps {
if qry, err := cmd.buffer.addPart(qps[i]); err != nil {
return errors.Wrap(err, "adding part to buffer")
} else if qry != nil {
if err := cmd.executeAndWriteQuery(qry); err != nil {
return errors.Wrap(err, "executing query")
}
// In addition to saving each line in the history, we also
// save each successful query.
if err := rl.SaveHistory(qry.String() + ";"); err != nil {
cmd.Errorf("Couldn't save query in history: %v\n", err)
}
inMidCommand = false
} else {
inMidCommand = true
}
}
return nil
}(); err != nil {
cmd.Errorf(err.Error() + "\n")
inMidCommand = false
continue
}
// This is wrapped in an anonymous function so we can capture any
// errors, ignore the rest of the line, and return back to a prompt.
if err := func() error {
for i := range mcs {
action, err := mcs[i].execute(cmd)
if err != nil {
return errors.Wrap(err, "executing meta command")
}
switch action {
case actionQuit:
close(cmd.quit)
return nil
case actionReset:
inMidCommand = false
}
}
return nil
}(); err != nil {
cmd.Errorf(err.Error() + "\n")
inMidCommand = false
continue
}
select {
case <-cmd.quit:
if err := cmd.close(); err != nil {
cmd.Errorf("closing: %s\n", err)
}
return nil
default:
// pass
}
}
}
// prompt constructs the prompt that the user sees based on the currently
// connected database and whether the user is in the middle of a sql statement.
func (cmd *Command) prompt(mid bool) string {
db := "fbsql" // default prompt when a database is not set.
if cmd.databaseName != "" {
db = cmd.databaseName
}
if mid {
return strings.Repeat(" ", len(db)) + "-# "
}
return db + "=# "
}
// close is called upon quitting. It should close any remaining open file
// handles used by the CLICommand.
func (cmd *Command) close() error {
return cmd.closeOutput()
}
// setupConfig sets up private struct members based on values provided via the
// configuration flags.
func (cmd *Command) setupConfig() error {
if cmd.Config == nil {
return nil
}
cmd.host = cmd.Config.Host
cmd.port = cmd.Config.Port
cmd.organizationID = cmd.Config.OrganizationID
cmd.database = cmd.Config.Database
cmd.historyPath = cmd.Config.HistoryPath
// Apply any pset flag arguments.
for _, pset := range cmd.Config.PSets {
if err := cmd.applyPSet(pset); err != nil {
return errors.Wrapf(err, "applying pset: %s", pset)
}
}
// If running with the `--csv` flag, configure things to ensure the output
// is correct (i.e. that it's just the csv).
if cmd.Config.CSV {
cmd.writeOptions.format = formatCSV
}
return nil
}
// applyPSet takes a pset string of the form `arg` or `arg=val` and applies it
// as if the user had run `\pset arg val`. The only difference is that applying
// pset here suppresses any output to stdout.
func (cmd *Command) applyPSet(pset string) error {
// We expect arg to be one of the folowing formats:
// arg
// arg=val
args := strings.SplitN(pset, "=", 2)
// This is kind of hacky, but until we re-think the metaCommand interface to
// take a printer interface somewhere (so we can pass in the nopPrinter
// here), we're just going to discard stdout for the duration of this apply,
// and then set stdout back to its previous writer after the apply.
hold := cmd.stdout
cmd.stdout = io.Discard
defer func() {
cmd.stdout = hold
}()
_, err := newMetaPSet(args).execute(cmd)
return err
}
func (cmd *Command) executeAndWriteQuery(qry query) error {
queryResponse, err := cmd.executeQuery(qry)
if err != nil {
if errors.Is(err, ErrOrganizationRequired) {
// Print an error message and return nil, effectively aborting any
// further writes for this query.
cmd.Errorf("Organization required. Use \\org to set an organization.\n")
return nil
}
return errors.Wrap(err, "making query")
}
if err := writeOutput(queryResponse, cmd.writeOptions, cmd.output, cmd.stdout, cmd.stderr); err != nil {
return errors.Wrap(err, "writing out response")
}
return nil
}
func (cmd *Command) executeQuery(qry query) (*featurebase.WireQueryResponse, error) {
wqr, err := cmd.Queryer.Query(cmd.organizationID, cmd.databaseID, qry.Reader())
if err != nil {
return nil, errors.Wrap(err, "executing query")
}
// If we're running in non-interactive mode, we need to check the error that
// comes back in the WireQueryResponse. If there's an error, we want to
// return it now (rather than just printing it later) so that we immediately
// stop any further execution of commands.
if cmd.nonInteractiveMode && wqr.Error != "" {
return nil, errors.Errorf(wqr.Error)
}
return wqr, nil
}
// printer is an interface which encapsulates the methods used to print output
// to the various io.Writers.
type printer interface {
Printf(format string, a ...any)
Outputf(format string, a ...any)
Errorf(format string, a ...any)
}
type nopPrinter struct{}
func newNopPrinter() *nopPrinter {
return &nopPrinter{}
}
func (n *nopPrinter) Printf(format string, a ...any) {}
func (n *nopPrinter) Outputf(format string, a ...any) {}
func (n *nopPrinter) Errorf(format string, a ...any) {}
// Printf is a helper method which sends the given payload to stdout.
func (cmd *Command) Printf(format string, a ...any) {
out := fmt.Sprintf(format, a...)
cmd.stdout.Write([]byte(out))
}
// Outputf is a helper method which sends the given payload to output.
func (cmd *Command) Outputf(format string, a ...any) {
out := fmt.Sprintf(format, a...)
cmd.output.Write([]byte(out))
}
// Errorf is a helper method which sends the given payload to stderr.
func (cmd *Command) Errorf(format string, a ...any) {
out := fmt.Sprintf(format, a...)
cmd.stderr.Write([]byte(out))
}
func (cmd *Command) setupHistory() {
// If HistoryPath has already been configured (i.e. with a command flag),
// don't bother setting up the default in the home directory.
if cmd.historyPath != "" {
return
}
historyPath := ""
if home, err := os.UserHomeDir(); err != nil {
cmd.Errorf("Error getting home directory, command history persistence will be disabled: %v\n", err)
} else {
historyDir := filepath.Join(home, ".featurebase")
err := os.MkdirAll(historyDir, 0o750)
if err != nil {
cmd.Errorf("Creating directory for history: %v\n", err)
} else {
historyPath = filepath.Join(historyDir, "fbsql_history")
}
}
cmd.historyPath = historyPath
}
// printConnInfo displays the currently set host.
// TODO(tlt): extend this to be the output of the /conninfo meta-command.
func (cmd *Command) printConnInfo() {
cmd.Printf("Host: %s\n", hostPort(cmd.host, cmd.port))
}
func (cmd *Command) connectToDatabase(dbName string) error {
var p printer = cmd
if cmd.nonInteractiveMode {
p = newNopPrinter()
}
// Providing a blank ("") or hyphen ("-") dbName is the equivalent of
// disconnecting from the current database. We support the hyphen option
// because calling the `\c` meta-command without an argument is how you
// print the current connection.
switch dbName {
case "-", "":
cmd.databaseID = ""
cmd.databaseName = ""
p.Printf(cmd.connectionMessage())
return nil
}
// Look up dbID based on dbName.
wqr, err := cmd.executeQuery(newRawQuery("SHOW DATABASES"))
if err != nil {
return errors.Wrap(err, "executing query")
}
for _, db := range wqr.Data {
// 0: _id
// 1: name
if db[1] == dbName {
cmd.databaseName = dbName
cmd.databaseID = db[0].(string)
p.Printf(cmd.connectionMessage())
return nil
}
}
return errors.Errorf("invalid database: %s", dbName)
}
func (cmd *Command) orgMessage() string {
if cmd.organizationID == "" {
return "You have not set an organization.\n"
}
return fmt.Sprintf("You have set organization \"%s\".\n", cmd.organizationID)
}
func (cmd *Command) connectionMessage() string {
if cmd.databaseName == "" {
return "You are not connected to a database.\n"
}
return fmt.Sprintf("You are now connected to database \"%s\" (%s).\n", cmd.databaseName, cmd.databaseID)
}
func (cmd *Command) setupClient() error {
// If the Queryer has already been set (in tests for example), don't bother
// trying to detect it.
if cmd.Queryer != nil {
return nil
}
var p printer = cmd
if cmd.nonInteractiveMode {
p = newNopPrinter()
}
if strings.TrimSpace(cmd.host) == "" {
return errors.Errorf("no host provided\n")
}
if !strings.HasPrefix(cmd.host, "http") {
cmd.host = "http://" + cmd.host
}
typ, err := cmd.detectFBType()
if err != nil {
return errors.Wrap(err, "detecting FeatureBase deployment type")
}
switch typ {
case featurebaseTypeOnPremClassic:
p.Printf("Detected on-prem, classic deployment.\n")
cmd.Queryer = &standardQueryer{
Host: cmd.host,
Port: cmd.port,
}
case featurebaseTypeOnPremServerless:
p.Printf("Detected on-prem, serverless deployment.\n")
cmd.Queryer = &serverlessQueryer{
Host: cmd.host,
Port: cmd.port,
}
case featurebaseTypeCloud:
p.Printf("Detected cloud deployment.\n")
cmd.Queryer = &fbcloud.Queryer{
Host: hostPort(cmd.host, cmd.port),
ClientID: cmd.Config.CloudAuth.ClientID,
Region: cmd.Config.CloudAuth.Region,
Email: cmd.Config.CloudAuth.Email,
Password: cmd.Config.CloudAuth.Password,
}
case featurebaseTypeUnknown:
p.Printf("Could not detect deployment\n")
// cmd.Queryer = &nopQueryer{}
// Instead of using a no-op queryer when the type can't be detected, we
// default to using a cloud queryer.
cmd.Queryer = &fbcloud.Queryer{
Host: hostPort(cmd.host, cmd.port),
ClientID: cmd.Config.CloudAuth.ClientID,
Region: cmd.Config.CloudAuth.Region,
Email: cmd.Config.CloudAuth.Email,
Password: cmd.Config.CloudAuth.Password,
}
default:
return errors.Errorf("unknown type: %s", typ)
}
return nil
}
type featurebaseType string
const (
featurebaseTypeUnknown featurebaseType = "unknown" // unknown
featurebaseTypeOnPremClassic featurebaseType = "on-prem-standard" // on-prem, classic
featurebaseTypeOnPremServerless featurebaseType = "on-prem-serverless" // on-prem, serverless
featurebaseTypeCloud featurebaseType = "cloud" // cloud, (both classic and serverless)?
)
func hostPort(host, port string) string {
if port == "" {
return host
}
return host + ":" + port
}
// detectFBType determines if we're talking to standalone FeatureBase
// or FeatureBase Cloud
func (cmd *Command) detectFBType() (featurebaseType, error) {
type trial struct {
port string
health string
typ featurebaseType
}
// trials is populated with the url/endpoints to try in order to detect if a
// process is running there which can support the cli requests.
trials := []trial{}
var clientTimeout time.Duration
if cmd.port != "" {
clientTimeout = 100 * time.Millisecond
trials = append(trials,
// on-prem, serverless
trial{
port: cmd.port,
health: "/queryer/health",
typ: featurebaseTypeOnPremServerless,
},
// on-prem, classic
trial{
port: cmd.port,
health: "/status",
typ: featurebaseTypeOnPremClassic,
},
)
} else if strings.HasPrefix(cmd.host, "https") {
// https suggesting we might be connecting to a cloud host
clientTimeout = 1 * time.Second
trials = append(trials,
// cloud
trial{
port: "",
health: "/health",
typ: featurebaseTypeCloud,
},
)
} else {
// Try default ports just in case.
clientTimeout = 100 * time.Millisecond
trials = append(trials,
// on-prem, serverless
trial{
port: "8080",
health: "/queryer/health",
typ: featurebaseTypeOnPremServerless,
},
// on-prem, classic
trial{
port: "10101",
health: "/status",
typ: featurebaseTypeOnPremClassic,
},
)
}
client := http.Client{
Timeout: clientTimeout,
}
for _, trial := range trials {
url := hostPort(cmd.host, trial.port) + trial.health
if resp, err := client.Get(url); err != nil {
continue
} else if resp.StatusCode/100 == 2 {
cmd.port = trial.port
return trial.typ, nil
}
}
return featurebaseTypeUnknown, nil
}
func (cmd *Command) closeOutput() error {
if cmd.output == nil {
return nil
}
if closer, ok := cmd.output.(io.Closer); ok {
return closer.Close()
}
return nil
}
func (cmd *Command) handleLine(line string) error {
// For single-line command handling, we handle either a meta-command, or
// query parts, but not both. The logic is that any line which begins with
// "\" will be handled as a meta-command, otherwise it will be handled as a
// query.
if len(line) == 0 {
return nil
} else if line[0] == byte('\\') {
return cmd.handleLineAsMetaCommand(line)
} else {
return cmd.handleLineAsQueryParts(line)
}
}
func (cmd *Command) handleLineAsMetaCommand(line string) error {
_, mcs, err := cmd.splitter.split(line)
if err != nil {
return errors.Wrapf(err, "splitting line")
}
for i := range mcs {
_, err := mcs[i].execute(cmd)
if err != nil {
return errors.Wrap(err, "executing meta command")
}
}
return nil
}
func (cmd *Command) handleLineAsQueryParts(line string) error {
qps, mcs, err := cmd.splitter.split(line)
if err != nil {
return errors.Wrapf(err, "splitting line")
} else if len(mcs) > 0 {
return errors.Errorf("--command does not support meta-commands")
}
// Add a termintor part to the end of []queryPart. We do this because the
// command is coming in from the --command flag, it may not end with a
// semi-colon, but we still want to execute it.
if len(qps) > 0 {
if _, ok := qps[len(qps)-1].(*partTerminator); !ok {
qps = append(qps, newPartTerminator())
}
}
for i := range qps {
if qry, err := cmd.buffer.addPart(qps[i]); err != nil {
return errors.Wrap(err, "adding part to buffer")
} else if qry != nil {
if err := cmd.executeAndWriteQuery(qry); err != nil {
return errors.Wrap(err, "executing query")
}
}
}
return nil
}
func (cmd *Command) Insert(sql string) error {
wqr, err := cmd.executeQuery(newRawQuery(sql))
if wqr.Error != "" {
return errors.Errorf(wqr.Error)
}
return err
}

View file

@ -1,257 +0,0 @@
package cli_test
import (
"bufio"
"context"
"fmt"
"os"
"strings"
"testing"
"time"
"github.com/featurebasedb/featurebase/v3/cli"
"github.com/featurebasedb/featurebase/v3/dax/server/test"
"github.com/featurebasedb/featurebase/v3/logger"
"github.com/stretchr/testify/require"
)
func TestCLIIntegration(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
ctx := context.Background()
t.Run("Stubbed Framework", func(t *testing.T) {
mc := test.MustRunManagedCommand(t)
defer mc.Close()
addr := mc.Address()
capture := newCapture(t)
comparer := newComparer(t)
comparer.run()
fbsql := cli.NewCommand(logger.StderrLogger)
fbsql.SetStdin(capture)
fbsql.SetStdout(comparer)
fbsql.SetStderr(comparer)
fbsql.Config = &cli.Config{
Host: addr.Host(),
Port: fmt.Sprintf("%d", addr.Port()),
}
// Run fbsql in a goroutine so we can continue to send it commands
// below.
didQuit := make(chan struct{})
go func() {
require.NoError(t, fbsql.Run(ctx))
close(didQuit)
}()
// testFiles reference files located in the cli/testdata directory. All
// tests should be placed there; other than adding another test file to
// this list, you probably shouldn't be editing this file unless you are
// trying to modify the way the test framework itself works.
testFiles := []string{
"setup",
"database",
"table",
// the tests below may be dependent on the previous tests, which do
// setup and some shared database and table creation.
"query_buffer",
// meta commands
"meta_bang",
"meta_cd",
"meta_echo",
"meta_describe",
"meta_file",
"meta_pset_border",
"meta_pset_expanded",
"meta_pset_format_csv",
"meta_pset_tuples_only",
"meta_include",
"meta_output",
"meta_set",
"meta_timing",
"meta_write",
}
for _, testFile := range testFiles {
t.Run(testFile, func(t *testing.T) {
f, err := os.Open("testdata/" + testFile)
require.NoError(t, err)
scanner := bufio.NewScanner(f)
var lineNo int
for scanner.Scan() {
line := scanner.Text()
lineNo++
// Empty lines and comments (//) are ignored.
if line == "" {
continue
} else if strings.HasPrefix(line, "//") {
continue
}
parts := strings.SplitN(line, ":", 2)
switch parts[0] {
case "SEND":
v := ""
if len(parts) == 2 {
v = parts[1]
}
capture.sendLine(v)
case "EXPECT":
v := ""
if len(parts) == 2 {
v = parts[1]
}
comparer.expectLine(v, testFile, lineNo)
case "EXPECTCOMP":
if len(parts) == 2 {
comps := strings.SplitN(parts[1], ":", 2)
v := ""
if len(comps) == 2 {
v = comps[1]
}
comparer.expectLineComp(comparator(comps[0]), v, testFile, lineNo)
} else {
t.Errorf("unexpected line: %s[%d]:%s", testFile, lineNo, line)
}
default:
t.Errorf("unexpected line: %s[%d]:%s", testFile, lineNo, line)
}
}
require.NoError(t, scanner.Err())
})
}
// End with quit to ensure that fbsql closes without error.
capture.sendLine(`\q`)
// Ensure fbsql quits cleanly.
select {
case <-didQuit:
case <-time.After(time.Second):
t.Fatalf("expected fbsql to quit")
}
})
}
// compare is used to compare fbsql output written to its Stdout with expected
// lines.
type comparer struct {
t *testing.T
out chan byte
outline chan []byte
exp chan []byte
}
func newComparer(t *testing.T) *comparer {
return &comparer{
t: t,
out: make(chan byte, 1024),
outline: make(chan []byte, 128),
exp: make(chan []byte, 1024),
}
}
func (c *comparer) run() {
// Read bytes off output, and for every line (designated by a line feed "\n"),
// push the line onto the outline channel.
go func() {
var line []byte
for {
b := <-c.out
if b == byte('\n') {
c.outline <- line
line = []byte{}
continue
}
line = append(line, b)
}
}()
}
type comparator string
const (
compEquals = "Equals"
compHasPrefix = "HasPrefix"
compWithFormat = "WithFormat"
)
// expectLine is a convenience method which calls expectLineComp with the compEq
// comparator and the given line.
func (c *comparer) expectLine(line string, fileName string, lineNo int) {
c.expectLineComp(compEquals, line, fileName, lineNo)
}
// expectLineComp reads the next line from the outline channel and compares it
// with the given `line`. A comparator can be provided to inform how the lines
// should be compared (for example, the compHasPrefix comparator will just
// compare the beginning part of the outline).
func (c *comparer) expectLineComp(comp comparator, line string, fileName string, lineNo int) {
var outline []byte
select {
case outline = <-c.outline:
case <-time.After(10 * time.Second):
// TODO(tlt): this is 10 seconds to account for the fb_views creation on
// a local mac. This should really be something like 2 seconds. Put this
// back to 2 once fb_views issue is addressed.
c.t.Fatalf("expected output line %s[%d]: >%s<", fileName, lineNo, line)
}
// msg is included in any require which fails.
msg := []interface{}{"exp: %s[%d], got: >%s<", fileName, lineNo, outline}
switch comp {
case compEquals:
require.Equal(c.t, []byte(line), outline, msg...)
case compHasPrefix:
require.True(c.t, strings.HasPrefix(string(outline), line), msg...)
case compWithFormat:
require.True(c.t, compareByteSlices(outline, []byte(line)), msg...)
default:
c.t.Fatalf("invalid comparator: %s", comp)
}
}
func (c *comparer) Write(b []byte) (n int, err error) {
for i := range b {
c.out <- b[i]
}
return len(b), err
}
// compareByteSlices compares a byte slice s with another byte slice format and
// returns true if they are the same. It will accept underscore as a
// single-character wildcard anywhere in slice format.
func compareByteSlices(s, format []byte) bool {
// Replace some helpers in format before comparing.
f := string(format)
f = strings.ReplaceAll(f, `{uuid}`, `________-____-____-____-____________`)
f = strings.ReplaceAll(f, `{timestamp}`, `____-__-__T__:__:__Z`)
format = []byte(f)
if len(s) != len(format) {
return false
}
for i := range s {
if format[i] == '_' {
continue
}
if s[i] != format[i] {
// log.Printf("DEBUG: characters differ: (%d): '%v' != '%v'", i, s[i], format[i])
return false
}
}
return true
}

View file

@ -1,199 +0,0 @@
package cli_test
import (
"context"
"io"
"strings"
"sync"
"testing"
"time"
featurebase "github.com/featurebasedb/featurebase/v3"
"github.com/featurebasedb/featurebase/v3/cli"
"github.com/featurebasedb/featurebase/v3/logger"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
)
func TestCLI(t *testing.T) {
t.Run("Input", func(t *testing.T) {
ctx := context.Background()
capture := newCapture(t)
cli := cli.NewCommand(logger.StderrLogger)
cli.SetStdin(capture)
cli.SetStdout(capture)
cli.Queryer = capture
go func() {
assert.NoError(t, cli.Run(ctx))
}()
none := []string{}
// One statement, one line.
capture.Assert("one;", []string{"one\n"})
// One statement, multiple lines.
capture.Assert("one", none)
capture.Assert(" two ", none)
capture.Assert("three;", []string{"one\ntwo\nthree\n"})
// Multiple statements, one line.
capture.Assert("foo; bar;", []string{"foo\n", "bar\n"})
// Multiple statements, multiple lines.
capture.Assert("a1", none)
capture.Assert("a2; b1", []string{"a1\na2\n"})
capture.Assert("b2;", []string{"b1\nb2\n"})
// Blank lines.
capture.Assert("one", none)
capture.Assert("", none)
capture.Assert("three;", []string{"one\nthree\n"})
// Just a semi-colon.
capture.Assert(";", []string{""})
// Multi-line with just a semi-colon.
capture.Assert("one", none)
capture.Assert(";", []string{"one\n"})
// Ensure a clean exit with no errors.
assert.NoError(t, capture.Exit())
})
}
////////////////////////////////////////////////////////
// Ensure type implementes interface.
var _ io.ReadCloser = (*capture)(nil)
var _ io.Writer = (*capture)(nil)
var _ cli.Queryer = (*capture)(nil)
// capture implements the various CLI interfaces in order to capture test input
// and submit it as though that input were being read from the command line. It
// also captures calls made to the Queryer.Query method and ensures the sql they
// contain is expected.
type capture struct {
t *testing.T
// ch is a channel of strings (one line at a time) of CLI input.
ch chan string
mu sync.RWMutex
sqls []string
// queryDone will receive an event any time the Query method is called and
// has completed. This is to tell the Assert method that it's safe to
// compare the sqls slice.
queryDone chan struct{}
asserting chan struct{}
err error
}
func newCapture(t *testing.T) *capture {
return &capture{
t: t,
ch: make(chan string),
sqls: make([]string, 0),
queryDone: make(chan struct{}),
}
}
func (c *capture) Exit() error {
c.sendLine(`\q`)
c.mu.RLock()
defer c.mu.RUnlock()
return c.err
}
func (c *capture) Assert(in string, out []string) {
c.asserting = make(chan struct{})
c.sendLine(in)
// Wait for the CLI command to complete processing the input and send the
// sql to Query() by blocking on the queryDone channel. Because Query gets
// called for every sql statement in the input, an input resulting in
// multiple sql statements needs to wait for all expected queries to
// complete. A timeout is included to this so it doesn't deadlock in the
// case where Query is expected to be called, but isn't; after the timeout,
// the test should fail completely. In summary: we wait on queryDone the
// number of sql statements we expect. If we receive fewer than expected,
// the timeout will occur. If we receive more than expected, the Query()
// method will effectively deadlock, reach its own timout, then write to
// capture.err, which will be reported upon Exit().
for range out {
select {
case <-c.queryDone:
case <-time.After(2 * time.Second):
c.t.Fatalf("expected Query() to be called")
}
}
close(c.asserting)
c.mu.Lock()
defer c.mu.Unlock()
assert.Equal(c.t, out, c.sqls)
// Reset the slice.
c.sqls = c.sqls[:0]
}
// sendLine sends the given string as a line input to the CLI command. It
// appends a line feed to the end of string in order to mimic the user hitting
// the return key.
func (c *capture) sendLine(s string) {
// Add a line feed before putting s on the channel in order to mimic the
// user hitting the return key.
c.ch <- s + "\n"
}
// Read is read by the CLI in place of user input. It effectively sends lines of
// input to the CLI, getting each line to be sent off the channel.
func (c *capture) Read(b []byte) (n int, err error) {
s := <-c.ch
return strings.NewReader(s).Read(b)
}
func (c *capture) Close() error {
close(c.ch)
return nil
}
// Write is called with anything written to output. This would included results
// from calling Query() under normal, non-testing conditions, as well as other
// informational text sent to output, such as the splash message.
func (c *capture) Write(b []byte) (n int, err error) {
return 0, nil
}
// Query is called by the CLI command once a full SQL statement is received
// (signified by the terminator: `;`).
func (c *capture) Query(org string, db string, sql io.Reader) (*featurebase.WireQueryResponse, error) {
tmpBuf := new(strings.Builder)
_, err := io.Copy(tmpBuf, sql)
if err != nil {
return nil, err
}
c.mu.Lock()
c.sqls = append(c.sqls, tmpBuf.String())
c.mu.Unlock()
select {
case c.queryDone <- struct{}{}:
case <-c.asserting:
c.mu.Lock()
c.err = errors.Errorf("unexpected query: %s", sql)
c.mu.Unlock()
}
return &featurebase.WireQueryResponse{}, nil
}

View file

@ -1,31 +0,0 @@
package cli
// Config represents the configuration for the command.
type Config struct {
Host string `json:"host"`
Port string `json:"port"`
OrganizationID string `json:"org-id"`
Database string `json:"db"`
// CloudAuth
CloudAuth CloudAuthConfig `json:"cloud-auth"`
// Kafka
KafkaConfig string `json:"kafka-config"`
HistoryPath string `json:"history-path"`
// CSV (Comma-Separated Values) table output mode.
CSV bool `json:"csv"`
// PSet takes one or more pset arguments of the form: `--pset=VAR[=ARG]`.
PSets []string `json:"pset"`
}
type CloudAuthConfig struct {
ClientID string `json:"client-id"`
Region string `json:"region"`
Email string `json:"email"`
Password string `json:"password"`
}

View file

@ -1,16 +0,0 @@
package cli
import (
"github.com/featurebasedb/featurebase/v3/errors"
)
const (
ErrOrganizationRequired errors.Code = "OrganizationRequired"
)
func NewErrOrganizationRequired() error {
return errors.New(
ErrOrganizationRequired,
"organization required",
)
}

View file

@ -1,79 +0,0 @@
package fbcloud
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/pkg/errors"
)
const (
authFlow = "USER_PASSWORD_AUTH"
cognitoURLTemplate = "https://cognito-idp.%s.amazonaws.com"
)
type cognitoParameters struct {
Email string `json:"USERNAME"`
Password string `json:"PASSWORD"`
}
type cognitoAuthRequest struct {
AuthParameters cognitoParameters `json:"AuthParameters"`
AuthFlow string `json:"AuthFlow"`
AppClientID string `json:"ClientId"`
}
type cognitoAuthResult struct {
IDToken string `json:"IdToken"`
}
type cognitoAuthResponse struct {
Result cognitoAuthResult `json:"AuthenticationResult"`
}
func authenticate(clientID, region, email, password string) (string, error) {
authPayload := cognitoAuthRequest{
AuthParameters: cognitoParameters{
Email: email,
Password: password,
},
AuthFlow: authFlow,
AppClientID: clientID,
}
data, err := json.Marshal(authPayload)
if err != nil {
return "", errors.Wrap(err, "marshaling json")
}
url := fmt.Sprintf(cognitoURLTemplate, region)
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(data))
if err != nil {
return "", errors.Wrap(err, "creating authentication request object")
}
req.Header.Add("Content-Type", "application/x-amz-json-1.1")
req.Header.Add("X-Amz-Target", "AWSCognitoIdentityProviderService.InitiateAuth")
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", errors.Wrap(err, "making request")
}
defer resp.Body.Close()
fullbod, err := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK || err != nil {
return "", errors.Errorf("HTTP status code=%d from Cognito authentication response. reading body: %v, body: '%s'", resp.StatusCode, err, fullbod)
}
var auth cognitoAuthResponse
err = json.Unmarshal(fullbod, &auth)
if err != nil {
return "", errors.Wrap(err, "decoding cognito auth response")
}
return auth.Result.IDToken, nil
}

View file

@ -1,131 +0,0 @@
package fbcloud
import (
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"time"
featurebase "github.com/featurebasedb/featurebase/v3"
"github.com/pkg/errors"
)
// TokenRefreshTimeout is currently hardcoded to be just under the
// Cognito token timeout for cloud which is 15 minutes (I think I
// heard that somewhere anyway). It seems to work.
const TokenRefreshTimeout = time.Minute * 13
type Queryer struct {
Host string
ClientID string
Region string
Email string
Password string
token string
lastRefresh time.Time
}
func (cq *Queryer) tokenRefresh() error {
token, err := authenticate(cq.ClientID, cq.Region, cq.Email, cq.Password)
if err != nil {
return errors.Wrap(err, "getting token")
}
cq.token = token
cq.lastRefresh = time.Now()
return nil
}
// Query issues a SQL query formatted for the FeatureBase cloud query endpoint.
func (cq *Queryer) Query(org string, db string, sql io.Reader) (*featurebase.WireQueryResponse, error) {
if time.Since(cq.lastRefresh) > TokenRefreshTimeout {
if err := cq.tokenRefresh(); err != nil {
return nil, errors.Wrap(err, "refreshing token")
}
}
url := fmt.Sprintf("%s/databases/%s/sql", cq.Host, db)
if db == "" {
url = fmt.Sprintf("%s/sql", cq.Host)
}
client := &http.Client{
Timeout: time.Second * 30,
}
req, err := http.NewRequest(http.MethodPost, url, sql)
if err != nil {
return nil, errors.Wrap(err, "creating new post request")
}
req.Header.Add("Content-Type", "text/plain")
req.Header.Add("Authorization", cq.token)
var resp *http.Response
if resp, err = client.Do(req); err != nil {
return nil, errors.Wrap(err, "executing post request")
}
fullbod, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "reading cloud response")
}
if resp.StatusCode/100 != 2 {
return nil, errors.Errorf("unexpected status: %s, full body: '%s'", resp.Status, fullbod)
}
var sqlResponse featurebase.WireQueryResponse
if err := json.Unmarshal(fullbod, &sqlResponse); err != nil {
return nil, errors.Wrapf(err, "decoding cloud response, body:\n%s", fullbod)
}
return &sqlResponse, nil
}
// HTTPRequest can make an arbitrary http request to the host and
// tries to json unmarshal the response body into v if v is
// non-nil. This is handy for hitting cloud endpoints other than the
// query endpoint which is handled by Query. I don't think this is
// currently used, but I'd like to keep it around for debugging.
func (cq *Queryer) HTTPRequest(method, path, body string, v interface{}) ([]byte, error) {
if time.Since(cq.lastRefresh) > TokenRefreshTimeout {
if err := cq.tokenRefresh(); err != nil {
return nil, errors.Wrap(err, "refreshing token")
}
}
var bod io.Reader
if body == "" {
bod = nil
} else {
bod = strings.NewReader(body)
}
req, err := http.NewRequest(method, fmt.Sprintf("%s%s", cq.Host, path), bod)
if err != nil {
return nil, errors.Errorf("creating request: %v", err)
}
// fmt.Printf("%+v\n", req)
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", cq.token))
if bod != nil {
req.Header.Add("Content-Type", "application/json")
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, errors.Errorf("doing request: %v", err)
}
bodbytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Errorf("reading response body: %v", err)
}
if resp.StatusCode/100 != 2 {
return nil, errors.Errorf("bad status: %s. body: '%s'", resp.Status, bodbytes)
}
if v != nil {
err = json.Unmarshal(bodbytes, v)
if err != nil {
return nil, errors.Errorf("unmarshaling: %v", err)
}
}
return bodbytes, nil
}

View file

@ -1,70 +0,0 @@
package cli
import (
"fmt"
"github.com/featurebasedb/featurebase/v3/cli/batch"
"github.com/featurebasedb/featurebase/v3/cli/kafka"
"github.com/featurebasedb/featurebase/v3/errors"
"github.com/spf13/viper"
)
func (cmd *Command) newKafkaRunner(cfgFile string) (*kafka.Runner, error) {
// Read the kafka config file.
v := viper.New()
v.SetConfigFile(cfgFile)
v.SetConfigType("toml")
err := v.ReadInConfig()
if err != nil {
return nil, fmt.Errorf("error reading configuration file '%s': %v", cfgFile, err)
}
cfg := kafka.Config{}
if err := v.Unmarshal(&cfg); err != nil {
return nil, errors.Wrap(err, "unmarshalling config")
}
if err := kafka.ValidateConfig(cfg); err != nil {
return nil, errors.Wrap(err, "validating config")
}
// Create a new config with defaults.
// Look up fields based on table provided in the config.
wqr, err := cmd.executeQuery(newRawQuery("SHOW COLUMNS FROM " + cfg.Table))
if err != nil {
return nil, errors.Wrap(err, "executing query")
}
scr, err := wqr.ShowColumnsResponse()
if err != nil {
return nil, errors.Wrap(err, "getting show columns from wire query response")
}
// If no fields were provided in the config, use the fields defined on the
// table and assume a 1-to-1 mapping of source to destination.
if len(cfg.Fields) == 0 {
cfg.Fields = kafka.FieldsToConfig(scr.Fields)
} else {
cfg.Fields, err = kafka.CheckFieldCompatibility(cfg.Fields, scr)
if err != nil {
return nil, errors.Wrap(err, "validating config fields")
}
}
idkCfg, err := kafka.ConvertConfig(cfg)
if err != nil {
return nil, errors.Wrap(err, "cleaning config")
}
flds, err := kafka.ConfigToFields(cfg)
if err != nil {
return nil, errors.Wrap(err, "getting fields from config")
}
return kafka.NewRunner(
idkCfg,
batch.NewSQLBatcher(cmd, flds),
cmd.stderr,
), nil
}

View file

@ -1,251 +0,0 @@
package kafka
import (
"fmt"
"time"
featurebase "github.com/featurebasedb/featurebase/v3"
"github.com/featurebasedb/featurebase/v3/dax"
"github.com/featurebasedb/featurebase/v3/idk"
"github.com/pkg/errors"
)
// Config is the user-facing configuration for kafka support in the CLI. This is
// unmarshalled from the the toml config file supplied by the user.
type Config struct {
Hosts []string `mapstructure:"hosts" help:"Kafka hosts."`
Group string `mapstructure:"group" help:"Kafka group."`
Topics []string `mapstructure:"topics" help:"Kafka topics to read from."`
BatchSize int `mapstructure:"batch-size" help:"Batch size."`
BatchMaxStaleness time.Duration `mapstructure:"batch-max-staleness" help:"Maximum length of time that the oldest record in a batch can exist before flushing the batch. Note that this can potentially stack with timeouts waiting for the source."`
Timeout time.Duration `mapstructure:"timeout" help:"Time to wait for more records from Kafka before flushing a batch. 0 to disable."`
Table string `mapstructure:"table" help:"Destination table name."`
Fields []Field `mapstructure:"fields"`
}
// Field is a user-facing configuration field.
type Field struct {
Name string `mapstructure:"name"`
SourceType string `mapstructure:"source-type"`
SourcePath []string `mapstructure:"source-path"`
PrimaryKey bool `mapstructure:"primary-key"`
}
// ConfigForIDK represents Config converted to values suitable for IDK. In
// particular, the idk.RawField is used in parsing the schema in IDK.
type ConfigForIDK struct {
Hosts []string
Group string
Topics []string
BatchSize int
BatchMaxStaleness time.Duration
Timeout time.Duration
Table string
IDField string
Fields []idk.RawField
}
// ValidateConfig validates the config is usable.
func ValidateConfig(c Config) error {
if c.Table == "" {
return errors.Errorf("table is required")
} else if len(c.Topics) == 0 {
return errors.Errorf("at least one topic is required")
} else if len(c.Fields) > 0 {
// We only need to do these checks if any fields are specified at all.
// If no fields are specified, that's ok because then we default to
// using fields based off the existing table.
if len(c.Fields) < 2 {
return errors.Errorf("at least two fields are required (one should be a primary key)")
} else {
var found int
for i := range c.Fields {
if c.Fields[i].PrimaryKey {
found++
}
if c.Fields[i].Name == "" {
return errors.Errorf("a name attribute (which isn't equal to \"\") should exist for all fields")
}
}
if found != 1 {
return errors.Errorf("exactly one primary key field is required")
}
}
}
return nil
}
// ConvertConfig converts a Config to one that suitable for IDK.
func ConvertConfig(c Config) (ConfigForIDK, error) {
// Set a default kafka host in case one isn't provided.
hosts := []string{"localhost:9092"}
if len(c.Hosts) > 0 {
hosts = c.Hosts
}
// Copy all the shared members from Config to ConfigForIDK.
out := ConfigForIDK{
Hosts: hosts,
Group: c.Group,
Topics: c.Topics,
BatchSize: c.BatchSize,
BatchMaxStaleness: c.BatchMaxStaleness,
Timeout: c.Timeout,
Table: c.Table,
}
if len(c.Fields) == 0 {
return out, errors.New("fields cannot be empty")
}
// rawFields wil be the same as c.Fields, but possibly enhanced.
rawFields := make([]idk.RawField, 0, len(c.Fields))
var foundPK bool
for _, fld := range c.Fields {
if fld.PrimaryKey {
out.IDField = fld.Name
foundPK = true
}
typ, quals, err := dax.SplitFieldType(fld.SourceType)
if err != nil {
return out, errors.Wrap(err, "getting base type")
}
rawFld := idk.RawField{
Name: fld.Name,
Type: string(typ),
Path: fld.SourcePath,
}
// If a SourcePath wasn't provided, default to using the field name.
if len(rawFld.Path) == 0 {
rawFld.Path = []string{fld.Name}
}
switch typ {
case dax.BaseTypeInt:
// We don't have to handle min/max because we don't create the table.
case dax.BaseTypeDecimal:
if len(quals) != 1 {
return out, errors.Errorf("expected decimal scale")
}
rawFld.Config = []byte(fmt.Sprintf(`{"scale":%d}`, quals[0]))
case dax.BaseTypeID:
rawFld.Config = []byte("{\"mutex\":true}")
case dax.BaseTypeIDSet:
rawFld.Type = "ids"
case dax.BaseTypeString:
rawFld.Config = []byte("{\"mutex\":true}")
case dax.BaseTypeStringSet:
rawFld.Type = "strings"
case dax.BaseTypeTimestamp:
// No timestamp options are handled for now.
}
rawFields = append(rawFields, rawFld)
}
if !foundPK {
return out, errors.New("primary-key not found in fields")
}
out.Fields = rawFields
return out, nil
}
// ConfigToFields returns a list of *dax.Field based on the IDField and Fields
// in the Config.
func ConfigToFields(c Config) ([]*dax.Field, error) {
// We don't know if a primary key will be found, so we can't set the
// capacity to `len(c.Fields)-1`.
out := make([]*dax.Field, 0, len(c.Fields))
for _, fld := range c.Fields {
if fld.PrimaryKey {
continue
}
typ, quals, err := dax.SplitFieldType(fld.SourceType)
if err != nil {
return nil, errors.Wrap(err, "splitting field type")
}
dfld := &dax.Field{
Name: dax.FieldName(fld.Name),
Type: typ,
}
switch typ {
case dax.BaseTypeDecimal:
if len(quals) != 1 {
return nil, errors.Errorf("expected decimal scale")
}
scale, ok := quals[0].(int64)
if !ok {
return nil, errors.Errorf("invalid decimal scale: %v", quals[0])
}
dfld.Options.Scale = scale
}
out = append(out, dfld)
}
return out, nil
}
// FieldsToConfig returns a Config.Fields based on a list of *dax.Field.
func FieldsToConfig(flds []*dax.Field) []Field {
out := make([]Field, 0, len(flds))
for _, fld := range flds {
out = append(out, Field{
Name: string(fld.Name),
SourceType: fld.FullType(),
PrimaryKey: fld.IsPrimaryKey(),
})
}
return out
}
// CheckFieldCompatibility ensures that the fields provided in the kafka config
// are compatible with the fields in the existing table. It returns a copy of
// the kafka config fields with empty values defaulted to the table field
// configuration.
func CheckFieldCompatibility(cflds []Field, scr *featurebase.ShowColumnsResponse) ([]Field, error) {
out := make([]Field, len(cflds))
for i, cfld := range cflds {
out[i] = cfld
cfldName := dax.FieldName(cfld.Name)
// Primary key field.
if cfld.PrimaryKey {
f := scr.Field(dax.PrimaryKeyFieldName)
if f == nil {
return nil, dax.NewErrFieldDoesNotExist(dax.PrimaryKeyFieldName) // It should be impossible to hit this.
}
if out[i].SourceType == "" {
if f.StringKeys() {
out[i].SourceType = dax.BaseTypeString
} else {
out[i].SourceType = dax.BaseTypeID
}
}
continue
}
// Non primary key fields.
if cfldName == dax.PrimaryKeyFieldName {
return nil, errors.Errorf("field named '%s' must be a primary key", dax.PrimaryKeyFieldName)
}
f := scr.Field(cfldName)
if f == nil {
return nil, dax.NewErrFieldDoesNotExist(cfldName)
}
if out[i].SourceType == "" {
out[i].SourceType = f.FullType()
}
}
return out, nil
}

View file

@ -1,67 +0,0 @@
package kafka
import (
"io"
"time"
fbbatch "github.com/featurebasedb/featurebase/v3/batch"
"github.com/featurebasedb/featurebase/v3/errors"
"github.com/featurebasedb/featurebase/v3/idk"
"github.com/featurebasedb/featurebase/v3/idk/kafka_static"
"github.com/featurebasedb/featurebase/v3/logger"
)
// Runner is a CLI-specific kafka consumer. It's similar to
// idk.kafka_static.Main in that it embeds idk.Main and contains additional
// functionality specific to its use case.
type Runner struct {
idk.Main `flag:"!embed"`
KafkaHosts []string `help:"Comma separated list of host:port pairs for Kafka."`
Group string `help:"Kafka group."`
Topics []string `help:"Kafka topics to read from."`
Timeout time.Duration `help:"Time to wait for more records from Kafka before flushing a batch. 0 to disable."`
Header []idk.RawField `help:"Header configuration."`
}
func NewRunner(cfg ConfigForIDK, batcher fbbatch.Batcher, logWriter io.Writer) *Runner {
idkMain := idk.NewMain()
idkMain.IDField = cfg.IDField
idkMain.Index = cfg.Table
idkMain.Batcher = batcher
idkMain.BatchSize = cfg.BatchSize
idkMain.BatchMaxStaleness = cfg.BatchMaxStaleness
idkMain.SetBasic()
idkMain.SetLog(logger.NewStandardLogger(logWriter))
kr := &Runner{
Main: *idkMain,
KafkaHosts: cfg.Hosts,
Group: cfg.Group,
Topics: cfg.Topics,
Header: cfg.Fields,
Timeout: cfg.Timeout,
}
kr.OffsetMode = true
kr.Main.Namespace = "cli_kafka_runner"
kr.Main.Pprof = "" // don't initialize pprof until we actually use it in tests
kr.NewSource = func() (idk.Source, error) {
source := kafka_static.NewSource()
source.Hosts = kr.KafkaHosts
source.Group = kr.Group
source.Topics = kr.Topics
source.Log = kr.Main.Log()
// source.TLS = m.KafkaTLS
source.Timeout = kr.Timeout
// source.SkipOld = m.SkipOld
source.HeaderFields = kr.Header
// source.S3Region = m.S3Region
// source.AllowMissingFields = m.AllowMissingFields
err := source.Open()
if err != nil {
return nil, errors.Wrap(err, "opening source")
}
return source, nil
}
return kr
}

File diff suppressed because it is too large Load diff

View file

@ -1,136 +0,0 @@
package cli
import (
"fmt"
"io"
"os"
"strings"
)
// query is a collection of queryParts which, when applied together, make up an
// executable SQL query.
type query []queryPart
func (q query) String() string {
var sb strings.Builder
for i := range q {
sb.WriteString(q[i].String())
if i < len(q)-1 {
sb.WriteRune('\n')
}
}
return sb.String()
}
// Reader returns the query as an io.Reader so that it can be passed to, for
// example, http.Post().
func (q query) Reader() io.Reader {
readers := make([]io.Reader, 0, len(q))
for i := range q {
readers = append(readers, q[i].Reader())
}
return io.MultiReader(readers...)
}
// queryPart is an interface representing anything which can use to build up a
// query.
type queryPart interface {
fmt.Stringer
Reader() io.Reader
}
func newRawQuery(s string) query {
return []queryPart{
newPartRaw(s),
}
}
// ////////////////////////////////////////////////////////////////////////////
// raw
// ////////////////////////////////////////////////////////////////////////////
// Ensure type implements interface.
var _ queryPart = (*partRaw)(nil)
type partRaw struct {
raw string
}
func newPartRaw(s string) *partRaw {
return &partRaw{
raw: s,
}
}
func (p *partRaw) Reader() io.Reader {
return strings.NewReader(p.raw + "\n")
}
func (p *partRaw) String() string {
return p.raw
}
// ////////////////////////////////////////////////////////////////////////////
// file
// ////////////////////////////////////////////////////////////////////////////
// Ensure type implements interface.
var _ queryPart = (*partFile)(nil)
type partFile struct {
file *os.File
}
func newPartFile(f *os.File) *partFile {
return &partFile{
file: f,
}
}
func (p *partFile) Reader() io.Reader {
return p.file
}
func (p *partFile) String() string {
return fmt.Sprintf("[file: %s]", p.file.Name())
}
// ////////////////////////////////////////////////////////////////////////////
// batch file
// ////////////////////////////////////////////////////////////////////////////
// Ensure type implements interface.
var _ queryPart = (*partBatchFile)(nil)
type partBatchFile struct {
file *os.File
}
func (p *partBatchFile) Reader() io.Reader {
return p.file
}
func (p *partBatchFile) String() string {
return p.file.Name()
}
// ////////////////////////////////////////////////////////////////////////////
// terminator (i.e. ";")
// ////////////////////////////////////////////////////////////////////////////
// Ensure type implements interface.
var _ queryPart = (*partTerminator)(nil)
type partTerminator struct{}
func newPartTerminator() *partTerminator {
return &partTerminator{}
}
func (p *partTerminator) Reader() io.Reader {
return nil
}
func (p *partTerminator) String() string {
return terminationChar
}

View file

@ -1,108 +0,0 @@
package cli
import (
"fmt"
"io"
"net/http"
"time"
featurebase "github.com/featurebasedb/featurebase/v3"
"github.com/pkg/errors"
)
type Queryer interface {
Query(org string, db string, sql io.Reader) (*featurebase.WireQueryResponse, error)
}
// Ensure type implements interface.
var _ Queryer = (*nopQueryer)(nil)
type nopQueryer struct{}
func (qryr *nopQueryer) Query(org string, db string, sql io.Reader) (*featurebase.WireQueryResponse, error) {
return nil, errors.Errorf("no-op queryer")
}
// Ensure type implements interface.
var _ Queryer = (*standardQueryer)(nil)
// standardQueryer supports a standard featurebase deployment hitting the /sql
// endpoint with a payload containing only the sql statement.
type standardQueryer struct {
Host string
Port string
}
func (qryr *standardQueryer) Query(org string, db string, sql io.Reader) (*featurebase.WireQueryResponse, error) {
url := fmt.Sprintf("%s/sql", hostPort(qryr.Host, qryr.Port))
resp, err := http.Post(url, "application/json", sql)
if err != nil {
return nil, errors.Wrapf(err, "posting query")
}
fullbod, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "reading response")
}
sqlResponse := &featurebase.WireQueryResponse{}
// TODO(tlt): switch this back once all responses are typed
// TODO(twg) 2023/03/01 using json.Number to decode large ints so care must be made
// if err := json.Unmarshal(fullbod, sqlResponse); err != nil {
if err := sqlResponse.UnmarshalJSONTyped(fullbod, true); err != nil {
return nil, errors.Wrapf(err, "unmarshaling query response, body:\n'%s'\n", fullbod)
}
return sqlResponse, nil
}
// Ensure type implements interface.
var _ Queryer = (*serverlessQueryer)(nil)
// serverlessQueryer is similar to the standardQueryer except that it hits a
// different endpoint, and its payload is database-aware.
type serverlessQueryer struct {
Host string
Port string
}
func (qryr *serverlessQueryer) Query(org string, db string, sql io.Reader) (*featurebase.WireQueryResponse, error) {
if org == "" {
return nil, NewErrOrganizationRequired()
}
url := fmt.Sprintf("%s/queryer/databases/%s/sql", hostPort(qryr.Host, qryr.Port), db)
if db == "" {
url = fmt.Sprintf("%s/queryer/sql", hostPort(qryr.Host, qryr.Port))
}
client := &http.Client{
Timeout: time.Second * 30,
}
req, err := http.NewRequest(http.MethodPost, url, sql)
if err != nil {
return nil, errors.Wrap(err, "creating new post request")
}
req.Header.Add("Content-Type", "text/plain")
req.Header.Add("OrganizationID", org)
var resp *http.Response
if resp, err = client.Do(req); err != nil {
return nil, errors.Wrap(err, "executing post request")
}
fullbod, err := io.ReadAll(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "reading response")
}
sqlResponse := &featurebase.WireQueryResponse{}
// TODO(tlt): switch this back once all responses are typed
// if err := json.Unmarshal(fullbod, sqlResponse); err != nil {
if err := sqlResponse.UnmarshalJSONTyped(fullbod, true); err != nil {
return nil, errors.Wrapf(err, "unmarshaling query response, body:\n'%s'\n", fullbod)
}
return sqlResponse, nil
}

View file

@ -1,109 +0,0 @@
package cli
import (
"strings"
"github.com/benhoyt/goawk/lexer"
)
// replacer can replace parts of a string based on some rules and the provided
// map[string]string. For example, the Command can replace strings with values
// in its `variables` map.
type replacer struct {
m map[string]string
}
func newReplacer(m map[string]string) *replacer {
return &replacer{
m: m,
}
}
// replace replaces all instances of the string pattern `:key` with the value at
// m[key]. For example we want something like this:
//
// GIVEN: `start :one,:'two', :"three" ::four ::`
//
// with map
//
// map[string]string{
// "one": "repl1",
// "three": "repl3",
// }
//
// WANT: `start repl1,:'two', "repl3" ::four ::`
func (r *replacer) replace(s string) string {
// If no variables have been added to the map, there's no need to parse the
// string for variable replacement.
if len(r.m) == 0 {
return s
}
line := []byte(s)
lex := lexer.NewLexer(line)
// finger contains the index into line at the start of non-variable text
// that we want to include, as-is in the output.
var finger int
// sb builds the string which will be the final output.
var sb strings.Builder
for {
pos, tok, _ := lex.Scan()
switch tok {
case lexer.COLON:
// last is the last normal character position before the colon.
last := pos.Column - 1
// Get the next byte to see if the colon value is quoted, and if so,
// whether its has single or double quotes.
b := lex.PeekByte()
// padding is the amount of padding we have to consider around the
// variable name. If the variable is not quoted, it doesn't require
// any padding. But if it has quotes, it needs 2 characters of
// paddings to accomodate the quotes.
padding := 0
// quote holds the character to use to quote the final, replaced
// output value. Because the lexer doesn't tell us how a certain
// `string` token was quoted, we need to keep track of that here so
// we can put them back.
quote := ""
switch b {
case byte('\''): // single quote
quote = `'`
padding = 2
case byte('"'): // double quote
quote = `"`
padding = 2
}
pos, tok, key := lex.Scan()
switch tok {
case lexer.NAME, lexer.STRING:
// Write the normal text up to the variable replacement
// position.
sb.Write(line[finger:last])
if v, ok := r.m[key]; ok {
// Write replaced variable with the quotes it had.
sb.WriteString(quote + v + quote)
} else {
// Since the variable was not found in the map, just write
// back what was already there.
sb.WriteString(":" + quote + key + quote)
}
// Reset finger to point to the next position after the
// variable.
finger = pos.Column + len(key) + padding - 1
}
case lexer.EOF:
// Write the remainder of the string and return.
sb.Write(line[finger:])
return sb.String()
}
}
}

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