Commit graph

102 commits

Author SHA1 Message Date
Seebs
54dbeec1af support null/non-null tests for non-BSI fields
There's a lot going on here. First, we were treating "the test is
a Condition" as implying BSI, which it doesn't anymore. Second, the
behavior of conditions was weird and BSI-specific. Third, we had
to propagate these changes and features throughout a bunch of code,
including both the core featurebase code and the DAX replacements/copies
of it, plus the SQL3 layer.

We refactor this so that tests for equality and inequality work for
non-BSI fields, so now if you accidentally use `==` in a Row call
on a non-BSI field, it still works; that's not specific to BSI
fields anymore.

We add a TrackExistence flag to fields, and propagate it through
things like our protobuf code, etcetera, so that we can successfully
create fields. Newly-created fields get this by default, because
we add it unconditionally to them, but the paths that are being
called with existing fields don't add it. So, when we "create"
(really, just load the definition of) a field from something stored
in the schema, we don't add TrackExistence to it, but any path to
creating a new field should.

A time quantum field with NoStandardView will *effectively*
lack TrackExistence.

For sets, mutexes, and time quantums with a standard view, anything
that sets bits will also set a corresponding bit for the record in
a new "existence" view. This allows us to distinguish between an
empty set and a null, and also allows null checks to be constant-time.

When clearing bits, we don't clear existence bits EXCEPT that if
you clear a bit in a mutex, *and the bit actually existed*, we clear
the existence bit. For sets and time quantums, clearing bits never
clears the existence bit.

Deleting records clears the existence bit.

We also add code to the `batch` subpackage to generate suitable
existence field bitmaps and import them. This logic correctly handles
empty sets and nils. The `batch` package does not allow specification
of anything equivalent to clearing a single bit from an existing
record, so we don't have to deal with the mutex complexity in that
case, which is good because it would be impossible.

This requires a number of other subtle changes, such as allowing
new fields to have more than one FieldOption specified for them.

We also drop the handful of implementation bits relating to the
"fullySorted" internal-use-only import flag, which existed only to
support the JSON ingest API, which we've removed.

The most dangerous part of this is that the mutex semantics are
impossible to implement on top of our existing API, because they
require us to know, not how *many* bits we cleared, but which
*specific* bits we cleared. I've implemented this as a new Tx method,
which is almost certainly going to be tech debt one day; if we some
day drop the Import API, we should remove that.

The testing for this is only currently covering the Set/Clear
behavior of PQL, and the Import API. The batch tests haven't been
written yet.

Fields that don't have existence tracking enabled refuse to perform
null/not-null tests. They should also report themselves as having
no null values -- if a record exists, sets in it are considered
empty rather than null.

The SQL3 support requires a number of subtle modifications to both
featurebase and some addon tooling. The essential thing is dropping
the unconditional translation of nil slices to non-nil empty slices
in translateResult, both in the executor and the orchestrator. We
also modify the logic that handles generating results from Extract
calls, to ensure that non-null sets get an empty slice created for
them even if they never have any values assigned.

The expected results for some tests are different now; we expect to
get nil slices, rather than 0-length non-nil slices, for fields which
were never written for a given record. Most tests were not changed.
(In every case, if a test was failing, I actually checked the logic
before changing expected results. This required a lot of tracking down
of edge cases.)

The batch package now rejects as an error attempts to clear single
bits from mutex fields, because so far as I can tell it's simply
impossible to have a roaring import that specifies the correct semantics
there; you can't tell whether to clear an existence bit without
access to the currently-set bits, which the batch API doesn't have.
We already supported the special case of specifying a clear value
of nil for clearing a mutex field; now that is the only allowed
value for a mutex field to have in row.Clears.

We change the logic for fixing up incoming view names (in two places)
to stop assuming that any view in a time field other than "" that does
not have viewStandard as a prefix is a partial time quantum name that
should have "standard_" prepended to it. This allows us to submit
bitmaps for "existence" to time quantum fields and not have them
silently transformed into "standard_existence" because that's what we'd
do with "202203".

We drop the field ClearBits method, which was totally unused.

We drop the sliceDifference function, which was used in a previous
mutex implementation and hasn't been used in ages, and the test
case for it, and the helper function used only by that test case.
2023-03-24 16:01:09 -05:00
Travis Turner
c79cc3b7db
linter: prealloc (#2315) 2023-03-11 21:19:05 -06:00
Joe Friedrich
7da67caa99 fix go deps, add lattice 2023-01-20 02:11:00 +00:00
pokeeffe-molecula
a1fc6d04a1 introduce performance counters and system table fanout, plus refactor metrics (#2363)
* performance counters

* first cut of perf counters and system table fanout and a wire protocol
* significantly refactored prometheus support; removed statsd and exprvar

* removed node_id

* put dax subquery test back

* Change Translator.TranslateFieldIDs method to take a dax.TableKeyer

There are a bunch of other calls to the Translator interface methods
with currently take an `index string`, and those need to be converted to
dax.TableKeyer as well. But I need to review each call, because in at
least one place I noticed one being called with `result.Index` instead
of with the qtbl available. And I don't yet know how those could be
different.

Co-authored-by: Travis Turner <travis@molecula.com>
(cherry picked from commit 7f6ea0e6e5)
2023-01-19 21:35:02 +00:00
Matthew Jaffee
0f67a0c432 first cut at automatic snapshotting
- had to make sure we don't snapshot until directive is fully applied
on a computer... otherwise there's races between loading the files and
truncating the write log.

- added a dirty bit to resources and a bool return to incrementing the
write log... don't snapshot if it returns false because that means
there's been no writes. (but make sure you close the storage transaction!)

- added the actually snapshotting routine which just fires every
<timeout> and serially snapshots everything.

- tweaked some logging

- added ability to get all tables in an org/db or literally all. I
think I just needed the "literally all", but it was natural to allow
it to be scoped to org or DB as well.

(cherry picked from commit b8b08bc9eb)
2023-01-10 23:26:29 +00:00
Matthew Jaffee
da85614c24 set transactions to writable: false for Max/Min/Value calls. these were mistakenly set to true during cleanup
(cherry picked from commit 53a8f58e91)
2023-01-10 23:22:58 +00:00
Seebs
ea69b0637d significant refactor of test setup and teardown
We centralize the creation paths for test indexes, fields,
etcetera so they all have a common path, all using standard
test holders. There's still two versions, one for test.* functions
and one for internal. They do share a TestHolderConfig though.

Large hunks of the related APIs are simplified/streamlined.
* Fragments are always created with a Field and don't need
  a workaround in case they don't have it.
* Creation of test fragments, etc., use optional FieldOptions
  but don't specify names because they're all using new holders
  for each thing created anyway. This dramatically reduces
  the complexity of the calls.
* test fragments are created inside test views which are created
  inside test fields, etcetera, so everything is using the same
  logic; test views aren't bypassing the other layers, they're
  creating themselves normally within a field.
* Quite a few things now use the standard runtime/production
  logic instead of being custom workarounds; for instance, instead
  of `mustOpenMutexFragment` creating a fragment and then creating
  a mutex vector for it, we just create a mutex-typed field and
  have the normal runtime code do this.
* Similarly, we now use the same field creation logic that production
  does, instead of having our own test-only thing that validates
  field names directly, so our test that we're validating field names
  is actually testing the runtime code. Yay.
* fragSpec goes away. it was a replacement for fragProxy which existed
  to solve memory allocation problems but replaced them with interface
  overhead problems. Now we just have pointers to things and maintain
  valid data structures.
* Many panics are now Fatal or Fatalf calls.
* Some specific bugs fixed, like a cluster which was requested and
  then had its first node directly overwritten, which isn't valid with
  shared clusters.
* Drop the temp-dir test flag and TempDir variable, we can just use
  $TMPDIR.
* Drop a benchmark of "write file to disk" that was purely a benchmark
  of file write speed, not a benchmark of rendering the data that needs
  to be written.
* Drop the unused "flags" parameter to fragment creation, which was
  only used back when we changed the BSI format.
* Use holder.Txf() rather than index.Txf(). The TxFactory has to be
  holder-level anyway, referring to it via the index is misleading.
* Test holders automatically close themselves and delete themselves,
  we remove various other things that thought they were responsible
  for deleting themselves.
2022-09-30 11:25:27 -07:00
Seebs
e8e655cf05 continue removing Tx parameters to view-type functions
A few view functions were taking a Tx, which had to be shard-specific,
but that's sort of awkward -- the view is inherently not shard-specific,
so it should be handling sharding internally.

There were also a couple of remaining obsolete checks for whether a
Tx was nil, at least two of which were in contexts where it absolutely
can't be. Remove all of them, and also the function itself.
2022-09-30 11:25:27 -07:00
Seebs
964e7d86c8 kill everything that tries to pass nil tx to field/view things
The "field/view will just synthesize a tx" behavior is awful and
also hides a number of fundamental flaws. We distinguish between
"we really do mean to work on a single shard here" and "we intend
to work on the whole field or view", and the latter now take
Qcx instead of Tx.

This eliminates a lot of very weird cases where we checked for
nil Tx and synthesized them, and also gets us away from
field and view taking Tx parameters when no possible Tx
can be constructed which is valid, because Tx are inherently
shard-specific at this time.
2022-09-30 11:10:47 -07:00
Fletcher Haynes
da9b57bd45 Updated dependency paths to reflect new repo location 2022-09-06 09:39:22 -07:00
Fletcher Haynes
eb06bb50ae Updated code to latest version for open-sourcing. 2022-09-02 13:23:39 -07:00
Seebs
e5ffed35a4 use labeled targets for break statements
break in a select in a for terminates the current case of the
select, but does not terminate the for loop. The worker queue
implementations for opening indexes/fields/views all suffered
from the same issue here.

Also fix a `<= 0` on a uint value.

All hail staticcheck.
2019-10-11 14:44:25 -05:00
Ben Johnson
c7c9c1e1d7
v2.0.0
Co-authored-by: Cody Soyland <codysoyland@gmail.com>
2019-10-08 14:56:17 -06:00
Seebs
2d9ca0888f Use work queue for opening/closing fragments
When starting up, we can have a large number of views, each
with some number of fragments, and by default these were being
opened sequentially. There's no real benefit to that; they're
all nicely independent from each other and don't need much
locking, so we implement a trivial semaphore and launch the
operations asynchronously. We also combine them into
errgroups.

Similarly, we do this for fields and views, capping the number
of fields (or views) opened in parallel to avoid hitting a
system-wide limit on threads created (oops). Note that the
limits are shared, not multiplicative; we cap this fairly
arbitrarily at 8 fields being opened, and 16 views being opened,
at a time, but NumCPU*2 fragments being opened by those views.

This dramatically increases CPU load during startup, but doesn't
seem to significantly increase total CPU time, it just scales
much better on machines with lots of cores.
2019-07-25 16:03:24 -05:00
Seebs
4b657c1962
use a queue for snapshot operations
As the size of a fragment grows, the cost of snapshots
increases; with a large fragment getting a lot of large writes,
every write will trigger a snapshot, while any other writes have
to wait for that snapshot before they, too, can trigger a snapshot.

To address this, we introduce a background queue of snapshots.
In general, operations which were omitting their ops log writes
and just snapshotting no longer do; they emit an ops log. This does
mean that, in some cases, the ops log is written and then a snapshot
takes place essentially immediately, which costs us some performance.
However, that only actually happens under very light load; under
heavier load, there's generally going to be multiple writes coalesced
into each snapshot, and the ops log writes for them will be much
cheaper than a full snapshot.
2019-07-01 13:16:02 -05:00
Seebs
b369dace69
remap storage on reopen, instead of remarshalling it
When we do a snapshot, we may end up with containers which are
mmapped to the old file, and containers which have allocated storage
identical to the contents of the new file. It would be nicer if they
were mapped to it. But unmarshalling the entire file is expensive.

Instead, we remap it. (Or, if we couldn't mmap it, just make sure
the old stuff is no longer using the old storage space before we
munmap it.)
2019-07-01 13:16:02 -05:00
Seebs
b2fb51be1f view.deleteFragment should hold the lock while altering fragments
If you delete a fragment while something else is calling allFragments,
you can cause a race. This almost never happens in practice, because
deleting fragments is rare, and the only likely overlap would be with
something like the holder cache flush, which only happens once a
minute. But if you slowed down the rest of the tests enough, and ran
with -race, you might see it.

We check v.fragments directly instead of calling v.Fragment, because
v.Fragment also needs a lock, and we don't want to drop the lock between
the check for existence and the delete operation.
2019-06-26 16:14:37 -05:00
Cody Soyland
9fb6d84d80 Remove extraneous stat tags to improve prometheus performance 2019-06-10 08:18:30 -05:00
Seebs
388efd0e73 use os.Rename semantically correctly
So it's true that Rename's arguments are called oldname/newname, and
you want to rename from the previous name to the new name.

And it's true that we're calling Rename on oldPath and newPath.

But in our case, oldPath is the name the fragment file had before
the operation, and newPath is the name of the temporary file
created during the operation. Use tmpPath and frag.path to make
the semantics clearer.
2019-06-04 10:00:16 -05:00
Ben Johnson
7ed9fba335
Unbounded BSI w/ sign magnitude
This commit implements BSI with variable bit depth using a
sign magnitudeto indicate whether a value is positive or negative.
This also rearranges the existence bit to be the first bit instead
of the last bit.
2019-05-17 15:52:17 -06:00
Travis Turner
875c95b2c3
add more Debugf() statements to the holder open process 2019-04-30 15:16:10 -05:00
Matt Jaffee
3a07abdeae
remove shard validation stuff
it seems to have a bug where there is some race on cluster startup
which can cause it to think that the node doesn't own any shards.
2019-04-22 17:36:40 -05:00
Seebs
77d49ded64 so much lint
So with the switch to a new linter, we get a lot of new warnings,
and the majority of them are harmless probably, but a few might be
real. Variously just use _ to suppress warnings, or report errors.
There's probably things here that deserve better fixes, but we can
always revisit it.
2019-04-16 12:07:18 -05:00
Todd Gruben
418a8788ed
gofmt missing 2019-03-20 22:04:20 -05:00
Todd Gruben
8edd2b3d13
applied travis suggestions 2019-03-20 22:04:20 -05:00
Todd Gruben
38de65eac0
only load shards that are applicable to node 2019-03-20 22:04:19 -05:00
Seebs
dde6954de4 view.go: deal with races in fragment creation
There existed a case where two goroutines would try to
CreateIfNotExists the same fragment, and the first would
create it, but not put it in the fragments table, then
drop the lock, try to broadcast a message, and if it
succeeded then populate the fragments table. The second
would come along during the broadcast, not find an
entry, try to create one, and fail because the file was
already locked.

Basic problem: At least one test in server/ will fail
if we don't delay to send out broadcast messages. Everything
will lock up if we can wait forever (or even just a very
long time) for the message broadcast. We don't ever want
to have an inconsistent state -- so we don't want to either
fail to get a fragment when one's been created, or get one
that's about to be deleted if the broadcast fails.

So, creation and stashing in the fragments table is
atomic and immediate. After that, we optimistically attempt
to broadcast. If we fail, we fail. We delay up to about
50ms for the broadcast to be done, but after that return
anyway. This way, if things are going well everything
works, and if there's unexpected delays, things work except
some nodes in a cluster may not know about available
shards on other nodes sometimes. But that would have
happened anyway. A proper fix is beyond the scope of this
patch.
2019-02-21 16:43:19 -06:00
Matt Jaffee
9d4a6e2be7
don't add the fragment and then remove it 2018-12-11 15:45:44 -06:00
Matt Jaffee
7304258967
improve comments 2018-12-11 15:45:44 -06:00
Matt Jaffee
4b786e1057
attempt to fix deadlock by releasing view lock before broadcasting CreateShard 2018-12-11 15:45:44 -06:00
Seebs
a203313143 move Logger and Stats to their own packages
I'd like to add stat tracking to Roaring, which means it
has to be able to import the stats package, which means
stats has to be a package rather than part of the pilosa
package. If stats stops being in pilosa, it still needs
a way to import logger, so logger also has to leave the
pilosa package. Then everything using them needs to import
them and use package selectors on their names.

This doesn't actually add the stats support to roaring,
it just makes it so there's a way to import the stats
code from something in the roaring package.
2018-11-15 15:10:44 -06:00
Travis Turner
dbe4197871
ensure view closes fragment on broadcast error 2018-10-01 11:22:35 -05:00
Travis Turner
4f17dbdbf1
add support for Bool fields
prevent import of non-boolean row values to bool fields
2018-09-21 09:25:41 -05:00
Ben Johnson
f4c9c0fed3
Maintain available shards set.
This commit removes the previous `MaxShard` tracking and replaces
it with an `Available Shards` set tracking. This allows sparse shard
tracking without implicitly tracking all shards in between.
2018-08-22 07:57:58 -06:00
Cody Soyland
e9523063b5 Fix linter issues: unused 2018-07-20 10:33:29 -05:00
Travis Turner
06f5d04f1c
swap out mapVector for rowsVector in mutex fields 2018-07-19 14:01:30 -05:00
Travis Turner
a07ed360ab
add mutex field type 2018-07-19 14:01:29 -05:00
Matt Jaffee
2cec75e399
add proto encoding subpackage and use for send and receive message 2018-07-05 12:00:42 -05:00
Matt Jaffee
cd8c63c125
tests passing 2018-07-04 21:43:18 -05:00
Matt Jaffee
2202bf467b
unexport view stuff 2018-07-02 17:18:00 -05:00
Matt Jaffee
cff01f46c2
unexport fragment.go stuff 2018-07-02 14:50:33 -05:00
Matt Jaffee
9ea300da20
unexport broadcaster 2018-07-02 08:34:58 -05:00
Matt Jaffee
6ff792c164
remove dead code (deadcode) 2018-06-29 08:12:04 -05:00
Travis Turner
e17096328d
Merge branch 'develop' into slice-to-shard 2018-06-28 15:38:40 -05:00
tgruben
a81e01b019
Merge branch 'develop' into clearbit-notime 2018-06-28 14:12:29 -05:00
Travis Turner
5dd7a9556a
rename slice to shard 2018-06-28 14:07:07 -05:00
Todd Gruben
fcecb871cf naming adjustments; code cleanup 2018-06-28 12:41:39 -05:00
Todd Gruben
4970083d4d refactored strategy for time based clearbit 2018-06-27 18:15:44 -05:00
Todd Gruben
35af580183 expanded views to contain viewType for special handling 2018-06-26 10:54:06 -05:00
Travis Turner
50794bf63b
move fieldOptions unmarshal to the handler
validate fieldOptions in http package
2018-06-25 15:14:22 -05:00