Commit Graph

315 Commits

Author SHA1 Message Date
Alex Roitman fe0216c42c Restore previous behavior where non-existing fields are treated as zero-value. 2020-04-09 09:54:47 -07:00
Alex Roitman f3cc365d24 Pre-allocate where and wherein arrays. 2020-04-09 09:36:12 -07:00
Mike Poindexter 042582aef3 Update comment 2020-04-08 11:38:12 -07:00
Mike Poindexter 2a4272c95f Improve kNN behavior
The current KNN implementation has two areas that can be improved:

- The current behavior is somewhat incorrect. When performing a kNN
query, the current code fetches k items from the index, and then sorts
these items according to Haversine distance. The problem with this
approach is that since the items fetched from the index are ordered by
a Euclidean metric, there is no guarantee that item k + 1 is not closer
than item k in great circle distance, and hence incorrect results can be
returned when closer items beyond k exist.

- The secondary sort is a performance killer. This requires buffering
all k items (again...they were already run through a priority queue in)
the index, and then a sort. Since the items are mostly sorted, and
Go's sort implementation is a quickSort this is the worst case for the
sort algorithm.

Both of these can be fixed by applying a proper distance metric in
the index nearby operation. In addition, this cleans up the code
considerably, removing a number of special cases that applied only
to NEARBY operations.

This change implements a geodetic distance metric that ensures that
the order from the index is correct, eliminating the need for the
secondary sort and special filtering cases in the ScanWriter code.
2020-04-07 20:10:58 -07:00
Alex Roitman 34cb2affdc Add clipby subcommand to INTERSECTS/WITHIN 2020-04-03 16:49:06 -07:00
Josh Baker f02dee3db2
Merge pull request #545 from tidwall/index-kind-geometry-nooverride
Match geometry indexing to server config
2020-04-02 08:15:38 -07:00
Josh Baker 12a98c53e4
Merge pull request #543 from rshura/fix-clip-empty-rings
Skip empty rings when clipping polygons.
2020-04-02 08:15:14 -07:00
tidwall 951fc58e02 Match geometry indexing to server config 2020-03-25 15:35:31 -07:00
Alex Roitman d5132a9eae Map field names to array indices in scanwriter, once per query. 2020-03-25 15:15:06 -07:00
Alex Roitman 9e7766b346 Array of values instead of map for whereins. 2020-03-25 15:14:51 -07:00
Alex Roitman 27c6980f82 Copy array and only loop if we need to pad. 2020-03-25 15:14:37 -07:00
Alex Roitman 91ef777771 Add benchmark for fieldMatch. 2020-03-25 14:49:21 -07:00
tidwall 5162ac5fd7 Stable sort roam notifications 2020-03-25 13:01:11 -07:00
tidwall a99df2892a Fixed false faraway notifications 2020-03-25 12:47:55 -07:00
Mike Poindexter 625a83f81e Add scan benchmark, with/without fields benchmarks 2020-03-25 11:09:50 -07:00
Mike Poindexter 9a5d608c21 Switch field storage to an array vs map 2020-03-25 10:24:02 -07:00
Alex Roitman c4b1dd3a72 Skip empty rings when clipping polygons.
Add a test for skipping empty rings.
2020-03-23 16:11:46 -07:00
tidwall ff48054d3d Fixed a missing faraway event for roaming geofences
This commit fixes a case where a roaming geofence will not fire
a "faraway" event when it's supposed to.

The fix required rewriting the nearby/faraway detection logic. It
is now much more accurate and takes overall less memory, but it's
also a little slower per operation because each object proximity
is checked twice per update. Once to compare the old object's
surrounding, and once to evaulated the new object. The two lists
are then used to generate accurate "nearby" and "faraway" results.
2020-03-22 11:54:56 -07:00
tidwall b482206894 Minimize sorting of collection fields 2020-03-22 07:58:03 -07:00
Josh Baker 0997f2e82b
Merge pull request #534 from rshura/optimize-scanwriter
Avoid sorting fields for each written object.
2020-03-22 06:33:33 -07:00
tidwall 65943e8f1a Fixed DEL geofence notifications missing "key" field
Closed #538
2020-03-21 17:48:31 -07:00
Mike Poindexter 84cabd77f9 Fix a concurrent write/read on the server conn map 2020-03-20 16:47:13 -07:00
Alex Roitman 5faccc3b4c Avoid sorting fields for each written object. 2020-03-03 13:39:43 -08:00
tidwall 66af8ab094 Fix tile38-cli from freezing with non-quoted geojson
This commit addresses an issue that began on 1.19 where the
deprecated tile38 native line protocol was removed in favor of
the more robust resp protocol. In turn the tile38 cli required
that all args are quoteless or quote escaped.

The commit ensures that the server returns the correct error
message and also loosens the strictness of the need for quoted
arguments in the tile38-cli.

fixes #513
2019-12-11 11:08:33 -07:00
tidwall fa4a1dd436 Added .github directory 2019-11-17 09:00:45 -07:00
tidwall 474ff810c0 Fixed panic on AOFSHRINK
closes #508
2019-11-17 07:25:25 -07:00
tidwall c084aeedc2 Code cleanup
This commit cleans up various Go code in the internal directory.
- Ensures comments on exported functions
- Changes all *Server receiver in all files to be "s", instead
  of mixed "c", "s", "server", etc.
- Silenced Go warnings for if/else with returns.
- Cleaned up import ordering.
2019-10-30 10:17:59 -07:00
tidwall feba00040e Added TLS support for Nats webhook provider
Use the `tls=1` and the set the the `tlscert` and `tlskey` query
string params. The cert and key files must be on the tile38
server and the Nats server must be started using the same files.

nats://54.12.34.121:4222/fleet?tls=1&tlscert=cert.crt&tlskey=cert.key
2019-10-30 08:17:40 -07:00
Josh Baker 981d9ece42
Merge pull request #503 from JordanArmstrong/fix-stats-cpu
Fix fprintf type error in stats_cpu.go for non-linux/darwin builds
2019-10-29 15:29:38 -07:00
Josh Baker 90c2474e3d
Merge pull request #501 from JordanArmstrong/strict-jset-numbers
Strictly check if values passed to JSET are numbers
2019-10-29 15:28:40 -07:00
tidwall 23b016d192 Fix excessive memory usage for objects with TTLs
This commit fixes an issue where Tile38 was using lots of extra
memory to track objects that are marked to expire. This was
creating problems with applications that set big TTLs.

How it worked before:

Every collection had a unique hashmap that stores expiration
timestamps for every object in that collection. Along with
the hashmaps, there's also one big server-wide list that gets
appended every time a new SET+EX is performed.

From a background routine, this list is looped over at least
10 times per second and is randomly searched for potential
candidates that might need expiring. The routine then removes
those entries from the list and tests if the objects matching
the entries have actually expired. If so, these objects are
deleted them from the database. When at least 25% of
the 20 candidates are deleted the loop is immediately
continued, otherwise the loop backs off with a 100ms pause.

Why this was a problem.

The list grows one entry for every SET+EX. When TTLs are long,
like 24-hours or more, it would take at least that much time
before the entry is removed. So for databased that have objects
that use TTLs and are updated often this could lead to a very
large list.

How it was fixed.

The list was removed and the hashmap is now search randomly. This
required a new hashmap implementation, as the built-in Go map
does not provide an operation for randomly geting entries. The
chosen implementation is a robinhood-hash because it provides
open-addressing, which makes for simple random bucket selections.

Issue #502
2019-10-29 11:19:33 -07:00
Jordan Armstrong 324b3b06d9 Fix go vet error in stats_cpu.go for non-linux/darwin builds 2019-10-28 22:39:27 -03:00
Jordan Armstrong e0eca0d55e Replace isJsonNumber with version from gjson 2019-10-28 22:35:44 -03:00
Josh Baker df477bf3f4
Merge pull request #464 from rshura/area-expression
Add area expressions.
2019-10-28 13:45:10 -07:00
tidwall 10f7bfc445 Fix invalid pubsub format for json output
This commit fixes a bug that causes bad formatting for geofence
notifications when a client's output is set to JSON.

closes #499
2019-10-28 12:51:44 -07:00
Jordan Armstrong 41fb410e2e Strictly check if values to JSET are numbers
Fixes #493
2019-10-26 23:37:48 -03:00
tidwall b092cea0d2 Use WaitTimeout for MQTT 2019-10-08 11:13:18 -07:00
tidwall 3d9915e055 Merge branch 'master' of https://github.com/neterror/tile38 into neterror-master 2019-10-08 11:10:16 -07:00
Plamen Todorov 6b82fd94eb randomize mqtt client id with math/rand
Cryptographic randomizer is not required for mqtt clientIds. They
should be unique only among currently selected clients.
2019-10-08 20:24:31 +03:00
tidwall 87185319b2 Fix JSET cancels expiry
issue #498
2019-10-08 09:45:46 -07:00
tidwall 13c206fe05 Fixed data race for hooks with ttls
issue #497
2019-10-08 09:26:55 -07:00
Plamen Todorov c3b9a689bb Use uuid as mqtt clientId
Use crypto/random to generate unique mqtt client id. The tile38 prefix
makes the connections easily identifiable in the mqtt broker logs.
2019-10-08 09:34:31 +03:00
Plamen Todorov fb2aef2ce6 MQTT clientId should be unique
Each mqtt hook establishes separate connection to the MQTT broker. If
their clientIds are all equal the MQTT broker will disconnect the clients - the
protocol does not allow 2 connected clients with the same name
2019-10-06 22:15:06 +03:00
tidwall 639f6e2deb Replaced boxtree for rbang 2019-09-12 18:42:53 -07:00
tidwall 3d96b17258 GC pauses be gone 2019-09-04 12:47:30 -07:00
tidwall 2571ce5106 Minimize AOF buffer releases 2019-09-03 17:01:26 -07:00
tidwall 4bd6b4b838 Moved ReadMemStats into a background polling function
This will keep profile commands such as SERVER and STATS from
stopping the world.
2019-09-03 16:57:49 -07:00
tidwall e167e88e8f removed diag 2019-09-03 16:39:51 -07:00
tidwall b6884fce63 diagnostics 2019-09-03 16:35:42 -07:00
tidwall aedd972516 Fixed invalid count for nearby queries
closes #489
2019-08-22 15:53:37 -07:00
saltatory ec5a5342a2 Added RLock on connections map 2019-08-09 08:48:23 -07:00
tidwall f7888c1edf Fixed malformed json for chans command
Mentioned by ds2xor on Slack
2019-08-03 10:10:28 -07:00
Alex Roitman b9e2c67933 Fix lua pool pruning 2019-08-01 11:55:52 -07:00
Alex Roitman dd09ffbe13 Fix parser for multiple negations. 2019-06-14 10:02:26 -07:00
Alex Roitman 7c541949b1 Unnecessary code. 2019-06-13 14:12:42 -07:00
Alex Roitman eb214cb889 Better naming and comments. 2019-06-13 13:33:07 -07:00
Alex Roitman 2d83e18934 Add expression errors test. Make parser stricter. 2019-06-13 13:10:47 -07:00
Alex Roitman 0c3a5d02ca Fixes 2019-06-13 12:04:04 -07:00
Alex Roitman 3ded4e3a44 Refactor using method expressions, to avoid repeating code. 2019-06-13 10:56:33 -07:00
Alex Roitman 81f57ba6f6 Fix one case in expression/expression tests 2019-06-13 09:53:17 -07:00
Alex Roitman 496ace25d3 Refactoring/cleanup/fixes. 2019-06-11 17:13:33 -07:00
Alex Roitman d0ca579f5c Add area expressions.
Add parser.
Hook up to test command.
Add tests for expressions in test command.
2019-06-10 14:47:42 -07:00
Josh Baker aa73fcd17b Added unsubscribing from active channel
related #448
2019-06-04 13:49:32 -07:00
Josh Baker ac3bac7d16
Merge pull request #454 from olevole/master
log: fix typo in Fatalf func
2019-06-04 08:39:48 -07:00
Melissa Baker 46f5d2d224 Fixed nearby json field results showing wrong data
issue #453
2019-05-28 12:17:59 -07:00
Oleg Ginzburg 80b2d4c5a8 log: fix typo in Fatalf func
fixed for x1b[31m[FATA] output
2019-05-17 13:24:05 +03:00
tidwall 3ae59274e3 Removed evio option 2019-04-26 11:50:49 -07:00
Alex Roitman cbf10b7472 Rework timeouts to allow prepending any command with the TIMEOUT seconds 2019-04-25 14:15:53 -07:00
Alex Roitman 49111a4dce Add timeouts for lua scripts 2019-04-24 17:00:52 -07:00
Alex Roitman 31525487c3 Add timeout tests. Fix a bug. 2019-04-24 13:20:57 -07:00
Alex Roitman e514a0287f Add timeout subcommand to scan/search commands.
Use per-query timeout for those commands, if it was given.
2019-04-24 12:02:39 -07:00
tidwall 0aecef6a5c Added TIMEOUT command 2019-04-24 05:09:41 -07:00
tidwall bb33467da1 Fix crash with fence ROAM
closes #440
2019-04-23 11:16:55 -07:00
tidwall 7e006af713 Add verbose messaging for aws/sqs 2019-03-17 18:40:34 -07:00
tidwall 8c69fbff31 Fixed clients blocking while webook sending
Closes #428
2019-03-16 15:43:33 -07:00
Josh Baker 55a175c767
Merge pull request #430 from tidwall/sqs-update
SQS Credentials Updates
2019-03-14 12:50:53 -07:00
tidwall 762607dc0a Added geofence delivery counter 2019-03-14 11:23:23 -07:00
tidwall 5335aec942 Allow for standard SQS URLs
Both now work:

https://sqs.us-east-1.amazonaws.com/349840735605/TestTile38Queue
sqs://us-east-1:349840735605/TestTile38Queue
2019-03-13 15:41:49 -07:00
tidwall ec57aaee1a Support SQS ChainProvider by default.
Unless the credpath query param is provided, the SQS credidentails
will be automatically chosen from one of the following:

- ~/.aws/credidentials
- Environment variables
- EC2 Role
2019-03-11 10:49:25 -07:00
tidwall 5333fab870 Recycle aof buffer 2019-03-10 10:48:14 -07:00
tidwall 95a5556d61 Added periodic yielding to iterators 2019-03-05 11:33:37 -07:00
tidwall fc3e8b4359 Fix nearby with match query invalid results
closes #421
2019-03-01 06:55:26 -07:00
Steven Wolfe fd20190bff Verify hook names match for processing 2019-02-22 15:58:13 -07:00
Parham Alvani e0ddd5e6a6 Adds Server command for lua scripts. 2019-02-17 13:28:20 +03:30
tidwall 99508c9af7 Allow slashes for MQTT topic, fixes #410 2019-02-12 06:58:43 -07:00
tidwall 30f903bd51 Require properties member for geojson features 2019-02-12 06:49:13 -07:00
tidwall fb7259b10b Changed clip errors and json result type 2019-02-12 05:33:20 -07:00
tidwall 62f44ed055 Merge branch 'master' of https://github.com/tidwall/tile38 2019-02-12 05:06:10 -07:00
Josh Baker 6fffa75b58
Merge pull request #409 from rshura/test_cmd
Test command
2019-02-12 05:05:50 -07:00
tidwall 14b616b150 More test fields 2019-02-11 15:42:35 -07:00
tidwall 92c1ce8ef9 Update tinybtree dep 2019-02-11 13:39:29 -07:00
Alex Roitman c849ab19ac Implement test command 2019-02-08 13:57:29 -08:00
Alex Roitman a300cb2bf8 Typo causing a bug in polygon clipping 2019-02-08 13:56:43 -08:00
Alex Roitman f7ba43360e Typo in error messages 2019-02-08 13:56:07 -08:00
Steven Wolfe 628e0882b8 Allow 201 & 202 status code on webhooks 2019-02-05 14:49:01 -07:00
Josh Baker bfa35d5db9
Merge pull request #404 from tidwall/Adding-more-replication-data-to-INFO-response
Adding more replication data to INFO response
2019-01-24 11:53:13 -07:00
tidwall 88595c35b0 Added small logo 2019-01-19 10:45:31 -07:00
Steven Wolfe 79c902efbf Adding more replication data to INFO response 2019-01-18 14:51:20 -07:00
Steven Wolfe ffd8ca915c Testing for valid INFO and CLIENT Json output 2019-01-15 11:08:19 -07:00
Steven Wolfe 0740ca13cd JSON Output for INFO and CLIENT 2019-01-14 15:29:29 -07:00
Steven Wolfe 4392fb44bd Fixing KEYS command and tests 2019-01-14 11:06:12 -07:00
Steven Wolfe 4ad2e920f5 Merge branch 'sl/requirevalid' of https://github.com/stevelacy/tile38 into stevelacy-sl/requirevalid 2019-01-10 12:49:48 -07:00
Steve Lacy d730e660cf
Return false from Valid() 2019-01-10 12:32:47 -07:00
Steve Lacy 1a8993feaf
Add RequireValid env variable and parse options 2019-01-10 09:36:58 -07:00
Steven Wolfe eb2ff76f86 Sorting > 1 and docs 2019-01-09 10:35:50 -07:00
Steven Wolfe a5fbcf5f15 Ensuring channel publish order 2019-01-09 00:23:53 -07:00
tidwall ed31f2bd4c Merge branch 'lua/distance_to' of https://github.com/rshura/tile38 into rshura-lua/distance_to 2019-01-06 10:29:59 -07:00
tidwall d7d0baa954 Fix roam fence missing 2019-01-06 10:23:57 -07:00
Alex Roitman 5e215c247d Add distance_to function to the tile38 namespace in lua.
distance_to(lat_a, lon_a, lat_b, lon_b) returns distance in meters between points A and B.
2019-01-04 14:57:00 -08:00
Alex Roitman e1c82e17f7 Refactor to be more consistent with redis responses. 2018-12-28 14:46:54 -08:00
Alex Roitman 01a7dda2a1 Add RENAME and RENAMENX commands. 2018-12-27 17:15:53 -08:00
tidwall 4a6764fd2a Updated readme 2018-12-13 18:56:18 -08:00
tidwall 1c972ad578 Fix massinsert dev call 2018-12-03 15:35:32 -07:00
tidwall f795567f9c Merge branch 'master' into Ext-server-stats 2018-11-29 15:22:48 -08:00
tidwall 6b2fc1f37f Fix multiple matches on different key hooks 2018-11-29 15:15:26 -08:00
Steven Wolfe 8619d35a5b Adding ext to SERVER command for more info 2018-11-26 14:19:08 -07:00
Josef Simonson e17d15f008 Kafka endpoint to create a key for each message based on key and id 2018-11-26 13:05:30 +01:00
tidwall 8b29e98359 Optimized spatial index for fences 2018-11-23 18:15:14 -07:00
tidwall f2c217c216 Refactor and comment command details 2018-11-23 15:53:33 -07:00
tidwall 1197cca40c Avoid extra broadcasts 2018-11-23 15:38:49 -07:00
tidwall 8906d8e65a Refactor and consolidate variables 2018-11-23 02:14:26 -07:00
tidwall 37531f9350 Removed unused atomics 2018-11-23 01:39:04 -07:00
tidwall 58421ef806 Removed unused code 2018-11-23 01:24:35 -07:00
tidwall 669823950a Fix script load issue 2018-11-20 10:25:48 -08:00
tidwall df41d44056 New logo 2018-11-18 13:58:16 -07:00
tidwall 737561fa8b Fix version not being set at build, close #386 2018-11-15 13:45:55 -07:00
tidwall a0f3b0049f Fix aof loading problem 2018-11-15 09:15:39 -07:00
Josh Baker 37afa7e92b
Merge pull request #385 from stevelacy/sl/server_version
Add server command for `version` - closes #384
2018-11-15 04:18:28 -07:00
tidwall 4c3ac62191 Hotfix replica sync needs flushing 2018-11-13 12:04:16 -07:00
Steve Lacy 5c6c280559
Add server command for `version` - closes #384 2018-11-13 10:24:15 -07:00
tidwall 6616b86eda Default numloops to number goprocs 2018-11-11 09:29:07 -07:00
tidwall b2203fcb97 Fix nearby fast-fail 2018-11-11 09:05:26 -07:00
tidwall 7cc9154eb8 Correct threads equals cpu 2018-11-11 09:05:26 -07:00
tidwall d065b979da net prewrite optimization 2018-11-11 09:05:26 -07:00
tidwall 464c193d73 Prewrite optimization flag 2018-11-11 09:05:26 -07:00
tidwall 3bf91077d9 Hang on to lower command 2018-11-11 09:05:26 -07:00
tidwall 372744b192 More hacking vendored circle.go 2018-11-11 09:04:00 -07:00
tidwall 161c6faff9 Added evio flag 2018-11-11 09:03:47 -07:00
tidwall 933f243c6c Code cleanup 2018-11-11 09:03:47 -07:00
tidwall e46c945f2c Fix windows build issue 2018-11-05 10:58:01 -07:00
tidwall 07bae979a5 Added Cursor interface 2018-11-02 06:09:56 -07:00
Josh Baker 0ea2ec216c
Merge pull request #378 from rshura/fast_cursor
Fast cursor
2018-11-02 05:14:53 -07:00
tidwall a4986d9cf8 Removed unneeded params 2018-11-02 05:09:51 -07:00
Alex Roitman bf5317f040 Fix tests. 2018-11-01 15:18:55 -07:00
Alex Roitman 0933c541f4 Refactor cursor/paging. 2018-10-31 22:01:37 -07:00
Alex Roitman b94f3685b6 Move iterating up to the cursor before any tests. 2018-10-31 22:01:24 -07:00
Alex Roitman f45d81d692 Simplification 2018-10-31 01:30:10 -07:00
Alex Roitman d2c687d61e camelCase 2018-10-31 00:45:16 -07:00
Alex Roitman 63b41691e6 Clean up obsolete code. 2018-10-31 00:40:09 -07:00
Alex Roitman 18d7398d50 Minor refactoring 2018-10-29 18:18:04 -07:00
Alex Roitman 2383594048 Use haversine instead of distance in knn if distance is not required. 2018-10-29 15:32:47 -07:00
tidwall 60b054d58c Fixed test 2018-10-29 08:16:04 -07:00
tidwall e577f60481 Updated redigo imports 2018-10-29 05:00:54 -07:00
tidwall 555e47036c Replaced net package with evio
- Added threads startup flag
- Replaced net package with evio
- Refactored controller into server
2018-10-28 15:51:47 -07:00
tidwall b17bbbd829 Merge branch 'always_knn_nearby' of https://github.com/rshura/tile38 into rshura-always_knn_nearby 2018-10-27 09:22:04 -07:00
tidwall e15cfb66d1 Inline optimization 2018-10-27 07:08:24 -07:00
Alex Roitman c673fa01d5 Pass Circle into nearestNeighbor. 2018-10-26 10:05:33 -07:00
Alex Roitman 33530075a4 Use new Meters() function. 2018-10-25 17:00:19 -07:00
Alex Roitman 7c803f355b Make NEARBY always use knn 2018-10-25 16:37:06 -07:00
tidwall b1370332e6 Always use compressed indexing 2018-10-23 11:23:55 -07:00
tidwall ccd6975f5f Fix some tests 2018-10-22 14:52:48 -07:00
tidwall 7cc4008442 Added multiple indexing kinds 2018-10-21 19:08:56 -07:00
tidwall 8ee4c10862 Added geom indexing environment options
T38IDXGEOM  -- Point threshold for indexing geometry
T38IDXMULTI -- Child threshold for indexing multi/collection

Default is 64
Using zero will disable indexing

Example:

T38IDXGEOM=0 tile38-server    # disables geometry indexing
T38IDXGEOM=256 tile38-server  # indexing geometries 256+ points
2018-10-19 06:29:47 -07:00
tidwall d64aad9be0 Change btree implementation for collections 2018-10-18 07:13:24 -07:00
tidwall 6257ddba78 Faster point in polygon / GeoJSON updates
The big change is that the GeoJSON package has been completely
rewritten to fix a few of geometry calculation bugs, increase
performance, and to better follow the GeoJSON spec RFC 7946.

GeoJSON updates

- A LineString now requires at least two points.
- All json members, even foreign, now persist with the object.
- The bbox member persists too but is no longer used for geometry
  calculations. This is change in behavior. Previously Tile38 would
  treat the bbox as the object's physical rectangle.
- Corrections to geometry intersects and within calculations.

Faster spatial queries

- The performance of Point-in-polygon and object intersect operations
  are greatly improved for complex polygons and line strings. It went
  from O(n) to roughly O(log n).
- The same for all collection types with many children, including
  FeatureCollection, GeometryCollection, MultiPoint, MultiLineString,
  and MultiPolygon.

Codebase changes

- The pkg directory has been renamed to internal
- The GeoJSON internal package has been moved to a seperate repo at
  https://github.com/tidwall/geojson. It's now vendored.

Please look out for higher memory usage for datasets using complex
shapes. A complex shape is one that has 64 or more points. For these
shapes it's expected that there will be increase of least 54 bytes per
point.
2018-10-13 04:30:48 -07:00