[MM-20979] Add first implementation of the Bleve search engine (#14562)
* [MM-20979] Add first implementation of the Bleve search engine * Fix i18n * Migrate searchengine utils tests * Fix linter * Don't add allTermsQ if both termQueries and notTermQueries are empty * Fix test that should work if user is system admin * Modify naming according to review comments * Abstract getIndexDir function * Extracting bleve engine name as a constant * Merge both Indexer interfaces into one * Add worker stopped message * Allow worker to be started/stopped with config change * Use constants for index names * Modify test order * Fix linter * Trying to unlock the CI
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
8d0343d2eb
Коммит
0154b8059b
@@ -86,6 +86,8 @@ type Routes struct {
|
|||||||
|
|
||||||
Elasticsearch *mux.Router // 'api/v4/elasticsearch'
|
Elasticsearch *mux.Router // 'api/v4/elasticsearch'
|
||||||
|
|
||||||
|
Bleve *mux.Router // 'api/v4/bleve'
|
||||||
|
|
||||||
DataRetention *mux.Router // 'api/v4/data_retention'
|
DataRetention *mux.Router // 'api/v4/data_retention'
|
||||||
|
|
||||||
Brand *mux.Router // 'api/v4/brand'
|
Brand *mux.Router // 'api/v4/brand'
|
||||||
@@ -198,6 +200,7 @@ func Init(configservice configservice.ConfigService, globalOptionsFunc app.AppOp
|
|||||||
api.BaseRoutes.Reactions = api.BaseRoutes.ApiRoot.PathPrefix("/reactions").Subrouter()
|
api.BaseRoutes.Reactions = api.BaseRoutes.ApiRoot.PathPrefix("/reactions").Subrouter()
|
||||||
api.BaseRoutes.Jobs = api.BaseRoutes.ApiRoot.PathPrefix("/jobs").Subrouter()
|
api.BaseRoutes.Jobs = api.BaseRoutes.ApiRoot.PathPrefix("/jobs").Subrouter()
|
||||||
api.BaseRoutes.Elasticsearch = api.BaseRoutes.ApiRoot.PathPrefix("/elasticsearch").Subrouter()
|
api.BaseRoutes.Elasticsearch = api.BaseRoutes.ApiRoot.PathPrefix("/elasticsearch").Subrouter()
|
||||||
|
api.BaseRoutes.Bleve = api.BaseRoutes.ApiRoot.PathPrefix("/bleve").Subrouter()
|
||||||
api.BaseRoutes.DataRetention = api.BaseRoutes.ApiRoot.PathPrefix("/data_retention").Subrouter()
|
api.BaseRoutes.DataRetention = api.BaseRoutes.ApiRoot.PathPrefix("/data_retention").Subrouter()
|
||||||
|
|
||||||
api.BaseRoutes.Emojis = api.BaseRoutes.ApiRoot.PathPrefix("/emoji").Subrouter()
|
api.BaseRoutes.Emojis = api.BaseRoutes.ApiRoot.PathPrefix("/emoji").Subrouter()
|
||||||
@@ -232,6 +235,7 @@ func Init(configservice configservice.ConfigService, globalOptionsFunc app.AppOp
|
|||||||
api.InitCluster()
|
api.InitCluster()
|
||||||
api.InitLdap()
|
api.InitLdap()
|
||||||
api.InitElasticsearch()
|
api.InitElasticsearch()
|
||||||
|
api.InitBleve()
|
||||||
api.InitDataRetention()
|
api.InitDataRetention()
|
||||||
api.InitBrand()
|
api.InitBrand()
|
||||||
api.InitJob()
|
api.InitJob()
|
||||||
|
|||||||
39
api4/bleve.go
Обычный файл
39
api4/bleve.go
Обычный файл
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package api4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/v5/audit"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (api *API) InitBleve() {
|
||||||
|
api.BaseRoutes.Bleve.Handle("/purge_indexes", api.ApiSessionRequired(purgeBleveIndexes)).Methods("POST")
|
||||||
|
}
|
||||||
|
|
||||||
|
func purgeBleveIndexes(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
auditRec := c.MakeAuditRecord("purgeBleveIndexes", audit.Fail)
|
||||||
|
defer c.LogAuditRec(auditRec)
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.App.Session(), model.PERMISSION_MANAGE_SYSTEM) {
|
||||||
|
c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if *c.App.Config().ExperimentalSettings.RestrictSystemAdmin {
|
||||||
|
c.Err = model.NewAppError("purgeBleveIndexes", "api.restricted_system_admin", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.App.PurgeBleveIndexes(); err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
auditRec.Success()
|
||||||
|
|
||||||
|
ReturnStatusOK(w)
|
||||||
|
}
|
||||||
32
api4/bleve_test.go
Обычный файл
32
api4/bleve_test.go
Обычный файл
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package api4
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestBlevePurgeIndexes(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
t.Run("as system user", func(t *testing.T) {
|
||||||
|
_, resp := th.Client.PurgeBleveIndexes()
|
||||||
|
CheckForbiddenStatus(t, resp)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("as system admin", func(t *testing.T) {
|
||||||
|
_, resp := th.SystemAdminClient.PurgeBleveIndexes()
|
||||||
|
CheckOKStatus(t, resp)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("as restricted system admin", func(t *testing.T) {
|
||||||
|
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ExperimentalSettings.RestrictSystemAdmin = true })
|
||||||
|
|
||||||
|
_, resp := th.SystemAdminClient.PurgeBleveIndexes()
|
||||||
|
CheckForbiddenStatus(t, resp)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -98,6 +98,9 @@ func (s *Server) initJobs() {
|
|||||||
if jobsPluginsInterface != nil {
|
if jobsPluginsInterface != nil {
|
||||||
s.Jobs.Plugins = jobsPluginsInterface(s.FakeApp())
|
s.Jobs.Plugins = jobsPluginsInterface(s.FakeApp())
|
||||||
}
|
}
|
||||||
|
if jobsBleveIndexerInterface != nil {
|
||||||
|
s.Jobs.BleveIndexer = jobsBleveIndexerInterface(s)
|
||||||
|
}
|
||||||
s.Jobs.Workers = s.Jobs.InitWorkers()
|
s.Jobs.Workers = s.Jobs.InitWorkers()
|
||||||
s.Jobs.Schedulers = s.Jobs.InitSchedulers()
|
s.Jobs.Schedulers = s.Jobs.InitSchedulers()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -782,6 +782,7 @@ type AppIface interface {
|
|||||||
ProcessSlackText(text string) string
|
ProcessSlackText(text string) string
|
||||||
Publish(message *model.WebSocketEvent)
|
Publish(message *model.WebSocketEvent)
|
||||||
PublishSkipClusterSend(message *model.WebSocketEvent)
|
PublishSkipClusterSend(message *model.WebSocketEvent)
|
||||||
|
PurgeBleveIndexes() *model.AppError
|
||||||
PurgeElasticsearchIndexes() *model.AppError
|
PurgeElasticsearchIndexes() *model.AppError
|
||||||
ReadFile(path string) ([]byte, *model.AppError)
|
ReadFile(path string) ([]byte, *model.AppError)
|
||||||
RecycleDatabaseConnection()
|
RecycleDatabaseConnection()
|
||||||
|
|||||||
@@ -60,9 +60,9 @@ func RegisterJobsElasticsearchAggregatorInterface(f func(*Server) ejobs.Elastics
|
|||||||
jobsElasticsearchAggregatorInterface = f
|
jobsElasticsearchAggregatorInterface = f
|
||||||
}
|
}
|
||||||
|
|
||||||
var jobsElasticsearchIndexerInterface func(*Server) ejobs.ElasticsearchIndexerInterface
|
var jobsElasticsearchIndexerInterface func(*Server) tjobs.IndexerJobInterface
|
||||||
|
|
||||||
func RegisterJobsElasticsearchIndexerInterface(f func(*Server) ejobs.ElasticsearchIndexerInterface) {
|
func RegisterJobsElasticsearchIndexerInterface(f func(*Server) tjobs.IndexerJobInterface) {
|
||||||
jobsElasticsearchIndexerInterface = f
|
jobsElasticsearchIndexerInterface = f
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +84,12 @@ func RegisterJobsPluginsJobInterface(f func(*App) tjobs.PluginsJobInterface) {
|
|||||||
jobsPluginsInterface = f
|
jobsPluginsInterface = f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var jobsBleveIndexerInterface func(*Server) tjobs.IndexerJobInterface
|
||||||
|
|
||||||
|
func RegisterJobsBleveIndexerInterface(f func(*Server) tjobs.IndexerJobInterface) {
|
||||||
|
jobsBleveIndexerInterface = f
|
||||||
|
}
|
||||||
|
|
||||||
var ldapInterface func(*App) einterfaces.LdapInterface
|
var ldapInterface func(*App) einterfaces.LdapInterface
|
||||||
|
|
||||||
func RegisterLdapInterface(f func(*App) einterfaces.LdapInterface) {
|
func RegisterLdapInterface(f func(*App) einterfaces.LdapInterface) {
|
||||||
|
|||||||
@@ -10856,6 +10856,28 @@ func (a *OpenTracingAppLayer) PublishSkipClusterSend(message *model.WebSocketEve
|
|||||||
a.app.PublishSkipClusterSend(message)
|
a.app.PublishSkipClusterSend(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) PurgeBleveIndexes() *model.AppError {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.PurgeBleveIndexes")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.PurgeBleveIndexes()
|
||||||
|
|
||||||
|
if resultVar0 != nil {
|
||||||
|
span.LogFields(spanlog.Error(resultVar0))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) PurgeElasticsearchIndexes() *model.AppError {
|
func (a *OpenTracingAppLayer) PurgeElasticsearchIndexes() *model.AppError {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.PurgeElasticsearchIndexes")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.PurgeElasticsearchIndexes")
|
||||||
|
|||||||
@@ -32,19 +32,31 @@ func (a *App) TestElasticsearch(cfg *model.Config) *model.AppError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) PurgeElasticsearchIndexes() *model.AppError {
|
func (a *App) PurgeElasticsearchIndexes() *model.AppError {
|
||||||
seI := a.SearchEngine().ElasticsearchEngine
|
engine := a.SearchEngine().ElasticsearchEngine
|
||||||
if seI == nil {
|
if engine == nil {
|
||||||
err := model.NewAppError("PurgeElasticsearchIndexes", "ent.elasticsearch.test_config.license.error", nil, "", http.StatusNotImplemented)
|
err := model.NewAppError("PurgeElasticsearchIndexes", "ent.elasticsearch.test_config.license.error", nil, "", http.StatusNotImplemented)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := seI.PurgeIndexes(); err != nil {
|
if err := engine.PurgeIndexes(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) PurgeBleveIndexes() *model.AppError {
|
||||||
|
engine := a.SearchEngine().BleveEngine
|
||||||
|
if engine == nil {
|
||||||
|
err := model.NewAppError("PurgeBleveIndexes", "searchengine.bleve.disabled.error", nil, "", http.StatusNotImplemented)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := engine.PurgeIndexes(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) SetSearchEngine(se *searchengine.Broker) {
|
func (a *App) SetSearchEngine(se *searchengine.Broker) {
|
||||||
a.searchEngine = se
|
a.searchEngine = se
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/v5/services/httpservice"
|
"github.com/mattermost/mattermost-server/v5/services/httpservice"
|
||||||
"github.com/mattermost/mattermost-server/v5/services/imageproxy"
|
"github.com/mattermost/mattermost-server/v5/services/imageproxy"
|
||||||
"github.com/mattermost/mattermost-server/v5/services/searchengine"
|
"github.com/mattermost/mattermost-server/v5/services/searchengine"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/services/searchengine/bleveengine"
|
||||||
"github.com/mattermost/mattermost-server/v5/services/timezones"
|
"github.com/mattermost/mattermost-server/v5/services/timezones"
|
||||||
"github.com/mattermost/mattermost-server/v5/services/tracing"
|
"github.com/mattermost/mattermost-server/v5/services/tracing"
|
||||||
"github.com/mattermost/mattermost-server/v5/store"
|
"github.com/mattermost/mattermost-server/v5/store"
|
||||||
@@ -225,7 +226,13 @@ func NewServer(options ...Option) (*Server, error) {
|
|||||||
return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
|
return nil, errors.Wrapf(err, "unable to load Mattermost translation files")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.SearchEngine = searchengine.NewBroker(s.Config(), s.Jobs)
|
searchEngine := searchengine.NewBroker(s.Config(), s.Jobs)
|
||||||
|
bleveEngine := bleveengine.NewBleveEngine(s.Config(), s.Jobs)
|
||||||
|
if err := bleveEngine.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
searchEngine.RegisterBleveEngine(bleveEngine)
|
||||||
|
s.SearchEngine = searchEngine
|
||||||
|
|
||||||
// at the moment we only have this implementation
|
// at the moment we only have this implementation
|
||||||
// in the future the cache provider will be built based on the loaded config
|
// in the future the cache provider will be built based on the loaded config
|
||||||
@@ -237,8 +244,7 @@ func NewServer(options ...Option) (*Server, error) {
|
|||||||
s.seenPendingPostIdsCache = s.CacheProvider.NewCache(PENDING_POST_IDS_CACHE_SIZE)
|
s.seenPendingPostIdsCache = s.CacheProvider.NewCache(PENDING_POST_IDS_CACHE_SIZE)
|
||||||
s.statusCache = s.CacheProvider.NewCache(model.STATUS_CACHE_SIZE)
|
s.statusCache = s.CacheProvider.NewCache(model.STATUS_CACHE_SIZE)
|
||||||
|
|
||||||
err := s.RunOldAppInitialization()
|
if err := s.RunOldAppInitialization(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -985,6 +991,9 @@ func (s *Server) stopSearchEngine() {
|
|||||||
if s.SearchEngine != nil && s.SearchEngine.ElasticsearchEngine != nil && s.SearchEngine.ElasticsearchEngine.IsActive() {
|
if s.SearchEngine != nil && s.SearchEngine.ElasticsearchEngine != nil && s.SearchEngine.ElasticsearchEngine.IsActive() {
|
||||||
s.SearchEngine.ElasticsearchEngine.Stop()
|
s.SearchEngine.ElasticsearchEngine.Stop()
|
||||||
}
|
}
|
||||||
|
if s.SearchEngine != nil && s.SearchEngine.BleveEngine != nil && s.SearchEngine.BleveEngine.IsActive() {
|
||||||
|
s.SearchEngine.BleveEngine.Stop()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) initDiagnostics(endpoint string) {
|
func (s *Server) initDiagnostics(endpoint string) {
|
||||||
|
|||||||
20
go.mod
20
go.mod
@@ -4,27 +4,35 @@ go 1.14
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/squirrel v1.2.0
|
github.com/Masterminds/squirrel v1.2.0
|
||||||
|
github.com/RoaringBitmap/roaring v0.4.23 // indirect
|
||||||
github.com/armon/go-metrics v0.3.0 // indirect
|
github.com/armon/go-metrics v0.3.0 // indirect
|
||||||
github.com/avct/uasurfer v0.0.0-20191028135549-26b5daa857f1
|
github.com/avct/uasurfer v0.0.0-20191028135549-26b5daa857f1
|
||||||
github.com/beevik/etree v1.1.0 // indirect
|
github.com/beevik/etree v1.1.0 // indirect
|
||||||
github.com/blang/semver v3.5.1+incompatible
|
github.com/blang/semver v3.5.1+incompatible
|
||||||
|
github.com/blevesearch/bleve v1.0.7
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||||
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
|
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd // indirect
|
||||||
github.com/corpix/uarand v0.1.1 // indirect
|
github.com/corpix/uarand v0.1.1 // indirect
|
||||||
|
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d // indirect
|
||||||
|
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 // indirect
|
||||||
|
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 // indirect
|
||||||
github.com/dgryski/dgoogauth v0.0.0-20190221195224-5a805980a5f3
|
github.com/dgryski/dgoogauth v0.0.0-20190221195224-5a805980a5f3
|
||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/dyatlov/go-opengraph v0.0.0-20180429202543-816b6608b3c8
|
github.com/dyatlov/go-opengraph v0.0.0-20180429202543-816b6608b3c8
|
||||||
|
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c // indirect
|
||||||
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||||
|
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 // indirect
|
||||||
github.com/fatih/color v1.9.0 // indirect
|
github.com/fatih/color v1.9.0 // indirect
|
||||||
github.com/fortytw2/leaktest v1.3.0 // indirect
|
github.com/fortytw2/leaktest v1.3.0 // indirect
|
||||||
github.com/francoispqt/gojay v1.2.13
|
github.com/francoispqt/gojay v1.2.13
|
||||||
github.com/fsnotify/fsnotify v1.4.9
|
github.com/fsnotify/fsnotify v1.4.9
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.4.1 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.4.1 // indirect
|
||||||
github.com/go-gorp/gorp v2.0.0+incompatible // indirect
|
github.com/go-gorp/gorp v2.0.0+incompatible // indirect
|
||||||
github.com/go-sql-driver/mysql v1.5.0
|
github.com/go-sql-driver/mysql v1.5.0
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
github.com/golang/protobuf v1.4.0 // indirect
|
github.com/golang/protobuf v1.4.2 // indirect
|
||||||
github.com/google/uuid v1.1.1 // indirect
|
github.com/google/uuid v1.1.1 // indirect
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect
|
|
||||||
github.com/gorilla/handlers v1.4.2
|
github.com/gorilla/handlers v1.4.2
|
||||||
github.com/gorilla/mux v1.7.4
|
github.com/gorilla/mux v1.7.4
|
||||||
github.com/gorilla/schema v1.1.0
|
github.com/gorilla/schema v1.1.0
|
||||||
@@ -44,7 +52,9 @@ require (
|
|||||||
github.com/hashicorp/yamux v0.0.0-20190923154419-df201c70410d // indirect
|
github.com/hashicorp/yamux v0.0.0-20190923154419-df201c70410d // indirect
|
||||||
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428
|
github.com/icrowley/fake v0.0.0-20180203215853-4178557ae428
|
||||||
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
|
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
|
||||||
|
github.com/jmhodges/levigo v1.0.0 // indirect
|
||||||
github.com/jmoiron/sqlx v1.2.0
|
github.com/jmoiron/sqlx v1.2.0
|
||||||
|
github.com/jonboulle/clockwork v0.1.0
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||||
github.com/lib/pq v1.4.0
|
github.com/lib/pq v1.4.0
|
||||||
github.com/magiconair/properties v1.8.1 // indirect
|
github.com/magiconair/properties v1.8.1 // indirect
|
||||||
@@ -72,7 +82,9 @@ require (
|
|||||||
github.com/pelletier/go-toml v1.7.0 // indirect
|
github.com/pelletier/go-toml v1.7.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/prometheus/client_golang v1.5.1
|
github.com/prometheus/client_golang v1.5.1
|
||||||
|
github.com/prometheus/client_model v0.2.0
|
||||||
github.com/prometheus/procfs v0.0.11 // indirect
|
github.com/prometheus/procfs v0.0.11 // indirect
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237 // indirect
|
||||||
github.com/rs/cors v1.7.0
|
github.com/rs/cors v1.7.0
|
||||||
github.com/rudderlabs/analytics-go v3.2.1+incompatible
|
github.com/rudderlabs/analytics-go v3.2.1+incompatible
|
||||||
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7
|
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7
|
||||||
@@ -90,7 +102,9 @@ require (
|
|||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||||
github.com/stretchr/objx v0.2.0 // indirect
|
github.com/stretchr/objx v0.2.0 // indirect
|
||||||
github.com/stretchr/testify v1.5.1
|
github.com/stretchr/testify v1.5.1
|
||||||
|
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
|
||||||
github.com/throttled/throttled v2.2.4+incompatible
|
github.com/throttled/throttled v2.2.4+incompatible
|
||||||
|
github.com/tinylib/msgp v1.1.2 // indirect
|
||||||
github.com/tylerb/graceful v1.2.15
|
github.com/tylerb/graceful v1.2.15
|
||||||
github.com/uber/jaeger-client-go v2.23.0+incompatible
|
github.com/uber/jaeger-client-go v2.23.0+incompatible
|
||||||
github.com/uber/jaeger-lib v2.2.0+incompatible
|
github.com/uber/jaeger-lib v2.2.0+incompatible
|
||||||
@@ -104,7 +118,7 @@ require (
|
|||||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1
|
golang.org/x/image v0.0.0-20200119044424-58c23975cae1
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
|
||||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5
|
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5
|
||||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect
|
||||||
golang.org/x/text v0.3.2
|
golang.org/x/text v0.3.2
|
||||||
golang.org/x/tools v0.0.0-20200428021058-7ae4988eb4d9
|
golang.org/x/tools v0.0.0-20200428021058-7ae4988eb4d9
|
||||||
google.golang.org/genproto v0.0.0-20200424135956-bca184e23272 // indirect
|
google.golang.org/genproto v0.0.0-20200424135956-bca184e23272 // indirect
|
||||||
|
|||||||
96
go.sum
96
go.sum
@@ -22,6 +22,10 @@ github.com/Masterminds/squirrel v1.2.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZl
|
|||||||
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/PaulARoy/azurestoragecache v0.0.0-20170906084534-3c249a3ba788/go.mod h1:lY1dZd8HBzJ10eqKERHn3CU59tfhzcAVb2c0ZhIWSOk=
|
github.com/PaulARoy/azurestoragecache v0.0.0-20170906084534-3c249a3ba788/go.mod h1:lY1dZd8HBzJ10eqKERHn3CU59tfhzcAVb2c0ZhIWSOk=
|
||||||
|
github.com/RoaringBitmap/roaring v0.4.21 h1:WJ/zIlNX4wQZ9x8Ey33O1UaD9TCTakYsdLFSBcTwH+8=
|
||||||
|
github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||||
|
github.com/RoaringBitmap/roaring v0.4.23 h1:gpyfd12QohbqhFO4NVDUdoPOCXsyahYRQhINmlHxKeo=
|
||||||
|
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
@@ -50,6 +54,22 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
|||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||||
|
github.com/blevesearch/bleve v1.0.7 h1:4PspZE7XABMSKcVpzAKp0E05Yer1PIYmTWk+1ngNr/c=
|
||||||
|
github.com/blevesearch/bleve v1.0.7/go.mod h1:3xvmBtaw12Y4C9iA1RTzwWCof5j5HjydjCTiDE2TeE0=
|
||||||
|
github.com/blevesearch/blevex v0.0.0-20190916190636-152f0fe5c040 h1:SjYVcfJVZoCfBlg+fkaq2eoZHTf5HaJfaTeTkOtyfHQ=
|
||||||
|
github.com/blevesearch/blevex v0.0.0-20190916190636-152f0fe5c040/go.mod h1:WH+MU2F4T0VmSdaPX+Wu5GYoZBrYWdOZWSjzvYcDmqQ=
|
||||||
|
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
|
||||||
|
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
|
||||||
|
github.com/blevesearch/mmap-go v1.0.2 h1:JtMHb+FgQCTTYIhtMvimw15dJwu1Y5lrZDMOFXVWPk0=
|
||||||
|
github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA=
|
||||||
|
github.com/blevesearch/segment v0.9.0 h1:5lG7yBCx98or7gK2cHMKPukPZ/31Kag7nONpoBt22Ac=
|
||||||
|
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
|
||||||
|
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
|
||||||
|
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
|
||||||
|
github.com/blevesearch/zap/v11 v11.0.7 h1:nnmAOP6eXBkqEa1Srq1eqA5Wmn4w+BZjLdjynNxvd+M=
|
||||||
|
github.com/blevesearch/zap/v11 v11.0.7/go.mod h1:bJoY56fdU2m/IP4LLz/1h4jY2thBoREvoqbuJ8zhm9k=
|
||||||
|
github.com/blevesearch/zap/v12 v12.0.7 h1:y8FWSAYkdc4p1dn4YLxNNr1dxXlSUsakJh2Fc/r6cj4=
|
||||||
|
github.com/blevesearch/zap/v12 v12.0.7/go.mod h1:70DNK4ZN4tb42LubeDbfpp6xnm8g3ROYVvvZ6pEoXD8=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
|
||||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
|
||||||
@@ -76,7 +96,18 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
|
|||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/corpix/uarand v0.1.1 h1:RMr1TWc9F4n5jiPDzFHtmaUXLKLNUFK0SgCLo4BhX/U=
|
github.com/corpix/uarand v0.1.1 h1:RMr1TWc9F4n5jiPDzFHtmaUXLKLNUFK0SgCLo4BhX/U=
|
||||||
github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU=
|
github.com/corpix/uarand v0.1.1/go.mod h1:SFKZvkcRoLqVRFZ4u25xPmp6m9ktANfbpXZ7SJ0/FNU=
|
||||||
|
github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k=
|
||||||
|
github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=
|
||||||
|
github.com/couchbase/vellum v1.0.1 h1:qrj9ohvZedvc51S5KzPfJ6P6z0Vqzv7Lx7k3mVc2WOk=
|
||||||
|
github.com/couchbase/vellum v1.0.1/go.mod h1:FcwrEivFpNi24R3jLOs3n+fs5RnuQnQqCLBJ1uAg1W4=
|
||||||
|
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
|
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d h1:SwD98825d6bdB+pEuTxWOXiSjBrHdOl/UVp75eI7JT8=
|
||||||
|
github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
|
||||||
|
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 h1:iwZdTE0PVqJCos1vaoKsclOGD3ADKpshg3SRtYBbwso=
|
||||||
|
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
|
||||||
|
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 h1:MZRmHqDBd0vxNwenEbKSQqRVT24d3C05ft8kduSwlqM=
|
||||||
|
github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -102,6 +133,12 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c h1:8ISkoahWXwZR41ois5lSJBSVw4D0OV19Ht/JSTzvSv0=
|
||||||
|
github.com/facebookgo/ensure v0.0.0-20200202191622-63f1cf65ac4c/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64=
|
||||||
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
||||||
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
|
||||||
|
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4 h1:7HZCaLC5+BZpmbhCOZJ293Lz68O7PYrF2EzeiFMwCLk=
|
||||||
|
github.com/facebookgo/subset v0.0.0-20200203212716-c811ad88dec4/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
|
||||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||||
@@ -118,6 +155,12 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
|
|||||||
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4=
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a h1:FQqoVvjbiUioBBFUL5up+h+GdCa/AnJsL/1bIs/veSI=
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
|
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8=
|
||||||
|
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.3.2-0.20191121212151-29be175fc3a3 h1:QW2p25fGTu/S0MvEftCo3wV7aEFHBt2m1DTg1HUwh+o=
|
github.com/go-asn1-ber/asn1-ber v1.3.2-0.20191121212151-29be175fc3a3 h1:QW2p25fGTu/S0MvEftCo3wV7aEFHBt2m1DTg1HUwh+o=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.3.2-0.20191121212151-29be175fc3a3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
github.com/go-asn1-ber/asn1-ber v1.3.2-0.20191121212151-29be175fc3a3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
|
||||||
github.com/go-asn1-ber/asn1-ber v1.4.1 h1:qP/QDxOtmMoJVgXHCXNzDpA0+wkgYB2x5QoLMVOciyw=
|
github.com/go-asn1-ber/asn1-ber v1.4.1 h1:qP/QDxOtmMoJVgXHCXNzDpA0+wkgYB2x5QoLMVOciyw=
|
||||||
@@ -158,7 +201,11 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
|
|||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||||
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
|
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||||
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
|
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
|
||||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
@@ -182,8 +229,8 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk
|
|||||||
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4=
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||||
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
||||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||||
@@ -264,6 +311,8 @@ github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0
|
|||||||
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
||||||
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
|
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
|
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
|
||||||
|
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
|
||||||
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
github.com/jmoiron/sqlx v1.2.0 h1:41Ip0zITnmWNR/vHV+S4m+VoUivnWY5E4OJfLZjCJMA=
|
||||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||||
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
|
||||||
@@ -277,6 +326,7 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||||
@@ -356,10 +406,6 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz
|
|||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.2.3 h1:f/MjBEBDLttYCGfRaKBbKSRVF5aV2O6fnBpzknuE3jU=
|
github.com/mitchellh/mapstructure v1.2.3 h1:f/MjBEBDLttYCGfRaKBbKSRVF5aV2O6fnBpzknuE3jU=
|
||||||
github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.2.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mkraft/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
|
|
||||||
github.com/mkraft/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
|
|
||||||
github.com/mkraft/gziphandler v1.1.2-0.20200509170533-f387ff5f65bc h1:S6AKguh0+X1d0bW9+catK3n+PMX/dke1lkL4uxxukd8=
|
|
||||||
github.com/mkraft/gziphandler v1.1.2-0.20200509170533-f387ff5f65bc/go.mod h1:gG8WEPb2aI5MHdmHv83au7bk3molRSZiAjdxYrEMJdQ=
|
|
||||||
github.com/mkraft/gziphandler v1.1.2-0.20200509175700-73dc64f3ad90 h1:qEm+0lDAcdszJkCnYSuP1oITiQf0TzDIAmeD2PlBtZU=
|
github.com/mkraft/gziphandler v1.1.2-0.20200509175700-73dc64f3ad90 h1:qEm+0lDAcdszJkCnYSuP1oITiQf0TzDIAmeD2PlBtZU=
|
||||||
github.com/mkraft/gziphandler v1.1.2-0.20200509175700-73dc64f3ad90/go.mod h1:gG8WEPb2aI5MHdmHv83au7bk3molRSZiAjdxYrEMJdQ=
|
github.com/mkraft/gziphandler v1.1.2-0.20200509175700-73dc64f3ad90/go.mod h1:gG8WEPb2aI5MHdmHv83au7bk3molRSZiAjdxYrEMJdQ=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
@@ -368,6 +414,10 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
|||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
|
||||||
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
|
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
|
||||||
|
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
|
||||||
github.com/muesli/smartcrop v0.2.1-0.20181030220600-548bbf0c0965 h1:BdOnvj+P+06ZFwYd07iFWXHPfRyrJd5sAXpX9+E8bxM=
|
github.com/muesli/smartcrop v0.2.1-0.20181030220600-548bbf0c0965 h1:BdOnvj+P+06ZFwYd07iFWXHPfRyrJd5sAXpX9+E8bxM=
|
||||||
github.com/muesli/smartcrop v0.2.1-0.20181030220600-548bbf0c0965/go.mod h1:i2fCI/UorTfgEpPPLWiFBv4pye+YAG78RwcQLUkocpI=
|
github.com/muesli/smartcrop v0.2.1-0.20181030220600-548bbf0c0965/go.mod h1:i2fCI/UorTfgEpPPLWiFBv4pye+YAG78RwcQLUkocpI=
|
||||||
github.com/muesli/smartcrop v0.3.0 h1:JTlSkmxWg/oQ1TcLDoypuirdE8Y/jzNirQeLkxpA6Oc=
|
github.com/muesli/smartcrop v0.3.0 h1:JTlSkmxWg/oQ1TcLDoypuirdE8Y/jzNirQeLkxpA6Oc=
|
||||||
@@ -408,6 +458,8 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
|
|||||||
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
github.com/peterbourgon/diskv v0.0.0-20171120014656-2973218375c3/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
github.com/peterbourgon/diskv v0.0.0-20171120014656-2973218375c3/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
|
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||||
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||||
@@ -459,6 +511,9 @@ github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia
|
|||||||
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237 h1:HQagqIiBmr8YXawX/le3+O26N+vPPC1PtjaF3mwnook=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||||
@@ -525,6 +580,7 @@ github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
|||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
|
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||||
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8=
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||||
@@ -535,9 +591,12 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
|
|||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
|
||||||
|
github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM=
|
||||||
|
github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7Z4dM9/Y=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
@@ -550,9 +609,17 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy
|
|||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||||
|
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
|
||||||
|
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok=
|
||||||
|
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
|
||||||
github.com/throttled/throttled v2.2.4+incompatible h1:aVKdoH/qT5Mo1Lm/678OkX2pFg7aRpHlTn1tfgaSKxs=
|
github.com/throttled/throttled v2.2.4+incompatible h1:aVKdoH/qT5Mo1Lm/678OkX2pFg7aRpHlTn1tfgaSKxs=
|
||||||
github.com/throttled/throttled v2.2.4+incompatible/go.mod h1:0BjlrEGQmvxps+HuXLsyRdqpSRvJpq0PNIsOtqP9Nos=
|
github.com/throttled/throttled v2.2.4+incompatible/go.mod h1:0BjlrEGQmvxps+HuXLsyRdqpSRvJpq0PNIsOtqP9Nos=
|
||||||
|
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
|
||||||
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
|
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
|
||||||
|
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||||
github.com/tylerb/graceful v1.2.15 h1:B0x01Y8fsJpogzZTkDg6BDi6eMf03s01lEKGdrv83oA=
|
github.com/tylerb/graceful v1.2.15 h1:B0x01Y8fsJpogzZTkDg6BDi6eMf03s01lEKGdrv83oA=
|
||||||
@@ -571,12 +638,10 @@ github.com/wiggin77/logr v1.0.4 h1:g8YO5AU9hhKvLQnXceP8/y3JJtw3wPKL4kTzMTUdN5k=
|
|||||||
github.com/wiggin77/logr v1.0.4/go.mod h1:h98FF6GPfThhDrHCg063hZA1sIyOEzQ/P85wgqI0IqE=
|
github.com/wiggin77/logr v1.0.4/go.mod h1:h98FF6GPfThhDrHCg063hZA1sIyOEzQ/P85wgqI0IqE=
|
||||||
github.com/wiggin77/merror v1.0.2 h1:V0nH9eFp64ASyaXC+pB5WpvBoCg7NUwvaCSKdzlcHqw=
|
github.com/wiggin77/merror v1.0.2 h1:V0nH9eFp64ASyaXC+pB5WpvBoCg7NUwvaCSKdzlcHqw=
|
||||||
github.com/wiggin77/merror v1.0.2/go.mod h1:uQTcIU0Z6jRK4OwqganPYerzQxSFJ4GSHM3aurxxQpg=
|
github.com/wiggin77/merror v1.0.2/go.mod h1:uQTcIU0Z6jRK4OwqganPYerzQxSFJ4GSHM3aurxxQpg=
|
||||||
github.com/wiggin77/srslog v0.0.0-20200405060129-9e4fac0bf76e h1:GbMgH03MQiRJErz8CT+cUTDTv97V19tUdJmlp5MEnZo=
|
|
||||||
github.com/wiggin77/srslog v0.0.0-20200405060129-9e4fac0bf76e/go.mod h1:fehkyYDq1QfuYn60TDPu9YdY2bB85VUW2mvN1WynEls=
|
|
||||||
github.com/wiggin77/srslog v1.0.0 h1:giZmgfUUM7ZnpH9b4r5DUmlanPch8iLxVS18S3SkCYQ=
|
|
||||||
github.com/wiggin77/srslog v1.0.0/go.mod h1:fehkyYDq1QfuYn60TDPu9YdY2bB85VUW2mvN1WynEls=
|
|
||||||
github.com/wiggin77/srslog v1.0.1 h1:gA2XjSMy3DrRdX9UqLuDtuVAAshb8bE1NhX1YK0Qe+8=
|
github.com/wiggin77/srslog v1.0.1 h1:gA2XjSMy3DrRdX9UqLuDtuVAAshb8bE1NhX1YK0Qe+8=
|
||||||
github.com/wiggin77/srslog v1.0.1/go.mod h1:fehkyYDq1QfuYn60TDPu9YdY2bB85VUW2mvN1WynEls=
|
github.com/wiggin77/srslog v1.0.1/go.mod h1:fehkyYDq1QfuYn60TDPu9YdY2bB85VUW2mvN1WynEls=
|
||||||
|
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
|
||||||
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
|
github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g=
|
||||||
@@ -585,6 +650,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
|
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
||||||
|
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
|
||||||
go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A=
|
go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A=
|
||||||
go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M=
|
go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M=
|
||||||
@@ -684,12 +751,14 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||||||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20181221143128-b4a75ba826a6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -698,10 +767,11 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3rzIsrrXfAQBWnYfn+w=
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
|
||||||
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||||
@@ -782,6 +852,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
|
|||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||||
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw=
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||||
|
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||||
|
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||||
|
|||||||
144
i18n/en.json
144
i18n/en.json
@@ -3838,6 +3838,122 @@
|
|||||||
"id": "app.user_access_token.invalid_or_missing",
|
"id": "app.user_access_token.invalid_or_missing",
|
||||||
"translation": "Invalid or missing token"
|
"translation": "Invalid or missing token"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.already_started.error",
|
||||||
|
"translation": "Bleve is alredy started."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.create_channel_index.error",
|
||||||
|
"translation": "Error creating the bleve channel index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.create_post_index.error",
|
||||||
|
"translation": "Error creating the bleve post index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.create_user_index.error",
|
||||||
|
"translation": "Error creating the bleve user index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.delete_channel.error",
|
||||||
|
"translation": "Failed to delete the channel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.delete_post.error",
|
||||||
|
"translation": "Failed to delete the post"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.delete_user.error",
|
||||||
|
"translation": "Failed to delete the user"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.index_channel.error",
|
||||||
|
"translation": "Failed to index the channel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.index_post.error",
|
||||||
|
"translation": "Failed to index the post"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.index_user.error",
|
||||||
|
"translation": "Failed to index the user"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.indexer.do_job.bulk_index_channels.batch_error",
|
||||||
|
"translation": "Failed to index channel batch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.indexer.do_job.bulk_index_posts.batch_error",
|
||||||
|
"translation": "Failed to index post batch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.indexer.do_job.bulk_index_users.batch_error",
|
||||||
|
"translation": "Failed to index user batch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.indexer.do_job.engine_inactive",
|
||||||
|
"translation": "Failed to run Bleve index job: engine is inactive"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.indexer.do_job.get_oldest_post.error",
|
||||||
|
"translation": "The oldest post could not be retrieved from the database"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.indexer.do_job.parse_end_time.error",
|
||||||
|
"translation": "Bleve indexing worker failed to parse the end time"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.indexer.do_job.parse_start_time.error",
|
||||||
|
"translation": "Bleve indexing worker failed to parse the start time"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.indexer.index_batch.nothing_left_to_index.error",
|
||||||
|
"translation": "Trying to index a new batch when all the entities are completed"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.purge_channel_index.error",
|
||||||
|
"translation": "Failed to purge channel indexes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.purge_post_index.error",
|
||||||
|
"translation": "Failed to purge post indexes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.purge_user_index.error",
|
||||||
|
"translation": "Failed to purge user indexes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.search_channels.error",
|
||||||
|
"translation": "Channel search failed to complete"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.search_posts.error",
|
||||||
|
"translation": "Post search failed to complete"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.search_users_in_channel.nuchan.error",
|
||||||
|
"translation": "User search failed to complete"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.search_users_in_channel.uchan.error",
|
||||||
|
"translation": "User search failed to complete"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.search_users_in_team.error",
|
||||||
|
"translation": "User search failed to complete"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.stop_channel_index.error",
|
||||||
|
"translation": "Failed to close channel index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.stop_post_index.error",
|
||||||
|
"translation": "Failed to close post index"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "bleveengine.stop_user_index.error",
|
||||||
|
"translation": "Failed to close user index"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "brand.save_brand_image.decode.app_error",
|
"id": "brand.save_brand_image.decode.app_error",
|
||||||
"translation": "Unable to decode the image data."
|
"translation": "Unable to decode the image data."
|
||||||
@@ -4028,7 +4144,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.elasticsearch.indexer.do_job.get_oldest_post.error",
|
"id": "ent.elasticsearch.indexer.do_job.get_oldest_post.error",
|
||||||
"translation": "The oldest post could not be retrieved from the database."
|
"translation": "The oldest post could not be retrieved from the database"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.elasticsearch.indexer.do_job.parse_end_time.error",
|
"id": "ent.elasticsearch.indexer.do_job.parse_end_time.error",
|
||||||
@@ -4040,7 +4156,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.elasticsearch.indexer.index_batch.nothing_left_to_index.error",
|
"id": "ent.elasticsearch.indexer.index_batch.nothing_left_to_index.error",
|
||||||
"translation": "Trying to index a new batch when all the entities are completed."
|
"translation": "Trying to index a new batch when all the entities are completed"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.elasticsearch.not_started.error",
|
"id": "ent.elasticsearch.not_started.error",
|
||||||
@@ -4758,6 +4874,22 @@
|
|||||||
"id": "model.config.is_valid.atmos_camo_image_proxy_url.app_error",
|
"id": "model.config.is_valid.atmos_camo_image_proxy_url.app_error",
|
||||||
"translation": "Invalid RemoteImageProxyURL for atmos/camo. Must be set to your shared key."
|
"translation": "Invalid RemoteImageProxyURL for atmos/camo. Must be set to your shared key."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "model.config.is_valid.bleve_search.bulk_indexing_time_window_seconds.app_error",
|
||||||
|
"translation": "Bleve Bulk Indexing Time Window must be at least 1 second."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "model.config.is_valid.bleve_search.enable_autocomplete.app_error",
|
||||||
|
"translation": "Bleve EnableIndexing setting must be set to true when Bleve EnableAutocomplete is set to true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "model.config.is_valid.bleve_search.enable_searching.app_error",
|
||||||
|
"translation": "Bleve EnableIndexing setting must be set to true when Bleve EnableSearching is set to true"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "model.config.is_valid.bleve_search.filename.app_error",
|
||||||
|
"translation": "Bleve EnableIndexing setting must be set to true when Bleve IndexingDir is set"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "model.config.is_valid.cluster_email_batching.app_error",
|
"id": "model.config.is_valid.cluster_email_batching.app_error",
|
||||||
"translation": "Unable to enable email batching when clustering is enabled."
|
"translation": "Unable to enable email batching when clustering is enabled."
|
||||||
@@ -4792,11 +4924,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "model.config.is_valid.elastic_search.enable_autocomplete.app_error",
|
"id": "model.config.is_valid.elastic_search.enable_autocomplete.app_error",
|
||||||
"translation": "Elasticsearch IndexingEnabled setting must be set to true when Elasticsearch AutocompleteEnabled is set to true."
|
"translation": "Elasticsearch EnableIndexing setting must be set to true when Elasticsearch EnableAutocomplete is set to true"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "model.config.is_valid.elastic_search.enable_searching.app_error",
|
"id": "model.config.is_valid.elastic_search.enable_searching.app_error",
|
||||||
"translation": "Elasticsearch IndexingEnabled setting must be set to true when Elasticsearch SearchEnabled is set to true."
|
"translation": "Elasticsearch EnableIndexing setting must be set to true when Elasticsearch EnableSearching is set to true"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "model.config.is_valid.elastic_search.live_indexing_batch_size.app_error",
|
"id": "model.config.is_valid.elastic_search.live_indexing_batch_size.app_error",
|
||||||
@@ -5770,6 +5902,10 @@
|
|||||||
"id": "plugin_api.send_mail.missing_to",
|
"id": "plugin_api.send_mail.missing_to",
|
||||||
"translation": "Missing TO address."
|
"translation": "Missing TO address."
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "searchengine.bleve.disabled.error",
|
||||||
|
"translation": "Error purging Bleve indexes: engine is disabled"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "store.insert_error",
|
"id": "store.insert_error",
|
||||||
"translation": "insert error"
|
"translation": "insert error"
|
||||||
|
|||||||
@@ -9,4 +9,7 @@ import (
|
|||||||
|
|
||||||
// This is a placeholder so this package can be imported in Team Edition when it will be otherwise empty.
|
// This is a placeholder so this package can be imported in Team Edition when it will be otherwise empty.
|
||||||
_ "github.com/mattermost/mattermost-server/v5/plugin/scheduler"
|
_ "github.com/mattermost/mattermost-server/v5/plugin/scheduler"
|
||||||
|
|
||||||
|
// This is a placeholder so this package can be imported in Team Edition when it will be otherwise empty.
|
||||||
|
_ "github.com/mattermost/mattermost-server/v5/services/searchengine/bleveengine/indexer"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,11 +7,6 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/v5/model"
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SearchEngineIndexerInterface interface {
|
type IndexerJobInterface interface {
|
||||||
MakeWorker() model.Worker
|
MakeWorker() model.Worker
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchEngineAggregatorInterface interface {
|
|
||||||
MakeWorker() model.Worker
|
|
||||||
MakeScheduler() model.Scheduler
|
|
||||||
}
|
|
||||||
@@ -100,6 +100,13 @@ func (watcher *Watcher) PollAndNotify() {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if job.Type == model.JOB_TYPE_BLEVE_POST_INDEXING {
|
||||||
|
if watcher.workers.BleveIndexing != nil {
|
||||||
|
select {
|
||||||
|
case watcher.workers.BleveIndexing.JobChannel() <- *job:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if job.Type == model.JOB_TYPE_LDAP_SYNC {
|
} else if job.Type == model.JOB_TYPE_LDAP_SYNC {
|
||||||
if watcher.workers.LdapSync != nil {
|
if watcher.workers.LdapSync != nil {
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ type JobServer struct {
|
|||||||
DataRetentionJob ejobs.DataRetentionJobInterface
|
DataRetentionJob ejobs.DataRetentionJobInterface
|
||||||
MessageExportJob ejobs.MessageExportJobInterface
|
MessageExportJob ejobs.MessageExportJobInterface
|
||||||
ElasticsearchAggregator ejobs.ElasticsearchAggregatorInterface
|
ElasticsearchAggregator ejobs.ElasticsearchAggregatorInterface
|
||||||
ElasticsearchIndexer ejobs.ElasticsearchIndexerInterface
|
ElasticsearchIndexer tjobs.IndexerJobInterface
|
||||||
LdapSync ejobs.LdapSyncInterface
|
LdapSync ejobs.LdapSyncInterface
|
||||||
Migrations tjobs.MigrationsJobInterface
|
Migrations tjobs.MigrationsJobInterface
|
||||||
Plugins tjobs.PluginsJobInterface
|
Plugins tjobs.PluginsJobInterface
|
||||||
|
BleveIndexer tjobs.IndexerJobInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewJobServer(configService configservice.ConfigService, store store.Store) *JobServer {
|
func NewJobServer(configService configservice.ConfigService, store store.Store) *JobServer {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type Workers struct {
|
|||||||
LdapSync model.Worker
|
LdapSync model.Worker
|
||||||
Migrations model.Worker
|
Migrations model.Worker
|
||||||
Plugins model.Worker
|
Plugins model.Worker
|
||||||
|
BleveIndexing model.Worker
|
||||||
|
|
||||||
listenerId string
|
listenerId string
|
||||||
}
|
}
|
||||||
@@ -61,6 +62,10 @@ func (srv *JobServer) InitWorkers() *Workers {
|
|||||||
workers.Plugins = pluginsInterface.MakeWorker()
|
workers.Plugins = pluginsInterface.MakeWorker()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if bleveIndexerInterface := srv.BleveIndexer; bleveIndexerInterface != nil {
|
||||||
|
workers.BleveIndexing = bleveIndexerInterface.MakeWorker()
|
||||||
|
}
|
||||||
|
|
||||||
return workers
|
return workers
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,6 +101,10 @@ func (workers *Workers) Start() *Workers {
|
|||||||
go workers.Plugins.Run()
|
go workers.Plugins.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if workers.BleveIndexing != nil && *workers.ConfigService.Config().BleveSettings.EnableIndexing && *workers.ConfigService.Config().BleveSettings.IndexDir != "" {
|
||||||
|
go workers.BleveIndexing.Run()
|
||||||
|
}
|
||||||
|
|
||||||
go workers.Watcher.Start()
|
go workers.Watcher.Start()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -146,6 +155,14 @@ func (workers *Workers) handleConfigChange(oldConfig *model.Config, newConfig *m
|
|||||||
workers.LdapSync.Stop()
|
workers.LdapSync.Stop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if workers.BleveIndexing != nil {
|
||||||
|
if !*oldConfig.BleveSettings.EnableIndexing && *newConfig.BleveSettings.EnableIndexing {
|
||||||
|
go workers.BleveIndexing.Run()
|
||||||
|
} else if *oldConfig.BleveSettings.EnableIndexing && !*newConfig.BleveSettings.EnableIndexing {
|
||||||
|
workers.BleveIndexing.Stop()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (workers *Workers) Stop() *Workers {
|
func (workers *Workers) Stop() *Workers {
|
||||||
@@ -181,6 +198,10 @@ func (workers *Workers) Stop() *Workers {
|
|||||||
workers.Plugins.Stop()
|
workers.Plugins.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if workers.BleveIndexing != nil && *workers.ConfigService.Config().BleveSettings.EnableIndexing {
|
||||||
|
workers.BleveIndexing.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
mlog.Info("Stopped workers")
|
mlog.Info("Stopped workers")
|
||||||
|
|
||||||
return workers
|
return workers
|
||||||
|
|||||||
@@ -353,6 +353,10 @@ func (c *Client4) GetElasticsearchRoute() string {
|
|||||||
return "/elasticsearch"
|
return "/elasticsearch"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client4) GetBleveRoute() string {
|
||||||
|
return fmt.Sprintf("/bleve")
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client4) GetCommandsRoute() string {
|
func (c *Client4) GetCommandsRoute() string {
|
||||||
return "/commands"
|
return "/commands"
|
||||||
}
|
}
|
||||||
@@ -4075,6 +4079,18 @@ func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) {
|
|||||||
return CheckStatusOK(r), BuildResponse(r)
|
return CheckStatusOK(r), BuildResponse(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bleve Section
|
||||||
|
|
||||||
|
// PurgeBleveIndexes immediately deletes all Bleve indexes.
|
||||||
|
func (c *Client4) PurgeBleveIndexes() (bool, *Response) {
|
||||||
|
r, err := c.DoApiPost(c.GetBleveRoute()+"/purge_indexes", "")
|
||||||
|
if err != nil {
|
||||||
|
return false, BuildErrorResponse(r, err)
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
return CheckStatusOK(r), BuildResponse(r)
|
||||||
|
}
|
||||||
|
|
||||||
// Data Retention Section
|
// Data Retention Section
|
||||||
|
|
||||||
// GetDataRetentionPolicy will get the current server data retention policy details.
|
// GetDataRetentionPolicy will get the current server data retention policy details.
|
||||||
|
|||||||
@@ -181,6 +181,9 @@ const (
|
|||||||
ELASTICSEARCH_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS = 3600
|
ELASTICSEARCH_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS = 3600
|
||||||
ELASTICSEARCH_SETTINGS_DEFAULT_REQUEST_TIMEOUT_SECONDS = 30
|
ELASTICSEARCH_SETTINGS_DEFAULT_REQUEST_TIMEOUT_SECONDS = 30
|
||||||
|
|
||||||
|
BLEVE_SETTINGS_DEFAULT_INDEX_DIR = ""
|
||||||
|
BLEVE_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS = 3600
|
||||||
|
|
||||||
DATA_RETENTION_SETTINGS_DEFAULT_MESSAGE_RETENTION_DAYS = 365
|
DATA_RETENTION_SETTINGS_DEFAULT_MESSAGE_RETENTION_DAYS = 365
|
||||||
DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS = 365
|
DATA_RETENTION_SETTINGS_DEFAULT_FILE_RETENTION_DAYS = 365
|
||||||
DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME = "02:00"
|
DATA_RETENTION_SETTINGS_DEFAULT_DELETION_JOB_START_TIME = "02:00"
|
||||||
@@ -2402,6 +2405,36 @@ func (s *ElasticsearchSettings) SetDefaults() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BleveSettings struct {
|
||||||
|
IndexDir *string
|
||||||
|
EnableIndexing *bool
|
||||||
|
EnableSearching *bool
|
||||||
|
EnableAutocomplete *bool
|
||||||
|
BulkIndexingTimeWindowSeconds *int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bs *BleveSettings) SetDefaults() {
|
||||||
|
if bs.IndexDir == nil {
|
||||||
|
bs.IndexDir = NewString(BLEVE_SETTINGS_DEFAULT_INDEX_DIR)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bs.EnableIndexing == nil {
|
||||||
|
bs.EnableIndexing = NewBool(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bs.EnableSearching == nil {
|
||||||
|
bs.EnableSearching = NewBool(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bs.EnableAutocomplete == nil {
|
||||||
|
bs.EnableAutocomplete = NewBool(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if bs.BulkIndexingTimeWindowSeconds == nil {
|
||||||
|
bs.BulkIndexingTimeWindowSeconds = NewInt(BLEVE_SETTINGS_DEFAULT_BULK_INDEXING_TIME_WINDOW_SECONDS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type DataRetentionSettings struct {
|
type DataRetentionSettings struct {
|
||||||
EnableMessageDeletion *bool
|
EnableMessageDeletion *bool
|
||||||
EnableFileDeletion *bool
|
EnableFileDeletion *bool
|
||||||
@@ -2704,6 +2737,7 @@ type Config struct {
|
|||||||
ExperimentalSettings ExperimentalSettings
|
ExperimentalSettings ExperimentalSettings
|
||||||
AnalyticsSettings AnalyticsSettings
|
AnalyticsSettings AnalyticsSettings
|
||||||
ElasticsearchSettings ElasticsearchSettings
|
ElasticsearchSettings ElasticsearchSettings
|
||||||
|
BleveSettings BleveSettings
|
||||||
DataRetentionSettings DataRetentionSettings
|
DataRetentionSettings DataRetentionSettings
|
||||||
MessageExportSettings MessageExportSettings
|
MessageExportSettings MessageExportSettings
|
||||||
JobSettings JobSettings
|
JobSettings JobSettings
|
||||||
@@ -2785,6 +2819,7 @@ func (o *Config) SetDefaults() {
|
|||||||
o.ComplianceSettings.SetDefaults()
|
o.ComplianceSettings.SetDefaults()
|
||||||
o.LocalizationSettings.SetDefaults()
|
o.LocalizationSettings.SetDefaults()
|
||||||
o.ElasticsearchSettings.SetDefaults()
|
o.ElasticsearchSettings.SetDefaults()
|
||||||
|
o.BleveSettings.SetDefaults()
|
||||||
o.NativeAppSettings.SetDefaults()
|
o.NativeAppSettings.SetDefaults()
|
||||||
o.DataRetentionSettings.SetDefaults()
|
o.DataRetentionSettings.SetDefaults()
|
||||||
o.RateLimitSettings.SetDefaults()
|
o.RateLimitSettings.SetDefaults()
|
||||||
@@ -2851,6 +2886,10 @@ func (o *Config) IsValid() *AppError {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := o.BleveSettings.isValid(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := o.DataRetentionSettings.isValid(); err != nil {
|
if err := o.DataRetentionSettings.isValid(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -3234,6 +3273,26 @@ func (s *ElasticsearchSettings) isValid() *AppError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (bs *BleveSettings) isValid() *AppError {
|
||||||
|
if *bs.EnableIndexing {
|
||||||
|
if len(*bs.IndexDir) == 0 {
|
||||||
|
return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.filename.app_error", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if *bs.EnableSearching {
|
||||||
|
return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.enable_searching.app_error", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
if *bs.EnableAutocomplete {
|
||||||
|
return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.enable_autocomplete.app_error", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if *bs.BulkIndexingTimeWindowSeconds < 1 {
|
||||||
|
return NewAppError("Config.IsValid", "model.config.is_valid.bleve_search.bulk_indexing_time_window_seconds.app_error", nil, "", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DataRetentionSettings) isValid() *AppError {
|
func (s *DataRetentionSettings) isValid() *AppError {
|
||||||
if *s.MessageRetentionDays <= 0 {
|
if *s.MessageRetentionDays <= 0 {
|
||||||
return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.message_retention_days_too_low.app_error", nil, "", http.StatusBadRequest)
|
return NewAppError("Config.IsValid", "model.config.is_valid.data_retention.message_retention_days_too_low.app_error", nil, "", http.StatusBadRequest)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const (
|
|||||||
JOB_TYPE_MESSAGE_EXPORT = "message_export"
|
JOB_TYPE_MESSAGE_EXPORT = "message_export"
|
||||||
JOB_TYPE_ELASTICSEARCH_POST_INDEXING = "elasticsearch_post_indexing"
|
JOB_TYPE_ELASTICSEARCH_POST_INDEXING = "elasticsearch_post_indexing"
|
||||||
JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION = "elasticsearch_post_aggregation"
|
JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION = "elasticsearch_post_aggregation"
|
||||||
|
JOB_TYPE_BLEVE_POST_INDEXING = "bleve_post_indexing"
|
||||||
JOB_TYPE_LDAP_SYNC = "ldap_sync"
|
JOB_TYPE_LDAP_SYNC = "ldap_sync"
|
||||||
JOB_TYPE_MIGRATIONS = "migrations"
|
JOB_TYPE_MIGRATIONS = "migrations"
|
||||||
JOB_TYPE_PLUGINS = "plugins"
|
JOB_TYPE_PLUGINS = "plugins"
|
||||||
@@ -53,6 +54,7 @@ func (j *Job) IsValid() *AppError {
|
|||||||
case JOB_TYPE_DATA_RETENTION:
|
case JOB_TYPE_DATA_RETENTION:
|
||||||
case JOB_TYPE_ELASTICSEARCH_POST_INDEXING:
|
case JOB_TYPE_ELASTICSEARCH_POST_INDEXING:
|
||||||
case JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION:
|
case JOB_TYPE_ELASTICSEARCH_POST_AGGREGATION:
|
||||||
|
case JOB_TYPE_BLEVE_POST_INDEXING:
|
||||||
case JOB_TYPE_LDAP_SYNC:
|
case JOB_TYPE_LDAP_SYNC:
|
||||||
case JOB_TYPE_MESSAGE_EXPORT:
|
case JOB_TYPE_MESSAGE_EXPORT:
|
||||||
case JOB_TYPE_MIGRATIONS:
|
case JOB_TYPE_MIGRATIONS:
|
||||||
|
|||||||
281
services/searchengine/bleveengine/bleve.go
Обычный файл
281
services/searchengine/bleveengine/bleve.go
Обычный файл
@@ -0,0 +1,281 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package bleveengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/v5/jobs"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/mlog"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve"
|
||||||
|
"github.com/blevesearch/bleve/analysis/analyzer/keyword"
|
||||||
|
"github.com/blevesearch/bleve/analysis/analyzer/standard"
|
||||||
|
"github.com/blevesearch/bleve/mapping"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ENGINE_NAME = "bleve"
|
||||||
|
POST_INDEX = "posts"
|
||||||
|
USER_INDEX = "users"
|
||||||
|
CHANNEL_INDEX = "channels"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BleveEngine struct {
|
||||||
|
PostIndex bleve.Index
|
||||||
|
UserIndex bleve.Index
|
||||||
|
ChannelIndex bleve.Index
|
||||||
|
Mutex sync.RWMutex
|
||||||
|
ready int32
|
||||||
|
cfg *model.Config
|
||||||
|
jobServer *jobs.JobServer
|
||||||
|
indexSync bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var keywordMapping *mapping.FieldMapping
|
||||||
|
var standardMapping *mapping.FieldMapping
|
||||||
|
var dateMapping *mapping.FieldMapping
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
keywordMapping = bleve.NewTextFieldMapping()
|
||||||
|
keywordMapping.Analyzer = keyword.Name
|
||||||
|
|
||||||
|
standardMapping = bleve.NewTextFieldMapping()
|
||||||
|
standardMapping.Analyzer = standard.Name
|
||||||
|
|
||||||
|
dateMapping = bleve.NewNumericFieldMapping()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getChannelIndexMapping() *mapping.IndexMappingImpl {
|
||||||
|
channelMapping := bleve.NewDocumentMapping()
|
||||||
|
channelMapping.AddFieldMappingsAt("Id", keywordMapping)
|
||||||
|
channelMapping.AddFieldMappingsAt("TeamId", keywordMapping)
|
||||||
|
channelMapping.AddFieldMappingsAt("NameSuggest", keywordMapping)
|
||||||
|
|
||||||
|
indexMapping := bleve.NewIndexMapping()
|
||||||
|
indexMapping.AddDocumentMapping("_default", channelMapping)
|
||||||
|
|
||||||
|
return indexMapping
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPostIndexMapping() *mapping.IndexMappingImpl {
|
||||||
|
postMapping := bleve.NewDocumentMapping()
|
||||||
|
postMapping.AddFieldMappingsAt("Id", keywordMapping)
|
||||||
|
postMapping.AddFieldMappingsAt("TeamId", keywordMapping)
|
||||||
|
postMapping.AddFieldMappingsAt("ChannelId", keywordMapping)
|
||||||
|
postMapping.AddFieldMappingsAt("UserId", keywordMapping)
|
||||||
|
postMapping.AddFieldMappingsAt("CreateAt", dateMapping)
|
||||||
|
postMapping.AddFieldMappingsAt("Message", standardMapping)
|
||||||
|
postMapping.AddFieldMappingsAt("Type", keywordMapping)
|
||||||
|
postMapping.AddFieldMappingsAt("Hashtags", standardMapping)
|
||||||
|
postMapping.AddFieldMappingsAt("Attachments", standardMapping)
|
||||||
|
|
||||||
|
indexMapping := bleve.NewIndexMapping()
|
||||||
|
indexMapping.AddDocumentMapping("_default", postMapping)
|
||||||
|
|
||||||
|
return indexMapping
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserIndexMapping() *mapping.IndexMappingImpl {
|
||||||
|
userMapping := bleve.NewDocumentMapping()
|
||||||
|
userMapping.AddFieldMappingsAt("Id", keywordMapping)
|
||||||
|
userMapping.AddFieldMappingsAt("SuggestionsWithFullname", keywordMapping)
|
||||||
|
userMapping.AddFieldMappingsAt("SuggestionsWithoutFullname", keywordMapping)
|
||||||
|
userMapping.AddFieldMappingsAt("TeamsIds", keywordMapping)
|
||||||
|
userMapping.AddFieldMappingsAt("ChannelsIds", keywordMapping)
|
||||||
|
|
||||||
|
indexMapping := bleve.NewIndexMapping()
|
||||||
|
indexMapping.AddDocumentMapping("_default", userMapping)
|
||||||
|
|
||||||
|
return indexMapping
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBleveEngine(cfg *model.Config, jobServer *jobs.JobServer) *BleveEngine {
|
||||||
|
return &BleveEngine{
|
||||||
|
cfg: cfg,
|
||||||
|
jobServer: jobServer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) getIndexDir(indexName string) string {
|
||||||
|
return filepath.Join(*b.cfg.BleveSettings.IndexDir, indexName+".bleve")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) createOrOpenIndex(indexName string, mapping *mapping.IndexMappingImpl) (bleve.Index, error) {
|
||||||
|
indexPath := b.getIndexDir(indexName)
|
||||||
|
if index, err := bleve.Open(indexPath); err == nil {
|
||||||
|
return index, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
index, err := bleve.New(indexPath, mapping)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return index, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) openIndexes() *model.AppError {
|
||||||
|
if atomic.LoadInt32(&b.ready) != 0 {
|
||||||
|
return model.NewAppError("Bleveengine.Start", "bleveengine.already_started.error", nil, "", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
b.PostIndex, err = b.createOrOpenIndex(POST_INDEX, getPostIndexMapping())
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.Start", "bleveengine.create_post_index.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.UserIndex, err = b.createOrOpenIndex(USER_INDEX, getUserIndexMapping())
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.Start", "bleveengine.create_user_index.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ChannelIndex, err = b.createOrOpenIndex(CHANNEL_INDEX, getChannelIndexMapping())
|
||||||
|
if err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.Start", "bleveengine.create_channel_index.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic.StoreInt32(&b.ready, 1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) Start() *model.AppError {
|
||||||
|
if !*b.cfg.BleveSettings.EnableIndexing || *b.cfg.BleveSettings.IndexDir == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Mutex.Lock()
|
||||||
|
defer b.Mutex.Unlock()
|
||||||
|
|
||||||
|
mlog.Info("EXPERIMENTAL: Starting Bleve")
|
||||||
|
|
||||||
|
return b.openIndexes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) closeIndexes() *model.AppError {
|
||||||
|
if b.IsActive() {
|
||||||
|
if err := b.PostIndex.Close(); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.Stop", "bleveengine.stop_post_index.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.UserIndex.Close(); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.Stop", "bleveengine.stop_user_index.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.ChannelIndex.Close(); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.Stop", "bleveengine.stop_channel_index.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic.StoreInt32(&b.ready, 0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) Stop() *model.AppError {
|
||||||
|
b.Mutex.Lock()
|
||||||
|
defer b.Mutex.Unlock()
|
||||||
|
|
||||||
|
mlog.Info("Stopping Bleve")
|
||||||
|
|
||||||
|
return b.closeIndexes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) IsActive() bool {
|
||||||
|
return atomic.LoadInt32(&b.ready) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) IsIndexingSync() bool {
|
||||||
|
return b.indexSync
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) RefreshIndexes() *model.AppError {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) GetVersion() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) GetName() string {
|
||||||
|
return ENGINE_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) TestConfig(cfg *model.Config) *model.AppError {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) deleteIndexes() *model.AppError {
|
||||||
|
if err := os.RemoveAll(b.getIndexDir(POST_INDEX)); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.PurgeIndexes", "bleveengine.purge_post_index.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
if err := os.RemoveAll(b.getIndexDir(USER_INDEX)); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.PurgeIndexes", "bleveengine.purge_user_index.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
if err := os.RemoveAll(b.getIndexDir(CHANNEL_INDEX)); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.PurgeIndexes", "bleveengine.purge_channel_index.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) PurgeIndexes() *model.AppError {
|
||||||
|
if *b.cfg.BleveSettings.IndexDir == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Mutex.Lock()
|
||||||
|
defer b.Mutex.Unlock()
|
||||||
|
|
||||||
|
mlog.Info("PurgeIndexes Bleve")
|
||||||
|
if err := b.closeIndexes(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := b.deleteIndexes(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.openIndexes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) DataRetentionDeleteIndexes(cutoff time.Time) *model.AppError {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) IsAutocompletionEnabled() bool {
|
||||||
|
return *b.cfg.BleveSettings.EnableAutocomplete
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) IsIndexingEnabled() bool {
|
||||||
|
return *b.cfg.BleveSettings.EnableIndexing
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) IsSearchEnabled() bool {
|
||||||
|
return *b.cfg.BleveSettings.EnableSearching
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) UpdateConfig(cfg *model.Config) {
|
||||||
|
b.Mutex.Lock()
|
||||||
|
defer b.Mutex.Unlock()
|
||||||
|
|
||||||
|
mlog.Info("UpdateConf Bleve")
|
||||||
|
|
||||||
|
if *cfg.BleveSettings.EnableIndexing != *b.cfg.BleveSettings.EnableIndexing || *cfg.BleveSettings.IndexDir != *b.cfg.BleveSettings.IndexDir {
|
||||||
|
if err := b.closeIndexes(); err != nil {
|
||||||
|
mlog.Error("Error closing Bleve indexes to update the config", mlog.Err(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.cfg = cfg
|
||||||
|
if err := b.openIndexes(); err != nil {
|
||||||
|
mlog.Error("Error opening Bleve indexes after updating the config", mlog.Err(err))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b.cfg = cfg
|
||||||
|
}
|
||||||
98
services/searchengine/bleveengine/bleve_test.go
Обычный файл
98
services/searchengine/bleveengine/bleve_test.go
Обычный файл
@@ -0,0 +1,98 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package bleveengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/services/searchengine"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/store/searchlayer"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/store/searchtest"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/store/sqlstore"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/store/storetest"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/testlib"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BleveEngineTestSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
|
||||||
|
SQLSettings *model.SqlSettings
|
||||||
|
SQLSupplier *sqlstore.SqlSupplier
|
||||||
|
SearchEngine *searchengine.Broker
|
||||||
|
Store *searchlayer.SearchStore
|
||||||
|
IndexDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBleveEngineTestSuite(t *testing.T) {
|
||||||
|
suite.Run(t, new(BleveEngineTestSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BleveEngineTestSuite) setupIndexes() {
|
||||||
|
indexDir, err := ioutil.TempDir("", "mmbleve")
|
||||||
|
if err != nil {
|
||||||
|
s.Require().FailNow("Cannot setup bleveengine tests: %s", err.Error())
|
||||||
|
}
|
||||||
|
s.IndexDir = indexDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BleveEngineTestSuite) setupStore() {
|
||||||
|
driverName := os.Getenv("MM_SQLSETTINGS_DRIVERNAME")
|
||||||
|
if driverName == "" {
|
||||||
|
driverName = model.DATABASE_DRIVER_POSTGRES
|
||||||
|
}
|
||||||
|
s.SQLSettings = storetest.MakeSqlSettings(driverName)
|
||||||
|
s.SQLSupplier = sqlstore.NewSqlSupplier(*s.SQLSettings, nil)
|
||||||
|
|
||||||
|
cfg := &model.Config{}
|
||||||
|
cfg.SetDefaults()
|
||||||
|
cfg.BleveSettings.EnableIndexing = model.NewBool(true)
|
||||||
|
cfg.BleveSettings.EnableSearching = model.NewBool(true)
|
||||||
|
cfg.BleveSettings.EnableAutocomplete = model.NewBool(true)
|
||||||
|
cfg.BleveSettings.IndexDir = model.NewString(s.IndexDir)
|
||||||
|
cfg.SqlSettings.DisableDatabaseSearch = model.NewBool(true)
|
||||||
|
|
||||||
|
s.SearchEngine = searchengine.NewBroker(cfg, nil)
|
||||||
|
s.Store = searchlayer.NewSearchLayer(&testlib.TestStore{Store: s.SQLSupplier}, s.SearchEngine, cfg)
|
||||||
|
|
||||||
|
bleveEngine := NewBleveEngine(cfg, nil)
|
||||||
|
bleveEngine.indexSync = true
|
||||||
|
s.SearchEngine.RegisterBleveEngine(bleveEngine)
|
||||||
|
if err := bleveEngine.Start(); err != nil {
|
||||||
|
s.Require().FailNow("Cannot start bleveengine: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BleveEngineTestSuite) SetupSuite() {
|
||||||
|
s.setupIndexes()
|
||||||
|
s.setupStore()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BleveEngineTestSuite) TearDownSuite() {
|
||||||
|
os.RemoveAll(s.IndexDir)
|
||||||
|
s.SQLSupplier.Close()
|
||||||
|
storetest.CleanupSqlSettings(s.SQLSettings)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *BleveEngineTestSuite) TestBleveSearchStoreTests() {
|
||||||
|
searchTestEngine := &searchtest.SearchTestEngine{
|
||||||
|
Driver: searchtest.ENGINE_BLEVE,
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Run("TestSearchChannelStore", func() {
|
||||||
|
searchtest.TestSearchChannelStore(s.T(), s.Store, searchTestEngine)
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Run("TestSearchUserStore", func() {
|
||||||
|
searchtest.TestSearchUserStore(s.T(), s.Store, searchTestEngine)
|
||||||
|
})
|
||||||
|
|
||||||
|
s.Run("TestSearchPostStore", func() {
|
||||||
|
searchtest.TestSearchPostStore(s.T(), s.Store, searchTestEngine)
|
||||||
|
})
|
||||||
|
}
|
||||||
116
services/searchengine/bleveengine/common.go
Обычный файл
116
services/searchengine/bleveengine/common.go
Обычный файл
@@ -0,0 +1,116 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package bleveengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/services/searchengine"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BLVChannel struct {
|
||||||
|
Id string
|
||||||
|
TeamId []string
|
||||||
|
NameSuggest []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BLVUser struct {
|
||||||
|
Id string
|
||||||
|
SuggestionsWithFullname []string
|
||||||
|
SuggestionsWithoutFullname []string
|
||||||
|
TeamsIds []string
|
||||||
|
ChannelsIds []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type BLVPost struct {
|
||||||
|
Id string
|
||||||
|
TeamId string
|
||||||
|
ChannelId string
|
||||||
|
UserId string
|
||||||
|
CreateAt int64
|
||||||
|
Message string
|
||||||
|
Type string
|
||||||
|
Hashtags []string
|
||||||
|
Attachments string
|
||||||
|
}
|
||||||
|
|
||||||
|
func BLVChannelFromChannel(channel *model.Channel) *BLVChannel {
|
||||||
|
displayNameInputs := searchengine.GetSuggestionInputsSplitBy(channel.DisplayName, " ")
|
||||||
|
nameInputs := searchengine.GetSuggestionInputsSplitByMultiple(channel.Name, []string{"-", "_"})
|
||||||
|
|
||||||
|
return &BLVChannel{
|
||||||
|
Id: channel.Id,
|
||||||
|
TeamId: []string{channel.TeamId},
|
||||||
|
NameSuggest: append(displayNameInputs, nameInputs...),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BLVUserFromUserAndTeams(user *model.User, teamsIds, channelsIds []string) *BLVUser {
|
||||||
|
usernameSuggestions := searchengine.GetSuggestionInputsSplitByMultiple(user.Username, []string{".", "-", "_"})
|
||||||
|
|
||||||
|
fullnameStrings := []string{}
|
||||||
|
if user.FirstName != "" {
|
||||||
|
fullnameStrings = append(fullnameStrings, user.FirstName)
|
||||||
|
}
|
||||||
|
if user.LastName != "" {
|
||||||
|
fullnameStrings = append(fullnameStrings, user.LastName)
|
||||||
|
}
|
||||||
|
|
||||||
|
fullnameSuggestions := []string{}
|
||||||
|
if len(fullnameStrings) > 0 {
|
||||||
|
fullname := strings.Join(fullnameStrings, " ")
|
||||||
|
fullnameSuggestions = searchengine.GetSuggestionInputsSplitBy(fullname, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
nicknameSuggesitons := []string{}
|
||||||
|
if user.Nickname != "" {
|
||||||
|
nicknameSuggesitons = searchengine.GetSuggestionInputsSplitBy(user.Nickname, " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
usernameAndNicknameSuggestions := append(usernameSuggestions, nicknameSuggesitons...)
|
||||||
|
|
||||||
|
return &BLVUser{
|
||||||
|
Id: user.Id,
|
||||||
|
SuggestionsWithFullname: append(usernameAndNicknameSuggestions, fullnameSuggestions...),
|
||||||
|
SuggestionsWithoutFullname: usernameAndNicknameSuggestions,
|
||||||
|
TeamsIds: teamsIds,
|
||||||
|
ChannelsIds: channelsIds,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BLVUserFromUserForIndexing(userForIndexing *model.UserForIndexing) *BLVUser {
|
||||||
|
user := &model.User{
|
||||||
|
Id: userForIndexing.Id,
|
||||||
|
Username: userForIndexing.Username,
|
||||||
|
Nickname: userForIndexing.Nickname,
|
||||||
|
FirstName: userForIndexing.FirstName,
|
||||||
|
LastName: userForIndexing.LastName,
|
||||||
|
CreateAt: userForIndexing.CreateAt,
|
||||||
|
DeleteAt: userForIndexing.DeleteAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
return BLVUserFromUserAndTeams(user, userForIndexing.TeamsIds, userForIndexing.ChannelsIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BLVPostFromPost(post *model.Post, teamId string) *BLVPost {
|
||||||
|
p := &model.PostForIndexing{
|
||||||
|
TeamId: teamId,
|
||||||
|
}
|
||||||
|
post.ShallowCopy(&p.Post)
|
||||||
|
return BLVPostFromPostForIndexing(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BLVPostFromPostForIndexing(post *model.PostForIndexing) *BLVPost {
|
||||||
|
return &BLVPost{
|
||||||
|
Id: post.Id,
|
||||||
|
TeamId: post.TeamId,
|
||||||
|
ChannelId: post.ChannelId,
|
||||||
|
UserId: post.UserId,
|
||||||
|
CreateAt: post.CreateAt,
|
||||||
|
Message: post.Message,
|
||||||
|
Type: post.Type,
|
||||||
|
Hashtags: strings.Fields(post.Hashtags),
|
||||||
|
}
|
||||||
|
}
|
||||||
510
services/searchengine/bleveengine/indexer/indexing_job.go
Обычный файл
510
services/searchengine/bleveengine/indexer/indexing_job.go
Обычный файл
@@ -0,0 +1,510 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package ebleveengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/v5/app"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/jobs"
|
||||||
|
tjobs "github.com/mattermost/mattermost-server/v5/jobs/interfaces"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/mlog"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
|
"github.com/mattermost/mattermost-server/v5/services/searchengine/bleveengine"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BATCH_SIZE = 1000
|
||||||
|
TIME_BETWEEN_BATCHES = 100
|
||||||
|
ESTIMATED_POST_COUNT = 10000000
|
||||||
|
ESTIMATED_CHANNEL_COUNT = 100000
|
||||||
|
ESTIMATED_USER_COUNT = 10000
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
app.RegisterJobsBleveIndexerInterface(func(s *app.Server) tjobs.IndexerJobInterface {
|
||||||
|
return &BleveIndexerInterfaceImpl{s}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type BleveIndexerInterfaceImpl struct {
|
||||||
|
Server *app.Server
|
||||||
|
}
|
||||||
|
|
||||||
|
type BleveIndexerWorker struct {
|
||||||
|
name string
|
||||||
|
stop chan bool
|
||||||
|
stopped chan bool
|
||||||
|
jobs chan model.Job
|
||||||
|
jobServer *jobs.JobServer
|
||||||
|
|
||||||
|
engine *bleveengine.BleveEngine
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bi *BleveIndexerInterfaceImpl) MakeWorker() model.Worker {
|
||||||
|
return &BleveIndexerWorker{
|
||||||
|
name: "BleveIndexer",
|
||||||
|
stop: make(chan bool, 1),
|
||||||
|
stopped: make(chan bool, 1),
|
||||||
|
jobs: make(chan model.Job),
|
||||||
|
jobServer: bi.Server.Jobs,
|
||||||
|
|
||||||
|
engine: bi.Server.SearchEngine.BleveEngine.(*bleveengine.BleveEngine),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type IndexingProgress struct {
|
||||||
|
Now time.Time
|
||||||
|
StartAtTime int64
|
||||||
|
EndAtTime int64
|
||||||
|
LastEntityTime int64
|
||||||
|
TotalPostsCount int64
|
||||||
|
DonePostsCount int64
|
||||||
|
DonePosts bool
|
||||||
|
TotalChannelsCount int64
|
||||||
|
DoneChannelsCount int64
|
||||||
|
DoneChannels bool
|
||||||
|
TotalUsersCount int64
|
||||||
|
DoneUsersCount int64
|
||||||
|
DoneUsers bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *IndexingProgress) CurrentProgress() int64 {
|
||||||
|
return (ip.DonePostsCount + ip.DoneChannelsCount + ip.DoneUsersCount) * 100 / (ip.TotalPostsCount + ip.TotalChannelsCount + ip.TotalUsersCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ip *IndexingProgress) IsDone() bool {
|
||||||
|
return ip.DonePosts && ip.DoneChannels && ip.DoneUsers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) JobChannel() chan<- model.Job {
|
||||||
|
return worker.jobs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) Run() {
|
||||||
|
mlog.Debug("Worker Started", mlog.String("workername", worker.name))
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
mlog.Debug("Worker: Finished", mlog.String("workername", worker.name))
|
||||||
|
worker.stopped <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-worker.stop:
|
||||||
|
mlog.Debug("Worker: Received stop signal", mlog.String("workername", worker.name))
|
||||||
|
return
|
||||||
|
case job := <-worker.jobs:
|
||||||
|
mlog.Debug("Worker: Received a new candidate job.", mlog.String("workername", worker.name))
|
||||||
|
worker.DoJob(&job)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) Stop() {
|
||||||
|
mlog.Debug("Worker Stopping", mlog.String("workername", worker.name))
|
||||||
|
worker.stop <- true
|
||||||
|
<-worker.stopped
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) DoJob(job *model.Job) {
|
||||||
|
claimed, err := worker.jobServer.ClaimJob(job)
|
||||||
|
if err != nil {
|
||||||
|
mlog.Warn("Worker: Error ocurred while trying to claim job", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !claimed {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mlog.Info("Worker: Indexing job claimed by worker", mlog.String("workername", worker.name), mlog.String("job_id", job.Id))
|
||||||
|
|
||||||
|
if !worker.engine.IsActive() {
|
||||||
|
appError := model.NewAppError("BleveIndexerWorker", "bleveengine.indexer.do_job.engine_inactive", nil, "", http.StatusInternalServerError)
|
||||||
|
if err := worker.jobServer.SetJobError(job, appError); err != nil {
|
||||||
|
mlog.Error("Worker: Failed to run job as ")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
progress := IndexingProgress{
|
||||||
|
Now: time.Now(),
|
||||||
|
DonePosts: false,
|
||||||
|
DoneChannels: false,
|
||||||
|
DoneUsers: false,
|
||||||
|
StartAtTime: 0,
|
||||||
|
EndAtTime: model.GetMillis(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the start and end times, if they are set.
|
||||||
|
if startString, ok := job.Data["start_time"]; ok {
|
||||||
|
startInt, err := strconv.ParseInt(startString, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
mlog.Error("Worker: Failed to parse start_time for job", mlog.String("workername", worker.name), mlog.String("start_time", startString), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
appError := model.NewAppError("BleveIndexerWorker", "bleveengine.indexer.do_job.parse_start_time.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
if err := worker.jobServer.SetJobError(job, appError); err != nil {
|
||||||
|
mlog.Error("Worker: Failed to set job error", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err), mlog.NamedErr("set_error", appError))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
progress.StartAtTime = startInt
|
||||||
|
progress.LastEntityTime = progress.StartAtTime
|
||||||
|
} else {
|
||||||
|
// Set start time to oldest post in the database.
|
||||||
|
oldestPost, err := worker.jobServer.Store.Post().GetOldest()
|
||||||
|
if err != nil {
|
||||||
|
mlog.Error("Worker: Failed to fetch oldest post for job.", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.String("start_time", startString), mlog.Err(err))
|
||||||
|
appError := model.NewAppError("BleveIndexerWorker", "bleveengine.indexer.do_job.get_oldest_post.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
if err := worker.jobServer.SetJobError(job, appError); err != nil {
|
||||||
|
mlog.Error("Worker: Failed to set job error", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err), mlog.NamedErr("set_error", appError))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
progress.StartAtTime = oldestPost.CreateAt
|
||||||
|
progress.LastEntityTime = progress.StartAtTime
|
||||||
|
}
|
||||||
|
|
||||||
|
if endString, ok := job.Data["end_time"]; ok {
|
||||||
|
endInt, err := strconv.ParseInt(endString, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
mlog.Error("Worker: Failed to parse end_time for job", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.String("end_time", endString), mlog.Err(err))
|
||||||
|
appError := model.NewAppError("BleveIndexerWorker", "bleveengine.indexer.do_job.parse_end_time.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
if err := worker.jobServer.SetJobError(job, appError); err != nil {
|
||||||
|
mlog.Error("Worker: Failed to set job errorv", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err), mlog.NamedErr("set_error", appError))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
progress.EndAtTime = endInt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Counting all posts may fail or timeout when the posts table is large. If this happens, log a warning, but carry
|
||||||
|
// on with the indexing job anyway. The only issue is that the progress % reporting will be inaccurate.
|
||||||
|
if count, err := worker.jobServer.Store.Post().AnalyticsPostCount("", false, false); err != nil {
|
||||||
|
mlog.Warn("Worker: Failed to fetch total post count for job. An estimated value will be used for progress reporting.", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
progress.TotalPostsCount = ESTIMATED_POST_COUNT
|
||||||
|
} else {
|
||||||
|
progress.TotalPostsCount = count
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same possible fail as above can happen when counting channels
|
||||||
|
if count, err := worker.jobServer.Store.Channel().AnalyticsTypeCount("", "O"); err != nil {
|
||||||
|
mlog.Warn("Worker: Failed to fetch total channel count for job. An estimated value will be used for progress reporting.", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
progress.TotalChannelsCount = ESTIMATED_CHANNEL_COUNT
|
||||||
|
} else {
|
||||||
|
progress.TotalChannelsCount = count
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same possible fail as above can happen when counting users
|
||||||
|
if count, err := worker.jobServer.Store.User().Count(model.UserCountOptions{}); err != nil {
|
||||||
|
mlog.Warn("Worker: Failed to fetch total user count for job. An estimated value will be used for progress reporting.", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
progress.TotalUsersCount = ESTIMATED_USER_COUNT
|
||||||
|
} else {
|
||||||
|
progress.TotalUsersCount = count
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelCtx, cancelCancelWatcher := context.WithCancel(context.Background())
|
||||||
|
cancelWatcherChan := make(chan interface{}, 1)
|
||||||
|
go worker.jobServer.CancellationWatcher(cancelCtx, job.Id, cancelWatcherChan)
|
||||||
|
|
||||||
|
defer cancelCancelWatcher()
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-cancelWatcherChan:
|
||||||
|
mlog.Info("Worker: Indexing job has been canceled via CancellationWatcher", mlog.String("workername", worker.name), mlog.String("job_id", job.Id))
|
||||||
|
if err := worker.jobServer.SetJobCanceled(job); err != nil {
|
||||||
|
mlog.Error("Worker: Failed to mark job as cancelled", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case <-worker.stop:
|
||||||
|
mlog.Info("Worker: Indexing has been canceled via Worker Stop", mlog.String("workername", worker.name), mlog.String("job_id", job.Id))
|
||||||
|
if err := worker.jobServer.SetJobCanceled(job); err != nil {
|
||||||
|
mlog.Error("Worker: Failed to mark job as canceled", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
|
||||||
|
case <-time.After(TIME_BETWEEN_BATCHES * time.Millisecond):
|
||||||
|
var err *model.AppError
|
||||||
|
if progress, err = worker.IndexBatch(progress); err != nil {
|
||||||
|
mlog.Error("Worker: Failed to index batch for job", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
if err2 := worker.jobServer.SetJobError(job, err); err2 != nil {
|
||||||
|
mlog.Error("Worker: Failed to set job error", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err2), mlog.NamedErr("set_error", err))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := worker.jobServer.SetJobProgress(job, progress.CurrentProgress()); err != nil {
|
||||||
|
mlog.Error("Worker: Failed to set progress for job", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
if err2 := worker.jobServer.SetJobError(job, err); err2 != nil {
|
||||||
|
mlog.Error("Worker: Failed to set error for job", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err2), mlog.NamedErr("set_error", err))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if progress.IsDone() {
|
||||||
|
if err := worker.jobServer.SetJobSuccess(job); err != nil {
|
||||||
|
mlog.Error("Worker: Failed to set success for job", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err))
|
||||||
|
if err2 := worker.jobServer.SetJobError(job, err); err2 != nil {
|
||||||
|
mlog.Error("Worker: Failed to set error for job", mlog.String("workername", worker.name), mlog.String("job_id", job.Id), mlog.Err(err2), mlog.NamedErr("set_error", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mlog.Info("Worker: Indexing job finished successfully", mlog.String("workername", worker.name), mlog.String("job_id", job.Id))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) IndexBatch(progress IndexingProgress) (IndexingProgress, *model.AppError) {
|
||||||
|
if !progress.DonePosts {
|
||||||
|
return worker.IndexPostsBatch(progress)
|
||||||
|
}
|
||||||
|
if !progress.DoneChannels {
|
||||||
|
return worker.IndexChannelsBatch(progress)
|
||||||
|
}
|
||||||
|
if !progress.DoneUsers {
|
||||||
|
return worker.IndexUsersBatch(progress)
|
||||||
|
}
|
||||||
|
return progress, model.NewAppError("BleveIndexerWorker", "bleveengine.indexer.index_batch.nothing_left_to_index.error", nil, "", http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) IndexPostsBatch(progress IndexingProgress) (IndexingProgress, *model.AppError) {
|
||||||
|
endTime := progress.LastEntityTime + int64(*worker.jobServer.Config().BleveSettings.BulkIndexingTimeWindowSeconds*1000)
|
||||||
|
|
||||||
|
var posts []*model.PostForIndexing
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for posts == nil {
|
||||||
|
var err *model.AppError
|
||||||
|
posts, err = worker.jobServer.Store.Post().GetPostsBatchForIndexing(progress.LastEntityTime, endTime, BATCH_SIZE)
|
||||||
|
if err != nil {
|
||||||
|
if tries >= 10 {
|
||||||
|
return progress, err
|
||||||
|
} else {
|
||||||
|
mlog.Warn("Failed to get posts batch for indexing. Retrying.", mlog.Err(err))
|
||||||
|
|
||||||
|
// Wait a bit before trying again.
|
||||||
|
time.Sleep(15 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tries++
|
||||||
|
}
|
||||||
|
|
||||||
|
newLastMessageTime, err := worker.BulkIndexPosts(posts, progress)
|
||||||
|
if err != nil {
|
||||||
|
return progress, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Due to the "endTime" parameter in the store query, we might get an incomplete batch before the end. In this
|
||||||
|
// case, set the "newLastMessageTime" to the endTime so we don't get stuck running the same query in a loop.
|
||||||
|
if len(posts) < BATCH_SIZE {
|
||||||
|
newLastMessageTime = endTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// When to Stop: we index either until we pass a batch of messages where the last
|
||||||
|
// message is created at or after the specified end time when setting up the batch
|
||||||
|
// index, or until two consecutive full batches have the same end time of their final
|
||||||
|
// messages. This second case is safe as long as the assumption that the database
|
||||||
|
// cannot contain more messages with the same CreateAt time than the batch size holds.
|
||||||
|
if progress.EndAtTime <= newLastMessageTime {
|
||||||
|
progress.DonePosts = true
|
||||||
|
progress.LastEntityTime = progress.StartAtTime
|
||||||
|
} else if progress.LastEntityTime == newLastMessageTime && len(posts) == BATCH_SIZE {
|
||||||
|
mlog.Error("More posts with the same CreateAt time were detected than the permitted batch size. Aborting indexing job.", mlog.Int64("CreateAt", newLastMessageTime), mlog.Int("Batch Size", BATCH_SIZE))
|
||||||
|
progress.DonePosts = true
|
||||||
|
progress.LastEntityTime = progress.StartAtTime
|
||||||
|
} else {
|
||||||
|
progress.LastEntityTime = newLastMessageTime
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.DonePostsCount += int64(len(posts))
|
||||||
|
|
||||||
|
return progress, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) BulkIndexPosts(posts []*model.PostForIndexing, progress IndexingProgress) (int64, *model.AppError) {
|
||||||
|
lastCreateAt := int64(0)
|
||||||
|
batch := worker.engine.PostIndex.NewBatch()
|
||||||
|
|
||||||
|
for _, post := range posts {
|
||||||
|
if post.DeleteAt == 0 {
|
||||||
|
searchPost := bleveengine.BLVPostFromPostForIndexing(post)
|
||||||
|
batch.Index(searchPost.Id, searchPost)
|
||||||
|
} else {
|
||||||
|
batch.Delete(post.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCreateAt = post.CreateAt
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.engine.Mutex.RLock()
|
||||||
|
defer worker.engine.Mutex.RUnlock()
|
||||||
|
|
||||||
|
if err := worker.engine.PostIndex.Batch(batch); err != nil {
|
||||||
|
return 0, model.NewAppError("BleveIndexerWorker.BulkIndexPosts", "bleveengine.indexer.do_job.bulk_index_posts.batch_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return lastCreateAt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) IndexChannelsBatch(progress IndexingProgress) (IndexingProgress, *model.AppError) {
|
||||||
|
endTime := progress.LastEntityTime + int64(*worker.jobServer.Config().BleveSettings.BulkIndexingTimeWindowSeconds*1000)
|
||||||
|
|
||||||
|
var channels []*model.Channel
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for channels == nil {
|
||||||
|
var err *model.AppError
|
||||||
|
channels, err = worker.jobServer.Store.Channel().GetChannelsBatchForIndexing(progress.LastEntityTime, endTime, BATCH_SIZE)
|
||||||
|
if err != nil {
|
||||||
|
if tries >= 10 {
|
||||||
|
return progress, err
|
||||||
|
}
|
||||||
|
|
||||||
|
mlog.Warn("Failed to get channels batch for indexing. Retrying.", mlog.Err(err))
|
||||||
|
|
||||||
|
// Wait a bit before trying again.
|
||||||
|
time.Sleep(15 * time.Second)
|
||||||
|
}
|
||||||
|
tries++
|
||||||
|
}
|
||||||
|
|
||||||
|
newLastChannelTime, err := worker.BulkIndexChannels(channels, progress)
|
||||||
|
if err != nil {
|
||||||
|
return progress, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Due to the "endTime" parameter in the store query, we might get an incomplete batch before the end. In this
|
||||||
|
// case, set the "newLastChannelTime" to the endTime so we don't get stuck running the same query in a loop.
|
||||||
|
if len(channels) < BATCH_SIZE {
|
||||||
|
newLastChannelTime = endTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// When to Stop: we index either until we pass a batch of channels where the last
|
||||||
|
// channel is created at or after the specified end time when setting up the batch
|
||||||
|
// index, or until two consecutive full batches have the same end time of their final
|
||||||
|
// channels. This second case is safe as long as the assumption that the database
|
||||||
|
// cannot contain more channels with the same CreateAt time than the batch size holds.
|
||||||
|
if progress.EndAtTime <= newLastChannelTime {
|
||||||
|
progress.DoneChannels = true
|
||||||
|
progress.LastEntityTime = progress.StartAtTime
|
||||||
|
} else if progress.LastEntityTime == newLastChannelTime && len(channels) == BATCH_SIZE {
|
||||||
|
mlog.Error("More channels with the same CreateAt time were detected than the permitted batch size. Aborting indexing job.", mlog.Int64("CreateAt", newLastChannelTime), mlog.Int("Batch Size", BATCH_SIZE))
|
||||||
|
progress.DoneChannels = true
|
||||||
|
progress.LastEntityTime = progress.StartAtTime
|
||||||
|
} else {
|
||||||
|
progress.LastEntityTime = newLastChannelTime
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.DoneChannelsCount += int64(len(channels))
|
||||||
|
|
||||||
|
return progress, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) BulkIndexChannels(channels []*model.Channel, progress IndexingProgress) (int64, *model.AppError) {
|
||||||
|
lastCreateAt := int64(0)
|
||||||
|
batch := worker.engine.ChannelIndex.NewBatch()
|
||||||
|
|
||||||
|
for _, channel := range channels {
|
||||||
|
if channel.DeleteAt == 0 {
|
||||||
|
searchChannel := bleveengine.BLVChannelFromChannel(channel)
|
||||||
|
batch.Index(searchChannel.Id, searchChannel)
|
||||||
|
} else {
|
||||||
|
batch.Delete(channel.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCreateAt = channel.CreateAt
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.engine.Mutex.RLock()
|
||||||
|
defer worker.engine.Mutex.RUnlock()
|
||||||
|
|
||||||
|
if err := worker.engine.ChannelIndex.Batch(batch); err != nil {
|
||||||
|
return 0, model.NewAppError("BleveIndexerWorker.BulkIndexChannels", "bleveengine.indexer.do_job.bulk_index_channels.batch_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return lastCreateAt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) IndexUsersBatch(progress IndexingProgress) (IndexingProgress, *model.AppError) {
|
||||||
|
endTime := progress.LastEntityTime + int64(*worker.jobServer.Config().BleveSettings.BulkIndexingTimeWindowSeconds*1000)
|
||||||
|
|
||||||
|
var users []*model.UserForIndexing
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for users == nil {
|
||||||
|
if usersBatch, err := worker.jobServer.Store.User().GetUsersBatchForIndexing(progress.LastEntityTime, endTime, BATCH_SIZE); err != nil {
|
||||||
|
if tries >= 10 {
|
||||||
|
return progress, err
|
||||||
|
} else {
|
||||||
|
mlog.Warn("Failed to get users batch for indexing. Retrying.", mlog.Err(err))
|
||||||
|
|
||||||
|
// Wait a bit before trying again.
|
||||||
|
time.Sleep(15 * time.Second)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
users = usersBatch
|
||||||
|
}
|
||||||
|
|
||||||
|
tries++
|
||||||
|
}
|
||||||
|
|
||||||
|
newLastUserTime, err := worker.BulkIndexUsers(users, progress)
|
||||||
|
if err != nil {
|
||||||
|
return progress, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Due to the "endTime" parameter in the store query, we might get an incomplete batch before the end. In this
|
||||||
|
// case, set the "newLastUserTime" to the endTime so we don't get stuck running the same query in a loop.
|
||||||
|
if len(users) < BATCH_SIZE {
|
||||||
|
newLastUserTime = endTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// When to Stop: we index either until we pass a batch of users where the last
|
||||||
|
// user is created at or after the specified end time when setting up the batch
|
||||||
|
// index, or until two consecutive full batches have the same end time of their final
|
||||||
|
// users. This second case is safe as long as the assumption that the database
|
||||||
|
// cannot contain more users with the same CreateAt time than the batch size holds.
|
||||||
|
if progress.EndAtTime <= newLastUserTime {
|
||||||
|
progress.DoneUsers = true
|
||||||
|
progress.LastEntityTime = progress.StartAtTime
|
||||||
|
} else if progress.LastEntityTime == newLastUserTime && len(users) == BATCH_SIZE {
|
||||||
|
mlog.Error("More users with the same CreateAt time were detected than the permitted batch size. Aborting indexing job.", mlog.Int64("CreateAt", newLastUserTime), mlog.Int("Batch Size", BATCH_SIZE))
|
||||||
|
progress.DoneUsers = true
|
||||||
|
progress.LastEntityTime = progress.StartAtTime
|
||||||
|
} else {
|
||||||
|
progress.LastEntityTime = newLastUserTime
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.DoneUsersCount += int64(len(users))
|
||||||
|
|
||||||
|
return progress, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (worker *BleveIndexerWorker) BulkIndexUsers(users []*model.UserForIndexing, progress IndexingProgress) (int64, *model.AppError) {
|
||||||
|
lastCreateAt := int64(0)
|
||||||
|
batch := worker.engine.UserIndex.NewBatch()
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
if user.DeleteAt == 0 {
|
||||||
|
searchUser := bleveengine.BLVUserFromUserForIndexing(user)
|
||||||
|
batch.Index(searchUser.Id, searchUser)
|
||||||
|
} else {
|
||||||
|
batch.Delete(user.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastCreateAt = user.CreateAt
|
||||||
|
}
|
||||||
|
|
||||||
|
worker.engine.Mutex.RLock()
|
||||||
|
defer worker.engine.Mutex.RUnlock()
|
||||||
|
|
||||||
|
if err := worker.engine.UserIndex.Batch(batch); err != nil {
|
||||||
|
return 0, model.NewAppError("BleveIndexerWorker.BulkIndexUsers", "bleveengine.indexer.do_job.bulk_index_users.batch_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return lastCreateAt, nil
|
||||||
|
}
|
||||||
419
services/searchengine/bleveengine/search.go
Обычный файл
419
services/searchengine/bleveengine/search.go
Обычный файл
@@ -0,0 +1,419 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package bleveengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/v5/model"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve"
|
||||||
|
"github.com/blevesearch/bleve/search/query"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *BleveEngine) IndexPost(post *model.Post, teamId string) *model.AppError {
|
||||||
|
b.Mutex.RLock()
|
||||||
|
defer b.Mutex.RUnlock()
|
||||||
|
|
||||||
|
blvPost := BLVPostFromPost(post, teamId)
|
||||||
|
if err := b.PostIndex.Index(blvPost.Id, blvPost); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.IndexPost", "bleveengine.index_post.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) SearchPosts(channels *model.ChannelList, searchParams []*model.SearchParams, page, perPage int) ([]string, model.PostSearchMatches, *model.AppError) {
|
||||||
|
channelQueries := []query.Query{}
|
||||||
|
for _, channel := range *channels {
|
||||||
|
channelIdQ := bleve.NewTermQuery(channel.Id)
|
||||||
|
channelIdQ.SetField("ChannelId")
|
||||||
|
channelQueries = append(channelQueries, channelIdQ)
|
||||||
|
}
|
||||||
|
channelDisjunctionQ := bleve.NewDisjunctionQuery(channelQueries...)
|
||||||
|
|
||||||
|
var termQueries []query.Query
|
||||||
|
var notTermQueries []query.Query
|
||||||
|
var filters []query.Query
|
||||||
|
var notFilters []query.Query
|
||||||
|
|
||||||
|
typeQ := bleve.NewTermQuery("")
|
||||||
|
typeQ.SetField("Type")
|
||||||
|
filters = append(filters, typeQ)
|
||||||
|
|
||||||
|
for i, params := range searchParams {
|
||||||
|
// Date, channels and FromUsers filters come in all
|
||||||
|
// searchParams iteration, and as they are global to the
|
||||||
|
// query, we only need to process them once
|
||||||
|
if i == 0 {
|
||||||
|
if len(params.InChannels) > 0 {
|
||||||
|
inChannels := []query.Query{}
|
||||||
|
for _, channelId := range params.InChannels {
|
||||||
|
channelQ := bleve.NewTermQuery(channelId)
|
||||||
|
channelQ.SetField("ChannelId")
|
||||||
|
inChannels = append(inChannels, channelQ)
|
||||||
|
}
|
||||||
|
filters = append(filters, bleve.NewDisjunctionQuery(inChannels...))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params.ExcludedChannels) > 0 {
|
||||||
|
excludedChannels := []query.Query{}
|
||||||
|
for _, channelId := range params.ExcludedChannels {
|
||||||
|
channelQ := bleve.NewTermQuery(channelId)
|
||||||
|
channelQ.SetField("ChannelId")
|
||||||
|
excludedChannels = append(excludedChannels, channelQ)
|
||||||
|
}
|
||||||
|
notFilters = append(notFilters, bleve.NewDisjunctionQuery(excludedChannels...))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params.FromUsers) > 0 {
|
||||||
|
fromUsers := []query.Query{}
|
||||||
|
for _, userId := range params.FromUsers {
|
||||||
|
userQ := bleve.NewTermQuery(userId)
|
||||||
|
userQ.SetField("UserId")
|
||||||
|
fromUsers = append(fromUsers, userQ)
|
||||||
|
}
|
||||||
|
filters = append(filters, bleve.NewDisjunctionQuery(fromUsers...))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params.ExcludedUsers) > 0 {
|
||||||
|
excludedUsers := []query.Query{}
|
||||||
|
for _, userId := range params.ExcludedUsers {
|
||||||
|
userQ := bleve.NewTermQuery(userId)
|
||||||
|
userQ.SetField("UserId")
|
||||||
|
excludedUsers = append(excludedUsers, userQ)
|
||||||
|
}
|
||||||
|
notFilters = append(notFilters, bleve.NewDisjunctionQuery(excludedUsers...))
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.OnDate != "" {
|
||||||
|
before, after := params.GetOnDateMillis()
|
||||||
|
beforeFloat64 := float64(before)
|
||||||
|
afterFloat64 := float64(after)
|
||||||
|
onDateQ := bleve.NewNumericRangeQuery(&beforeFloat64, &afterFloat64)
|
||||||
|
onDateQ.SetField("CreateAt")
|
||||||
|
filters = append(filters, onDateQ)
|
||||||
|
} else {
|
||||||
|
if params.AfterDate != "" || params.BeforeDate != "" {
|
||||||
|
var min, max *float64
|
||||||
|
if params.AfterDate != "" {
|
||||||
|
minf := float64(params.GetAfterDateMillis())
|
||||||
|
min = &minf
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.BeforeDate != "" {
|
||||||
|
maxf := float64(params.GetBeforeDateMillis())
|
||||||
|
max = &maxf
|
||||||
|
}
|
||||||
|
|
||||||
|
dateQ := bleve.NewNumericRangeQuery(min, max)
|
||||||
|
dateQ.SetField("CreateAt")
|
||||||
|
filters = append(filters, dateQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.ExcludedAfterDate != "" {
|
||||||
|
minf := float64(params.GetExcludedAfterDateMillis())
|
||||||
|
dateQ := bleve.NewNumericRangeQuery(&minf, nil)
|
||||||
|
dateQ.SetField("CreateAt")
|
||||||
|
notFilters = append(notFilters, dateQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.ExcludedBeforeDate != "" {
|
||||||
|
maxf := float64(params.GetExcludedBeforeDateMillis())
|
||||||
|
dateQ := bleve.NewNumericRangeQuery(nil, &maxf)
|
||||||
|
dateQ.SetField("CreateAt")
|
||||||
|
notFilters = append(notFilters, dateQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.ExcludedDate != "" {
|
||||||
|
before, after := params.GetExcludedDateMillis()
|
||||||
|
beforef := float64(before)
|
||||||
|
afterf := float64(after)
|
||||||
|
onDateQ := bleve.NewNumericRangeQuery(&beforef, &afterf)
|
||||||
|
onDateQ.SetField("CreateAt")
|
||||||
|
notFilters = append(notFilters, onDateQ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.IsHashtag {
|
||||||
|
if params.Terms != "" {
|
||||||
|
hashtagQ := bleve.NewMatchQuery(params.Terms)
|
||||||
|
hashtagQ.SetField("Hashtags")
|
||||||
|
termQueries = append(termQueries, hashtagQ)
|
||||||
|
} else if params.ExcludedTerms != "" {
|
||||||
|
hashtagQ := bleve.NewMatchQuery(params.ExcludedTerms)
|
||||||
|
hashtagQ.SetField("Hashtags")
|
||||||
|
notTermQueries = append(notTermQueries, hashtagQ)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if len(params.Terms) > 0 {
|
||||||
|
query := bleve.NewBooleanQuery()
|
||||||
|
messageQ := bleve.NewMatchQuery(params.Terms)
|
||||||
|
messageQ.SetField("Message")
|
||||||
|
|
||||||
|
if searchParams[0].OrTerms {
|
||||||
|
query.AddShould(messageQ)
|
||||||
|
} else {
|
||||||
|
query.AddMust(messageQ)
|
||||||
|
}
|
||||||
|
termQueries = append(termQueries, messageQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(params.ExcludedTerms) > 0 {
|
||||||
|
messageQ := bleve.NewMatchQuery(params.ExcludedTerms)
|
||||||
|
messageQ.SetField("Message")
|
||||||
|
notTermQueries = append(notTermQueries, messageQ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allTermsQ := bleve.NewBooleanQuery()
|
||||||
|
allTermsQ.AddMustNot(notTermQueries...)
|
||||||
|
if searchParams[0].OrTerms {
|
||||||
|
allTermsQ.AddShould(termQueries...)
|
||||||
|
} else {
|
||||||
|
allTermsQ.AddMust(termQueries...)
|
||||||
|
}
|
||||||
|
|
||||||
|
query := bleve.NewBooleanQuery()
|
||||||
|
query.AddMust(channelDisjunctionQ)
|
||||||
|
|
||||||
|
if len(termQueries) > 0 || len(notTermQueries) > 0 {
|
||||||
|
query.AddMust(allTermsQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(filters) > 0 {
|
||||||
|
query.AddMust(bleve.NewConjunctionQuery(filters...))
|
||||||
|
}
|
||||||
|
if len(notFilters) > 0 {
|
||||||
|
query.AddMustNot(notFilters...)
|
||||||
|
}
|
||||||
|
|
||||||
|
search := bleve.NewSearchRequest(query)
|
||||||
|
results, err := b.PostIndex.Search(search)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, model.NewAppError("Bleveengine.SearchPosts", "bleveengine.search_posts.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
postIds := []string{}
|
||||||
|
matches := model.PostSearchMatches{}
|
||||||
|
|
||||||
|
for _, r := range results.Hits {
|
||||||
|
postIds = append(postIds, r.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return postIds, matches, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) DeletePost(post *model.Post) *model.AppError {
|
||||||
|
b.Mutex.RLock()
|
||||||
|
defer b.Mutex.RUnlock()
|
||||||
|
|
||||||
|
if err := b.PostIndex.Delete(post.Id); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.DeletePost", "bleveengine.delete_post.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) IndexChannel(channel *model.Channel) *model.AppError {
|
||||||
|
b.Mutex.RLock()
|
||||||
|
defer b.Mutex.RUnlock()
|
||||||
|
|
||||||
|
blvChannel := BLVChannelFromChannel(channel)
|
||||||
|
if err := b.ChannelIndex.Index(blvChannel.Id, blvChannel); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.IndexChannel", "bleveengine.index_channel.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) SearchChannels(teamId, term string) ([]string, *model.AppError) {
|
||||||
|
teamIdQ := bleve.NewTermQuery(teamId)
|
||||||
|
teamIdQ.SetField("TeamId")
|
||||||
|
queries := []query.Query{teamIdQ}
|
||||||
|
|
||||||
|
if term != "" {
|
||||||
|
nameSuggestQ := bleve.NewPrefixQuery(strings.ToLower(term))
|
||||||
|
nameSuggestQ.SetField("NameSuggest")
|
||||||
|
queries = append(queries, nameSuggestQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
query := bleve.NewSearchRequest(bleve.NewConjunctionQuery(queries...))
|
||||||
|
results, err := b.ChannelIndex.Search(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("Bleveengine.SearchChannels", "bleveengine.search_channels.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
channelIds := []string{}
|
||||||
|
for _, result := range results.Hits {
|
||||||
|
channelIds = append(channelIds, result.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return channelIds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) DeleteChannel(channel *model.Channel) *model.AppError {
|
||||||
|
b.Mutex.RLock()
|
||||||
|
defer b.Mutex.RUnlock()
|
||||||
|
|
||||||
|
if err := b.ChannelIndex.Delete(channel.Id); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.DeleteChannel", "bleveengine.delete_channel.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) IndexUser(user *model.User, teamsIds, channelsIds []string) *model.AppError {
|
||||||
|
b.Mutex.RLock()
|
||||||
|
defer b.Mutex.RUnlock()
|
||||||
|
|
||||||
|
blvUser := BLVUserFromUserAndTeams(user, teamsIds, channelsIds)
|
||||||
|
if err := b.UserIndex.Index(blvUser.Id, blvUser); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.IndexUser", "bleveengine.index_user.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) SearchUsersInChannel(teamId, channelId string, restrictedToChannels []string, term string, options *model.UserSearchOptions) ([]string, []string, *model.AppError) {
|
||||||
|
if restrictedToChannels != nil && len(restrictedToChannels) == 0 {
|
||||||
|
return []string{}, []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// users in channel
|
||||||
|
var queries []query.Query
|
||||||
|
if term != "" {
|
||||||
|
termQ := bleve.NewPrefixQuery(strings.ToLower(term))
|
||||||
|
if options.AllowFullNames {
|
||||||
|
termQ.SetField("SuggestionsWithFullname")
|
||||||
|
} else {
|
||||||
|
termQ.SetField("SuggestionsWithoutFullname")
|
||||||
|
}
|
||||||
|
queries = append(queries, termQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
channelIdQ := bleve.NewTermQuery(channelId)
|
||||||
|
channelIdQ.SetField("ChannelsIds")
|
||||||
|
queries = append(queries, channelIdQ)
|
||||||
|
|
||||||
|
query := bleve.NewConjunctionQuery(queries...)
|
||||||
|
|
||||||
|
uchan, err := b.UserIndex.Search(bleve.NewSearchRequest(query))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, model.NewAppError("Bleveengine.SearchUsersInChannel", "bleveengine.search_users_in_channel.uchan.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// users not in channel
|
||||||
|
boolQ := bleve.NewBooleanQuery()
|
||||||
|
|
||||||
|
if term != "" {
|
||||||
|
termQ := bleve.NewPrefixQuery(strings.ToLower(term))
|
||||||
|
if options.AllowFullNames {
|
||||||
|
termQ.SetField("SuggestionsWithFullname")
|
||||||
|
} else {
|
||||||
|
termQ.SetField("SuggestionsWithoutFullname")
|
||||||
|
}
|
||||||
|
boolQ.AddMust(termQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
teamIdQ := bleve.NewTermQuery(teamId)
|
||||||
|
teamIdQ.SetField("TeamsIds")
|
||||||
|
boolQ.AddMust(teamIdQ)
|
||||||
|
|
||||||
|
outsideChannelIdQ := bleve.NewTermQuery(channelId)
|
||||||
|
outsideChannelIdQ.SetField("ChannelsIds")
|
||||||
|
boolQ.AddMustNot(outsideChannelIdQ)
|
||||||
|
|
||||||
|
if len(restrictedToChannels) > 0 {
|
||||||
|
restrictedChannelsQ := bleve.NewDisjunctionQuery()
|
||||||
|
for _, channelId := range restrictedToChannels {
|
||||||
|
restrictedChannelQ := bleve.NewTermQuery(channelId)
|
||||||
|
restrictedChannelsQ.AddQuery(restrictedChannelQ)
|
||||||
|
}
|
||||||
|
boolQ.AddMust(restrictedChannelsQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
nuchan, err := b.UserIndex.Search(bleve.NewSearchRequest(boolQ))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, model.NewAppError("Bleveengine.SearchUsersInChannel", "bleveengine.search_users_in_channel.nuchan.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
uchanIds := []string{}
|
||||||
|
for _, result := range uchan.Hits {
|
||||||
|
uchanIds = append(uchanIds, result.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
nuchanIds := []string{}
|
||||||
|
for _, result := range nuchan.Hits {
|
||||||
|
nuchanIds = append(nuchanIds, result.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uchanIds, nuchanIds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) SearchUsersInTeam(teamId string, restrictedToChannels []string, term string, options *model.UserSearchOptions) ([]string, *model.AppError) {
|
||||||
|
if restrictedToChannels != nil && len(restrictedToChannels) == 0 {
|
||||||
|
return []string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootQ query.Query
|
||||||
|
if term == "" && teamId == "" && restrictedToChannels == nil {
|
||||||
|
rootQ = bleve.NewMatchAllQuery()
|
||||||
|
} else {
|
||||||
|
boolQ := bleve.NewBooleanQuery()
|
||||||
|
|
||||||
|
if term != "" {
|
||||||
|
termQ := bleve.NewPrefixQuery(strings.ToLower(term))
|
||||||
|
if options.AllowFullNames {
|
||||||
|
termQ.SetField("SuggestionsWithFullname")
|
||||||
|
} else {
|
||||||
|
termQ.SetField("SuggestionsWithoutFullname")
|
||||||
|
}
|
||||||
|
boolQ.AddMust(termQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(restrictedToChannels) > 0 {
|
||||||
|
// restricted channels are already filtered by team, so we
|
||||||
|
// can search only those matches
|
||||||
|
restrictedChannelsQ := []query.Query{}
|
||||||
|
for _, channelId := range restrictedToChannels {
|
||||||
|
channelIdQ := bleve.NewTermQuery(channelId)
|
||||||
|
channelIdQ.SetField("ChannelsIds")
|
||||||
|
restrictedChannelsQ = append(restrictedChannelsQ, channelIdQ)
|
||||||
|
}
|
||||||
|
boolQ.AddMust(bleve.NewDisjunctionQuery(restrictedChannelsQ...))
|
||||||
|
} else {
|
||||||
|
// this means that we only need to restrict by team
|
||||||
|
if teamId != "" {
|
||||||
|
teamIdQ := bleve.NewTermQuery(teamId)
|
||||||
|
teamIdQ.SetField("TeamsIds")
|
||||||
|
boolQ.AddMust(teamIdQ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootQ = boolQ
|
||||||
|
}
|
||||||
|
|
||||||
|
search := bleve.NewSearchRequest(rootQ)
|
||||||
|
|
||||||
|
results, err := b.UserIndex.Search(search)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("Bleveengine.SearchUsersInTeam", "bleveengine.search_users_in_team.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
usersIds := []string{}
|
||||||
|
for _, r := range results.Hits {
|
||||||
|
usersIds = append(usersIds, r.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return usersIds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *BleveEngine) DeleteUser(user *model.User) *model.AppError {
|
||||||
|
b.Mutex.RLock()
|
||||||
|
defer b.Mutex.RUnlock()
|
||||||
|
|
||||||
|
if err := b.UserIndex.Delete(user.Id); err != nil {
|
||||||
|
return model.NewAppError("Bleveengine.DeleteUser", "bleveengine.delete_user.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -19,10 +19,15 @@ func (seb *Broker) RegisterElasticsearchEngine(es SearchEngineInterface) {
|
|||||||
seb.ElasticsearchEngine = es
|
seb.ElasticsearchEngine = es
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (seb *Broker) RegisterBleveEngine(be SearchEngineInterface) {
|
||||||
|
seb.BleveEngine = be
|
||||||
|
}
|
||||||
|
|
||||||
type Broker struct {
|
type Broker struct {
|
||||||
cfg *model.Config
|
cfg *model.Config
|
||||||
jobServer *jobs.JobServer
|
jobServer *jobs.JobServer
|
||||||
ElasticsearchEngine SearchEngineInterface
|
ElasticsearchEngine SearchEngineInterface
|
||||||
|
BleveEngine SearchEngineInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (seb *Broker) UpdateConfig(cfg *model.Config) *model.AppError {
|
func (seb *Broker) UpdateConfig(cfg *model.Config) *model.AppError {
|
||||||
@@ -31,6 +36,10 @@ func (seb *Broker) UpdateConfig(cfg *model.Config) *model.AppError {
|
|||||||
seb.ElasticsearchEngine.UpdateConfig(cfg)
|
seb.ElasticsearchEngine.UpdateConfig(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if seb.BleveEngine != nil {
|
||||||
|
seb.BleveEngine.UpdateConfig(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,5 +48,8 @@ func (seb *Broker) GetActiveEngines() []SearchEngineInterface {
|
|||||||
if seb.ElasticsearchEngine != nil && seb.ElasticsearchEngine.IsActive() {
|
if seb.ElasticsearchEngine != nil && seb.ElasticsearchEngine.IsActive() {
|
||||||
engines = append(engines, seb.ElasticsearchEngine)
|
engines = append(engines, seb.ElasticsearchEngine)
|
||||||
}
|
}
|
||||||
|
if seb.BleveEngine != nil && seb.BleveEngine.IsActive() {
|
||||||
|
engines = append(engines, seb.BleveEngine)
|
||||||
|
}
|
||||||
return engines
|
return engines
|
||||||
}
|
}
|
||||||
|
|||||||
44
services/searchengine/utils.go
Обычный файл
44
services/searchengine/utils.go
Обычный файл
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package searchengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/v5/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var EmailRegex = regexp.MustCompile(`^[^\s"]+@[^\s"]+$`)
|
||||||
|
|
||||||
|
func GetSuggestionInputsSplitBy(term, splitStr string) []string {
|
||||||
|
splitTerm := strings.Split(strings.ToLower(term), splitStr)
|
||||||
|
var initialSuggestionList []string
|
||||||
|
for i := range splitTerm {
|
||||||
|
initialSuggestionList = append(initialSuggestionList, strings.Join(splitTerm[i:], splitStr))
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestionList := []string{}
|
||||||
|
// If splitStr is not an empty space, we create a suggestion with it at the beginning
|
||||||
|
if splitStr == " " {
|
||||||
|
suggestionList = initialSuggestionList
|
||||||
|
} else {
|
||||||
|
for i, suggestion := range initialSuggestionList {
|
||||||
|
if i == 0 {
|
||||||
|
suggestionList = append(suggestionList, suggestion)
|
||||||
|
} else {
|
||||||
|
suggestionList = append(suggestionList, splitStr+suggestion, suggestion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return suggestionList
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSuggestionInputsSplitByMultiple(term string, splitStrs []string) []string {
|
||||||
|
suggestionList := []string{}
|
||||||
|
for _, splitStr := range splitStrs {
|
||||||
|
suggestionList = append(suggestionList, GetSuggestionInputsSplitBy(term, splitStr)...)
|
||||||
|
}
|
||||||
|
return utils.RemoveDuplicatesFromStringArray(suggestionList)
|
||||||
|
}
|
||||||
57
services/searchengine/utils_test.go
Обычный файл
57
services/searchengine/utils_test.go
Обычный файл
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
package searchengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestElasticsearchGetSuggestionsSplitBy(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
Name string
|
||||||
|
Term string
|
||||||
|
SplitStr string ``
|
||||||
|
Expected []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "Single string",
|
||||||
|
Term: "string",
|
||||||
|
SplitStr: " ",
|
||||||
|
Expected: []string{"string"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "String with spaces",
|
||||||
|
Term: "String with spaces",
|
||||||
|
SplitStr: " ",
|
||||||
|
Expected: []string{"string with spaces", "with spaces", "spaces"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Username split by a dot",
|
||||||
|
Term: "name.surname",
|
||||||
|
SplitStr: ".",
|
||||||
|
Expected: []string{"name.surname", ".surname", "surname"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "String split by several dashes",
|
||||||
|
Term: "one-two-three",
|
||||||
|
SplitStr: "-",
|
||||||
|
Expected: []string{"one-two-three", "-two-three", "two-three", "-three", "three"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
res := GetSuggestionInputsSplitBy(tc.Term, tc.SplitStr)
|
||||||
|
assert.ElementsMatch(t, res, tc.Expected)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestElasticsearchGetSuggestionsSplitByMultiple(t *testing.T) {
|
||||||
|
r1 := GetSuggestionInputsSplitByMultiple("String with user.name", []string{" ", "."})
|
||||||
|
expectedR1 := []string{"string with user.name", "with user.name", "user.name", ".name", "name"}
|
||||||
|
assert.ElementsMatch(t, r1, expectedR1)
|
||||||
|
}
|
||||||
@@ -30,12 +30,12 @@ var searchChannelStoreTests = []searchTest{
|
|||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete a channel by a part of its name when has parts splitted by _ character",
|
Name: "Should be able to autocomplete a channel by a part of its name when has parts splitted by _ character",
|
||||||
Fn: testAutocompleteChannelByNameSplittedWithUnderscoreChar,
|
Fn: testAutocompleteChannelByNameSplittedWithUnderscoreChar,
|
||||||
Tags: []string{ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
|
Tags: []string{ENGINE_MYSQL, ENGINE_ELASTICSEARCH, ENGINE_BLEVE},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete a channel by a part of its display name when has parts splitted by whitespace character",
|
Name: "Should be able to autocomplete a channel by a part of its display name when has parts splitted by whitespace character",
|
||||||
Fn: testAutocompleteChannelByDisplayNameSplittedByWhitespaces,
|
Fn: testAutocompleteChannelByDisplayNameSplittedByWhitespaces,
|
||||||
Tags: []string{ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
|
Tags: []string{ENGINE_MYSQL, ENGINE_ELASTICSEARCH, ENGINE_BLEVE},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete retrieving all channels if the term is empty",
|
Name: "Should be able to autocomplete retrieving all channels if the term is empty",
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ var searchPostStoreTests = []searchTest{
|
|||||||
{
|
{
|
||||||
Name: "Should be able to search for exact phrases in quotes",
|
Name: "Should be able to search for exact phrases in quotes",
|
||||||
Fn: testSearchExactPhraseInQuotes,
|
Fn: testSearchExactPhraseInQuotes,
|
||||||
Tags: []string{ENGINE_ALL},
|
Tags: []string{ENGINE_POSTGRES, ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should be able to search for email addresses with or without quotes",
|
Name: "Should be able to search for email addresses with or without quotes",
|
||||||
@@ -69,8 +69,8 @@ var searchPostStoreTests = []searchTest{
|
|||||||
Tags: []string{ENGINE_ALL},
|
Tags: []string{ENGINE_ALL},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should be able to filter messages written on a specific date",
|
Name: "Should be able to filter messages written after a specific date",
|
||||||
Fn: testFilterMessagesInSpecificDate,
|
Fn: testFilterMessagesAfterSpecificDate,
|
||||||
Tags: []string{ENGINE_ALL},
|
Tags: []string{ENGINE_ALL},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -79,8 +79,8 @@ var searchPostStoreTests = []searchTest{
|
|||||||
Tags: []string{ENGINE_ALL},
|
Tags: []string{ENGINE_ALL},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should be able to filter messages written after a specific date",
|
Name: "Should be able to filter messages written on a specific date",
|
||||||
Fn: testFilterMessagesAfterSpecificDate,
|
Fn: testFilterMessagesInSpecificDate,
|
||||||
Tags: []string{ENGINE_ALL},
|
Tags: []string{ENGINE_ALL},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -111,7 +111,7 @@ var searchPostStoreTests = []searchTest{
|
|||||||
{
|
{
|
||||||
Name: "Should support search with wildcards",
|
Name: "Should support search with wildcards",
|
||||||
Fn: testSupportWildcards,
|
Fn: testSupportWildcards,
|
||||||
Tags: []string{ENGINE_ALL},
|
Tags: []string{ENGINE_POSTGRES, ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should not support search with preceding wildcards",
|
Name: "Should not support search with preceding wildcards",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const (
|
|||||||
ENGINE_MYSQL = "mysql"
|
ENGINE_MYSQL = "mysql"
|
||||||
ENGINE_POSTGRES = "postgres"
|
ENGINE_POSTGRES = "postgres"
|
||||||
ENGINE_ELASTICSEARCH = "elasticsearch"
|
ENGINE_ELASTICSEARCH = "elasticsearch"
|
||||||
|
ENGINE_BLEVE = "bleve"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SearchTestEngine struct {
|
type SearchTestEngine struct {
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ var searchUserStoreTests = []searchTest{
|
|||||||
{
|
{
|
||||||
Name: "Should honor channel restrictions when autocompleting users",
|
Name: "Should honor channel restrictions when autocompleting users",
|
||||||
Fn: testHonorChannelRestrictionsAutocompletingUsers,
|
Fn: testHonorChannelRestrictionsAutocompletingUsers,
|
||||||
Tags: []string{ENGINE_ELASTICSEARCH},
|
Tags: []string{ENGINE_ELASTICSEARCH, ENGINE_BLEVE},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should honor team restrictions when autocompleting users",
|
Name: "Should honor team restrictions when autocompleting users",
|
||||||
Fn: testHonorTeamRestrictionsAutocompletingUsers,
|
Fn: testHonorTeamRestrictionsAutocompletingUsers,
|
||||||
Tags: []string{ENGINE_ELASTICSEARCH},
|
Tags: []string{ENGINE_ELASTICSEARCH, ENGINE_BLEVE},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should return nothing if the user can't access the channels of a given search",
|
Name: "Should return nothing if the user can't access the channels of a given search",
|
||||||
@@ -69,17 +69,17 @@ var searchUserStoreTests = []searchTest{
|
|||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete a user by part of its username splitted by Dot",
|
Name: "Should be able to autocomplete a user by part of its username splitted by Dot",
|
||||||
Fn: testAutocompleteUserByUsernameWithDot,
|
Fn: testAutocompleteUserByUsernameWithDot,
|
||||||
Tags: []string{ENGINE_ELASTICSEARCH},
|
Tags: []string{ENGINE_ELASTICSEARCH, ENGINE_BLEVE},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete a user by part of its username splitted by underscore",
|
Name: "Should be able to autocomplete a user by part of its username splitted by underscore",
|
||||||
Fn: testAutocompleteUserByUsernameWithUnderscore,
|
Fn: testAutocompleteUserByUsernameWithUnderscore,
|
||||||
Tags: []string{ENGINE_ELASTICSEARCH},
|
Tags: []string{ENGINE_ELASTICSEARCH, ENGINE_BLEVE},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete a user by part of its username splitted by hyphen",
|
Name: "Should be able to autocomplete a user by part of its username splitted by hyphen",
|
||||||
Fn: testAutocompleteUserByUsernameWithHyphen,
|
Fn: testAutocompleteUserByUsernameWithHyphen,
|
||||||
Tags: []string{ENGINE_ELASTICSEARCH},
|
Tags: []string{ENGINE_ELASTICSEARCH, ENGINE_BLEVE},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should escape the percentage character",
|
Name: "Should escape the percentage character",
|
||||||
|
|||||||
20
vendor/github.com/RoaringBitmap/roaring/.drone.yml
сгенерированный
поставляемый
Обычный файл
20
vendor/github.com/RoaringBitmap/roaring/.drone.yml
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,20 @@
|
|||||||
|
kind: pipeline
|
||||||
|
name: default
|
||||||
|
|
||||||
|
workspace:
|
||||||
|
base: /go
|
||||||
|
path: src/github.com/RoaringBitmap/roaring
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: test
|
||||||
|
image: golang
|
||||||
|
commands:
|
||||||
|
- go get -t
|
||||||
|
- go test
|
||||||
|
- go test -race -run TestConcurrent*
|
||||||
|
- go build -tags appengine
|
||||||
|
- go test -tags appengine
|
||||||
|
- GOARCH=386 go build
|
||||||
|
- GOARCH=386 go test
|
||||||
|
- GOARCH=arm go build
|
||||||
|
- GOARCH=arm64 go build
|
||||||
6
vendor/github.com/RoaringBitmap/roaring/.gitignore
сгенерированный
поставляемый
Обычный файл
6
vendor/github.com/RoaringBitmap/roaring/.gitignore
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,6 @@
|
|||||||
|
*~
|
||||||
|
roaring-fuzz.zip
|
||||||
|
workdir
|
||||||
|
coverage.out
|
||||||
|
testdata/all3.classic
|
||||||
|
testdata/all3.msgp.snappy
|
||||||
0
vendor/github.com/RoaringBitmap/roaring/.gitmodules
сгенерированный
поставляемый
Обычный файл
0
vendor/github.com/RoaringBitmap/roaring/.gitmodules
сгенерированный
поставляемый
Обычный файл
37
vendor/github.com/RoaringBitmap/roaring/.travis.yml
сгенерированный
поставляемый
Обычный файл
37
vendor/github.com/RoaringBitmap/roaring/.travis.yml
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,37 @@
|
|||||||
|
language: go
|
||||||
|
sudo: false
|
||||||
|
install:
|
||||||
|
- go get -t github.com/RoaringBitmap/roaring
|
||||||
|
- go get -t golang.org/x/tools/cmd/cover
|
||||||
|
- go get -t github.com/mattn/goveralls
|
||||||
|
- go get -t github.com/mschoch/smat
|
||||||
|
notifications:
|
||||||
|
email: false
|
||||||
|
go:
|
||||||
|
- "1.7.x"
|
||||||
|
- "1.8.x"
|
||||||
|
- "1.9.x"
|
||||||
|
- "1.10.x"
|
||||||
|
- "1.11.x"
|
||||||
|
- "1.12.x"
|
||||||
|
- "1.13.x"
|
||||||
|
- tip
|
||||||
|
|
||||||
|
# whitelist
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
script:
|
||||||
|
- goveralls -v -service travis-ci -ignore arraycontainer_gen.go,bitmapcontainer_gen.go,rle16_gen.go,rle_gen.go,roaringarray_gen.go,rle.go || go test
|
||||||
|
- go test -race -run TestConcurrent*
|
||||||
|
- go build -tags appengine
|
||||||
|
- go test -tags appengine
|
||||||
|
- GOARCH=arm64 go build
|
||||||
|
- GOARCH=386 go build
|
||||||
|
- GOARCH=386 go test
|
||||||
|
- GOARCH=arm go build
|
||||||
|
- GOARCH=arm64 go build
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- go: tip
|
||||||
11
vendor/github.com/RoaringBitmap/roaring/AUTHORS
сгенерированный
поставляемый
Обычный файл
11
vendor/github.com/RoaringBitmap/roaring/AUTHORS
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,11 @@
|
|||||||
|
# This is the official list of roaring authors for copyright purposes.
|
||||||
|
|
||||||
|
Todd Gruben (@tgruben),
|
||||||
|
Daniel Lemire (@lemire),
|
||||||
|
Elliot Murphy (@statik),
|
||||||
|
Bob Potter (@bpot),
|
||||||
|
Tyson Maly (@tvmaly),
|
||||||
|
Will Glynn (@willglynn),
|
||||||
|
Brent Pedersen (@brentp)
|
||||||
|
Maciej Biłas (@maciej),
|
||||||
|
Joe Nall (@joenall)
|
||||||
16
vendor/github.com/RoaringBitmap/roaring/CONTRIBUTORS
сгенерированный
поставляемый
Обычный файл
16
vendor/github.com/RoaringBitmap/roaring/CONTRIBUTORS
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,16 @@
|
|||||||
|
# This is the official list of roaring contributors
|
||||||
|
|
||||||
|
Todd Gruben (@tgruben),
|
||||||
|
Daniel Lemire (@lemire),
|
||||||
|
Elliot Murphy (@statik),
|
||||||
|
Bob Potter (@bpot),
|
||||||
|
Tyson Maly (@tvmaly),
|
||||||
|
Will Glynn (@willglynn),
|
||||||
|
Brent Pedersen (@brentp),
|
||||||
|
Jason E. Aten (@glycerine),
|
||||||
|
Vali Malinoiu (@0x4139),
|
||||||
|
Forud Ghafouri (@fzerorubigd),
|
||||||
|
Joe Nall (@joenall),
|
||||||
|
(@fredim),
|
||||||
|
Edd Robinson (@e-dard),
|
||||||
|
Alexander Petrov (@alldroll)
|
||||||
235
vendor/github.com/RoaringBitmap/roaring/LICENSE
сгенерированный
поставляемый
Обычный файл
235
vendor/github.com/RoaringBitmap/roaring/LICENSE
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,235 @@
|
|||||||
|
|
||||||
|
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 2016 by the authors
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
Portions of runcontainer.go are from the Go standard library, which is licensed
|
||||||
|
under:
|
||||||
|
|
||||||
|
Copyright (c) 2009 The Go Authors. 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 Google Inc. 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
|
||||||
|
OWNER 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.
|
||||||
202
vendor/github.com/RoaringBitmap/roaring/LICENSE-2.0.txt
сгенерированный
поставляемый
Обычный файл
202
vendor/github.com/RoaringBitmap/roaring/LICENSE-2.0.txt
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
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 2016 by the authors
|
||||||
|
|
||||||
|
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.
|
||||||
111
vendor/github.com/RoaringBitmap/roaring/Makefile
сгенерированный
поставляемый
Обычный файл
111
vendor/github.com/RoaringBitmap/roaring/Makefile
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,111 @@
|
|||||||
|
.PHONY: help all test format fmtcheck vet lint qa deps clean nuke ser fetch-real-roaring-datasets
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Display general help about this command
|
||||||
|
help:
|
||||||
|
@echo ""
|
||||||
|
@echo "The following commands are available:"
|
||||||
|
@echo ""
|
||||||
|
@echo " make qa : Run all the tests"
|
||||||
|
@echo " make test : Run the unit tests"
|
||||||
|
@echo ""
|
||||||
|
@echo " make format : Format the source code"
|
||||||
|
@echo " make fmtcheck : Check if the source code has been formatted"
|
||||||
|
@echo " make vet : Check for suspicious constructs"
|
||||||
|
@echo " make lint : Check for style errors"
|
||||||
|
@echo ""
|
||||||
|
@echo " make deps : Get the dependencies"
|
||||||
|
@echo " make clean : Remove any build artifact"
|
||||||
|
@echo " make nuke : Deletes any intermediate file"
|
||||||
|
@echo ""
|
||||||
|
@echo " make fuzz-smat : Fuzzy testing with smat"
|
||||||
|
@echo " make fuzz-stream : Fuzzy testing with stream deserialization"
|
||||||
|
@echo " make fuzz-buffer : Fuzzy testing with buffer deserialization"
|
||||||
|
@echo ""
|
||||||
|
|
||||||
|
# Alias for help target
|
||||||
|
all: help
|
||||||
|
test:
|
||||||
|
go test
|
||||||
|
go test -race -run TestConcurrent*
|
||||||
|
# Format the source code
|
||||||
|
format:
|
||||||
|
@find ./ -type f -name "*.go" -exec gofmt -w {} \;
|
||||||
|
|
||||||
|
# Check if the source code has been formatted
|
||||||
|
fmtcheck:
|
||||||
|
@mkdir -p target
|
||||||
|
@find ./ -type f -name "*.go" -exec gofmt -d {} \; | tee target/format.diff
|
||||||
|
@test ! -s target/format.diff || { echo "ERROR: the source code has not been formatted - please use 'make format' or 'gofmt'"; exit 1; }
|
||||||
|
|
||||||
|
# Check for syntax errors
|
||||||
|
vet:
|
||||||
|
GOPATH=$(GOPATH) go vet ./...
|
||||||
|
|
||||||
|
# Check for style errors
|
||||||
|
lint:
|
||||||
|
GOPATH=$(GOPATH) PATH=$(GOPATH)/bin:$(PATH) golint ./...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Alias to run all quality-assurance checks
|
||||||
|
qa: fmtcheck test vet lint
|
||||||
|
|
||||||
|
# --- INSTALL ---
|
||||||
|
|
||||||
|
# Get the dependencies
|
||||||
|
deps:
|
||||||
|
GOPATH=$(GOPATH) go get github.com/stretchr/testify
|
||||||
|
GOPATH=$(GOPATH) go get github.com/willf/bitset
|
||||||
|
GOPATH=$(GOPATH) go get github.com/golang/lint/golint
|
||||||
|
GOPATH=$(GOPATH) go get github.com/mschoch/smat
|
||||||
|
GOPATH=$(GOPATH) go get github.com/dvyukov/go-fuzz/go-fuzz
|
||||||
|
GOPATH=$(GOPATH) go get github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||||
|
GOPATH=$(GOPATH) go get github.com/glycerine/go-unsnap-stream
|
||||||
|
GOPATH=$(GOPATH) go get github.com/philhofer/fwd
|
||||||
|
GOPATH=$(GOPATH) go get github.com/jtolds/gls
|
||||||
|
|
||||||
|
fuzz-smat:
|
||||||
|
go test -tags=gofuzz -run=TestGenerateSmatCorpus
|
||||||
|
go-fuzz-build -func FuzzSmat github.com/RoaringBitmap/roaring
|
||||||
|
go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200
|
||||||
|
|
||||||
|
|
||||||
|
fuzz-stream:
|
||||||
|
go-fuzz-build -func FuzzSerializationStream github.com/RoaringBitmap/roaring
|
||||||
|
go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200
|
||||||
|
|
||||||
|
|
||||||
|
fuzz-buffer:
|
||||||
|
go-fuzz-build -func FuzzSerializationBuffer github.com/RoaringBitmap/roaring
|
||||||
|
go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200
|
||||||
|
|
||||||
|
# Remove any build artifact
|
||||||
|
clean:
|
||||||
|
GOPATH=$(GOPATH) go clean ./...
|
||||||
|
|
||||||
|
# Deletes any intermediate file
|
||||||
|
nuke:
|
||||||
|
rm -rf ./target
|
||||||
|
GOPATH=$(GOPATH) go clean -i ./...
|
||||||
|
|
||||||
|
|
||||||
|
ser:
|
||||||
|
go generate
|
||||||
|
|
||||||
|
cover:
|
||||||
|
go test -coverprofile=coverage.out
|
||||||
|
go tool cover -html=coverage.out
|
||||||
|
|
||||||
|
fetch-real-roaring-datasets:
|
||||||
|
# pull github.com/RoaringBitmap/real-roaring-datasets -> testdata/real-roaring-datasets
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
253
vendor/github.com/RoaringBitmap/roaring/README.md
сгенерированный
поставляемый
Обычный файл
253
vendor/github.com/RoaringBitmap/roaring/README.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,253 @@
|
|||||||
|
roaring [](https://travis-ci.org/RoaringBitmap/roaring) [](https://coveralls.io/github/RoaringBitmap/roaring?branch=master) [](https://godoc.org/github.com/RoaringBitmap/roaring) [](https://goreportcard.com/report/github.com/RoaringBitmap/roaring)
|
||||||
|
[](https://cloud.drone.io/RoaringBitmap/roaring)
|
||||||
|
=============
|
||||||
|
|
||||||
|
This is a go version of the Roaring bitmap data structure.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Roaring bitmaps are used by several major systems such as [Apache Lucene][lucene] and derivative systems such as [Solr][solr] and
|
||||||
|
[Elasticsearch][elasticsearch], [Apache Druid (Incubating)][druid], [LinkedIn Pinot][pinot], [Netflix Atlas][atlas], [Apache Spark][spark], [OpenSearchServer][opensearchserver], [Cloud Torrent][cloudtorrent], [Whoosh][whoosh], [Pilosa][pilosa], [Microsoft Visual Studio Team Services (VSTS)][vsts], and eBay's [Apache Kylin][kylin].
|
||||||
|
|
||||||
|
[lucene]: https://lucene.apache.org/
|
||||||
|
[solr]: https://lucene.apache.org/solr/
|
||||||
|
[elasticsearch]: https://www.elastic.co/products/elasticsearch
|
||||||
|
[druid]: https://druid.apache.org/
|
||||||
|
[spark]: https://spark.apache.org/
|
||||||
|
[opensearchserver]: http://www.opensearchserver.com
|
||||||
|
[cloudtorrent]: https://github.com/jpillora/cloud-torrent
|
||||||
|
[whoosh]: https://bitbucket.org/mchaput/whoosh/wiki/Home
|
||||||
|
[pilosa]: https://www.pilosa.com/
|
||||||
|
[kylin]: http://kylin.apache.org/
|
||||||
|
[pinot]: http://github.com/linkedin/pinot/wiki
|
||||||
|
[vsts]: https://www.visualstudio.com/team-services/
|
||||||
|
[atlas]: https://github.com/Netflix/atlas
|
||||||
|
|
||||||
|
Roaring bitmaps are found to work well in many important applications:
|
||||||
|
|
||||||
|
> Use Roaring for bitmap compression whenever possible. Do not use other bitmap compression methods ([Wang et al., SIGMOD 2017](http://db.ucsd.edu/wp-content/uploads/2017/03/sidm338-wangA.pdf))
|
||||||
|
|
||||||
|
|
||||||
|
The ``roaring`` Go library is used by
|
||||||
|
* [Cloud Torrent](https://github.com/jpillora/cloud-torrent)
|
||||||
|
* [runv](https://github.com/hyperhq/runv)
|
||||||
|
* [InfluxDB](https://www.influxdata.com)
|
||||||
|
* [Pilosa](https://www.pilosa.com/)
|
||||||
|
* [Bleve](http://www.blevesearch.com)
|
||||||
|
* [lindb](https://github.com/lindb/lindb)
|
||||||
|
* [Elasticell](https://github.com/deepfabric/elasticell)
|
||||||
|
* [SourceGraph](https://github.com/sourcegraph/sourcegraph)
|
||||||
|
* [M3](https://github.com/m3db/m3)
|
||||||
|
* [trident](https://github.com/NetApp/trident)
|
||||||
|
|
||||||
|
|
||||||
|
This library is used in production in several systems, it is part of the [Awesome Go collection](https://awesome-go.com).
|
||||||
|
|
||||||
|
|
||||||
|
There are also [Java](https://github.com/RoaringBitmap/RoaringBitmap) and [C/C++](https://github.com/RoaringBitmap/CRoaring) versions. The Java, C, C++ and Go version are binary compatible: e.g, you can save bitmaps
|
||||||
|
from a Java program and load them back in Go, and vice versa. We have a [format specification](https://github.com/RoaringBitmap/RoaringFormatSpec).
|
||||||
|
|
||||||
|
|
||||||
|
This code is licensed under Apache License, Version 2.0 (ASL2.0).
|
||||||
|
|
||||||
|
Copyright 2016-... by the authors.
|
||||||
|
|
||||||
|
|
||||||
|
### References
|
||||||
|
|
||||||
|
- Daniel Lemire, Owen Kaser, Nathan Kurz, Luca Deri, Chris O'Hara, François Saint-Jacques, Gregory Ssi-Yan-Kai, Roaring Bitmaps: Implementation of an Optimized Software Library, Software: Practice and Experience 48 (4), 2018 [arXiv:1709.07821](https://arxiv.org/abs/1709.07821)
|
||||||
|
- Samy Chambi, Daniel Lemire, Owen Kaser, Robert Godin,
|
||||||
|
Better bitmap performance with Roaring bitmaps,
|
||||||
|
Software: Practice and Experience 46 (5), 2016.
|
||||||
|
http://arxiv.org/abs/1402.6407 This paper used data from http://lemire.me/data/realroaring2014.html
|
||||||
|
- Daniel Lemire, Gregory Ssi-Yan-Kai, Owen Kaser, Consistently faster and smaller compressed bitmaps with Roaring, Software: Practice and Experience 46 (11), 2016. http://arxiv.org/abs/1603.06549
|
||||||
|
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
Dependencies are fetched automatically by giving the `-t` flag to `go get`.
|
||||||
|
|
||||||
|
they include
|
||||||
|
- github.com/willf/bitset
|
||||||
|
- github.com/mschoch/smat
|
||||||
|
- github.com/glycerine/go-unsnap-stream
|
||||||
|
- github.com/philhofer/fwd
|
||||||
|
- github.com/jtolds/gls
|
||||||
|
|
||||||
|
Note that the smat library requires Go 1.6 or better.
|
||||||
|
|
||||||
|
#### Installation
|
||||||
|
|
||||||
|
- go get -t github.com/RoaringBitmap/roaring
|
||||||
|
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
Here is a simplified but complete example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/RoaringBitmap/roaring"
|
||||||
|
"bytes"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// example inspired by https://github.com/fzandona/goroar
|
||||||
|
fmt.Println("==roaring==")
|
||||||
|
rb1 := roaring.BitmapOf(1, 2, 3, 4, 5, 100, 1000)
|
||||||
|
fmt.Println(rb1.String())
|
||||||
|
|
||||||
|
rb2 := roaring.BitmapOf(3, 4, 1000)
|
||||||
|
fmt.Println(rb2.String())
|
||||||
|
|
||||||
|
rb3 := roaring.New()
|
||||||
|
fmt.Println(rb3.String())
|
||||||
|
|
||||||
|
fmt.Println("Cardinality: ", rb1.GetCardinality())
|
||||||
|
|
||||||
|
fmt.Println("Contains 3? ", rb1.Contains(3))
|
||||||
|
|
||||||
|
rb1.And(rb2)
|
||||||
|
|
||||||
|
rb3.Add(1)
|
||||||
|
rb3.Add(5)
|
||||||
|
|
||||||
|
rb3.Or(rb1)
|
||||||
|
|
||||||
|
// computes union of the three bitmaps in parallel using 4 workers
|
||||||
|
roaring.ParOr(4, rb1, rb2, rb3)
|
||||||
|
// computes intersection of the three bitmaps in parallel using 4 workers
|
||||||
|
roaring.ParAnd(4, rb1, rb2, rb3)
|
||||||
|
|
||||||
|
|
||||||
|
// prints 1, 3, 4, 5, 1000
|
||||||
|
i := rb3.Iterator()
|
||||||
|
for i.HasNext() {
|
||||||
|
fmt.Println(i.Next())
|
||||||
|
}
|
||||||
|
fmt.Println()
|
||||||
|
|
||||||
|
// next we include an example of serialization
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
rb1.WriteTo(buf) // we omit error handling
|
||||||
|
newrb:= roaring.New()
|
||||||
|
newrb.ReadFrom(buf)
|
||||||
|
if rb1.Equals(newrb) {
|
||||||
|
fmt.Println("I wrote the content to a byte stream and read it back.")
|
||||||
|
}
|
||||||
|
// you can iterate over bitmaps using ReverseIterator(), Iterator, ManyIterator()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wish to use serialization and handle errors, you might want to
|
||||||
|
consider the following sample of code:
|
||||||
|
|
||||||
|
```go
|
||||||
|
rb := BitmapOf(1, 2, 3, 4, 5, 100, 1000)
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
size,err:=rb.WriteTo(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed writing")
|
||||||
|
}
|
||||||
|
newrb:= New()
|
||||||
|
size,err=newrb.ReadFrom(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed reading")
|
||||||
|
}
|
||||||
|
if ! rb.Equals(newrb) {
|
||||||
|
t.Errorf("Cannot retrieve serialized version")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Given N integers in [0,x), then the serialized size in bytes of
|
||||||
|
a Roaring bitmap should never exceed this bound:
|
||||||
|
|
||||||
|
`` 8 + 9 * ((long)x+65535)/65536 + 2 * N ``
|
||||||
|
|
||||||
|
That is, given a fixed overhead for the universe size (x), Roaring
|
||||||
|
bitmaps never use more than 2 bytes per integer. You can call
|
||||||
|
``BoundSerializedSizeInBytes`` for a more precise estimate.
|
||||||
|
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
Current documentation is available at http://godoc.org/github.com/RoaringBitmap/roaring
|
||||||
|
|
||||||
|
### Goroutine safety
|
||||||
|
|
||||||
|
In general, it should not generally be considered safe to access
|
||||||
|
the same bitmaps using different goroutines--they are left
|
||||||
|
unsynchronized for performance. Should you want to access
|
||||||
|
a Bitmap from more than one goroutine, you should
|
||||||
|
provide synchronization. Typically this is done by using channels to pass
|
||||||
|
the *Bitmap around (in Go style; so there is only ever one owner),
|
||||||
|
or by using `sync.Mutex` to serialize operations on Bitmaps.
|
||||||
|
|
||||||
|
### Coverage
|
||||||
|
|
||||||
|
We test our software. For a report on our test coverage, see
|
||||||
|
|
||||||
|
https://coveralls.io/github/RoaringBitmap/roaring?branch=master
|
||||||
|
|
||||||
|
### Benchmark
|
||||||
|
|
||||||
|
Type
|
||||||
|
|
||||||
|
go test -bench Benchmark -run -
|
||||||
|
|
||||||
|
To run benchmarks on [Real Roaring Datasets](https://github.com/RoaringBitmap/real-roaring-datasets)
|
||||||
|
run the following:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go get github.com/RoaringBitmap/real-roaring-datasets
|
||||||
|
BENCH_REAL_DATA=1 go test -bench BenchmarkRealData -run -
|
||||||
|
```
|
||||||
|
|
||||||
|
### Iterative use
|
||||||
|
|
||||||
|
You can use roaring with gore:
|
||||||
|
|
||||||
|
- go get -u github.com/motemen/gore
|
||||||
|
- Make sure that ``$GOPATH/bin`` is in your ``$PATH``.
|
||||||
|
- go get github.com/RoaringBitmap/roaring
|
||||||
|
|
||||||
|
```go
|
||||||
|
$ gore
|
||||||
|
gore version 0.2.6 :help for help
|
||||||
|
gore> :import github.com/RoaringBitmap/roaring
|
||||||
|
gore> x:=roaring.New()
|
||||||
|
gore> x.Add(1)
|
||||||
|
gore> x.String()
|
||||||
|
"{1}"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Fuzzy testing
|
||||||
|
|
||||||
|
You can help us test further the library with fuzzy testing:
|
||||||
|
|
||||||
|
go get github.com/dvyukov/go-fuzz/go-fuzz
|
||||||
|
go get github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||||
|
go test -tags=gofuzz -run=TestGenerateSmatCorpus
|
||||||
|
go-fuzz-build github.com/RoaringBitmap/roaring
|
||||||
|
go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200
|
||||||
|
|
||||||
|
Let it run, and if the # of crashers is > 0, check out the reports in
|
||||||
|
the workdir where you should be able to find the panic goroutine stack
|
||||||
|
traces.
|
||||||
|
|
||||||
|
### Alternative in Go
|
||||||
|
|
||||||
|
There is a Go version wrapping the C/C++ implementation https://github.com/RoaringBitmap/gocroaring
|
||||||
|
|
||||||
|
For an alternative implementation in Go, see https://github.com/fzandona/goroar
|
||||||
|
The two versions were written independently.
|
||||||
|
|
||||||
|
|
||||||
|
### Mailing list/discussion group
|
||||||
|
|
||||||
|
https://groups.google.com/forum/#!forum/roaring-bitmaps
|
||||||
980
vendor/github.com/RoaringBitmap/roaring/arraycontainer.go
сгенерированный
поставляемый
Обычный файл
980
vendor/github.com/RoaringBitmap/roaring/arraycontainer.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,980 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate msgp -unexported
|
||||||
|
|
||||||
|
type arrayContainer struct {
|
||||||
|
content []uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) String() string {
|
||||||
|
s := "{"
|
||||||
|
for it := ac.getShortIterator(); it.hasNext(); {
|
||||||
|
s += fmt.Sprintf("%v, ", it.next())
|
||||||
|
}
|
||||||
|
return s + "}"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) fillLeastSignificant16bits(x []uint32, i int, mask uint32) {
|
||||||
|
for k := 0; k < len(ac.content); k++ {
|
||||||
|
x[k+i] = uint32(ac.content[k]) | mask
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iterate(cb func(x uint16) bool) bool {
|
||||||
|
iterator := shortIterator{ac.content, 0}
|
||||||
|
|
||||||
|
for iterator.hasNext() {
|
||||||
|
if !cb(iterator.next()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) getShortIterator() shortPeekable {
|
||||||
|
return &shortIterator{ac.content, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) getReverseIterator() shortIterable {
|
||||||
|
return &reverseIterator{ac.content, len(ac.content) - 1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) getManyIterator() manyIterable {
|
||||||
|
return &shortIterator{ac.content, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) minimum() uint16 {
|
||||||
|
return ac.content[0] // assume not empty
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) maximum() uint16 {
|
||||||
|
return ac.content[len(ac.content)-1] // assume not empty
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) getSizeInBytes() int {
|
||||||
|
return ac.getCardinality() * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) serializedSizeInBytes() int {
|
||||||
|
return ac.getCardinality() * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func arrayContainerSizeInBytes(card int) int {
|
||||||
|
return card * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the values in the range [firstOfRange,endx)
|
||||||
|
func (ac *arrayContainer) iaddRange(firstOfRange, endx int) container {
|
||||||
|
if firstOfRange >= endx {
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
indexstart := binarySearch(ac.content, uint16(firstOfRange))
|
||||||
|
if indexstart < 0 {
|
||||||
|
indexstart = -indexstart - 1
|
||||||
|
}
|
||||||
|
indexend := binarySearch(ac.content, uint16(endx-1))
|
||||||
|
if indexend < 0 {
|
||||||
|
indexend = -indexend - 1
|
||||||
|
} else {
|
||||||
|
indexend++
|
||||||
|
}
|
||||||
|
rangelength := endx - firstOfRange
|
||||||
|
newcardinality := indexstart + (ac.getCardinality() - indexend) + rangelength
|
||||||
|
if newcardinality > arrayDefaultMaxSize {
|
||||||
|
a := ac.toBitmapContainer()
|
||||||
|
return a.iaddRange(firstOfRange, endx)
|
||||||
|
}
|
||||||
|
if cap(ac.content) < newcardinality {
|
||||||
|
tmp := make([]uint16, newcardinality, newcardinality)
|
||||||
|
copy(tmp[:indexstart], ac.content[:indexstart])
|
||||||
|
copy(tmp[indexstart+rangelength:], ac.content[indexend:])
|
||||||
|
|
||||||
|
ac.content = tmp
|
||||||
|
} else {
|
||||||
|
ac.content = ac.content[:newcardinality]
|
||||||
|
copy(ac.content[indexstart+rangelength:], ac.content[indexend:])
|
||||||
|
|
||||||
|
}
|
||||||
|
for k := 0; k < rangelength; k++ {
|
||||||
|
ac.content[k+indexstart] = uint16(firstOfRange + k)
|
||||||
|
}
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the values in the range [firstOfRange,endx)
|
||||||
|
func (ac *arrayContainer) iremoveRange(firstOfRange, endx int) container {
|
||||||
|
if firstOfRange >= endx {
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
indexstart := binarySearch(ac.content, uint16(firstOfRange))
|
||||||
|
if indexstart < 0 {
|
||||||
|
indexstart = -indexstart - 1
|
||||||
|
}
|
||||||
|
indexend := binarySearch(ac.content, uint16(endx-1))
|
||||||
|
if indexend < 0 {
|
||||||
|
indexend = -indexend - 1
|
||||||
|
} else {
|
||||||
|
indexend++
|
||||||
|
}
|
||||||
|
rangelength := indexend - indexstart
|
||||||
|
answer := ac
|
||||||
|
copy(answer.content[indexstart:], ac.content[indexstart+rangelength:])
|
||||||
|
answer.content = answer.content[:ac.getCardinality()-rangelength]
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
// flip the values in the range [firstOfRange,endx)
|
||||||
|
func (ac *arrayContainer) not(firstOfRange, endx int) container {
|
||||||
|
if firstOfRange >= endx {
|
||||||
|
return ac.clone()
|
||||||
|
}
|
||||||
|
return ac.notClose(firstOfRange, endx-1) // remove everything in [firstOfRange,endx-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// flip the values in the range [firstOfRange,lastOfRange]
|
||||||
|
func (ac *arrayContainer) notClose(firstOfRange, lastOfRange int) container {
|
||||||
|
if firstOfRange > lastOfRange { // unlike add and remove, not uses an inclusive range [firstOfRange,lastOfRange]
|
||||||
|
return ac.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine the span of array indices to be affected^M
|
||||||
|
startIndex := binarySearch(ac.content, uint16(firstOfRange))
|
||||||
|
if startIndex < 0 {
|
||||||
|
startIndex = -startIndex - 1
|
||||||
|
}
|
||||||
|
lastIndex := binarySearch(ac.content, uint16(lastOfRange))
|
||||||
|
if lastIndex < 0 {
|
||||||
|
lastIndex = -lastIndex - 2
|
||||||
|
}
|
||||||
|
currentValuesInRange := lastIndex - startIndex + 1
|
||||||
|
spanToBeFlipped := lastOfRange - firstOfRange + 1
|
||||||
|
newValuesInRange := spanToBeFlipped - currentValuesInRange
|
||||||
|
cardinalityChange := newValuesInRange - currentValuesInRange
|
||||||
|
newCardinality := len(ac.content) + cardinalityChange
|
||||||
|
if newCardinality > arrayDefaultMaxSize {
|
||||||
|
return ac.toBitmapContainer().not(firstOfRange, lastOfRange+1)
|
||||||
|
}
|
||||||
|
answer := newArrayContainer()
|
||||||
|
answer.content = make([]uint16, newCardinality, newCardinality) //a hack for sure
|
||||||
|
|
||||||
|
copy(answer.content, ac.content[:startIndex])
|
||||||
|
outPos := startIndex
|
||||||
|
inPos := startIndex
|
||||||
|
valInRange := firstOfRange
|
||||||
|
for ; valInRange <= lastOfRange && inPos <= lastIndex; valInRange++ {
|
||||||
|
if uint16(valInRange) != ac.content[inPos] {
|
||||||
|
answer.content[outPos] = uint16(valInRange)
|
||||||
|
outPos++
|
||||||
|
} else {
|
||||||
|
inPos++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; valInRange <= lastOfRange; valInRange++ {
|
||||||
|
answer.content[outPos] = uint16(valInRange)
|
||||||
|
outPos++
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := lastIndex + 1; i < len(ac.content); i++ {
|
||||||
|
answer.content[outPos] = ac.content[i]
|
||||||
|
outPos++
|
||||||
|
}
|
||||||
|
answer.content = answer.content[:newCardinality]
|
||||||
|
return answer
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) equals(o container) bool {
|
||||||
|
|
||||||
|
srb, ok := o.(*arrayContainer)
|
||||||
|
if ok {
|
||||||
|
// Check if the containers are the same object.
|
||||||
|
if ac == srb {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(srb.content) != len(ac.content) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range ac.content {
|
||||||
|
if v != srb.content[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// use generic comparison
|
||||||
|
bCard := o.getCardinality()
|
||||||
|
aCard := ac.getCardinality()
|
||||||
|
if bCard != aCard {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
ait := ac.getShortIterator()
|
||||||
|
bit := o.getShortIterator()
|
||||||
|
for ait.hasNext() {
|
||||||
|
if bit.next() != ait.next() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) toBitmapContainer() *bitmapContainer {
|
||||||
|
bc := newBitmapContainer()
|
||||||
|
bc.loadData(ac)
|
||||||
|
return bc
|
||||||
|
|
||||||
|
}
|
||||||
|
func (ac *arrayContainer) iadd(x uint16) (wasNew bool) {
|
||||||
|
// Special case adding to the end of the container.
|
||||||
|
l := len(ac.content)
|
||||||
|
if l > 0 && l < arrayDefaultMaxSize && ac.content[l-1] < x {
|
||||||
|
ac.content = append(ac.content, x)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
loc := binarySearch(ac.content, x)
|
||||||
|
|
||||||
|
if loc < 0 {
|
||||||
|
s := ac.content
|
||||||
|
i := -loc - 1
|
||||||
|
s = append(s, 0)
|
||||||
|
copy(s[i+1:], s[i:])
|
||||||
|
s[i] = x
|
||||||
|
ac.content = s
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iaddReturnMinimized(x uint16) container {
|
||||||
|
// Special case adding to the end of the container.
|
||||||
|
l := len(ac.content)
|
||||||
|
if l > 0 && l < arrayDefaultMaxSize && ac.content[l-1] < x {
|
||||||
|
ac.content = append(ac.content, x)
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
loc := binarySearch(ac.content, x)
|
||||||
|
|
||||||
|
if loc < 0 {
|
||||||
|
if len(ac.content) >= arrayDefaultMaxSize {
|
||||||
|
a := ac.toBitmapContainer()
|
||||||
|
a.iadd(x)
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
s := ac.content
|
||||||
|
i := -loc - 1
|
||||||
|
s = append(s, 0)
|
||||||
|
copy(s[i+1:], s[i:])
|
||||||
|
s[i] = x
|
||||||
|
ac.content = s
|
||||||
|
}
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
// iremoveReturnMinimized is allowed to change the return type to minimize storage.
|
||||||
|
func (ac *arrayContainer) iremoveReturnMinimized(x uint16) container {
|
||||||
|
ac.iremove(x)
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iremove(x uint16) bool {
|
||||||
|
loc := binarySearch(ac.content, x)
|
||||||
|
if loc >= 0 {
|
||||||
|
s := ac.content
|
||||||
|
s = append(s[:loc], s[loc+1:]...)
|
||||||
|
ac.content = s
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) remove(x uint16) container {
|
||||||
|
out := &arrayContainer{make([]uint16, len(ac.content))}
|
||||||
|
copy(out.content, ac.content[:])
|
||||||
|
|
||||||
|
loc := binarySearch(out.content, x)
|
||||||
|
if loc >= 0 {
|
||||||
|
s := out.content
|
||||||
|
s = append(s[:loc], s[loc+1:]...)
|
||||||
|
out.content = s
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) or(a container) container {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.orArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return x.orArray(ac)
|
||||||
|
case *runContainer16:
|
||||||
|
if x.isFull() {
|
||||||
|
return x.clone()
|
||||||
|
}
|
||||||
|
return x.orArray(ac)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) orCardinality(a container) int {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.orArrayCardinality(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return x.orArrayCardinality(ac)
|
||||||
|
case *runContainer16:
|
||||||
|
return x.orArrayCardinality(ac)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) ior(a container) container {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.iorArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return a.(*bitmapContainer).orArray(ac)
|
||||||
|
//return ac.iorBitmap(x) // note: this does not make sense
|
||||||
|
case *runContainer16:
|
||||||
|
if x.isFull() {
|
||||||
|
return x.clone()
|
||||||
|
}
|
||||||
|
return ac.iorRun16(x)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iorArray(value2 *arrayContainer) container {
|
||||||
|
value1 := ac
|
||||||
|
len1 := value1.getCardinality()
|
||||||
|
len2 := value2.getCardinality()
|
||||||
|
maxPossibleCardinality := len1 + len2
|
||||||
|
if maxPossibleCardinality > arrayDefaultMaxSize { // it could be a bitmap!
|
||||||
|
bc := newBitmapContainer()
|
||||||
|
for k := 0; k < len(value2.content); k++ {
|
||||||
|
v := value2.content[k]
|
||||||
|
i := uint(v) >> 6
|
||||||
|
mask := uint64(1) << (v % 64)
|
||||||
|
bc.bitmap[i] |= mask
|
||||||
|
}
|
||||||
|
for k := 0; k < len(ac.content); k++ {
|
||||||
|
v := ac.content[k]
|
||||||
|
i := uint(v) >> 6
|
||||||
|
mask := uint64(1) << (v % 64)
|
||||||
|
bc.bitmap[i] |= mask
|
||||||
|
}
|
||||||
|
bc.cardinality = int(popcntSlice(bc.bitmap))
|
||||||
|
if bc.cardinality <= arrayDefaultMaxSize {
|
||||||
|
return bc.toArrayContainer()
|
||||||
|
}
|
||||||
|
return bc
|
||||||
|
}
|
||||||
|
if maxPossibleCardinality > cap(value1.content) {
|
||||||
|
newcontent := make([]uint16, 0, maxPossibleCardinality)
|
||||||
|
copy(newcontent[len2:maxPossibleCardinality], ac.content[0:len1])
|
||||||
|
ac.content = newcontent
|
||||||
|
} else {
|
||||||
|
copy(ac.content[len2:maxPossibleCardinality], ac.content[0:len1])
|
||||||
|
}
|
||||||
|
nl := union2by2(value1.content[len2:maxPossibleCardinality], value2.content, ac.content)
|
||||||
|
ac.content = ac.content[:nl] // reslice to match actual used capacity
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: such code does not make practical sense, except for lazy evaluations
|
||||||
|
func (ac *arrayContainer) iorBitmap(bc2 *bitmapContainer) container {
|
||||||
|
bc1 := ac.toBitmapContainer()
|
||||||
|
bc1.iorBitmap(bc2)
|
||||||
|
*ac = *newArrayContainerFromBitmap(bc1)
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iorRun16(rc *runContainer16) container {
|
||||||
|
bc1 := ac.toBitmapContainer()
|
||||||
|
bc2 := rc.toBitmapContainer()
|
||||||
|
bc1.iorBitmap(bc2)
|
||||||
|
*ac = *newArrayContainerFromBitmap(bc1)
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) lazyIOR(a container) container {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.lazyIorArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return ac.lazyIorBitmap(x)
|
||||||
|
case *runContainer16:
|
||||||
|
if x.isFull() {
|
||||||
|
return x.clone()
|
||||||
|
}
|
||||||
|
return ac.lazyIorRun16(x)
|
||||||
|
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) lazyIorArray(ac2 *arrayContainer) container {
|
||||||
|
// TODO actually make this lazy
|
||||||
|
return ac.iorArray(ac2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) lazyIorBitmap(bc *bitmapContainer) container {
|
||||||
|
// TODO actually make this lazy
|
||||||
|
return ac.iorBitmap(bc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) lazyIorRun16(rc *runContainer16) container {
|
||||||
|
// TODO actually make this lazy
|
||||||
|
return ac.iorRun16(rc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) lazyOR(a container) container {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.lazyorArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return a.lazyOR(ac)
|
||||||
|
case *runContainer16:
|
||||||
|
if x.isFull() {
|
||||||
|
return x.clone()
|
||||||
|
}
|
||||||
|
return x.orArray(ac)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) orArray(value2 *arrayContainer) container {
|
||||||
|
value1 := ac
|
||||||
|
maxPossibleCardinality := value1.getCardinality() + value2.getCardinality()
|
||||||
|
if maxPossibleCardinality > arrayDefaultMaxSize { // it could be a bitmap!
|
||||||
|
bc := newBitmapContainer()
|
||||||
|
for k := 0; k < len(value2.content); k++ {
|
||||||
|
v := value2.content[k]
|
||||||
|
i := uint(v) >> 6
|
||||||
|
mask := uint64(1) << (v % 64)
|
||||||
|
bc.bitmap[i] |= mask
|
||||||
|
}
|
||||||
|
for k := 0; k < len(ac.content); k++ {
|
||||||
|
v := ac.content[k]
|
||||||
|
i := uint(v) >> 6
|
||||||
|
mask := uint64(1) << (v % 64)
|
||||||
|
bc.bitmap[i] |= mask
|
||||||
|
}
|
||||||
|
bc.cardinality = int(popcntSlice(bc.bitmap))
|
||||||
|
if bc.cardinality <= arrayDefaultMaxSize {
|
||||||
|
return bc.toArrayContainer()
|
||||||
|
}
|
||||||
|
return bc
|
||||||
|
}
|
||||||
|
answer := newArrayContainerCapacity(maxPossibleCardinality)
|
||||||
|
nl := union2by2(value1.content, value2.content, answer.content)
|
||||||
|
answer.content = answer.content[:nl] // reslice to match actual used capacity
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) orArrayCardinality(value2 *arrayContainer) int {
|
||||||
|
return union2by2Cardinality(ac.content, value2.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) lazyorArray(value2 *arrayContainer) container {
|
||||||
|
value1 := ac
|
||||||
|
maxPossibleCardinality := value1.getCardinality() + value2.getCardinality()
|
||||||
|
if maxPossibleCardinality > arrayLazyLowerBound { // it could be a bitmap!^M
|
||||||
|
bc := newBitmapContainer()
|
||||||
|
for k := 0; k < len(value2.content); k++ {
|
||||||
|
v := value2.content[k]
|
||||||
|
i := uint(v) >> 6
|
||||||
|
mask := uint64(1) << (v % 64)
|
||||||
|
bc.bitmap[i] |= mask
|
||||||
|
}
|
||||||
|
for k := 0; k < len(ac.content); k++ {
|
||||||
|
v := ac.content[k]
|
||||||
|
i := uint(v) >> 6
|
||||||
|
mask := uint64(1) << (v % 64)
|
||||||
|
bc.bitmap[i] |= mask
|
||||||
|
}
|
||||||
|
bc.cardinality = invalidCardinality
|
||||||
|
return bc
|
||||||
|
}
|
||||||
|
answer := newArrayContainerCapacity(maxPossibleCardinality)
|
||||||
|
nl := union2by2(value1.content, value2.content, answer.content)
|
||||||
|
answer.content = answer.content[:nl] // reslice to match actual used capacity
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) and(a container) container {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.andArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return x.and(ac)
|
||||||
|
case *runContainer16:
|
||||||
|
if x.isFull() {
|
||||||
|
return ac.clone()
|
||||||
|
}
|
||||||
|
return x.andArray(ac)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) andCardinality(a container) int {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.andArrayCardinality(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return x.andCardinality(ac)
|
||||||
|
case *runContainer16:
|
||||||
|
return x.andArrayCardinality(ac)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) intersects(a container) bool {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.intersectsArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return x.intersects(ac)
|
||||||
|
case *runContainer16:
|
||||||
|
return x.intersects(ac)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iand(a container) container {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.iandArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return ac.iandBitmap(x)
|
||||||
|
case *runContainer16:
|
||||||
|
if x.isFull() {
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
return x.andArray(ac)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iandBitmap(bc *bitmapContainer) container {
|
||||||
|
pos := 0
|
||||||
|
c := ac.getCardinality()
|
||||||
|
for k := 0; k < c; k++ {
|
||||||
|
// branchless
|
||||||
|
v := ac.content[k]
|
||||||
|
ac.content[pos] = v
|
||||||
|
pos += int(bc.bitValue(v))
|
||||||
|
}
|
||||||
|
ac.content = ac.content[:pos]
|
||||||
|
return ac
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) xor(a container) container {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.xorArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return a.xor(ac)
|
||||||
|
case *runContainer16:
|
||||||
|
return x.xorArray(ac)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) xorArray(value2 *arrayContainer) container {
|
||||||
|
value1 := ac
|
||||||
|
totalCardinality := value1.getCardinality() + value2.getCardinality()
|
||||||
|
if totalCardinality > arrayDefaultMaxSize { // it could be a bitmap!
|
||||||
|
bc := newBitmapContainer()
|
||||||
|
for k := 0; k < len(value2.content); k++ {
|
||||||
|
v := value2.content[k]
|
||||||
|
i := uint(v) >> 6
|
||||||
|
bc.bitmap[i] ^= (uint64(1) << (v % 64))
|
||||||
|
}
|
||||||
|
for k := 0; k < len(ac.content); k++ {
|
||||||
|
v := ac.content[k]
|
||||||
|
i := uint(v) >> 6
|
||||||
|
bc.bitmap[i] ^= (uint64(1) << (v % 64))
|
||||||
|
}
|
||||||
|
bc.computeCardinality()
|
||||||
|
if bc.cardinality <= arrayDefaultMaxSize {
|
||||||
|
return bc.toArrayContainer()
|
||||||
|
}
|
||||||
|
return bc
|
||||||
|
}
|
||||||
|
desiredCapacity := totalCardinality
|
||||||
|
answer := newArrayContainerCapacity(desiredCapacity)
|
||||||
|
length := exclusiveUnion2by2(value1.content, value2.content, answer.content)
|
||||||
|
answer.content = answer.content[:length]
|
||||||
|
return answer
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) andNot(a container) container {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.andNotArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return ac.andNotBitmap(x)
|
||||||
|
case *runContainer16:
|
||||||
|
return ac.andNotRun16(x)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) andNotRun16(rc *runContainer16) container {
|
||||||
|
acb := ac.toBitmapContainer()
|
||||||
|
rcb := rc.toBitmapContainer()
|
||||||
|
return acb.andNotBitmap(rcb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iandNot(a container) container {
|
||||||
|
switch x := a.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return ac.iandNotArray(x)
|
||||||
|
case *bitmapContainer:
|
||||||
|
return ac.iandNotBitmap(x)
|
||||||
|
case *runContainer16:
|
||||||
|
return ac.iandNotRun16(x)
|
||||||
|
}
|
||||||
|
panic("unsupported container type")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iandNotRun16(rc *runContainer16) container {
|
||||||
|
rcb := rc.toBitmapContainer()
|
||||||
|
acb := ac.toBitmapContainer()
|
||||||
|
acb.iandNotBitmapSurely(rcb)
|
||||||
|
*ac = *(acb.toArrayContainer())
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) andNotArray(value2 *arrayContainer) container {
|
||||||
|
value1 := ac
|
||||||
|
desiredcapacity := value1.getCardinality()
|
||||||
|
answer := newArrayContainerCapacity(desiredcapacity)
|
||||||
|
length := difference(value1.content, value2.content, answer.content)
|
||||||
|
answer.content = answer.content[:length]
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iandNotArray(value2 *arrayContainer) container {
|
||||||
|
length := difference(ac.content, value2.content, ac.content)
|
||||||
|
ac.content = ac.content[:length]
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) andNotBitmap(value2 *bitmapContainer) container {
|
||||||
|
desiredcapacity := ac.getCardinality()
|
||||||
|
answer := newArrayContainerCapacity(desiredcapacity)
|
||||||
|
answer.content = answer.content[:desiredcapacity]
|
||||||
|
pos := 0
|
||||||
|
for _, v := range ac.content {
|
||||||
|
answer.content[pos] = v
|
||||||
|
pos += 1 - int(value2.bitValue(v))
|
||||||
|
}
|
||||||
|
answer.content = answer.content[:pos]
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) andBitmap(value2 *bitmapContainer) container {
|
||||||
|
desiredcapacity := ac.getCardinality()
|
||||||
|
answer := newArrayContainerCapacity(desiredcapacity)
|
||||||
|
answer.content = answer.content[:desiredcapacity]
|
||||||
|
pos := 0
|
||||||
|
for _, v := range ac.content {
|
||||||
|
answer.content[pos] = v
|
||||||
|
pos += int(value2.bitValue(v))
|
||||||
|
}
|
||||||
|
answer.content = answer.content[:pos]
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iandNotBitmap(value2 *bitmapContainer) container {
|
||||||
|
pos := 0
|
||||||
|
for _, v := range ac.content {
|
||||||
|
ac.content[pos] = v
|
||||||
|
pos += 1 - int(value2.bitValue(v))
|
||||||
|
}
|
||||||
|
ac.content = ac.content[:pos]
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyOf(array []uint16, size int) []uint16 {
|
||||||
|
result := make([]uint16, size)
|
||||||
|
for i, x := range array {
|
||||||
|
if i == size {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result[i] = x
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// flip the values in the range [firstOfRange,endx)
|
||||||
|
func (ac *arrayContainer) inot(firstOfRange, endx int) container {
|
||||||
|
if firstOfRange >= endx {
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
return ac.inotClose(firstOfRange, endx-1) // remove everything in [firstOfRange,endx-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// flip the values in the range [firstOfRange,lastOfRange]
|
||||||
|
func (ac *arrayContainer) inotClose(firstOfRange, lastOfRange int) container {
|
||||||
|
if firstOfRange > lastOfRange { // unlike add and remove, not uses an inclusive range [firstOfRange,lastOfRange]
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
// determine the span of array indices to be affected
|
||||||
|
startIndex := binarySearch(ac.content, uint16(firstOfRange))
|
||||||
|
if startIndex < 0 {
|
||||||
|
startIndex = -startIndex - 1
|
||||||
|
}
|
||||||
|
lastIndex := binarySearch(ac.content, uint16(lastOfRange))
|
||||||
|
if lastIndex < 0 {
|
||||||
|
lastIndex = -lastIndex - 1 - 1
|
||||||
|
}
|
||||||
|
currentValuesInRange := lastIndex - startIndex + 1
|
||||||
|
spanToBeFlipped := lastOfRange - firstOfRange + 1
|
||||||
|
|
||||||
|
newValuesInRange := spanToBeFlipped - currentValuesInRange
|
||||||
|
buffer := make([]uint16, newValuesInRange)
|
||||||
|
cardinalityChange := newValuesInRange - currentValuesInRange
|
||||||
|
newCardinality := len(ac.content) + cardinalityChange
|
||||||
|
if cardinalityChange > 0 {
|
||||||
|
if newCardinality > len(ac.content) {
|
||||||
|
if newCardinality > arrayDefaultMaxSize {
|
||||||
|
bcRet := ac.toBitmapContainer()
|
||||||
|
bcRet.inot(firstOfRange, lastOfRange+1)
|
||||||
|
*ac = *bcRet.toArrayContainer()
|
||||||
|
return bcRet
|
||||||
|
}
|
||||||
|
ac.content = copyOf(ac.content, newCardinality)
|
||||||
|
}
|
||||||
|
base := lastIndex + 1
|
||||||
|
copy(ac.content[lastIndex+1+cardinalityChange:], ac.content[base:base+len(ac.content)-1-lastIndex])
|
||||||
|
ac.negateRange(buffer, startIndex, lastIndex, firstOfRange, lastOfRange+1)
|
||||||
|
} else { // no expansion needed
|
||||||
|
ac.negateRange(buffer, startIndex, lastIndex, firstOfRange, lastOfRange+1)
|
||||||
|
if cardinalityChange < 0 {
|
||||||
|
|
||||||
|
for i := startIndex + newValuesInRange; i < newCardinality; i++ {
|
||||||
|
ac.content[i] = ac.content[i-cardinalityChange]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ac.content = ac.content[:newCardinality]
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) negateRange(buffer []uint16, startIndex, lastIndex, startRange, lastRange int) {
|
||||||
|
// compute the negation into buffer
|
||||||
|
outPos := 0
|
||||||
|
inPos := startIndex // value here always >= valInRange,
|
||||||
|
// until it is exhausted
|
||||||
|
// n.b., we can start initially exhausted.
|
||||||
|
|
||||||
|
valInRange := startRange
|
||||||
|
for ; valInRange < lastRange && inPos <= lastIndex; valInRange++ {
|
||||||
|
if uint16(valInRange) != ac.content[inPos] {
|
||||||
|
buffer[outPos] = uint16(valInRange)
|
||||||
|
outPos++
|
||||||
|
} else {
|
||||||
|
inPos++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there are extra items (greater than the biggest
|
||||||
|
// pre-existing one in range), buffer them
|
||||||
|
for ; valInRange < lastRange; valInRange++ {
|
||||||
|
buffer[outPos] = uint16(valInRange)
|
||||||
|
outPos++
|
||||||
|
}
|
||||||
|
|
||||||
|
if outPos != len(buffer) {
|
||||||
|
panic("negateRange: internal bug")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, item := range buffer {
|
||||||
|
ac.content[i+startIndex] = item
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) isFull() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) andArray(value2 *arrayContainer) container {
|
||||||
|
desiredcapacity := minOfInt(ac.getCardinality(), value2.getCardinality())
|
||||||
|
answer := newArrayContainerCapacity(desiredcapacity)
|
||||||
|
length := intersection2by2(
|
||||||
|
ac.content,
|
||||||
|
value2.content,
|
||||||
|
answer.content)
|
||||||
|
answer.content = answer.content[:length]
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) andArrayCardinality(value2 *arrayContainer) int {
|
||||||
|
return intersection2by2Cardinality(
|
||||||
|
ac.content,
|
||||||
|
value2.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) intersectsArray(value2 *arrayContainer) bool {
|
||||||
|
return intersects2by2(
|
||||||
|
ac.content,
|
||||||
|
value2.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) iandArray(value2 *arrayContainer) container {
|
||||||
|
length := intersection2by2(
|
||||||
|
ac.content,
|
||||||
|
value2.content,
|
||||||
|
ac.content)
|
||||||
|
ac.content = ac.content[:length]
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) getCardinality() int {
|
||||||
|
return len(ac.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) rank(x uint16) int {
|
||||||
|
answer := binarySearch(ac.content, x)
|
||||||
|
if answer >= 0 {
|
||||||
|
return answer + 1
|
||||||
|
}
|
||||||
|
return -answer - 1
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) selectInt(x uint16) int {
|
||||||
|
return int(ac.content[x])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) clone() container {
|
||||||
|
ptr := arrayContainer{make([]uint16, len(ac.content))}
|
||||||
|
copy(ptr.content, ac.content[:])
|
||||||
|
return &ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) contains(x uint16) bool {
|
||||||
|
return binarySearch(ac.content, x) >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) loadData(bitmapContainer *bitmapContainer) {
|
||||||
|
ac.content = make([]uint16, bitmapContainer.cardinality, bitmapContainer.cardinality)
|
||||||
|
bitmapContainer.fillArray(ac.content)
|
||||||
|
}
|
||||||
|
func newArrayContainer() *arrayContainer {
|
||||||
|
p := new(arrayContainer)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func newArrayContainerFromBitmap(bc *bitmapContainer) *arrayContainer {
|
||||||
|
ac := &arrayContainer{}
|
||||||
|
ac.loadData(bc)
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
|
||||||
|
func newArrayContainerCapacity(size int) *arrayContainer {
|
||||||
|
p := new(arrayContainer)
|
||||||
|
p.content = make([]uint16, 0, size)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func newArrayContainerSize(size int) *arrayContainer {
|
||||||
|
p := new(arrayContainer)
|
||||||
|
p.content = make([]uint16, size, size)
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func newArrayContainerRange(firstOfRun, lastOfRun int) *arrayContainer {
|
||||||
|
valuesInRange := lastOfRun - firstOfRun + 1
|
||||||
|
this := newArrayContainerCapacity(valuesInRange)
|
||||||
|
for i := 0; i < valuesInRange; i++ {
|
||||||
|
this.content = append(this.content, uint16(firstOfRun+i))
|
||||||
|
}
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) numberOfRuns() (nr int) {
|
||||||
|
n := len(ac.content)
|
||||||
|
var runlen uint16
|
||||||
|
var cur, prev uint16
|
||||||
|
|
||||||
|
switch n {
|
||||||
|
case 0:
|
||||||
|
return 0
|
||||||
|
case 1:
|
||||||
|
return 1
|
||||||
|
default:
|
||||||
|
for i := 1; i < n; i++ {
|
||||||
|
prev = ac.content[i-1]
|
||||||
|
cur = ac.content[i]
|
||||||
|
|
||||||
|
if cur == prev+1 {
|
||||||
|
runlen++
|
||||||
|
} else {
|
||||||
|
if cur < prev {
|
||||||
|
panic("then fundamental arrayContainer assumption of sorted ac.content was broken")
|
||||||
|
}
|
||||||
|
if cur == prev {
|
||||||
|
panic("then fundamental arrayContainer assumption of deduplicated content was broken")
|
||||||
|
} else {
|
||||||
|
nr++
|
||||||
|
runlen = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nr++
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to run or array *if needed*
|
||||||
|
func (ac *arrayContainer) toEfficientContainer() container {
|
||||||
|
|
||||||
|
numRuns := ac.numberOfRuns()
|
||||||
|
|
||||||
|
sizeAsRunContainer := runContainer16SerializedSizeInBytes(numRuns)
|
||||||
|
sizeAsBitmapContainer := bitmapContainerSizeInBytes()
|
||||||
|
card := ac.getCardinality()
|
||||||
|
sizeAsArrayContainer := arrayContainerSizeInBytes(card)
|
||||||
|
|
||||||
|
if sizeAsRunContainer <= minOfInt(sizeAsBitmapContainer, sizeAsArrayContainer) {
|
||||||
|
return newRunContainer16FromArray(ac)
|
||||||
|
}
|
||||||
|
if card <= arrayDefaultMaxSize {
|
||||||
|
return ac
|
||||||
|
}
|
||||||
|
return ac.toBitmapContainer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) containerType() contype {
|
||||||
|
return arrayContype
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *arrayContainer) addOffset(x uint16) []container {
|
||||||
|
low := &arrayContainer{}
|
||||||
|
high := &arrayContainer{}
|
||||||
|
for _, val := range ac.content {
|
||||||
|
y := uint32(val) + uint32(x)
|
||||||
|
if highbits(y) > 0 {
|
||||||
|
high.content = append(high.content, lowbits(y))
|
||||||
|
} else {
|
||||||
|
low.content = append(low.content, lowbits(y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return []container{low, high}
|
||||||
|
}
|
||||||
134
vendor/github.com/RoaringBitmap/roaring/arraycontainer_gen.go
сгенерированный
поставляемый
Обычный файл
134
vendor/github.com/RoaringBitmap/roaring/arraycontainer_gen.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,134 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
// NOTE: THIS FILE WAS PRODUCED BY THE
|
||||||
|
// MSGP CODE GENERATION TOOL (github.com/tinylib/msgp)
|
||||||
|
// DO NOT EDIT
|
||||||
|
|
||||||
|
import "github.com/tinylib/msgp/msgp"
|
||||||
|
|
||||||
|
// Deprecated: DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *arrayContainer) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zbzg uint32
|
||||||
|
zbzg, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zbzg > 0 {
|
||||||
|
zbzg--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "content":
|
||||||
|
var zbai uint32
|
||||||
|
zbai, err = dc.ReadArrayHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.content) >= int(zbai) {
|
||||||
|
z.content = (z.content)[:zbai]
|
||||||
|
} else {
|
||||||
|
z.content = make([]uint16, zbai)
|
||||||
|
}
|
||||||
|
for zxvk := range z.content {
|
||||||
|
z.content[zxvk], err = dc.ReadUint16()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *arrayContainer) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 1
|
||||||
|
// write "content"
|
||||||
|
err = en.Append(0x81, 0xa7, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteArrayHeader(uint32(len(z.content)))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zxvk := range z.content {
|
||||||
|
err = en.WriteUint16(z.content[zxvk])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z *arrayContainer) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 1
|
||||||
|
// string "content"
|
||||||
|
o = append(o, 0x81, 0xa7, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74)
|
||||||
|
o = msgp.AppendArrayHeader(o, uint32(len(z.content)))
|
||||||
|
for zxvk := range z.content {
|
||||||
|
o = msgp.AppendUint16(o, z.content[zxvk])
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *arrayContainer) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zcmr uint32
|
||||||
|
zcmr, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zcmr > 0 {
|
||||||
|
zcmr--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "content":
|
||||||
|
var zajw uint32
|
||||||
|
zajw, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.content) >= int(zajw) {
|
||||||
|
z.content = (z.content)[:zajw]
|
||||||
|
} else {
|
||||||
|
z.content = make([]uint16, zajw)
|
||||||
|
}
|
||||||
|
for zxvk := range z.content {
|
||||||
|
z.content[zxvk], bts, err = msgp.ReadUint16Bytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z *arrayContainer) Msgsize() (s int) {
|
||||||
|
s = 1 + 8 + msgp.ArrayHeaderSize + (len(z.content) * (msgp.Uint16Size))
|
||||||
|
return
|
||||||
|
}
|
||||||
1098
vendor/github.com/RoaringBitmap/roaring/bitmapcontainer.go
сгенерированный
поставляемый
Обычный файл
1098
vendor/github.com/RoaringBitmap/roaring/bitmapcontainer.go
сгенерированный
поставляемый
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
415
vendor/github.com/RoaringBitmap/roaring/bitmapcontainer_gen.go
сгенерированный
поставляемый
Обычный файл
415
vendor/github.com/RoaringBitmap/roaring/bitmapcontainer_gen.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,415 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
// NOTE: THIS FILE WAS PRODUCED BY THE
|
||||||
|
// MSGP CODE GENERATION TOOL (github.com/tinylib/msgp)
|
||||||
|
// DO NOT EDIT
|
||||||
|
|
||||||
|
import "github.com/tinylib/msgp/msgp"
|
||||||
|
|
||||||
|
// Deprecated: DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *bitmapContainer) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zbzg uint32
|
||||||
|
zbzg, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zbzg > 0 {
|
||||||
|
zbzg--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "cardinality":
|
||||||
|
z.cardinality, err = dc.ReadInt()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "bitmap":
|
||||||
|
var zbai uint32
|
||||||
|
zbai, err = dc.ReadArrayHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.bitmap) >= int(zbai) {
|
||||||
|
z.bitmap = (z.bitmap)[:zbai]
|
||||||
|
} else {
|
||||||
|
z.bitmap = make([]uint64, zbai)
|
||||||
|
}
|
||||||
|
for zxvk := range z.bitmap {
|
||||||
|
z.bitmap[zxvk], err = dc.ReadUint64()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *bitmapContainer) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 2
|
||||||
|
// write "cardinality"
|
||||||
|
err = en.Append(0x82, 0xab, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteInt(z.cardinality)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "bitmap"
|
||||||
|
err = en.Append(0xa6, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteArrayHeader(uint32(len(z.bitmap)))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zxvk := range z.bitmap {
|
||||||
|
err = en.WriteUint64(z.bitmap[zxvk])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z *bitmapContainer) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 2
|
||||||
|
// string "cardinality"
|
||||||
|
o = append(o, 0x82, 0xab, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79)
|
||||||
|
o = msgp.AppendInt(o, z.cardinality)
|
||||||
|
// string "bitmap"
|
||||||
|
o = append(o, 0xa6, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70)
|
||||||
|
o = msgp.AppendArrayHeader(o, uint32(len(z.bitmap)))
|
||||||
|
for zxvk := range z.bitmap {
|
||||||
|
o = msgp.AppendUint64(o, z.bitmap[zxvk])
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *bitmapContainer) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zcmr uint32
|
||||||
|
zcmr, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zcmr > 0 {
|
||||||
|
zcmr--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "cardinality":
|
||||||
|
z.cardinality, bts, err = msgp.ReadIntBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "bitmap":
|
||||||
|
var zajw uint32
|
||||||
|
zajw, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.bitmap) >= int(zajw) {
|
||||||
|
z.bitmap = (z.bitmap)[:zajw]
|
||||||
|
} else {
|
||||||
|
z.bitmap = make([]uint64, zajw)
|
||||||
|
}
|
||||||
|
for zxvk := range z.bitmap {
|
||||||
|
z.bitmap[zxvk], bts, err = msgp.ReadUint64Bytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z *bitmapContainer) Msgsize() (s int) {
|
||||||
|
s = 1 + 12 + msgp.IntSize + 7 + msgp.ArrayHeaderSize + (len(z.bitmap) * (msgp.Uint64Size))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *bitmapContainerShortIterator) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zhct uint32
|
||||||
|
zhct, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zhct > 0 {
|
||||||
|
zhct--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "ptr":
|
||||||
|
if dc.IsNil() {
|
||||||
|
err = dc.ReadNil()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.ptr = nil
|
||||||
|
} else {
|
||||||
|
if z.ptr == nil {
|
||||||
|
z.ptr = new(bitmapContainer)
|
||||||
|
}
|
||||||
|
var zcua uint32
|
||||||
|
zcua, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zcua > 0 {
|
||||||
|
zcua--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "cardinality":
|
||||||
|
z.ptr.cardinality, err = dc.ReadInt()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "bitmap":
|
||||||
|
var zxhx uint32
|
||||||
|
zxhx, err = dc.ReadArrayHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.ptr.bitmap) >= int(zxhx) {
|
||||||
|
z.ptr.bitmap = (z.ptr.bitmap)[:zxhx]
|
||||||
|
} else {
|
||||||
|
z.ptr.bitmap = make([]uint64, zxhx)
|
||||||
|
}
|
||||||
|
for zwht := range z.ptr.bitmap {
|
||||||
|
z.ptr.bitmap[zwht], err = dc.ReadUint64()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "i":
|
||||||
|
z.i, err = dc.ReadInt()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *bitmapContainerShortIterator) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 2
|
||||||
|
// write "ptr"
|
||||||
|
err = en.Append(0x82, 0xa3, 0x70, 0x74, 0x72)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if z.ptr == nil {
|
||||||
|
err = en.WriteNil()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// map header, size 2
|
||||||
|
// write "cardinality"
|
||||||
|
err = en.Append(0x82, 0xab, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteInt(z.ptr.cardinality)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "bitmap"
|
||||||
|
err = en.Append(0xa6, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteArrayHeader(uint32(len(z.ptr.bitmap)))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zwht := range z.ptr.bitmap {
|
||||||
|
err = en.WriteUint64(z.ptr.bitmap[zwht])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write "i"
|
||||||
|
err = en.Append(0xa1, 0x69)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteInt(z.i)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z *bitmapContainerShortIterator) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 2
|
||||||
|
// string "ptr"
|
||||||
|
o = append(o, 0x82, 0xa3, 0x70, 0x74, 0x72)
|
||||||
|
if z.ptr == nil {
|
||||||
|
o = msgp.AppendNil(o)
|
||||||
|
} else {
|
||||||
|
// map header, size 2
|
||||||
|
// string "cardinality"
|
||||||
|
o = append(o, 0x82, 0xab, 0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x74, 0x79)
|
||||||
|
o = msgp.AppendInt(o, z.ptr.cardinality)
|
||||||
|
// string "bitmap"
|
||||||
|
o = append(o, 0xa6, 0x62, 0x69, 0x74, 0x6d, 0x61, 0x70)
|
||||||
|
o = msgp.AppendArrayHeader(o, uint32(len(z.ptr.bitmap)))
|
||||||
|
for zwht := range z.ptr.bitmap {
|
||||||
|
o = msgp.AppendUint64(o, z.ptr.bitmap[zwht])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// string "i"
|
||||||
|
o = append(o, 0xa1, 0x69)
|
||||||
|
o = msgp.AppendInt(o, z.i)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *bitmapContainerShortIterator) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zlqf uint32
|
||||||
|
zlqf, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zlqf > 0 {
|
||||||
|
zlqf--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "ptr":
|
||||||
|
if msgp.IsNil(bts) {
|
||||||
|
bts, err = msgp.ReadNilBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
z.ptr = nil
|
||||||
|
} else {
|
||||||
|
if z.ptr == nil {
|
||||||
|
z.ptr = new(bitmapContainer)
|
||||||
|
}
|
||||||
|
var zdaf uint32
|
||||||
|
zdaf, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zdaf > 0 {
|
||||||
|
zdaf--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "cardinality":
|
||||||
|
z.ptr.cardinality, bts, err = msgp.ReadIntBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "bitmap":
|
||||||
|
var zpks uint32
|
||||||
|
zpks, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.ptr.bitmap) >= int(zpks) {
|
||||||
|
z.ptr.bitmap = (z.ptr.bitmap)[:zpks]
|
||||||
|
} else {
|
||||||
|
z.ptr.bitmap = make([]uint64, zpks)
|
||||||
|
}
|
||||||
|
for zwht := range z.ptr.bitmap {
|
||||||
|
z.ptr.bitmap[zwht], bts, err = msgp.ReadUint64Bytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "i":
|
||||||
|
z.i, bts, err = msgp.ReadIntBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z *bitmapContainerShortIterator) Msgsize() (s int) {
|
||||||
|
s = 1 + 4
|
||||||
|
if z.ptr == nil {
|
||||||
|
s += msgp.NilSize
|
||||||
|
} else {
|
||||||
|
s += 1 + 12 + msgp.IntSize + 7 + msgp.ArrayHeaderSize + (len(z.ptr.bitmap) * (msgp.Uint64Size))
|
||||||
|
}
|
||||||
|
s += 2 + msgp.IntSize
|
||||||
|
return
|
||||||
|
}
|
||||||
161
vendor/github.com/RoaringBitmap/roaring/byte_input.go
сгенерированный
поставляемый
Обычный файл
161
vendor/github.com/RoaringBitmap/roaring/byte_input.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,161 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type byteInput interface {
|
||||||
|
// next returns a slice containing the next n bytes from the buffer,
|
||||||
|
// advancing the buffer as if the bytes had been returned by Read.
|
||||||
|
next(n int) ([]byte, error)
|
||||||
|
// readUInt32 reads uint32 with LittleEndian order
|
||||||
|
readUInt32() (uint32, error)
|
||||||
|
// readUInt16 reads uint16 with LittleEndian order
|
||||||
|
readUInt16() (uint16, error)
|
||||||
|
// getReadBytes returns read bytes
|
||||||
|
getReadBytes() int64
|
||||||
|
// skipBytes skips exactly n bytes
|
||||||
|
skipBytes(n int) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func newByteInputFromReader(reader io.Reader) byteInput {
|
||||||
|
return &byteInputAdapter{
|
||||||
|
r: reader,
|
||||||
|
readBytes: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newByteInput(buf []byte) byteInput {
|
||||||
|
return &byteBuffer{
|
||||||
|
buf: buf,
|
||||||
|
off: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type byteBuffer struct {
|
||||||
|
buf []byte
|
||||||
|
off int
|
||||||
|
}
|
||||||
|
|
||||||
|
// next returns a slice containing the next n bytes from the reader
|
||||||
|
// If there are fewer bytes than the given n, io.ErrUnexpectedEOF will be returned
|
||||||
|
func (b *byteBuffer) next(n int) ([]byte, error) {
|
||||||
|
m := len(b.buf) - b.off
|
||||||
|
|
||||||
|
if n > m {
|
||||||
|
return nil, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
data := b.buf[b.off : b.off+n]
|
||||||
|
b.off += n
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readUInt32 reads uint32 with LittleEndian order
|
||||||
|
func (b *byteBuffer) readUInt32() (uint32, error) {
|
||||||
|
if len(b.buf)-b.off < 4 {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
v := binary.LittleEndian.Uint32(b.buf[b.off:])
|
||||||
|
b.off += 4
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readUInt16 reads uint16 with LittleEndian order
|
||||||
|
func (b *byteBuffer) readUInt16() (uint16, error) {
|
||||||
|
if len(b.buf)-b.off < 2 {
|
||||||
|
return 0, io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
v := binary.LittleEndian.Uint16(b.buf[b.off:])
|
||||||
|
b.off += 2
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getReadBytes returns read bytes
|
||||||
|
func (b *byteBuffer) getReadBytes() int64 {
|
||||||
|
return int64(b.off)
|
||||||
|
}
|
||||||
|
|
||||||
|
// skipBytes skips exactly n bytes
|
||||||
|
func (b *byteBuffer) skipBytes(n int) error {
|
||||||
|
m := len(b.buf) - b.off
|
||||||
|
|
||||||
|
if n > m {
|
||||||
|
return io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
b.off += n
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset resets the given buffer with a new byte slice
|
||||||
|
func (b *byteBuffer) reset(buf []byte) {
|
||||||
|
b.buf = buf
|
||||||
|
b.off = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type byteInputAdapter struct {
|
||||||
|
r io.Reader
|
||||||
|
readBytes int
|
||||||
|
}
|
||||||
|
|
||||||
|
// next returns a slice containing the next n bytes from the buffer,
|
||||||
|
// advancing the buffer as if the bytes had been returned by Read.
|
||||||
|
func (b *byteInputAdapter) next(n int) ([]byte, error) {
|
||||||
|
buf := make([]byte, n)
|
||||||
|
m, err := io.ReadAtLeast(b.r, buf, n)
|
||||||
|
b.readBytes += m
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readUInt32 reads uint32 with LittleEndian order
|
||||||
|
func (b *byteInputAdapter) readUInt32() (uint32, error) {
|
||||||
|
buf, err := b.next(4)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return binary.LittleEndian.Uint32(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// readUInt16 reads uint16 with LittleEndian order
|
||||||
|
func (b *byteInputAdapter) readUInt16() (uint16, error) {
|
||||||
|
buf, err := b.next(2)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return binary.LittleEndian.Uint16(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getReadBytes returns read bytes
|
||||||
|
func (b *byteInputAdapter) getReadBytes() int64 {
|
||||||
|
return int64(b.readBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// skipBytes skips exactly n bytes
|
||||||
|
func (b *byteInputAdapter) skipBytes(n int) error {
|
||||||
|
_, err := b.next(n)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset resets the given buffer with a new stream
|
||||||
|
func (b *byteInputAdapter) reset(stream io.Reader) {
|
||||||
|
b.r = stream
|
||||||
|
b.readBytes = 0
|
||||||
|
}
|
||||||
11
vendor/github.com/RoaringBitmap/roaring/clz.go
сгенерированный
поставляемый
Обычный файл
11
vendor/github.com/RoaringBitmap/roaring/clz.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,11 @@
|
|||||||
|
// +build go1.9
|
||||||
|
// "go1.9", from Go version 1.9 onward
|
||||||
|
// See https://golang.org/pkg/go/build/#hdr-Build_Constraints
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
import "math/bits"
|
||||||
|
|
||||||
|
func countLeadingZeros(x uint64) int {
|
||||||
|
return bits.LeadingZeros64(x)
|
||||||
|
}
|
||||||
36
vendor/github.com/RoaringBitmap/roaring/clz_compat.go
сгенерированный
поставляемый
Обычный файл
36
vendor/github.com/RoaringBitmap/roaring/clz_compat.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,36 @@
|
|||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
// LeadingZeroBits returns the number of consecutive most significant zero
|
||||||
|
// bits of x.
|
||||||
|
func countLeadingZeros(i uint64) int {
|
||||||
|
if i == 0 {
|
||||||
|
return 64
|
||||||
|
}
|
||||||
|
n := 1
|
||||||
|
x := uint32(i >> 32)
|
||||||
|
if x == 0 {
|
||||||
|
n += 32
|
||||||
|
x = uint32(i)
|
||||||
|
}
|
||||||
|
if (x >> 16) == 0 {
|
||||||
|
n += 16
|
||||||
|
x <<= 16
|
||||||
|
}
|
||||||
|
if (x >> 24) == 0 {
|
||||||
|
n += 8
|
||||||
|
x <<= 8
|
||||||
|
}
|
||||||
|
if x>>28 == 0 {
|
||||||
|
n += 4
|
||||||
|
x <<= 4
|
||||||
|
}
|
||||||
|
if x>>30 == 0 {
|
||||||
|
n += 2
|
||||||
|
x <<= 2
|
||||||
|
|
||||||
|
}
|
||||||
|
n -= int(x >> 31)
|
||||||
|
return n
|
||||||
|
}
|
||||||
11
vendor/github.com/RoaringBitmap/roaring/ctz.go
сгенерированный
поставляемый
Обычный файл
11
vendor/github.com/RoaringBitmap/roaring/ctz.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,11 @@
|
|||||||
|
// +build go1.9
|
||||||
|
// "go1.9", from Go version 1.9 onward
|
||||||
|
// See https://golang.org/pkg/go/build/#hdr-Build_Constraints
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
import "math/bits"
|
||||||
|
|
||||||
|
func countTrailingZeros(x uint64) int {
|
||||||
|
return bits.TrailingZeros64(x)
|
||||||
|
}
|
||||||
71
vendor/github.com/RoaringBitmap/roaring/ctz_compat.go
сгенерированный
поставляемый
Обычный файл
71
vendor/github.com/RoaringBitmap/roaring/ctz_compat.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,71 @@
|
|||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
// Reuse of portions of go/src/math/big standard lib code
|
||||||
|
// under this license:
|
||||||
|
/*
|
||||||
|
Copyright (c) 2009 The Go Authors. 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 Google Inc. 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
|
||||||
|
OWNER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const deBruijn32 = 0x077CB531
|
||||||
|
|
||||||
|
var deBruijn32Lookup = []byte{
|
||||||
|
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
|
||||||
|
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
|
||||||
|
}
|
||||||
|
|
||||||
|
const deBruijn64 = 0x03f79d71b4ca8b09
|
||||||
|
|
||||||
|
var deBruijn64Lookup = []byte{
|
||||||
|
0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
|
||||||
|
62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
|
||||||
|
63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
|
||||||
|
54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
// trailingZeroBits returns the number of consecutive least significant zero
|
||||||
|
// bits of x.
|
||||||
|
func countTrailingZeros(x uint64) int {
|
||||||
|
// x & -x leaves only the right-most bit set in the word. Let k be the
|
||||||
|
// index of that bit. Since only a single bit is set, the value is two
|
||||||
|
// to the power of k. Multiplying by a power of two is equivalent to
|
||||||
|
// left shifting, in this case by k bits. The de Bruijn constant is
|
||||||
|
// such that all six bit, consecutive substrings are distinct.
|
||||||
|
// Therefore, if we have a left shifted version of this constant we can
|
||||||
|
// find by how many bits it was shifted by looking at which six bit
|
||||||
|
// substring ended up at the top of the word.
|
||||||
|
// (Knuth, volume 4, section 7.3.1)
|
||||||
|
if x == 0 {
|
||||||
|
// We have to special case 0; the fomula
|
||||||
|
// below doesn't work for 0.
|
||||||
|
return 64
|
||||||
|
}
|
||||||
|
return int(deBruijn64Lookup[((x&-x)*(deBruijn64))>>58])
|
||||||
|
}
|
||||||
215
vendor/github.com/RoaringBitmap/roaring/fastaggregation.go
сгенерированный
поставляемый
Обычный файл
215
vendor/github.com/RoaringBitmap/roaring/fastaggregation.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,215 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/heap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Or function that requires repairAfterLazy
|
||||||
|
func lazyOR(x1, x2 *Bitmap) *Bitmap {
|
||||||
|
answer := NewBitmap()
|
||||||
|
pos1 := 0
|
||||||
|
pos2 := 0
|
||||||
|
length1 := x1.highlowcontainer.size()
|
||||||
|
length2 := x2.highlowcontainer.size()
|
||||||
|
main:
|
||||||
|
for (pos1 < length1) && (pos2 < length2) {
|
||||||
|
s1 := x1.highlowcontainer.getKeyAtIndex(pos1)
|
||||||
|
s2 := x2.highlowcontainer.getKeyAtIndex(pos2)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if s1 < s2 {
|
||||||
|
answer.highlowcontainer.appendCopy(x1.highlowcontainer, pos1)
|
||||||
|
pos1++
|
||||||
|
if pos1 == length1 {
|
||||||
|
break main
|
||||||
|
}
|
||||||
|
s1 = x1.highlowcontainer.getKeyAtIndex(pos1)
|
||||||
|
} else if s1 > s2 {
|
||||||
|
answer.highlowcontainer.appendCopy(x2.highlowcontainer, pos2)
|
||||||
|
pos2++
|
||||||
|
if pos2 == length2 {
|
||||||
|
break main
|
||||||
|
}
|
||||||
|
s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
|
||||||
|
} else {
|
||||||
|
c1 := x1.highlowcontainer.getContainerAtIndex(pos1)
|
||||||
|
switch t := c1.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
c1 = t.toBitmapContainer()
|
||||||
|
case *runContainer16:
|
||||||
|
if !t.isFull() {
|
||||||
|
c1 = t.toBitmapContainer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
answer.highlowcontainer.appendContainer(s1, c1.lazyOR(x2.highlowcontainer.getContainerAtIndex(pos2)), false)
|
||||||
|
pos1++
|
||||||
|
pos2++
|
||||||
|
if (pos1 == length1) || (pos2 == length2) {
|
||||||
|
break main
|
||||||
|
}
|
||||||
|
s1 = x1.highlowcontainer.getKeyAtIndex(pos1)
|
||||||
|
s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pos1 == length1 {
|
||||||
|
answer.highlowcontainer.appendCopyMany(x2.highlowcontainer, pos2, length2)
|
||||||
|
} else if pos2 == length2 {
|
||||||
|
answer.highlowcontainer.appendCopyMany(x1.highlowcontainer, pos1, length1)
|
||||||
|
}
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
// In-place Or function that requires repairAfterLazy
|
||||||
|
func (x1 *Bitmap) lazyOR(x2 *Bitmap) *Bitmap {
|
||||||
|
pos1 := 0
|
||||||
|
pos2 := 0
|
||||||
|
length1 := x1.highlowcontainer.size()
|
||||||
|
length2 := x2.highlowcontainer.size()
|
||||||
|
main:
|
||||||
|
for (pos1 < length1) && (pos2 < length2) {
|
||||||
|
s1 := x1.highlowcontainer.getKeyAtIndex(pos1)
|
||||||
|
s2 := x2.highlowcontainer.getKeyAtIndex(pos2)
|
||||||
|
|
||||||
|
for {
|
||||||
|
if s1 < s2 {
|
||||||
|
pos1++
|
||||||
|
if pos1 == length1 {
|
||||||
|
break main
|
||||||
|
}
|
||||||
|
s1 = x1.highlowcontainer.getKeyAtIndex(pos1)
|
||||||
|
} else if s1 > s2 {
|
||||||
|
x1.highlowcontainer.insertNewKeyValueAt(pos1, s2, x2.highlowcontainer.getContainerAtIndex(pos2).clone())
|
||||||
|
pos2++
|
||||||
|
pos1++
|
||||||
|
length1++
|
||||||
|
if pos2 == length2 {
|
||||||
|
break main
|
||||||
|
}
|
||||||
|
s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
|
||||||
|
} else {
|
||||||
|
c1 := x1.highlowcontainer.getContainerAtIndex(pos1)
|
||||||
|
switch t := c1.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
c1 = t.toBitmapContainer()
|
||||||
|
case *runContainer16:
|
||||||
|
if !t.isFull() {
|
||||||
|
c1 = t.toBitmapContainer()
|
||||||
|
}
|
||||||
|
case *bitmapContainer:
|
||||||
|
c1 = x1.highlowcontainer.getWritableContainerAtIndex(pos1)
|
||||||
|
}
|
||||||
|
|
||||||
|
x1.highlowcontainer.containers[pos1] = c1.lazyIOR(x2.highlowcontainer.getContainerAtIndex(pos2))
|
||||||
|
x1.highlowcontainer.needCopyOnWrite[pos1] = false
|
||||||
|
pos1++
|
||||||
|
pos2++
|
||||||
|
if (pos1 == length1) || (pos2 == length2) {
|
||||||
|
break main
|
||||||
|
}
|
||||||
|
s1 = x1.highlowcontainer.getKeyAtIndex(pos1)
|
||||||
|
s2 = x2.highlowcontainer.getKeyAtIndex(pos2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if pos1 == length1 {
|
||||||
|
x1.highlowcontainer.appendCopyMany(x2.highlowcontainer, pos2, length2)
|
||||||
|
}
|
||||||
|
return x1
|
||||||
|
}
|
||||||
|
|
||||||
|
// to be called after lazy aggregates
|
||||||
|
func (x1 *Bitmap) repairAfterLazy() {
|
||||||
|
for pos := 0; pos < x1.highlowcontainer.size(); pos++ {
|
||||||
|
c := x1.highlowcontainer.getContainerAtIndex(pos)
|
||||||
|
switch c.(type) {
|
||||||
|
case *bitmapContainer:
|
||||||
|
if c.(*bitmapContainer).cardinality == invalidCardinality {
|
||||||
|
c = x1.highlowcontainer.getWritableContainerAtIndex(pos)
|
||||||
|
c.(*bitmapContainer).computeCardinality()
|
||||||
|
if c.(*bitmapContainer).getCardinality() <= arrayDefaultMaxSize {
|
||||||
|
x1.highlowcontainer.setContainerAtIndex(pos, c.(*bitmapContainer).toArrayContainer())
|
||||||
|
} else if c.(*bitmapContainer).isFull() {
|
||||||
|
x1.highlowcontainer.setContainerAtIndex(pos, newRunContainer16Range(0, MaxUint16))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastAnd computes the intersection between many bitmaps quickly
|
||||||
|
// Compared to the And function, it can take many bitmaps as input, thus saving the trouble
|
||||||
|
// of manually calling "And" many times.
|
||||||
|
func FastAnd(bitmaps ...*Bitmap) *Bitmap {
|
||||||
|
if len(bitmaps) == 0 {
|
||||||
|
return NewBitmap()
|
||||||
|
} else if len(bitmaps) == 1 {
|
||||||
|
return bitmaps[0].Clone()
|
||||||
|
}
|
||||||
|
answer := And(bitmaps[0], bitmaps[1])
|
||||||
|
for _, bm := range bitmaps[2:] {
|
||||||
|
answer.And(bm)
|
||||||
|
}
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
// FastOr computes the union between many bitmaps quickly, as opposed to having to call Or repeatedly.
|
||||||
|
// It might also be faster than calling Or repeatedly.
|
||||||
|
func FastOr(bitmaps ...*Bitmap) *Bitmap {
|
||||||
|
if len(bitmaps) == 0 {
|
||||||
|
return NewBitmap()
|
||||||
|
} else if len(bitmaps) == 1 {
|
||||||
|
return bitmaps[0].Clone()
|
||||||
|
}
|
||||||
|
answer := lazyOR(bitmaps[0], bitmaps[1])
|
||||||
|
for _, bm := range bitmaps[2:] {
|
||||||
|
answer = answer.lazyOR(bm)
|
||||||
|
}
|
||||||
|
// here is where repairAfterLazy is called.
|
||||||
|
answer.repairAfterLazy()
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeapOr computes the union between many bitmaps quickly using a heap.
|
||||||
|
// It might be faster than calling Or repeatedly.
|
||||||
|
func HeapOr(bitmaps ...*Bitmap) *Bitmap {
|
||||||
|
if len(bitmaps) == 0 {
|
||||||
|
return NewBitmap()
|
||||||
|
}
|
||||||
|
// TODO: for better speed, we could do the operation lazily, see Java implementation
|
||||||
|
pq := make(priorityQueue, len(bitmaps))
|
||||||
|
for i, bm := range bitmaps {
|
||||||
|
pq[i] = &item{bm, i}
|
||||||
|
}
|
||||||
|
heap.Init(&pq)
|
||||||
|
|
||||||
|
for pq.Len() > 1 {
|
||||||
|
x1 := heap.Pop(&pq).(*item)
|
||||||
|
x2 := heap.Pop(&pq).(*item)
|
||||||
|
heap.Push(&pq, &item{Or(x1.value, x2.value), 0})
|
||||||
|
}
|
||||||
|
return heap.Pop(&pq).(*item).value
|
||||||
|
}
|
||||||
|
|
||||||
|
// HeapXor computes the symmetric difference between many bitmaps quickly (as opposed to calling Xor repeated).
|
||||||
|
// Internally, this function uses a heap.
|
||||||
|
// It might be faster than calling Xor repeatedly.
|
||||||
|
func HeapXor(bitmaps ...*Bitmap) *Bitmap {
|
||||||
|
if len(bitmaps) == 0 {
|
||||||
|
return NewBitmap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pq := make(priorityQueue, len(bitmaps))
|
||||||
|
for i, bm := range bitmaps {
|
||||||
|
pq[i] = &item{bm, i}
|
||||||
|
}
|
||||||
|
heap.Init(&pq)
|
||||||
|
|
||||||
|
for pq.Len() > 1 {
|
||||||
|
x1 := heap.Pop(&pq).(*item)
|
||||||
|
x2 := heap.Pop(&pq).(*item)
|
||||||
|
heap.Push(&pq, &item{Xor(x1.value, x2.value), 0})
|
||||||
|
}
|
||||||
|
return heap.Pop(&pq).(*item).value
|
||||||
|
}
|
||||||
16
vendor/github.com/RoaringBitmap/roaring/go.mod
сгенерированный
поставляемый
Обычный файл
16
vendor/github.com/RoaringBitmap/roaring/go.mod
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,16 @@
|
|||||||
|
module github.com/RoaringBitmap/roaring
|
||||||
|
|
||||||
|
go 1.12
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2
|
||||||
|
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 // indirect
|
||||||
|
github.com/golang/snappy v0.0.1 // indirect
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible // indirect
|
||||||
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae
|
||||||
|
github.com/philhofer/fwd v1.0.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.4.0
|
||||||
|
github.com/tinylib/msgp v1.1.0
|
||||||
|
github.com/willf/bitset v1.1.10
|
||||||
|
)
|
||||||
30
vendor/github.com/RoaringBitmap/roaring/go.sum
сгенерированный
поставляемый
Обычный файл
30
vendor/github.com/RoaringBitmap/roaring/go.sum
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,30 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2 h1:Ujru1hufTHVb++eG6OuNDKMxZnGIvF6o/u8q/8h2+I4=
|
||||||
|
github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE=
|
||||||
|
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31 h1:gclg6gY70GLy3PbkQ1AERPfmLMMagS60DKF78eWwLn8=
|
||||||
|
github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24=
|
||||||
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 h1:twflg0XRTjwKpxb/jFExr4HGq6on2dEOmnL6FV+fgPw=
|
||||||
|
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae h1:VeRdUYdCw49yizlSbMEn2SZ+gT+3IUKx8BqxyQdz+BY=
|
||||||
|
github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg=
|
||||||
|
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
|
||||||
|
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
|
||||||
|
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
|
||||||
|
github.com/willf/bitset v1.1.10 h1:NotGKqX0KwQ72NUzqrjZq5ipPNDQex9lo3WpaS8L2sc=
|
||||||
|
github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
18
vendor/github.com/RoaringBitmap/roaring/manyiterator.go
сгенерированный
поставляемый
Обычный файл
18
vendor/github.com/RoaringBitmap/roaring/manyiterator.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,18 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
type manyIterable interface {
|
||||||
|
nextMany(hs uint32, buf []uint32) int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *shortIterator) nextMany(hs uint32, buf []uint32) int {
|
||||||
|
n := 0
|
||||||
|
l := si.loc
|
||||||
|
s := si.slice
|
||||||
|
for n < len(buf) && l < len(s) {
|
||||||
|
buf[n] = uint32(s[l]) | hs
|
||||||
|
l++
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
si.loc = l
|
||||||
|
return n
|
||||||
|
}
|
||||||
613
vendor/github.com/RoaringBitmap/roaring/parallel.go
сгенерированный
поставляемый
Обычный файл
613
vendor/github.com/RoaringBitmap/roaring/parallel.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,613 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"container/heap"
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultWorkerCount = runtime.NumCPU()
|
||||||
|
|
||||||
|
type bitmapContainerKey struct {
|
||||||
|
key uint16
|
||||||
|
idx int
|
||||||
|
bitmap *Bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
type multipleContainers struct {
|
||||||
|
key uint16
|
||||||
|
containers []container
|
||||||
|
idx int
|
||||||
|
}
|
||||||
|
|
||||||
|
type keyedContainer struct {
|
||||||
|
key uint16
|
||||||
|
container container
|
||||||
|
idx int
|
||||||
|
}
|
||||||
|
|
||||||
|
type bitmapContainerHeap []bitmapContainerKey
|
||||||
|
|
||||||
|
func (h bitmapContainerHeap) Len() int { return len(h) }
|
||||||
|
func (h bitmapContainerHeap) Less(i, j int) bool { return h[i].key < h[j].key }
|
||||||
|
func (h bitmapContainerHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||||
|
|
||||||
|
func (h *bitmapContainerHeap) Push(x interface{}) {
|
||||||
|
// Push and Pop use pointer receivers because they modify the slice's length,
|
||||||
|
// not just its contents.
|
||||||
|
*h = append(*h, x.(bitmapContainerKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *bitmapContainerHeap) Pop() interface{} {
|
||||||
|
old := *h
|
||||||
|
n := len(old)
|
||||||
|
x := old[n-1]
|
||||||
|
*h = old[0 : n-1]
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h bitmapContainerHeap) Peek() bitmapContainerKey {
|
||||||
|
return h[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *bitmapContainerHeap) popIncrementing() (key uint16, container container) {
|
||||||
|
k := h.Peek()
|
||||||
|
key = k.key
|
||||||
|
container = k.bitmap.highlowcontainer.containers[k.idx]
|
||||||
|
|
||||||
|
newIdx := k.idx + 1
|
||||||
|
if newIdx < k.bitmap.highlowcontainer.size() {
|
||||||
|
k = bitmapContainerKey{
|
||||||
|
k.bitmap.highlowcontainer.keys[newIdx],
|
||||||
|
newIdx,
|
||||||
|
k.bitmap,
|
||||||
|
}
|
||||||
|
(*h)[0] = k
|
||||||
|
heap.Fix(h, 0)
|
||||||
|
} else {
|
||||||
|
heap.Pop(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *bitmapContainerHeap) Next(containers []container) multipleContainers {
|
||||||
|
if h.Len() == 0 {
|
||||||
|
return multipleContainers{}
|
||||||
|
}
|
||||||
|
|
||||||
|
key, container := h.popIncrementing()
|
||||||
|
containers = append(containers, container)
|
||||||
|
|
||||||
|
for h.Len() > 0 && key == h.Peek().key {
|
||||||
|
_, container = h.popIncrementing()
|
||||||
|
containers = append(containers, container)
|
||||||
|
}
|
||||||
|
|
||||||
|
return multipleContainers{
|
||||||
|
key,
|
||||||
|
containers,
|
||||||
|
-1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBitmapContainerHeap(bitmaps ...*Bitmap) bitmapContainerHeap {
|
||||||
|
// Initialize heap
|
||||||
|
var h bitmapContainerHeap = make([]bitmapContainerKey, 0, len(bitmaps))
|
||||||
|
for _, bitmap := range bitmaps {
|
||||||
|
if !bitmap.IsEmpty() {
|
||||||
|
key := bitmapContainerKey{
|
||||||
|
bitmap.highlowcontainer.keys[0],
|
||||||
|
0,
|
||||||
|
bitmap,
|
||||||
|
}
|
||||||
|
h = append(h, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
heap.Init(&h)
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func repairAfterLazy(c container) container {
|
||||||
|
switch t := c.(type) {
|
||||||
|
case *bitmapContainer:
|
||||||
|
if t.cardinality == invalidCardinality {
|
||||||
|
t.computeCardinality()
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.getCardinality() <= arrayDefaultMaxSize {
|
||||||
|
return t.toArrayContainer()
|
||||||
|
} else if c.(*bitmapContainer).isFull() {
|
||||||
|
return newRunContainer16Range(0, MaxUint16)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func toBitmapContainer(c container) container {
|
||||||
|
switch t := c.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
return t.toBitmapContainer()
|
||||||
|
case *runContainer16:
|
||||||
|
if !t.isFull() {
|
||||||
|
return t.toBitmapContainer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func appenderRoutine(bitmapChan chan<- *Bitmap, resultChan <-chan keyedContainer, expectedKeysChan <-chan int) {
|
||||||
|
expectedKeys := -1
|
||||||
|
appendedKeys := 0
|
||||||
|
var keys []uint16
|
||||||
|
var containers []container
|
||||||
|
for appendedKeys != expectedKeys {
|
||||||
|
select {
|
||||||
|
case item := <-resultChan:
|
||||||
|
if len(keys) <= item.idx {
|
||||||
|
keys = append(keys, make([]uint16, item.idx-len(keys)+1)...)
|
||||||
|
containers = append(containers, make([]container, item.idx-len(containers)+1)...)
|
||||||
|
}
|
||||||
|
keys[item.idx] = item.key
|
||||||
|
containers[item.idx] = item.container
|
||||||
|
|
||||||
|
appendedKeys++
|
||||||
|
case msg := <-expectedKeysChan:
|
||||||
|
expectedKeys = msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
answer := &Bitmap{
|
||||||
|
roaringArray{
|
||||||
|
make([]uint16, 0, expectedKeys),
|
||||||
|
make([]container, 0, expectedKeys),
|
||||||
|
make([]bool, 0, expectedKeys),
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i := range keys {
|
||||||
|
if containers[i] != nil { // in case a resulting container was empty, see ParAnd function
|
||||||
|
answer.highlowcontainer.appendContainer(keys[i], containers[i], false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmapChan <- answer
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParHeapOr computes the union (OR) of all provided bitmaps in parallel,
|
||||||
|
// where the parameter "parallelism" determines how many workers are to be used
|
||||||
|
// (if it is set to 0, a default number of workers is chosen)
|
||||||
|
// ParHeapOr uses a heap to compute the union. For rare cases it might be faster than ParOr
|
||||||
|
func ParHeapOr(parallelism int, bitmaps ...*Bitmap) *Bitmap {
|
||||||
|
|
||||||
|
bitmapCount := len(bitmaps)
|
||||||
|
if bitmapCount == 0 {
|
||||||
|
return NewBitmap()
|
||||||
|
} else if bitmapCount == 1 {
|
||||||
|
return bitmaps[0].Clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
if parallelism == 0 {
|
||||||
|
parallelism = defaultWorkerCount
|
||||||
|
}
|
||||||
|
|
||||||
|
h := newBitmapContainerHeap(bitmaps...)
|
||||||
|
|
||||||
|
bitmapChan := make(chan *Bitmap)
|
||||||
|
inputChan := make(chan multipleContainers, 128)
|
||||||
|
resultChan := make(chan keyedContainer, 32)
|
||||||
|
expectedKeysChan := make(chan int)
|
||||||
|
|
||||||
|
pool := sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
return make([]container, 0, len(bitmaps))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
orFunc := func() {
|
||||||
|
// Assumes only structs with >=2 containers are passed
|
||||||
|
for input := range inputChan {
|
||||||
|
c := toBitmapContainer(input.containers[0]).lazyOR(input.containers[1])
|
||||||
|
for _, next := range input.containers[2:] {
|
||||||
|
c = c.lazyIOR(next)
|
||||||
|
}
|
||||||
|
c = repairAfterLazy(c)
|
||||||
|
kx := keyedContainer{
|
||||||
|
input.key,
|
||||||
|
c,
|
||||||
|
input.idx,
|
||||||
|
}
|
||||||
|
resultChan <- kx
|
||||||
|
pool.Put(input.containers[:0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go appenderRoutine(bitmapChan, resultChan, expectedKeysChan)
|
||||||
|
|
||||||
|
for i := 0; i < parallelism; i++ {
|
||||||
|
go orFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := 0
|
||||||
|
for h.Len() > 0 {
|
||||||
|
ck := h.Next(pool.Get().([]container))
|
||||||
|
if len(ck.containers) == 1 {
|
||||||
|
resultChan <- keyedContainer{
|
||||||
|
ck.key,
|
||||||
|
ck.containers[0],
|
||||||
|
idx,
|
||||||
|
}
|
||||||
|
pool.Put(ck.containers[:0])
|
||||||
|
} else {
|
||||||
|
ck.idx = idx
|
||||||
|
inputChan <- ck
|
||||||
|
}
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
expectedKeysChan <- idx
|
||||||
|
|
||||||
|
bitmap := <-bitmapChan
|
||||||
|
|
||||||
|
close(inputChan)
|
||||||
|
close(resultChan)
|
||||||
|
close(expectedKeysChan)
|
||||||
|
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParAnd computes the intersection (AND) of all provided bitmaps in parallel,
|
||||||
|
// where the parameter "parallelism" determines how many workers are to be used
|
||||||
|
// (if it is set to 0, a default number of workers is chosen)
|
||||||
|
func ParAnd(parallelism int, bitmaps ...*Bitmap) *Bitmap {
|
||||||
|
bitmapCount := len(bitmaps)
|
||||||
|
if bitmapCount == 0 {
|
||||||
|
return NewBitmap()
|
||||||
|
} else if bitmapCount == 1 {
|
||||||
|
return bitmaps[0].Clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
if parallelism == 0 {
|
||||||
|
parallelism = defaultWorkerCount
|
||||||
|
}
|
||||||
|
|
||||||
|
h := newBitmapContainerHeap(bitmaps...)
|
||||||
|
|
||||||
|
bitmapChan := make(chan *Bitmap)
|
||||||
|
inputChan := make(chan multipleContainers, 128)
|
||||||
|
resultChan := make(chan keyedContainer, 32)
|
||||||
|
expectedKeysChan := make(chan int)
|
||||||
|
|
||||||
|
andFunc := func() {
|
||||||
|
// Assumes only structs with >=2 containers are passed
|
||||||
|
for input := range inputChan {
|
||||||
|
c := input.containers[0].and(input.containers[1])
|
||||||
|
for _, next := range input.containers[2:] {
|
||||||
|
if c.getCardinality() == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c = c.iand(next)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a nil explicitly if the result of the intersection is an empty container
|
||||||
|
if c.getCardinality() == 0 {
|
||||||
|
c = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
kx := keyedContainer{
|
||||||
|
input.key,
|
||||||
|
c,
|
||||||
|
input.idx,
|
||||||
|
}
|
||||||
|
resultChan <- kx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go appenderRoutine(bitmapChan, resultChan, expectedKeysChan)
|
||||||
|
|
||||||
|
for i := 0; i < parallelism; i++ {
|
||||||
|
go andFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
idx := 0
|
||||||
|
for h.Len() > 0 {
|
||||||
|
ck := h.Next(make([]container, 0, 4))
|
||||||
|
if len(ck.containers) == bitmapCount {
|
||||||
|
ck.idx = idx
|
||||||
|
inputChan <- ck
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expectedKeysChan <- idx
|
||||||
|
|
||||||
|
bitmap := <-bitmapChan
|
||||||
|
|
||||||
|
close(inputChan)
|
||||||
|
close(resultChan)
|
||||||
|
close(expectedKeysChan)
|
||||||
|
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParOr computes the union (OR) of all provided bitmaps in parallel,
|
||||||
|
// where the parameter "parallelism" determines how many workers are to be used
|
||||||
|
// (if it is set to 0, a default number of workers is chosen)
|
||||||
|
func ParOr(parallelism int, bitmaps ...*Bitmap) *Bitmap {
|
||||||
|
var lKey uint16 = MaxUint16
|
||||||
|
var hKey uint16
|
||||||
|
|
||||||
|
bitmapsFiltered := bitmaps[:0]
|
||||||
|
for _, b := range bitmaps {
|
||||||
|
if !b.IsEmpty() {
|
||||||
|
bitmapsFiltered = append(bitmapsFiltered, b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitmaps = bitmapsFiltered
|
||||||
|
|
||||||
|
for _, b := range bitmaps {
|
||||||
|
lKey = minOfUint16(lKey, b.highlowcontainer.keys[0])
|
||||||
|
hKey = maxOfUint16(hKey, b.highlowcontainer.keys[b.highlowcontainer.size()-1])
|
||||||
|
}
|
||||||
|
|
||||||
|
if lKey == MaxUint16 && hKey == 0 {
|
||||||
|
return New()
|
||||||
|
} else if len(bitmaps) == 1 {
|
||||||
|
return bitmaps[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
keyRange := hKey - lKey + 1
|
||||||
|
if keyRange == 1 {
|
||||||
|
// revert to FastOr. Since the key range is 0
|
||||||
|
// no container-level aggregation parallelism is achievable
|
||||||
|
return FastOr(bitmaps...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if parallelism == 0 {
|
||||||
|
parallelism = defaultWorkerCount
|
||||||
|
}
|
||||||
|
|
||||||
|
var chunkSize int
|
||||||
|
var chunkCount int
|
||||||
|
if parallelism*4 > int(keyRange) {
|
||||||
|
chunkSize = 1
|
||||||
|
chunkCount = int(keyRange)
|
||||||
|
} else {
|
||||||
|
chunkCount = parallelism * 4
|
||||||
|
chunkSize = (int(keyRange) + chunkCount - 1) / chunkCount
|
||||||
|
}
|
||||||
|
|
||||||
|
if chunkCount*chunkSize < int(keyRange) {
|
||||||
|
// it's fine to panic to indicate an implementation error
|
||||||
|
panic(fmt.Sprintf("invariant check failed: chunkCount * chunkSize < keyRange, %d * %d < %d", chunkCount, chunkSize, keyRange))
|
||||||
|
}
|
||||||
|
|
||||||
|
chunks := make([]*roaringArray, chunkCount)
|
||||||
|
|
||||||
|
chunkSpecChan := make(chan parChunkSpec, minOfInt(maxOfInt(64, 2*parallelism), int(chunkCount)))
|
||||||
|
chunkChan := make(chan parChunk, minOfInt(32, int(chunkCount)))
|
||||||
|
|
||||||
|
orFunc := func() {
|
||||||
|
for spec := range chunkSpecChan {
|
||||||
|
ra := lazyOrOnRange(&bitmaps[0].highlowcontainer, &bitmaps[1].highlowcontainer, spec.start, spec.end)
|
||||||
|
for _, b := range bitmaps[2:] {
|
||||||
|
ra = lazyIOrOnRange(ra, &b.highlowcontainer, spec.start, spec.end)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range ra.containers {
|
||||||
|
ra.containers[i] = repairAfterLazy(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
chunkChan <- parChunk{ra, spec.idx}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < parallelism; i++ {
|
||||||
|
go orFunc()
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < chunkCount; i++ {
|
||||||
|
spec := parChunkSpec{
|
||||||
|
start: uint16(int(lKey) + i*chunkSize),
|
||||||
|
end: uint16(minOfInt(int(lKey)+(i+1)*chunkSize-1, int(hKey))),
|
||||||
|
idx: int(i),
|
||||||
|
}
|
||||||
|
chunkSpecChan <- spec
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
chunksRemaining := chunkCount
|
||||||
|
for chunk := range chunkChan {
|
||||||
|
chunks[chunk.idx] = chunk.ra
|
||||||
|
chunksRemaining--
|
||||||
|
if chunksRemaining == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(chunkChan)
|
||||||
|
close(chunkSpecChan)
|
||||||
|
|
||||||
|
containerCount := 0
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
containerCount += chunk.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
result := Bitmap{
|
||||||
|
roaringArray{
|
||||||
|
containers: make([]container, containerCount),
|
||||||
|
keys: make([]uint16, containerCount),
|
||||||
|
needCopyOnWrite: make([]bool, containerCount),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
resultOffset := 0
|
||||||
|
for _, chunk := range chunks {
|
||||||
|
copy(result.highlowcontainer.containers[resultOffset:], chunk.containers)
|
||||||
|
copy(result.highlowcontainer.keys[resultOffset:], chunk.keys)
|
||||||
|
copy(result.highlowcontainer.needCopyOnWrite[resultOffset:], chunk.needCopyOnWrite)
|
||||||
|
resultOffset += chunk.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|
||||||
|
type parChunkSpec struct {
|
||||||
|
start uint16
|
||||||
|
end uint16
|
||||||
|
idx int
|
||||||
|
}
|
||||||
|
|
||||||
|
type parChunk struct {
|
||||||
|
ra *roaringArray
|
||||||
|
idx int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c parChunk) size() int {
|
||||||
|
return c.ra.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
func parNaiveStartAt(ra *roaringArray, start uint16, last uint16) int {
|
||||||
|
for idx, key := range ra.keys {
|
||||||
|
if key >= start && key <= last {
|
||||||
|
return idx
|
||||||
|
} else if key > last {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ra.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
func lazyOrOnRange(ra1, ra2 *roaringArray, start, last uint16) *roaringArray {
|
||||||
|
answer := newRoaringArray()
|
||||||
|
length1 := ra1.size()
|
||||||
|
length2 := ra2.size()
|
||||||
|
|
||||||
|
idx1 := parNaiveStartAt(ra1, start, last)
|
||||||
|
idx2 := parNaiveStartAt(ra2, start, last)
|
||||||
|
|
||||||
|
var key1 uint16
|
||||||
|
var key2 uint16
|
||||||
|
if idx1 < length1 && idx2 < length2 {
|
||||||
|
key1 = ra1.getKeyAtIndex(idx1)
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
|
||||||
|
for key1 <= last && key2 <= last {
|
||||||
|
|
||||||
|
if key1 < key2 {
|
||||||
|
answer.appendCopy(*ra1, idx1)
|
||||||
|
idx1++
|
||||||
|
if idx1 == length1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
key1 = ra1.getKeyAtIndex(idx1)
|
||||||
|
} else if key1 > key2 {
|
||||||
|
answer.appendCopy(*ra2, idx2)
|
||||||
|
idx2++
|
||||||
|
if idx2 == length2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
} else {
|
||||||
|
c1 := ra1.getFastContainerAtIndex(idx1, false)
|
||||||
|
|
||||||
|
answer.appendContainer(key1, c1.lazyOR(ra2.getContainerAtIndex(idx2)), false)
|
||||||
|
idx1++
|
||||||
|
idx2++
|
||||||
|
if idx1 == length1 || idx2 == length2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
key1 = ra1.getKeyAtIndex(idx1)
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx2 < length2 {
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
for key2 <= last {
|
||||||
|
answer.appendCopy(*ra2, idx2)
|
||||||
|
idx2++
|
||||||
|
if idx2 == length2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if idx1 < length1 {
|
||||||
|
key1 = ra1.getKeyAtIndex(idx1)
|
||||||
|
for key1 <= last {
|
||||||
|
answer.appendCopy(*ra1, idx1)
|
||||||
|
idx1++
|
||||||
|
if idx1 == length1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
key1 = ra1.getKeyAtIndex(idx1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
func lazyIOrOnRange(ra1, ra2 *roaringArray, start, last uint16) *roaringArray {
|
||||||
|
length1 := ra1.size()
|
||||||
|
length2 := ra2.size()
|
||||||
|
|
||||||
|
idx1 := 0
|
||||||
|
idx2 := parNaiveStartAt(ra2, start, last)
|
||||||
|
|
||||||
|
var key1 uint16
|
||||||
|
var key2 uint16
|
||||||
|
if idx1 < length1 && idx2 < length2 {
|
||||||
|
key1 = ra1.getKeyAtIndex(idx1)
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
|
||||||
|
for key1 <= last && key2 <= last {
|
||||||
|
if key1 < key2 {
|
||||||
|
idx1++
|
||||||
|
if idx1 >= length1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
key1 = ra1.getKeyAtIndex(idx1)
|
||||||
|
} else if key1 > key2 {
|
||||||
|
ra1.insertNewKeyValueAt(idx1, key2, ra2.getContainerAtIndex(idx2))
|
||||||
|
ra1.needCopyOnWrite[idx1] = true
|
||||||
|
idx2++
|
||||||
|
idx1++
|
||||||
|
length1++
|
||||||
|
if idx2 >= length2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
} else {
|
||||||
|
c1 := ra1.getFastContainerAtIndex(idx1, true)
|
||||||
|
|
||||||
|
ra1.containers[idx1] = c1.lazyIOR(ra2.getContainerAtIndex(idx2))
|
||||||
|
ra1.needCopyOnWrite[idx1] = false
|
||||||
|
idx1++
|
||||||
|
idx2++
|
||||||
|
if idx1 >= length1 || idx2 >= length2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
key1 = ra1.getKeyAtIndex(idx1)
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if idx2 < length2 {
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
for key2 <= last {
|
||||||
|
ra1.appendCopy(*ra2, idx2)
|
||||||
|
idx2++
|
||||||
|
if idx2 >= length2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
key2 = ra2.getKeyAtIndex(idx2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ra1
|
||||||
|
}
|
||||||
11
vendor/github.com/RoaringBitmap/roaring/popcnt.go
сгенерированный
поставляемый
Обычный файл
11
vendor/github.com/RoaringBitmap/roaring/popcnt.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,11 @@
|
|||||||
|
// +build go1.9
|
||||||
|
// "go1.9", from Go version 1.9 onward
|
||||||
|
// See https://golang.org/pkg/go/build/#hdr-Build_Constraints
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
import "math/bits"
|
||||||
|
|
||||||
|
func popcount(x uint64) uint64 {
|
||||||
|
return uint64(bits.OnesCount64(x))
|
||||||
|
}
|
||||||
103
vendor/github.com/RoaringBitmap/roaring/popcnt_amd64.s
сгенерированный
поставляемый
Обычный файл
103
vendor/github.com/RoaringBitmap/roaring/popcnt_amd64.s
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,103 @@
|
|||||||
|
// +build amd64,!appengine,!go1.9
|
||||||
|
|
||||||
|
TEXT ·hasAsm(SB),4,$0-1
|
||||||
|
MOVQ $1, AX
|
||||||
|
CPUID
|
||||||
|
SHRQ $23, CX
|
||||||
|
ANDQ $1, CX
|
||||||
|
MOVB CX, ret+0(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
#define POPCNTQ_DX_DX BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0xd2
|
||||||
|
|
||||||
|
TEXT ·popcntSliceAsm(SB),4,$0-32
|
||||||
|
XORQ AX, AX
|
||||||
|
MOVQ s+0(FP), SI
|
||||||
|
MOVQ s_len+8(FP), CX
|
||||||
|
TESTQ CX, CX
|
||||||
|
JZ popcntSliceEnd
|
||||||
|
popcntSliceLoop:
|
||||||
|
BYTE $0xf3; BYTE $0x48; BYTE $0x0f; BYTE $0xb8; BYTE $0x16 // POPCNTQ (SI), DX
|
||||||
|
ADDQ DX, AX
|
||||||
|
ADDQ $8, SI
|
||||||
|
LOOP popcntSliceLoop
|
||||||
|
popcntSliceEnd:
|
||||||
|
MOVQ AX, ret+24(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT ·popcntMaskSliceAsm(SB),4,$0-56
|
||||||
|
XORQ AX, AX
|
||||||
|
MOVQ s+0(FP), SI
|
||||||
|
MOVQ s_len+8(FP), CX
|
||||||
|
TESTQ CX, CX
|
||||||
|
JZ popcntMaskSliceEnd
|
||||||
|
MOVQ m+24(FP), DI
|
||||||
|
popcntMaskSliceLoop:
|
||||||
|
MOVQ (DI), DX
|
||||||
|
NOTQ DX
|
||||||
|
ANDQ (SI), DX
|
||||||
|
POPCNTQ_DX_DX
|
||||||
|
ADDQ DX, AX
|
||||||
|
ADDQ $8, SI
|
||||||
|
ADDQ $8, DI
|
||||||
|
LOOP popcntMaskSliceLoop
|
||||||
|
popcntMaskSliceEnd:
|
||||||
|
MOVQ AX, ret+48(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT ·popcntAndSliceAsm(SB),4,$0-56
|
||||||
|
XORQ AX, AX
|
||||||
|
MOVQ s+0(FP), SI
|
||||||
|
MOVQ s_len+8(FP), CX
|
||||||
|
TESTQ CX, CX
|
||||||
|
JZ popcntAndSliceEnd
|
||||||
|
MOVQ m+24(FP), DI
|
||||||
|
popcntAndSliceLoop:
|
||||||
|
MOVQ (DI), DX
|
||||||
|
ANDQ (SI), DX
|
||||||
|
POPCNTQ_DX_DX
|
||||||
|
ADDQ DX, AX
|
||||||
|
ADDQ $8, SI
|
||||||
|
ADDQ $8, DI
|
||||||
|
LOOP popcntAndSliceLoop
|
||||||
|
popcntAndSliceEnd:
|
||||||
|
MOVQ AX, ret+48(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT ·popcntOrSliceAsm(SB),4,$0-56
|
||||||
|
XORQ AX, AX
|
||||||
|
MOVQ s+0(FP), SI
|
||||||
|
MOVQ s_len+8(FP), CX
|
||||||
|
TESTQ CX, CX
|
||||||
|
JZ popcntOrSliceEnd
|
||||||
|
MOVQ m+24(FP), DI
|
||||||
|
popcntOrSliceLoop:
|
||||||
|
MOVQ (DI), DX
|
||||||
|
ORQ (SI), DX
|
||||||
|
POPCNTQ_DX_DX
|
||||||
|
ADDQ DX, AX
|
||||||
|
ADDQ $8, SI
|
||||||
|
ADDQ $8, DI
|
||||||
|
LOOP popcntOrSliceLoop
|
||||||
|
popcntOrSliceEnd:
|
||||||
|
MOVQ AX, ret+48(FP)
|
||||||
|
RET
|
||||||
|
|
||||||
|
TEXT ·popcntXorSliceAsm(SB),4,$0-56
|
||||||
|
XORQ AX, AX
|
||||||
|
MOVQ s+0(FP), SI
|
||||||
|
MOVQ s_len+8(FP), CX
|
||||||
|
TESTQ CX, CX
|
||||||
|
JZ popcntXorSliceEnd
|
||||||
|
MOVQ m+24(FP), DI
|
||||||
|
popcntXorSliceLoop:
|
||||||
|
MOVQ (DI), DX
|
||||||
|
XORQ (SI), DX
|
||||||
|
POPCNTQ_DX_DX
|
||||||
|
ADDQ DX, AX
|
||||||
|
ADDQ $8, SI
|
||||||
|
ADDQ $8, DI
|
||||||
|
LOOP popcntXorSliceLoop
|
||||||
|
popcntXorSliceEnd:
|
||||||
|
MOVQ AX, ret+48(FP)
|
||||||
|
RET
|
||||||
67
vendor/github.com/RoaringBitmap/roaring/popcnt_asm.go
сгенерированный
поставляемый
Обычный файл
67
vendor/github.com/RoaringBitmap/roaring/popcnt_asm.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,67 @@
|
|||||||
|
// +build amd64,!appengine,!go1.9
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
// *** the following functions are defined in popcnt_amd64.s
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
|
||||||
|
func hasAsm() bool
|
||||||
|
|
||||||
|
// useAsm is a flag used to select the GO or ASM implementation of the popcnt function
|
||||||
|
var useAsm = hasAsm()
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
|
||||||
|
func popcntSliceAsm(s []uint64) uint64
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
|
||||||
|
func popcntMaskSliceAsm(s, m []uint64) uint64
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
|
||||||
|
func popcntAndSliceAsm(s, m []uint64) uint64
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
|
||||||
|
func popcntOrSliceAsm(s, m []uint64) uint64
|
||||||
|
|
||||||
|
//go:noescape
|
||||||
|
|
||||||
|
func popcntXorSliceAsm(s, m []uint64) uint64
|
||||||
|
|
||||||
|
func popcntSlice(s []uint64) uint64 {
|
||||||
|
if useAsm {
|
||||||
|
return popcntSliceAsm(s)
|
||||||
|
}
|
||||||
|
return popcntSliceGo(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntMaskSlice(s, m []uint64) uint64 {
|
||||||
|
if useAsm {
|
||||||
|
return popcntMaskSliceAsm(s, m)
|
||||||
|
}
|
||||||
|
return popcntMaskSliceGo(s, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntAndSlice(s, m []uint64) uint64 {
|
||||||
|
if useAsm {
|
||||||
|
return popcntAndSliceAsm(s, m)
|
||||||
|
}
|
||||||
|
return popcntAndSliceGo(s, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntOrSlice(s, m []uint64) uint64 {
|
||||||
|
if useAsm {
|
||||||
|
return popcntOrSliceAsm(s, m)
|
||||||
|
}
|
||||||
|
return popcntOrSliceGo(s, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntXorSlice(s, m []uint64) uint64 {
|
||||||
|
if useAsm {
|
||||||
|
return popcntXorSliceAsm(s, m)
|
||||||
|
}
|
||||||
|
return popcntXorSliceGo(s, m)
|
||||||
|
}
|
||||||
17
vendor/github.com/RoaringBitmap/roaring/popcnt_compat.go
сгенерированный
поставляемый
Обычный файл
17
vendor/github.com/RoaringBitmap/roaring/popcnt_compat.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,17 @@
|
|||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
// bit population count, take from
|
||||||
|
// https://code.google.com/p/go/issues/detail?id=4988#c11
|
||||||
|
// credit: https://code.google.com/u/arnehormann/
|
||||||
|
// credit: https://play.golang.org/p/U7SogJ7psJ
|
||||||
|
// credit: http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
|
||||||
|
func popcount(x uint64) uint64 {
|
||||||
|
x -= (x >> 1) & 0x5555555555555555
|
||||||
|
x = (x>>2)&0x3333333333333333 + x&0x3333333333333333
|
||||||
|
x += x >> 4
|
||||||
|
x &= 0x0f0f0f0f0f0f0f0f
|
||||||
|
x *= 0x0101010101010101
|
||||||
|
return x >> 56
|
||||||
|
}
|
||||||
23
vendor/github.com/RoaringBitmap/roaring/popcnt_generic.go
сгенерированный
поставляемый
Обычный файл
23
vendor/github.com/RoaringBitmap/roaring/popcnt_generic.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,23 @@
|
|||||||
|
// +build !amd64 appengine go1.9
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
func popcntSlice(s []uint64) uint64 {
|
||||||
|
return popcntSliceGo(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntMaskSlice(s, m []uint64) uint64 {
|
||||||
|
return popcntMaskSliceGo(s, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntAndSlice(s, m []uint64) uint64 {
|
||||||
|
return popcntAndSliceGo(s, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntOrSlice(s, m []uint64) uint64 {
|
||||||
|
return popcntOrSliceGo(s, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntXorSlice(s, m []uint64) uint64 {
|
||||||
|
return popcntXorSliceGo(s, m)
|
||||||
|
}
|
||||||
41
vendor/github.com/RoaringBitmap/roaring/popcnt_slices.go
сгенерированный
поставляемый
Обычный файл
41
vendor/github.com/RoaringBitmap/roaring/popcnt_slices.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,41 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
func popcntSliceGo(s []uint64) uint64 {
|
||||||
|
cnt := uint64(0)
|
||||||
|
for _, x := range s {
|
||||||
|
cnt += popcount(x)
|
||||||
|
}
|
||||||
|
return cnt
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntMaskSliceGo(s, m []uint64) uint64 {
|
||||||
|
cnt := uint64(0)
|
||||||
|
for i := range s {
|
||||||
|
cnt += popcount(s[i] &^ m[i])
|
||||||
|
}
|
||||||
|
return cnt
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntAndSliceGo(s, m []uint64) uint64 {
|
||||||
|
cnt := uint64(0)
|
||||||
|
for i := range s {
|
||||||
|
cnt += popcount(s[i] & m[i])
|
||||||
|
}
|
||||||
|
return cnt
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntOrSliceGo(s, m []uint64) uint64 {
|
||||||
|
cnt := uint64(0)
|
||||||
|
for i := range s {
|
||||||
|
cnt += popcount(s[i] | m[i])
|
||||||
|
}
|
||||||
|
return cnt
|
||||||
|
}
|
||||||
|
|
||||||
|
func popcntXorSliceGo(s, m []uint64) uint64 {
|
||||||
|
cnt := uint64(0)
|
||||||
|
for i := range s {
|
||||||
|
cnt += popcount(s[i] ^ m[i])
|
||||||
|
}
|
||||||
|
return cnt
|
||||||
|
}
|
||||||
101
vendor/github.com/RoaringBitmap/roaring/priorityqueue.go
сгенерированный
поставляемый
Обычный файл
101
vendor/github.com/RoaringBitmap/roaring/priorityqueue.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,101 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
import "container/heap"
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// The priorityQueue is used to keep Bitmaps sorted.
|
||||||
|
////////////
|
||||||
|
|
||||||
|
type item struct {
|
||||||
|
value *Bitmap
|
||||||
|
index int
|
||||||
|
}
|
||||||
|
|
||||||
|
type priorityQueue []*item
|
||||||
|
|
||||||
|
func (pq priorityQueue) Len() int { return len(pq) }
|
||||||
|
|
||||||
|
func (pq priorityQueue) Less(i, j int) bool {
|
||||||
|
return pq[i].value.GetSizeInBytes() < pq[j].value.GetSizeInBytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq priorityQueue) Swap(i, j int) {
|
||||||
|
pq[i], pq[j] = pq[j], pq[i]
|
||||||
|
pq[i].index = i
|
||||||
|
pq[j].index = j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue) Push(x interface{}) {
|
||||||
|
n := len(*pq)
|
||||||
|
item := x.(*item)
|
||||||
|
item.index = n
|
||||||
|
*pq = append(*pq, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue) Pop() interface{} {
|
||||||
|
old := *pq
|
||||||
|
n := len(old)
|
||||||
|
item := old[n-1]
|
||||||
|
item.index = -1 // for safety
|
||||||
|
*pq = old[0 : n-1]
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *priorityQueue) update(item *item, value *Bitmap) {
|
||||||
|
item.value = value
|
||||||
|
heap.Fix(pq, item.index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////
|
||||||
|
// The containerPriorityQueue is used to keep the containers of various Bitmaps sorted.
|
||||||
|
////////////
|
||||||
|
|
||||||
|
type containeritem struct {
|
||||||
|
value *Bitmap
|
||||||
|
keyindex int
|
||||||
|
index int
|
||||||
|
}
|
||||||
|
|
||||||
|
type containerPriorityQueue []*containeritem
|
||||||
|
|
||||||
|
func (pq containerPriorityQueue) Len() int { return len(pq) }
|
||||||
|
|
||||||
|
func (pq containerPriorityQueue) Less(i, j int) bool {
|
||||||
|
k1 := pq[i].value.highlowcontainer.getKeyAtIndex(pq[i].keyindex)
|
||||||
|
k2 := pq[j].value.highlowcontainer.getKeyAtIndex(pq[j].keyindex)
|
||||||
|
if k1 != k2 {
|
||||||
|
return k1 < k2
|
||||||
|
}
|
||||||
|
c1 := pq[i].value.highlowcontainer.getContainerAtIndex(pq[i].keyindex)
|
||||||
|
c2 := pq[j].value.highlowcontainer.getContainerAtIndex(pq[j].keyindex)
|
||||||
|
|
||||||
|
return c1.getCardinality() > c2.getCardinality()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq containerPriorityQueue) Swap(i, j int) {
|
||||||
|
pq[i], pq[j] = pq[j], pq[i]
|
||||||
|
pq[i].index = i
|
||||||
|
pq[j].index = j
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *containerPriorityQueue) Push(x interface{}) {
|
||||||
|
n := len(*pq)
|
||||||
|
item := x.(*containeritem)
|
||||||
|
item.index = n
|
||||||
|
*pq = append(*pq, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (pq *containerPriorityQueue) Pop() interface{} {
|
||||||
|
old := *pq
|
||||||
|
n := len(old)
|
||||||
|
item := old[n-1]
|
||||||
|
item.index = -1 // for safety
|
||||||
|
*pq = old[0 : n-1]
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
//func (pq *containerPriorityQueue) update(item *containeritem, value *Bitmap, keyindex int) {
|
||||||
|
// item.value = value
|
||||||
|
// item.keyindex = keyindex
|
||||||
|
// heap.Fix(pq, item.index)
|
||||||
|
//}
|
||||||
1557
vendor/github.com/RoaringBitmap/roaring/roaring.go
сгенерированный
поставляемый
Обычный файл
1557
vendor/github.com/RoaringBitmap/roaring/roaring.go
сгенерированный
поставляемый
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
834
vendor/github.com/RoaringBitmap/roaring/roaringarray.go
сгенерированный
поставляемый
Обычный файл
834
vendor/github.com/RoaringBitmap/roaring/roaringarray.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,834 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
snappy "github.com/glycerine/go-unsnap-stream"
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:generate msgp -unexported
|
||||||
|
|
||||||
|
type container interface {
|
||||||
|
addOffset(uint16) []container
|
||||||
|
|
||||||
|
clone() container
|
||||||
|
and(container) container
|
||||||
|
andCardinality(container) int
|
||||||
|
iand(container) container // i stands for inplace
|
||||||
|
andNot(container) container
|
||||||
|
iandNot(container) container // i stands for inplace
|
||||||
|
getCardinality() int
|
||||||
|
// rank returns the number of integers that are
|
||||||
|
// smaller or equal to x. rank(infinity) would be getCardinality().
|
||||||
|
rank(uint16) int
|
||||||
|
|
||||||
|
iadd(x uint16) bool // inplace, returns true if x was new.
|
||||||
|
iaddReturnMinimized(uint16) container // may change return type to minimize storage.
|
||||||
|
|
||||||
|
//addRange(start, final int) container // range is [firstOfRange,lastOfRange) (unused)
|
||||||
|
iaddRange(start, endx int) container // i stands for inplace, range is [firstOfRange,endx)
|
||||||
|
|
||||||
|
iremove(x uint16) bool // inplace, returns true if x was present.
|
||||||
|
iremoveReturnMinimized(uint16) container // may change return type to minimize storage.
|
||||||
|
|
||||||
|
not(start, final int) container // range is [firstOfRange,lastOfRange)
|
||||||
|
inot(firstOfRange, endx int) container // i stands for inplace, range is [firstOfRange,endx)
|
||||||
|
xor(r container) container
|
||||||
|
getShortIterator() shortPeekable
|
||||||
|
iterate(cb func(x uint16) bool) bool
|
||||||
|
getReverseIterator() shortIterable
|
||||||
|
getManyIterator() manyIterable
|
||||||
|
contains(i uint16) bool
|
||||||
|
maximum() uint16
|
||||||
|
minimum() uint16
|
||||||
|
|
||||||
|
// equals is now logical equals; it does not require the
|
||||||
|
// same underlying container types, but compares across
|
||||||
|
// any of the implementations.
|
||||||
|
equals(r container) bool
|
||||||
|
|
||||||
|
fillLeastSignificant16bits(array []uint32, i int, mask uint32)
|
||||||
|
or(r container) container
|
||||||
|
orCardinality(r container) int
|
||||||
|
isFull() bool
|
||||||
|
ior(r container) container // i stands for inplace
|
||||||
|
intersects(r container) bool // whether the two containers intersect
|
||||||
|
lazyOR(r container) container
|
||||||
|
lazyIOR(r container) container
|
||||||
|
getSizeInBytes() int
|
||||||
|
//removeRange(start, final int) container // range is [firstOfRange,lastOfRange) (unused)
|
||||||
|
iremoveRange(start, final int) container // i stands for inplace, range is [firstOfRange,lastOfRange)
|
||||||
|
selectInt(x uint16) int // selectInt returns the xth integer in the container
|
||||||
|
serializedSizeInBytes() int
|
||||||
|
writeTo(io.Writer) (int, error)
|
||||||
|
|
||||||
|
numberOfRuns() int
|
||||||
|
toEfficientContainer() container
|
||||||
|
String() string
|
||||||
|
containerType() contype
|
||||||
|
}
|
||||||
|
|
||||||
|
type contype uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
bitmapContype contype = iota
|
||||||
|
arrayContype
|
||||||
|
run16Contype
|
||||||
|
run32Contype
|
||||||
|
)
|
||||||
|
|
||||||
|
// careful: range is [firstOfRange,lastOfRange]
|
||||||
|
func rangeOfOnes(start, last int) container {
|
||||||
|
if start > MaxUint16 {
|
||||||
|
panic("rangeOfOnes called with start > MaxUint16")
|
||||||
|
}
|
||||||
|
if last > MaxUint16 {
|
||||||
|
panic("rangeOfOnes called with last > MaxUint16")
|
||||||
|
}
|
||||||
|
if start < 0 {
|
||||||
|
panic("rangeOfOnes called with start < 0")
|
||||||
|
}
|
||||||
|
if last < 0 {
|
||||||
|
panic("rangeOfOnes called with last < 0")
|
||||||
|
}
|
||||||
|
return newRunContainer16Range(uint16(start), uint16(last))
|
||||||
|
}
|
||||||
|
|
||||||
|
type roaringArray struct {
|
||||||
|
keys []uint16
|
||||||
|
containers []container `msg:"-"` // don't try to serialize directly.
|
||||||
|
needCopyOnWrite []bool
|
||||||
|
copyOnWrite bool
|
||||||
|
|
||||||
|
// conserz is used at serialization time
|
||||||
|
// to serialize containers. Otherwise empty.
|
||||||
|
conserz []containerSerz
|
||||||
|
}
|
||||||
|
|
||||||
|
// containerSerz facilitates serializing container (tricky to
|
||||||
|
// serialize because it is an interface) by providing a
|
||||||
|
// light wrapper with a type identifier.
|
||||||
|
type containerSerz struct {
|
||||||
|
t contype `msg:"t"` // type
|
||||||
|
r msgp.Raw `msg:"r"` // Raw msgpack of the actual container type
|
||||||
|
}
|
||||||
|
|
||||||
|
func newRoaringArray() *roaringArray {
|
||||||
|
return &roaringArray{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// runOptimize compresses the element containers to minimize space consumed.
|
||||||
|
// Q: how does this interact with copyOnWrite and needCopyOnWrite?
|
||||||
|
// A: since we aren't changing the logical content, just the representation,
|
||||||
|
// we don't bother to check the needCopyOnWrite bits. We replace
|
||||||
|
// (possibly all) elements of ra.containers in-place with space
|
||||||
|
// optimized versions.
|
||||||
|
func (ra *roaringArray) runOptimize() {
|
||||||
|
for i := range ra.containers {
|
||||||
|
ra.containers[i] = ra.containers[i].toEfficientContainer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) appendContainer(key uint16, value container, mustCopyOnWrite bool) {
|
||||||
|
ra.keys = append(ra.keys, key)
|
||||||
|
ra.containers = append(ra.containers, value)
|
||||||
|
ra.needCopyOnWrite = append(ra.needCopyOnWrite, mustCopyOnWrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) appendWithoutCopy(sa roaringArray, startingindex int) {
|
||||||
|
mustCopyOnWrite := sa.needCopyOnWrite[startingindex]
|
||||||
|
ra.appendContainer(sa.keys[startingindex], sa.containers[startingindex], mustCopyOnWrite)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) appendCopy(sa roaringArray, startingindex int) {
|
||||||
|
// cow only if the two request it, or if we already have a lightweight copy
|
||||||
|
copyonwrite := (ra.copyOnWrite && sa.copyOnWrite) || sa.needsCopyOnWrite(startingindex)
|
||||||
|
if !copyonwrite {
|
||||||
|
// since there is no copy-on-write, we need to clone the container (this is important)
|
||||||
|
ra.appendContainer(sa.keys[startingindex], sa.containers[startingindex].clone(), copyonwrite)
|
||||||
|
} else {
|
||||||
|
ra.appendContainer(sa.keys[startingindex], sa.containers[startingindex], copyonwrite)
|
||||||
|
if !sa.needsCopyOnWrite(startingindex) {
|
||||||
|
sa.setNeedsCopyOnWrite(startingindex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) appendWithoutCopyMany(sa roaringArray, startingindex, end int) {
|
||||||
|
for i := startingindex; i < end; i++ {
|
||||||
|
ra.appendWithoutCopy(sa, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) appendCopyMany(sa roaringArray, startingindex, end int) {
|
||||||
|
for i := startingindex; i < end; i++ {
|
||||||
|
ra.appendCopy(sa, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) appendCopiesUntil(sa roaringArray, stoppingKey uint16) {
|
||||||
|
// cow only if the two request it, or if we already have a lightweight copy
|
||||||
|
copyonwrite := ra.copyOnWrite && sa.copyOnWrite
|
||||||
|
|
||||||
|
for i := 0; i < sa.size(); i++ {
|
||||||
|
if sa.keys[i] >= stoppingKey {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
thiscopyonewrite := copyonwrite || sa.needsCopyOnWrite(i)
|
||||||
|
if thiscopyonewrite {
|
||||||
|
ra.appendContainer(sa.keys[i], sa.containers[i], thiscopyonewrite)
|
||||||
|
if !sa.needsCopyOnWrite(i) {
|
||||||
|
sa.setNeedsCopyOnWrite(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// since there is no copy-on-write, we need to clone the container (this is important)
|
||||||
|
ra.appendContainer(sa.keys[i], sa.containers[i].clone(), thiscopyonewrite)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) appendCopiesAfter(sa roaringArray, beforeStart uint16) {
|
||||||
|
// cow only if the two request it, or if we already have a lightweight copy
|
||||||
|
copyonwrite := ra.copyOnWrite && sa.copyOnWrite
|
||||||
|
|
||||||
|
startLocation := sa.getIndex(beforeStart)
|
||||||
|
if startLocation >= 0 {
|
||||||
|
startLocation++
|
||||||
|
} else {
|
||||||
|
startLocation = -startLocation - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := startLocation; i < sa.size(); i++ {
|
||||||
|
thiscopyonewrite := copyonwrite || sa.needsCopyOnWrite(i)
|
||||||
|
if thiscopyonewrite {
|
||||||
|
ra.appendContainer(sa.keys[i], sa.containers[i], thiscopyonewrite)
|
||||||
|
if !sa.needsCopyOnWrite(i) {
|
||||||
|
sa.setNeedsCopyOnWrite(i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// since there is no copy-on-write, we need to clone the container (this is important)
|
||||||
|
ra.appendContainer(sa.keys[i], sa.containers[i].clone(), thiscopyonewrite)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) removeIndexRange(begin, end int) {
|
||||||
|
if end <= begin {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r := end - begin
|
||||||
|
|
||||||
|
copy(ra.keys[begin:], ra.keys[end:])
|
||||||
|
copy(ra.containers[begin:], ra.containers[end:])
|
||||||
|
copy(ra.needCopyOnWrite[begin:], ra.needCopyOnWrite[end:])
|
||||||
|
|
||||||
|
ra.resize(len(ra.keys) - r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) resize(newsize int) {
|
||||||
|
for k := newsize; k < len(ra.containers); k++ {
|
||||||
|
ra.containers[k] = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ra.keys = ra.keys[:newsize]
|
||||||
|
ra.containers = ra.containers[:newsize]
|
||||||
|
ra.needCopyOnWrite = ra.needCopyOnWrite[:newsize]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) clear() {
|
||||||
|
ra.resize(0)
|
||||||
|
ra.copyOnWrite = false
|
||||||
|
ra.conserz = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) clone() *roaringArray {
|
||||||
|
|
||||||
|
sa := roaringArray{}
|
||||||
|
sa.copyOnWrite = ra.copyOnWrite
|
||||||
|
|
||||||
|
// this is where copyOnWrite is used.
|
||||||
|
if ra.copyOnWrite {
|
||||||
|
sa.keys = make([]uint16, len(ra.keys))
|
||||||
|
copy(sa.keys, ra.keys)
|
||||||
|
sa.containers = make([]container, len(ra.containers))
|
||||||
|
copy(sa.containers, ra.containers)
|
||||||
|
sa.needCopyOnWrite = make([]bool, len(ra.needCopyOnWrite))
|
||||||
|
|
||||||
|
ra.markAllAsNeedingCopyOnWrite()
|
||||||
|
sa.markAllAsNeedingCopyOnWrite()
|
||||||
|
|
||||||
|
// sa.needCopyOnWrite is shared
|
||||||
|
} else {
|
||||||
|
// make a full copy
|
||||||
|
|
||||||
|
sa.keys = make([]uint16, len(ra.keys))
|
||||||
|
copy(sa.keys, ra.keys)
|
||||||
|
|
||||||
|
sa.containers = make([]container, len(ra.containers))
|
||||||
|
for i := range sa.containers {
|
||||||
|
sa.containers[i] = ra.containers[i].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
sa.needCopyOnWrite = make([]bool, len(ra.needCopyOnWrite))
|
||||||
|
}
|
||||||
|
return &sa
|
||||||
|
}
|
||||||
|
|
||||||
|
// clone all containers which have needCopyOnWrite set to true
|
||||||
|
// This can be used to make sure it is safe to munmap a []byte
|
||||||
|
// that the roaring array may still have a reference to.
|
||||||
|
func (ra *roaringArray) cloneCopyOnWriteContainers() {
|
||||||
|
for i, needCopyOnWrite := range ra.needCopyOnWrite {
|
||||||
|
if needCopyOnWrite {
|
||||||
|
ra.containers[i] = ra.containers[i].clone()
|
||||||
|
ra.needCopyOnWrite[i] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unused function:
|
||||||
|
//func (ra *roaringArray) containsKey(x uint16) bool {
|
||||||
|
// return (ra.binarySearch(0, int64(len(ra.keys)), x) >= 0)
|
||||||
|
//}
|
||||||
|
|
||||||
|
func (ra *roaringArray) getContainer(x uint16) container {
|
||||||
|
i := ra.binarySearch(0, int64(len(ra.keys)), x)
|
||||||
|
if i < 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ra.containers[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) getContainerAtIndex(i int) container {
|
||||||
|
return ra.containers[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) getFastContainerAtIndex(i int, needsWriteable bool) container {
|
||||||
|
c := ra.getContainerAtIndex(i)
|
||||||
|
switch t := c.(type) {
|
||||||
|
case *arrayContainer:
|
||||||
|
c = t.toBitmapContainer()
|
||||||
|
case *runContainer16:
|
||||||
|
if !t.isFull() {
|
||||||
|
c = t.toBitmapContainer()
|
||||||
|
}
|
||||||
|
case *bitmapContainer:
|
||||||
|
if needsWriteable && ra.needCopyOnWrite[i] {
|
||||||
|
c = ra.containers[i].clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) getWritableContainerAtIndex(i int) container {
|
||||||
|
if ra.needCopyOnWrite[i] {
|
||||||
|
ra.containers[i] = ra.containers[i].clone()
|
||||||
|
ra.needCopyOnWrite[i] = false
|
||||||
|
}
|
||||||
|
return ra.containers[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) getIndex(x uint16) int {
|
||||||
|
// before the binary search, we optimize for frequent cases
|
||||||
|
size := len(ra.keys)
|
||||||
|
if (size == 0) || (ra.keys[size-1] == x) {
|
||||||
|
return size - 1
|
||||||
|
}
|
||||||
|
return ra.binarySearch(0, int64(size), x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) getKeyAtIndex(i int) uint16 {
|
||||||
|
return ra.keys[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) insertNewKeyValueAt(i int, key uint16, value container) {
|
||||||
|
ra.keys = append(ra.keys, 0)
|
||||||
|
ra.containers = append(ra.containers, nil)
|
||||||
|
|
||||||
|
copy(ra.keys[i+1:], ra.keys[i:])
|
||||||
|
copy(ra.containers[i+1:], ra.containers[i:])
|
||||||
|
|
||||||
|
ra.keys[i] = key
|
||||||
|
ra.containers[i] = value
|
||||||
|
|
||||||
|
ra.needCopyOnWrite = append(ra.needCopyOnWrite, false)
|
||||||
|
copy(ra.needCopyOnWrite[i+1:], ra.needCopyOnWrite[i:])
|
||||||
|
ra.needCopyOnWrite[i] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) remove(key uint16) bool {
|
||||||
|
i := ra.binarySearch(0, int64(len(ra.keys)), key)
|
||||||
|
if i >= 0 { // if a new key
|
||||||
|
ra.removeAtIndex(i)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) removeAtIndex(i int) {
|
||||||
|
copy(ra.keys[i:], ra.keys[i+1:])
|
||||||
|
copy(ra.containers[i:], ra.containers[i+1:])
|
||||||
|
|
||||||
|
copy(ra.needCopyOnWrite[i:], ra.needCopyOnWrite[i+1:])
|
||||||
|
|
||||||
|
ra.resize(len(ra.keys) - 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) setContainerAtIndex(i int, c container) {
|
||||||
|
ra.containers[i] = c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) replaceKeyAndContainerAtIndex(i int, key uint16, c container, mustCopyOnWrite bool) {
|
||||||
|
ra.keys[i] = key
|
||||||
|
ra.containers[i] = c
|
||||||
|
ra.needCopyOnWrite[i] = mustCopyOnWrite
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) size() int {
|
||||||
|
return len(ra.keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) binarySearch(begin, end int64, ikey uint16) int {
|
||||||
|
low := begin
|
||||||
|
high := end - 1
|
||||||
|
for low+16 <= high {
|
||||||
|
middleIndex := low + (high-low)/2 // avoid overflow
|
||||||
|
middleValue := ra.keys[middleIndex]
|
||||||
|
|
||||||
|
if middleValue < ikey {
|
||||||
|
low = middleIndex + 1
|
||||||
|
} else if middleValue > ikey {
|
||||||
|
high = middleIndex - 1
|
||||||
|
} else {
|
||||||
|
return int(middleIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ; low <= high; low++ {
|
||||||
|
val := ra.keys[low]
|
||||||
|
if val >= ikey {
|
||||||
|
if val == ikey {
|
||||||
|
return int(low)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -int(low + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) equals(o interface{}) bool {
|
||||||
|
srb, ok := o.(roaringArray)
|
||||||
|
if ok {
|
||||||
|
|
||||||
|
if srb.size() != ra.size() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i, k := range ra.keys {
|
||||||
|
if k != srb.keys[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range ra.containers {
|
||||||
|
if !c.equals(srb.containers[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) headerSize() uint64 {
|
||||||
|
size := uint64(len(ra.keys))
|
||||||
|
if ra.hasRunCompression() {
|
||||||
|
if size < noOffsetThreshold { // for small bitmaps, we omit the offsets
|
||||||
|
return 4 + (size+7)/8 + 4*size
|
||||||
|
}
|
||||||
|
return 4 + (size+7)/8 + 8*size // - 4 because we pack the size with the cookie
|
||||||
|
}
|
||||||
|
return 4 + 4 + 8*size
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// should be dirt cheap
|
||||||
|
func (ra *roaringArray) serializedSizeInBytes() uint64 {
|
||||||
|
answer := ra.headerSize()
|
||||||
|
for _, c := range ra.containers {
|
||||||
|
answer += uint64(c.serializedSizeInBytes())
|
||||||
|
}
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
|
||||||
|
//
|
||||||
|
func (ra *roaringArray) writeTo(w io.Writer) (n int64, err error) {
|
||||||
|
hasRun := ra.hasRunCompression()
|
||||||
|
isRunSizeInBytes := 0
|
||||||
|
cookieSize := 8
|
||||||
|
if hasRun {
|
||||||
|
cookieSize = 4
|
||||||
|
isRunSizeInBytes = (len(ra.keys) + 7) / 8
|
||||||
|
}
|
||||||
|
descriptiveHeaderSize := 4 * len(ra.keys)
|
||||||
|
preambleSize := cookieSize + isRunSizeInBytes + descriptiveHeaderSize
|
||||||
|
|
||||||
|
buf := make([]byte, preambleSize+4*len(ra.keys))
|
||||||
|
|
||||||
|
nw := 0
|
||||||
|
|
||||||
|
if hasRun {
|
||||||
|
binary.LittleEndian.PutUint16(buf[0:], uint16(serialCookie))
|
||||||
|
nw += 2
|
||||||
|
binary.LittleEndian.PutUint16(buf[2:], uint16(len(ra.keys)-1))
|
||||||
|
nw += 2
|
||||||
|
// compute isRun bitmap without temporary allocation
|
||||||
|
var runbitmapslice = buf[nw:nw+isRunSizeInBytes]
|
||||||
|
for i, c := range ra.containers {
|
||||||
|
switch c.(type) {
|
||||||
|
case *runContainer16:
|
||||||
|
runbitmapslice[i / 8] |= 1<<(uint(i)%8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nw += isRunSizeInBytes
|
||||||
|
} else {
|
||||||
|
binary.LittleEndian.PutUint32(buf[0:], uint32(serialCookieNoRunContainer))
|
||||||
|
nw += 4
|
||||||
|
binary.LittleEndian.PutUint32(buf[4:], uint32(len(ra.keys)))
|
||||||
|
nw += 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// descriptive header
|
||||||
|
for i, key := range ra.keys {
|
||||||
|
binary.LittleEndian.PutUint16(buf[nw:], key)
|
||||||
|
nw += 2
|
||||||
|
c := ra.containers[i]
|
||||||
|
binary.LittleEndian.PutUint16(buf[nw:], uint16(c.getCardinality()-1))
|
||||||
|
nw += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
startOffset := int64(preambleSize + 4*len(ra.keys))
|
||||||
|
if !hasRun || (len(ra.keys) >= noOffsetThreshold) {
|
||||||
|
// offset header
|
||||||
|
for _, c := range ra.containers {
|
||||||
|
binary.LittleEndian.PutUint32(buf[nw:], uint32(startOffset))
|
||||||
|
nw += 4
|
||||||
|
switch rc := c.(type) {
|
||||||
|
case *runContainer16:
|
||||||
|
startOffset += 2 + int64(len(rc.iv))*4
|
||||||
|
default:
|
||||||
|
startOffset += int64(getSizeInBytesFromCardinality(c.getCardinality()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
written, err := w.Write(buf[:nw])
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
n += int64(written)
|
||||||
|
|
||||||
|
for _, c := range ra.containers {
|
||||||
|
written, err := c.writeTo(w)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
n += int64(written)
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
|
||||||
|
//
|
||||||
|
func (ra *roaringArray) toBytes() ([]byte, error) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_, err := ra.writeTo(&buf)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) readFrom(stream byteInput) (int64, error) {
|
||||||
|
cookie, err := stream.readUInt32()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("error in roaringArray.readFrom: could not read initial cookie: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var size uint32
|
||||||
|
var isRunBitmap []byte
|
||||||
|
|
||||||
|
if cookie&0x0000FFFF == serialCookie {
|
||||||
|
size = uint32(uint16(cookie>>16) + 1)
|
||||||
|
// create is-run-container bitmap
|
||||||
|
isRunBitmapSize := (int(size) + 7) / 8
|
||||||
|
isRunBitmap, err = stream.next(isRunBitmapSize)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("malformed bitmap, failed to read is-run bitmap, got: %s", err)
|
||||||
|
}
|
||||||
|
} else if cookie == serialCookieNoRunContainer {
|
||||||
|
size, err = stream.readUInt32()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("malformed bitmap, failed to read a bitmap size: %s", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("error in roaringArray.readFrom: did not find expected serialCookie in header")
|
||||||
|
}
|
||||||
|
|
||||||
|
if size > (1 << 16) {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("it is logically impossible to have more than (1<<16) containers")
|
||||||
|
}
|
||||||
|
|
||||||
|
// descriptive header
|
||||||
|
buf, err := stream.next(2 * 2 * int(size))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("failed to read descriptive header: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
keycard := byteSliceAsUint16Slice(buf)
|
||||||
|
|
||||||
|
if isRunBitmap == nil || size >= noOffsetThreshold {
|
||||||
|
if err := stream.skipBytes(int(size) * 4); err != nil {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("failed to skip bytes: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate slices upfront as number of containers is known
|
||||||
|
if cap(ra.containers) >= int(size) {
|
||||||
|
ra.containers = ra.containers[:size]
|
||||||
|
} else {
|
||||||
|
ra.containers = make([]container, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cap(ra.keys) >= int(size) {
|
||||||
|
ra.keys = ra.keys[:size]
|
||||||
|
} else {
|
||||||
|
ra.keys = make([]uint16, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cap(ra.needCopyOnWrite) >= int(size) {
|
||||||
|
ra.needCopyOnWrite = ra.needCopyOnWrite[:size]
|
||||||
|
} else {
|
||||||
|
ra.needCopyOnWrite = make([]bool, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint32(0); i < size; i++ {
|
||||||
|
key := keycard[2*i]
|
||||||
|
card := int(keycard[2*i+1]) + 1
|
||||||
|
ra.keys[i] = key
|
||||||
|
ra.needCopyOnWrite[i] = true
|
||||||
|
|
||||||
|
if isRunBitmap != nil && isRunBitmap[i/8]&(1<<(i%8)) != 0 {
|
||||||
|
// run container
|
||||||
|
nr, err := stream.readUInt16()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to read runtime container size: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf, err := stream.next(int(nr) * 4)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("failed to read runtime container content: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nb := runContainer16{
|
||||||
|
iv: byteSliceAsInterval16Slice(buf),
|
||||||
|
card: int64(card),
|
||||||
|
}
|
||||||
|
|
||||||
|
ra.containers[i] = &nb
|
||||||
|
} else if card > arrayDefaultMaxSize {
|
||||||
|
// bitmap container
|
||||||
|
buf, err := stream.next(arrayDefaultMaxSize * 2)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("failed to read bitmap container: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nb := bitmapContainer{
|
||||||
|
cardinality: card,
|
||||||
|
bitmap: byteSliceAsUint64Slice(buf),
|
||||||
|
}
|
||||||
|
|
||||||
|
ra.containers[i] = &nb
|
||||||
|
} else {
|
||||||
|
// array container
|
||||||
|
buf, err := stream.next(card * 2)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return stream.getReadBytes(), fmt.Errorf("failed to read array container: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nb := arrayContainer{
|
||||||
|
byteSliceAsUint16Slice(buf),
|
||||||
|
}
|
||||||
|
|
||||||
|
ra.containers[i] = &nb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream.getReadBytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) hasRunCompression() bool {
|
||||||
|
for _, c := range ra.containers {
|
||||||
|
switch c.(type) {
|
||||||
|
case *runContainer16:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) writeToMsgpack(stream io.Writer) error {
|
||||||
|
|
||||||
|
ra.conserz = make([]containerSerz, len(ra.containers))
|
||||||
|
for i, v := range ra.containers {
|
||||||
|
switch cn := v.(type) {
|
||||||
|
case *bitmapContainer:
|
||||||
|
bts, err := cn.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ra.conserz[i].t = bitmapContype
|
||||||
|
ra.conserz[i].r = bts
|
||||||
|
case *arrayContainer:
|
||||||
|
bts, err := cn.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ra.conserz[i].t = arrayContype
|
||||||
|
ra.conserz[i].r = bts
|
||||||
|
case *runContainer16:
|
||||||
|
bts, err := cn.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ra.conserz[i].t = run16Contype
|
||||||
|
ra.conserz[i].r = bts
|
||||||
|
default:
|
||||||
|
panic(fmt.Errorf("Unrecognized container implementation: %T", cn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w := snappy.NewWriter(stream)
|
||||||
|
err := msgp.Encode(w, ra)
|
||||||
|
ra.conserz = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) readFromMsgpack(stream io.Reader) error {
|
||||||
|
r := snappy.NewReader(stream)
|
||||||
|
err := msgp.Decode(r, ra)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ra.containers) != len(ra.keys) {
|
||||||
|
ra.containers = make([]container, len(ra.keys))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range ra.conserz {
|
||||||
|
switch v.t {
|
||||||
|
case bitmapContype:
|
||||||
|
c := &bitmapContainer{}
|
||||||
|
_, err = c.UnmarshalMsg(v.r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ra.containers[i] = c
|
||||||
|
case arrayContype:
|
||||||
|
c := &arrayContainer{}
|
||||||
|
_, err = c.UnmarshalMsg(v.r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ra.containers[i] = c
|
||||||
|
case run16Contype:
|
||||||
|
c := &runContainer16{}
|
||||||
|
_, err = c.UnmarshalMsg(v.r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ra.containers[i] = c
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unrecognized contype serialization code: '%v'", v.t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ra.conserz = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) advanceUntil(min uint16, pos int) int {
|
||||||
|
lower := pos + 1
|
||||||
|
|
||||||
|
if lower >= len(ra.keys) || ra.keys[lower] >= min {
|
||||||
|
return lower
|
||||||
|
}
|
||||||
|
|
||||||
|
spansize := 1
|
||||||
|
|
||||||
|
for lower+spansize < len(ra.keys) && ra.keys[lower+spansize] < min {
|
||||||
|
spansize *= 2
|
||||||
|
}
|
||||||
|
var upper int
|
||||||
|
if lower+spansize < len(ra.keys) {
|
||||||
|
upper = lower + spansize
|
||||||
|
} else {
|
||||||
|
upper = len(ra.keys) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ra.keys[upper] == min {
|
||||||
|
return upper
|
||||||
|
}
|
||||||
|
|
||||||
|
if ra.keys[upper] < min {
|
||||||
|
// means
|
||||||
|
// array
|
||||||
|
// has no
|
||||||
|
// item
|
||||||
|
// >= min
|
||||||
|
// pos = array.length;
|
||||||
|
return len(ra.keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
// we know that the next-smallest span was too small
|
||||||
|
lower += (spansize >> 1)
|
||||||
|
|
||||||
|
mid := 0
|
||||||
|
for lower+1 != upper {
|
||||||
|
mid = (lower + upper) >> 1
|
||||||
|
if ra.keys[mid] == min {
|
||||||
|
return mid
|
||||||
|
} else if ra.keys[mid] < min {
|
||||||
|
lower = mid
|
||||||
|
} else {
|
||||||
|
upper = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return upper
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) markAllAsNeedingCopyOnWrite() {
|
||||||
|
for i := range ra.needCopyOnWrite {
|
||||||
|
ra.needCopyOnWrite[i] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) needsCopyOnWrite(i int) bool {
|
||||||
|
return ra.needCopyOnWrite[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ra *roaringArray) setNeedsCopyOnWrite(i int) {
|
||||||
|
ra.needCopyOnWrite[i] = true
|
||||||
|
}
|
||||||
529
vendor/github.com/RoaringBitmap/roaring/roaringarray_gen.go
сгенерированный
поставляемый
Обычный файл
529
vendor/github.com/RoaringBitmap/roaring/roaringarray_gen.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,529 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
// NOTE: THIS FILE WAS PRODUCED BY THE
|
||||||
|
// MSGP CODE GENERATION TOOL (github.com/tinylib/msgp)
|
||||||
|
// DO NOT EDIT
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Deprecated: DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *containerSerz) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zxvk uint32
|
||||||
|
zxvk, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zxvk > 0 {
|
||||||
|
zxvk--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "t":
|
||||||
|
{
|
||||||
|
var zbzg uint8
|
||||||
|
zbzg, err = dc.ReadUint8()
|
||||||
|
z.t = contype(zbzg)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "r":
|
||||||
|
err = z.r.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *containerSerz) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 2
|
||||||
|
// write "t"
|
||||||
|
err = en.Append(0x82, 0xa1, 0x74)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteUint8(uint8(z.t))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "r"
|
||||||
|
err = en.Append(0xa1, 0x72)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = z.r.EncodeMsg(en)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z *containerSerz) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 2
|
||||||
|
// string "t"
|
||||||
|
o = append(o, 0x82, 0xa1, 0x74)
|
||||||
|
o = msgp.AppendUint8(o, uint8(z.t))
|
||||||
|
// string "r"
|
||||||
|
o = append(o, 0xa1, 0x72)
|
||||||
|
o, err = z.r.MarshalMsg(o)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *containerSerz) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zbai uint32
|
||||||
|
zbai, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zbai > 0 {
|
||||||
|
zbai--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "t":
|
||||||
|
{
|
||||||
|
var zcmr uint8
|
||||||
|
zcmr, bts, err = msgp.ReadUint8Bytes(bts)
|
||||||
|
z.t = contype(zcmr)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "r":
|
||||||
|
bts, err = z.r.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z *containerSerz) Msgsize() (s int) {
|
||||||
|
s = 1 + 2 + msgp.Uint8Size + 2 + z.r.Msgsize()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *contype) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
{
|
||||||
|
var zajw uint8
|
||||||
|
zajw, err = dc.ReadUint8()
|
||||||
|
(*z) = contype(zajw)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: EncodeMsg implements msgp.Encodable
|
||||||
|
func (z contype) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
err = en.WriteUint8(uint8(z))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z contype) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
o = msgp.AppendUint8(o, uint8(z))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *contype) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
{
|
||||||
|
var zwht uint8
|
||||||
|
zwht, bts, err = msgp.ReadUint8Bytes(bts)
|
||||||
|
(*z) = contype(zwht)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z contype) Msgsize() (s int) {
|
||||||
|
s = msgp.Uint8Size
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: DecodeMsg implements msgp.Decodable
|
||||||
|
func (z *roaringArray) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zlqf uint32
|
||||||
|
zlqf, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zlqf > 0 {
|
||||||
|
zlqf--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "keys":
|
||||||
|
var zdaf uint32
|
||||||
|
zdaf, err = dc.ReadArrayHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.keys) >= int(zdaf) {
|
||||||
|
z.keys = (z.keys)[:zdaf]
|
||||||
|
} else {
|
||||||
|
z.keys = make([]uint16, zdaf)
|
||||||
|
}
|
||||||
|
for zhct := range z.keys {
|
||||||
|
z.keys[zhct], err = dc.ReadUint16()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "needCopyOnWrite":
|
||||||
|
var zpks uint32
|
||||||
|
zpks, err = dc.ReadArrayHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.needCopyOnWrite) >= int(zpks) {
|
||||||
|
z.needCopyOnWrite = (z.needCopyOnWrite)[:zpks]
|
||||||
|
} else {
|
||||||
|
z.needCopyOnWrite = make([]bool, zpks)
|
||||||
|
}
|
||||||
|
for zcua := range z.needCopyOnWrite {
|
||||||
|
z.needCopyOnWrite[zcua], err = dc.ReadBool()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "copyOnWrite":
|
||||||
|
z.copyOnWrite, err = dc.ReadBool()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "conserz":
|
||||||
|
var zjfb uint32
|
||||||
|
zjfb, err = dc.ReadArrayHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.conserz) >= int(zjfb) {
|
||||||
|
z.conserz = (z.conserz)[:zjfb]
|
||||||
|
} else {
|
||||||
|
z.conserz = make([]containerSerz, zjfb)
|
||||||
|
}
|
||||||
|
for zxhx := range z.conserz {
|
||||||
|
var zcxo uint32
|
||||||
|
zcxo, err = dc.ReadMapHeader()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zcxo > 0 {
|
||||||
|
zcxo--
|
||||||
|
field, err = dc.ReadMapKeyPtr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "t":
|
||||||
|
{
|
||||||
|
var zeff uint8
|
||||||
|
zeff, err = dc.ReadUint8()
|
||||||
|
z.conserz[zxhx].t = contype(zeff)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "r":
|
||||||
|
err = z.conserz[zxhx].r.DecodeMsg(dc)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
err = dc.Skip()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: EncodeMsg implements msgp.Encodable
|
||||||
|
func (z *roaringArray) EncodeMsg(en *msgp.Writer) (err error) {
|
||||||
|
// map header, size 4
|
||||||
|
// write "keys"
|
||||||
|
err = en.Append(0x84, 0xa4, 0x6b, 0x65, 0x79, 0x73)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteArrayHeader(uint32(len(z.keys)))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zhct := range z.keys {
|
||||||
|
err = en.WriteUint16(z.keys[zhct])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write "needCopyOnWrite"
|
||||||
|
err = en.Append(0xaf, 0x6e, 0x65, 0x65, 0x64, 0x43, 0x6f, 0x70, 0x79, 0x4f, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteArrayHeader(uint32(len(z.needCopyOnWrite)))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zcua := range z.needCopyOnWrite {
|
||||||
|
err = en.WriteBool(z.needCopyOnWrite[zcua])
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// write "copyOnWrite"
|
||||||
|
err = en.Append(0xab, 0x63, 0x6f, 0x70, 0x79, 0x4f, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteBool(z.copyOnWrite)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "conserz"
|
||||||
|
err = en.Append(0xa7, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x72, 0x7a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteArrayHeader(uint32(len(z.conserz)))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zxhx := range z.conserz {
|
||||||
|
// map header, size 2
|
||||||
|
// write "t"
|
||||||
|
err = en.Append(0x82, 0xa1, 0x74)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = en.WriteUint8(uint8(z.conserz[zxhx].t))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// write "r"
|
||||||
|
err = en.Append(0xa1, 0x72)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = z.conserz[zxhx].r.EncodeMsg(en)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: MarshalMsg implements msgp.Marshaler
|
||||||
|
func (z *roaringArray) MarshalMsg(b []byte) (o []byte, err error) {
|
||||||
|
o = msgp.Require(b, z.Msgsize())
|
||||||
|
// map header, size 4
|
||||||
|
// string "keys"
|
||||||
|
o = append(o, 0x84, 0xa4, 0x6b, 0x65, 0x79, 0x73)
|
||||||
|
o = msgp.AppendArrayHeader(o, uint32(len(z.keys)))
|
||||||
|
for zhct := range z.keys {
|
||||||
|
o = msgp.AppendUint16(o, z.keys[zhct])
|
||||||
|
}
|
||||||
|
// string "needCopyOnWrite"
|
||||||
|
o = append(o, 0xaf, 0x6e, 0x65, 0x65, 0x64, 0x43, 0x6f, 0x70, 0x79, 0x4f, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65)
|
||||||
|
o = msgp.AppendArrayHeader(o, uint32(len(z.needCopyOnWrite)))
|
||||||
|
for zcua := range z.needCopyOnWrite {
|
||||||
|
o = msgp.AppendBool(o, z.needCopyOnWrite[zcua])
|
||||||
|
}
|
||||||
|
// string "copyOnWrite"
|
||||||
|
o = append(o, 0xab, 0x63, 0x6f, 0x70, 0x79, 0x4f, 0x6e, 0x57, 0x72, 0x69, 0x74, 0x65)
|
||||||
|
o = msgp.AppendBool(o, z.copyOnWrite)
|
||||||
|
// string "conserz"
|
||||||
|
o = append(o, 0xa7, 0x63, 0x6f, 0x6e, 0x73, 0x65, 0x72, 0x7a)
|
||||||
|
o = msgp.AppendArrayHeader(o, uint32(len(z.conserz)))
|
||||||
|
for zxhx := range z.conserz {
|
||||||
|
// map header, size 2
|
||||||
|
// string "t"
|
||||||
|
o = append(o, 0x82, 0xa1, 0x74)
|
||||||
|
o = msgp.AppendUint8(o, uint8(z.conserz[zxhx].t))
|
||||||
|
// string "r"
|
||||||
|
o = append(o, 0xa1, 0x72)
|
||||||
|
o, err = z.conserz[zxhx].r.MarshalMsg(o)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: UnmarshalMsg implements msgp.Unmarshaler
|
||||||
|
func (z *roaringArray) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||||
|
var field []byte
|
||||||
|
_ = field
|
||||||
|
var zrsw uint32
|
||||||
|
zrsw, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zrsw > 0 {
|
||||||
|
zrsw--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "keys":
|
||||||
|
var zxpk uint32
|
||||||
|
zxpk, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.keys) >= int(zxpk) {
|
||||||
|
z.keys = (z.keys)[:zxpk]
|
||||||
|
} else {
|
||||||
|
z.keys = make([]uint16, zxpk)
|
||||||
|
}
|
||||||
|
for zhct := range z.keys {
|
||||||
|
z.keys[zhct], bts, err = msgp.ReadUint16Bytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "needCopyOnWrite":
|
||||||
|
var zdnj uint32
|
||||||
|
zdnj, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.needCopyOnWrite) >= int(zdnj) {
|
||||||
|
z.needCopyOnWrite = (z.needCopyOnWrite)[:zdnj]
|
||||||
|
} else {
|
||||||
|
z.needCopyOnWrite = make([]bool, zdnj)
|
||||||
|
}
|
||||||
|
for zcua := range z.needCopyOnWrite {
|
||||||
|
z.needCopyOnWrite[zcua], bts, err = msgp.ReadBoolBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "copyOnWrite":
|
||||||
|
z.copyOnWrite, bts, err = msgp.ReadBoolBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "conserz":
|
||||||
|
var zobc uint32
|
||||||
|
zobc, bts, err = msgp.ReadArrayHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cap(z.conserz) >= int(zobc) {
|
||||||
|
z.conserz = (z.conserz)[:zobc]
|
||||||
|
} else {
|
||||||
|
z.conserz = make([]containerSerz, zobc)
|
||||||
|
}
|
||||||
|
for zxhx := range z.conserz {
|
||||||
|
var zsnv uint32
|
||||||
|
zsnv, bts, err = msgp.ReadMapHeaderBytes(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for zsnv > 0 {
|
||||||
|
zsnv--
|
||||||
|
field, bts, err = msgp.ReadMapKeyZC(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch msgp.UnsafeString(field) {
|
||||||
|
case "t":
|
||||||
|
{
|
||||||
|
var zkgt uint8
|
||||||
|
zkgt, bts, err = msgp.ReadUint8Bytes(bts)
|
||||||
|
z.conserz[zxhx].t = contype(zkgt)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case "r":
|
||||||
|
bts, err = z.conserz[zxhx].r.UnmarshalMsg(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
bts, err = msgp.Skip(bts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
o = bts
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Msgsize returns an upper bound estimate of the number of bytes occupied by the serialized message
|
||||||
|
func (z *roaringArray) Msgsize() (s int) {
|
||||||
|
s = 1 + 5 + msgp.ArrayHeaderSize + (len(z.keys) * (msgp.Uint16Size)) + 16 + msgp.ArrayHeaderSize + (len(z.needCopyOnWrite) * (msgp.BoolSize)) + 12 + msgp.BoolSize + 8 + msgp.ArrayHeaderSize
|
||||||
|
for zxhx := range z.conserz {
|
||||||
|
s += 1 + 2 + msgp.Uint8Size + 2 + z.conserz[zxhx].r.Msgsize()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
2526
vendor/github.com/RoaringBitmap/roaring/runcontainer.go
сгенерированный
поставляемый
Обычный файл
2526
vendor/github.com/RoaringBitmap/roaring/runcontainer.go
сгенерированный
поставляемый
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
1104
vendor/github.com/RoaringBitmap/roaring/runcontainer_gen.go
сгенерированный
поставляемый
Обычный файл
1104
vendor/github.com/RoaringBitmap/roaring/runcontainer_gen.go
сгенерированный
поставляемый
Обычный файл
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
34
vendor/github.com/RoaringBitmap/roaring/serialization.go
сгенерированный
поставляемый
Обычный файл
34
vendor/github.com/RoaringBitmap/roaring/serialization.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,34 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/tinylib/msgp/msgp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// writeTo for runContainer16 follows this
|
||||||
|
// spec: https://github.com/RoaringBitmap/RoaringFormatSpec
|
||||||
|
//
|
||||||
|
func (b *runContainer16) writeTo(stream io.Writer) (int, error) {
|
||||||
|
buf := make([]byte, 2+4*len(b.iv))
|
||||||
|
binary.LittleEndian.PutUint16(buf[0:], uint16(len(b.iv)))
|
||||||
|
for i, v := range b.iv {
|
||||||
|
binary.LittleEndian.PutUint16(buf[2+i*4:], v.start)
|
||||||
|
binary.LittleEndian.PutUint16(buf[2+2+i*4:], v.length)
|
||||||
|
}
|
||||||
|
return stream.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *runContainer16) writeToMsgpack(stream io.Writer) (int, error) {
|
||||||
|
bts, err := b.MarshalMsg(nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return stream.Write(bts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *runContainer16) readFromMsgpack(stream io.Reader) (int, error) {
|
||||||
|
err := msgp.Decode(stream, b)
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
133
vendor/github.com/RoaringBitmap/roaring/serialization_generic.go
сгенерированный
поставляемый
Обычный файл
133
vendor/github.com/RoaringBitmap/roaring/serialization_generic.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,133 @@
|
|||||||
|
// +build !amd64,!386 appengine
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *arrayContainer) writeTo(stream io.Writer) (int, error) {
|
||||||
|
buf := make([]byte, 2*len(b.content))
|
||||||
|
for i, v := range b.content {
|
||||||
|
base := i * 2
|
||||||
|
buf[base] = byte(v)
|
||||||
|
buf[base+1] = byte(v >> 8)
|
||||||
|
}
|
||||||
|
return stream.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *arrayContainer) readFrom(stream io.Reader) (int, error) {
|
||||||
|
err := binary.Read(stream, binary.LittleEndian, b.content)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return 2 * len(b.content), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bitmapContainer) writeTo(stream io.Writer) (int, error) {
|
||||||
|
if b.cardinality <= arrayDefaultMaxSize {
|
||||||
|
return 0, errors.New("refusing to write bitmap container with cardinality of array container")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write set
|
||||||
|
buf := make([]byte, 8*len(b.bitmap))
|
||||||
|
for i, v := range b.bitmap {
|
||||||
|
base := i * 8
|
||||||
|
buf[base] = byte(v)
|
||||||
|
buf[base+1] = byte(v >> 8)
|
||||||
|
buf[base+2] = byte(v >> 16)
|
||||||
|
buf[base+3] = byte(v >> 24)
|
||||||
|
buf[base+4] = byte(v >> 32)
|
||||||
|
buf[base+5] = byte(v >> 40)
|
||||||
|
buf[base+6] = byte(v >> 48)
|
||||||
|
buf[base+7] = byte(v >> 56)
|
||||||
|
}
|
||||||
|
return stream.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *bitmapContainer) readFrom(stream io.Reader) (int, error) {
|
||||||
|
err := binary.Read(stream, binary.LittleEndian, b.bitmap)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
b.computeCardinality()
|
||||||
|
return 8 * len(b.bitmap), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *bitmapContainer) asLittleEndianByteSlice() []byte {
|
||||||
|
by := make([]byte, len(bc.bitmap)*8)
|
||||||
|
for i := range bc.bitmap {
|
||||||
|
binary.LittleEndian.PutUint64(by[i*8:], bc.bitmap[i])
|
||||||
|
}
|
||||||
|
return by
|
||||||
|
}
|
||||||
|
|
||||||
|
func uint64SliceAsByteSlice(slice []uint64) []byte {
|
||||||
|
by := make([]byte, len(slice)*8)
|
||||||
|
|
||||||
|
for i, v := range slice {
|
||||||
|
binary.LittleEndian.PutUint64(by[i*8:], v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return by
|
||||||
|
}
|
||||||
|
|
||||||
|
func uint16SliceAsByteSlice(slice []uint16) []byte {
|
||||||
|
by := make([]byte, len(slice)*2)
|
||||||
|
|
||||||
|
for i, v := range slice {
|
||||||
|
binary.LittleEndian.PutUint16(by[i*2:], v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return by
|
||||||
|
}
|
||||||
|
|
||||||
|
func byteSliceAsUint16Slice(slice []byte) []uint16 {
|
||||||
|
if len(slice)%2 != 0 {
|
||||||
|
panic("Slice size should be divisible by 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]uint16, len(slice)/2)
|
||||||
|
|
||||||
|
for i := range b {
|
||||||
|
b[i] = binary.LittleEndian.Uint16(slice[2*i:])
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func byteSliceAsUint64Slice(slice []byte) []uint64 {
|
||||||
|
if len(slice)%8 != 0 {
|
||||||
|
panic("Slice size should be divisible by 8")
|
||||||
|
}
|
||||||
|
|
||||||
|
b := make([]uint64, len(slice)/8)
|
||||||
|
|
||||||
|
for i := range b {
|
||||||
|
b[i] = binary.LittleEndian.Uint64(slice[8*i:])
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts a byte slice to a interval16 slice.
|
||||||
|
// The function assumes that the slice byte buffer is run container data
|
||||||
|
// encoded according to Roaring Format Spec
|
||||||
|
func byteSliceAsInterval16Slice(byteSlice []byte) []interval16 {
|
||||||
|
if len(byteSlice)%4 != 0 {
|
||||||
|
panic("Slice size should be divisible by 4")
|
||||||
|
}
|
||||||
|
|
||||||
|
intervalSlice := make([]interval16, len(byteSlice)/4)
|
||||||
|
|
||||||
|
for i := range intervalSlice {
|
||||||
|
intervalSlice[i] = interval16{
|
||||||
|
start: binary.LittleEndian.Uint16(byteSlice[i*4:]),
|
||||||
|
length: binary.LittleEndian.Uint16(byteSlice[i*4+2:]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return intervalSlice
|
||||||
|
}
|
||||||
134
vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go
сгенерированный
поставляемый
Обычный файл
134
vendor/github.com/RoaringBitmap/roaring/serialization_littleendian.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,134 @@
|
|||||||
|
// +build 386 amd64,!appengine
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (ac *arrayContainer) writeTo(stream io.Writer) (int, error) {
|
||||||
|
buf := uint16SliceAsByteSlice(ac.content)
|
||||||
|
return stream.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *bitmapContainer) writeTo(stream io.Writer) (int, error) {
|
||||||
|
if bc.cardinality <= arrayDefaultMaxSize {
|
||||||
|
return 0, errors.New("refusing to write bitmap container with cardinality of array container")
|
||||||
|
}
|
||||||
|
buf := uint64SliceAsByteSlice(bc.bitmap)
|
||||||
|
return stream.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func uint64SliceAsByteSlice(slice []uint64) []byte {
|
||||||
|
// make a new slice header
|
||||||
|
header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
|
||||||
|
|
||||||
|
// update its capacity and length
|
||||||
|
header.Len *= 8
|
||||||
|
header.Cap *= 8
|
||||||
|
|
||||||
|
// instantiate result and use KeepAlive so data isn't unmapped.
|
||||||
|
result := *(*[]byte)(unsafe.Pointer(&header))
|
||||||
|
runtime.KeepAlive(&slice)
|
||||||
|
|
||||||
|
// return it
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func uint16SliceAsByteSlice(slice []uint16) []byte {
|
||||||
|
// make a new slice header
|
||||||
|
header := *(*reflect.SliceHeader)(unsafe.Pointer(&slice))
|
||||||
|
|
||||||
|
// update its capacity and length
|
||||||
|
header.Len *= 2
|
||||||
|
header.Cap *= 2
|
||||||
|
|
||||||
|
// instantiate result and use KeepAlive so data isn't unmapped.
|
||||||
|
result := *(*[]byte)(unsafe.Pointer(&header))
|
||||||
|
runtime.KeepAlive(&slice)
|
||||||
|
|
||||||
|
// return it
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *bitmapContainer) asLittleEndianByteSlice() []byte {
|
||||||
|
return uint64SliceAsByteSlice(bc.bitmap)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deserialization code follows
|
||||||
|
|
||||||
|
////
|
||||||
|
// These methods (byteSliceAsUint16Slice,...) do not make copies,
|
||||||
|
// they are pointer-based (unsafe). The caller is responsible to
|
||||||
|
// ensure that the input slice does not get garbage collected, deleted
|
||||||
|
// or modified while you hold the returned slince.
|
||||||
|
////
|
||||||
|
func byteSliceAsUint16Slice(slice []byte) (result []uint16) { // here we create a new slice holder
|
||||||
|
if len(slice)%2 != 0 {
|
||||||
|
panic("Slice size should be divisible by 2")
|
||||||
|
}
|
||||||
|
// reference: https://go101.org/article/unsafe.html
|
||||||
|
|
||||||
|
// make a new slice header
|
||||||
|
bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
|
||||||
|
rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
|
||||||
|
|
||||||
|
// transfer the data from the given slice to a new variable (our result)
|
||||||
|
rHeader.Data = bHeader.Data
|
||||||
|
rHeader.Len = bHeader.Len / 2
|
||||||
|
rHeader.Cap = bHeader.Cap / 2
|
||||||
|
|
||||||
|
// instantiate result and use KeepAlive so data isn't unmapped.
|
||||||
|
runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
|
||||||
|
|
||||||
|
// return result
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func byteSliceAsUint64Slice(slice []byte) (result []uint64) {
|
||||||
|
if len(slice)%8 != 0 {
|
||||||
|
panic("Slice size should be divisible by 8")
|
||||||
|
}
|
||||||
|
// reference: https://go101.org/article/unsafe.html
|
||||||
|
|
||||||
|
// make a new slice header
|
||||||
|
bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
|
||||||
|
rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
|
||||||
|
|
||||||
|
// transfer the data from the given slice to a new variable (our result)
|
||||||
|
rHeader.Data = bHeader.Data
|
||||||
|
rHeader.Len = bHeader.Len / 8
|
||||||
|
rHeader.Cap = bHeader.Cap / 8
|
||||||
|
|
||||||
|
// instantiate result and use KeepAlive so data isn't unmapped.
|
||||||
|
runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
|
||||||
|
|
||||||
|
// return result
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func byteSliceAsInterval16Slice(slice []byte) (result []interval16) {
|
||||||
|
if len(slice)%4 != 0 {
|
||||||
|
panic("Slice size should be divisible by 4")
|
||||||
|
}
|
||||||
|
// reference: https://go101.org/article/unsafe.html
|
||||||
|
|
||||||
|
// make a new slice header
|
||||||
|
bHeader := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
|
||||||
|
rHeader := (*reflect.SliceHeader)(unsafe.Pointer(&result))
|
||||||
|
|
||||||
|
// transfer the data from the given slice to a new variable (our result)
|
||||||
|
rHeader.Data = bHeader.Data
|
||||||
|
rHeader.Len = bHeader.Len / 4
|
||||||
|
rHeader.Cap = bHeader.Cap / 4
|
||||||
|
|
||||||
|
// instantiate result and use KeepAlive so data isn't unmapped.
|
||||||
|
runtime.KeepAlive(&slice) // it is still crucial, GC can free it)
|
||||||
|
|
||||||
|
// return result
|
||||||
|
return
|
||||||
|
}
|
||||||
21
vendor/github.com/RoaringBitmap/roaring/serializationfuzz.go
сгенерированный
поставляемый
Обычный файл
21
vendor/github.com/RoaringBitmap/roaring/serializationfuzz.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,21 @@
|
|||||||
|
// +build gofuzz
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
import "bytes"
|
||||||
|
|
||||||
|
func FuzzSerializationStream(data []byte) int {
|
||||||
|
newrb := NewBitmap()
|
||||||
|
if _, err := newrb.ReadFrom(bytes.NewReader(data)); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func FuzzSerializationBuffer(data []byte) int {
|
||||||
|
newrb := NewBitmap()
|
||||||
|
if _, err := newrb.FromBuffer(data); err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return 1
|
||||||
|
}
|
||||||
610
vendor/github.com/RoaringBitmap/roaring/setutil.go
сгенерированный
поставляемый
Обычный файл
610
vendor/github.com/RoaringBitmap/roaring/setutil.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,610 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
func equal(a, b []uint16) bool {
|
||||||
|
if len(a) != len(b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range a {
|
||||||
|
if a[i] != b[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func difference(set1 []uint16, set2 []uint16, buffer []uint16) int {
|
||||||
|
if 0 == len(set2) {
|
||||||
|
buffer = buffer[:len(set1)]
|
||||||
|
for k := 0; k < len(set1); k++ {
|
||||||
|
buffer[k] = set1[k]
|
||||||
|
}
|
||||||
|
return len(set1)
|
||||||
|
}
|
||||||
|
if 0 == len(set1) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
pos := 0
|
||||||
|
k1 := 0
|
||||||
|
k2 := 0
|
||||||
|
buffer = buffer[:cap(buffer)]
|
||||||
|
s1 := set1[k1]
|
||||||
|
s2 := set2[k2]
|
||||||
|
for {
|
||||||
|
if s1 < s2 {
|
||||||
|
buffer[pos] = s1
|
||||||
|
pos++
|
||||||
|
k1++
|
||||||
|
if k1 >= len(set1) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
} else if s1 == s2 {
|
||||||
|
k1++
|
||||||
|
k2++
|
||||||
|
if k1 >= len(set1) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
if k2 >= len(set2) {
|
||||||
|
for ; k1 < len(set1); k1++ {
|
||||||
|
buffer[pos] = set1[k1]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
} else { // if (val1>val2)
|
||||||
|
k2++
|
||||||
|
if k2 >= len(set2) {
|
||||||
|
for ; k1 < len(set1); k1++ {
|
||||||
|
buffer[pos] = set1[k1]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func exclusiveUnion2by2(set1 []uint16, set2 []uint16, buffer []uint16) int {
|
||||||
|
if 0 == len(set2) {
|
||||||
|
buffer = buffer[:len(set1)]
|
||||||
|
copy(buffer, set1[:])
|
||||||
|
return len(set1)
|
||||||
|
}
|
||||||
|
if 0 == len(set1) {
|
||||||
|
buffer = buffer[:len(set2)]
|
||||||
|
copy(buffer, set2[:])
|
||||||
|
return len(set2)
|
||||||
|
}
|
||||||
|
pos := 0
|
||||||
|
k1 := 0
|
||||||
|
k2 := 0
|
||||||
|
s1 := set1[k1]
|
||||||
|
s2 := set2[k2]
|
||||||
|
buffer = buffer[:cap(buffer)]
|
||||||
|
for {
|
||||||
|
if s1 < s2 {
|
||||||
|
buffer[pos] = s1
|
||||||
|
pos++
|
||||||
|
k1++
|
||||||
|
if k1 >= len(set1) {
|
||||||
|
for ; k2 < len(set2); k2++ {
|
||||||
|
buffer[pos] = set2[k2]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
} else if s1 == s2 {
|
||||||
|
k1++
|
||||||
|
k2++
|
||||||
|
if k1 >= len(set1) {
|
||||||
|
for ; k2 < len(set2); k2++ {
|
||||||
|
buffer[pos] = set2[k2]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if k2 >= len(set2) {
|
||||||
|
for ; k1 < len(set1); k1++ {
|
||||||
|
buffer[pos] = set1[k1]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
s2 = set2[k2]
|
||||||
|
} else { // if (val1>val2)
|
||||||
|
buffer[pos] = s2
|
||||||
|
pos++
|
||||||
|
k2++
|
||||||
|
if k2 >= len(set2) {
|
||||||
|
for ; k1 < len(set1); k1++ {
|
||||||
|
buffer[pos] = set1[k1]
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func union2by2(set1 []uint16, set2 []uint16, buffer []uint16) int {
|
||||||
|
pos := 0
|
||||||
|
k1 := 0
|
||||||
|
k2 := 0
|
||||||
|
if 0 == len(set2) {
|
||||||
|
buffer = buffer[:len(set1)]
|
||||||
|
copy(buffer, set1[:])
|
||||||
|
return len(set1)
|
||||||
|
}
|
||||||
|
if 0 == len(set1) {
|
||||||
|
buffer = buffer[:len(set2)]
|
||||||
|
copy(buffer, set2[:])
|
||||||
|
return len(set2)
|
||||||
|
}
|
||||||
|
s1 := set1[k1]
|
||||||
|
s2 := set2[k2]
|
||||||
|
buffer = buffer[:cap(buffer)]
|
||||||
|
for {
|
||||||
|
if s1 < s2 {
|
||||||
|
buffer[pos] = s1
|
||||||
|
pos++
|
||||||
|
k1++
|
||||||
|
if k1 >= len(set1) {
|
||||||
|
copy(buffer[pos:], set2[k2:])
|
||||||
|
pos += len(set2) - k2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
} else if s1 == s2 {
|
||||||
|
buffer[pos] = s1
|
||||||
|
pos++
|
||||||
|
k1++
|
||||||
|
k2++
|
||||||
|
if k1 >= len(set1) {
|
||||||
|
copy(buffer[pos:], set2[k2:])
|
||||||
|
pos += len(set2) - k2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if k2 >= len(set2) {
|
||||||
|
copy(buffer[pos:], set1[k1:])
|
||||||
|
pos += len(set1) - k1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
s2 = set2[k2]
|
||||||
|
} else { // if (set1[k1]>set2[k2])
|
||||||
|
buffer[pos] = s2
|
||||||
|
pos++
|
||||||
|
k2++
|
||||||
|
if k2 >= len(set2) {
|
||||||
|
copy(buffer[pos:], set1[k1:])
|
||||||
|
pos += len(set1) - k1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func union2by2Cardinality(set1 []uint16, set2 []uint16) int {
|
||||||
|
pos := 0
|
||||||
|
k1 := 0
|
||||||
|
k2 := 0
|
||||||
|
if 0 == len(set2) {
|
||||||
|
return len(set1)
|
||||||
|
}
|
||||||
|
if 0 == len(set1) {
|
||||||
|
return len(set2)
|
||||||
|
}
|
||||||
|
s1 := set1[k1]
|
||||||
|
s2 := set2[k2]
|
||||||
|
for {
|
||||||
|
if s1 < s2 {
|
||||||
|
pos++
|
||||||
|
k1++
|
||||||
|
if k1 >= len(set1) {
|
||||||
|
pos += len(set2) - k2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
} else if s1 == s2 {
|
||||||
|
pos++
|
||||||
|
k1++
|
||||||
|
k2++
|
||||||
|
if k1 >= len(set1) {
|
||||||
|
pos += len(set2) - k2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if k2 >= len(set2) {
|
||||||
|
pos += len(set1) - k1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
s2 = set2[k2]
|
||||||
|
} else { // if (set1[k1]>set2[k2])
|
||||||
|
pos++
|
||||||
|
k2++
|
||||||
|
if k2 >= len(set2) {
|
||||||
|
pos += len(set1) - k1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func intersection2by2(
|
||||||
|
set1 []uint16,
|
||||||
|
set2 []uint16,
|
||||||
|
buffer []uint16) int {
|
||||||
|
|
||||||
|
if len(set1)*64 < len(set2) {
|
||||||
|
return onesidedgallopingintersect2by2(set1, set2, buffer)
|
||||||
|
} else if len(set2)*64 < len(set1) {
|
||||||
|
return onesidedgallopingintersect2by2(set2, set1, buffer)
|
||||||
|
} else {
|
||||||
|
return localintersect2by2(set1, set2, buffer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func intersection2by2Cardinality(
|
||||||
|
set1 []uint16,
|
||||||
|
set2 []uint16) int {
|
||||||
|
|
||||||
|
if len(set1)*64 < len(set2) {
|
||||||
|
return onesidedgallopingintersect2by2Cardinality(set1, set2)
|
||||||
|
} else if len(set2)*64 < len(set1) {
|
||||||
|
return onesidedgallopingintersect2by2Cardinality(set2, set1)
|
||||||
|
} else {
|
||||||
|
return localintersect2by2Cardinality(set1, set2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func intersects2by2(
|
||||||
|
set1 []uint16,
|
||||||
|
set2 []uint16) bool {
|
||||||
|
// could be optimized if one set is much larger than the other one
|
||||||
|
if (0 == len(set1)) || (0 == len(set2)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
k1 := 0
|
||||||
|
k2 := 0
|
||||||
|
s1 := set1[k1]
|
||||||
|
s2 := set2[k2]
|
||||||
|
mainwhile:
|
||||||
|
for {
|
||||||
|
|
||||||
|
if s2 < s1 {
|
||||||
|
for {
|
||||||
|
k2++
|
||||||
|
if k2 == len(set2) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
if s2 >= s1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s1 < s2 {
|
||||||
|
for {
|
||||||
|
k1++
|
||||||
|
if k1 == len(set1) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
if s1 >= s2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// (set2[k2] == set1[k1])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func localintersect2by2(
|
||||||
|
set1 []uint16,
|
||||||
|
set2 []uint16,
|
||||||
|
buffer []uint16) int {
|
||||||
|
|
||||||
|
if (0 == len(set1)) || (0 == len(set2)) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
k1 := 0
|
||||||
|
k2 := 0
|
||||||
|
pos := 0
|
||||||
|
buffer = buffer[:cap(buffer)]
|
||||||
|
s1 := set1[k1]
|
||||||
|
s2 := set2[k2]
|
||||||
|
mainwhile:
|
||||||
|
for {
|
||||||
|
if s2 < s1 {
|
||||||
|
for {
|
||||||
|
k2++
|
||||||
|
if k2 == len(set2) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
if s2 >= s1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s1 < s2 {
|
||||||
|
for {
|
||||||
|
k1++
|
||||||
|
if k1 == len(set1) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
if s1 >= s2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// (set2[k2] == set1[k1])
|
||||||
|
buffer[pos] = s1
|
||||||
|
pos++
|
||||||
|
k1++
|
||||||
|
if k1 == len(set1) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
k2++
|
||||||
|
if k2 == len(set2) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func localintersect2by2Cardinality(
|
||||||
|
set1 []uint16,
|
||||||
|
set2 []uint16) int {
|
||||||
|
|
||||||
|
if (0 == len(set1)) || (0 == len(set2)) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
k1 := 0
|
||||||
|
k2 := 0
|
||||||
|
pos := 0
|
||||||
|
s1 := set1[k1]
|
||||||
|
s2 := set2[k2]
|
||||||
|
mainwhile:
|
||||||
|
for {
|
||||||
|
if s2 < s1 {
|
||||||
|
for {
|
||||||
|
k2++
|
||||||
|
if k2 == len(set2) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
if s2 >= s1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s1 < s2 {
|
||||||
|
for {
|
||||||
|
k1++
|
||||||
|
if k1 == len(set1) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
if s1 >= s2 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// (set2[k2] == set1[k1])
|
||||||
|
pos++
|
||||||
|
k1++
|
||||||
|
if k1 == len(set1) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s1 = set1[k1]
|
||||||
|
k2++
|
||||||
|
if k2 == len(set2) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s2 = set2[k2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func advanceUntil(
|
||||||
|
array []uint16,
|
||||||
|
pos int,
|
||||||
|
length int,
|
||||||
|
min uint16) int {
|
||||||
|
lower := pos + 1
|
||||||
|
|
||||||
|
if lower >= length || array[lower] >= min {
|
||||||
|
return lower
|
||||||
|
}
|
||||||
|
|
||||||
|
spansize := 1
|
||||||
|
|
||||||
|
for lower+spansize < length && array[lower+spansize] < min {
|
||||||
|
spansize *= 2
|
||||||
|
}
|
||||||
|
var upper int
|
||||||
|
if lower+spansize < length {
|
||||||
|
upper = lower + spansize
|
||||||
|
} else {
|
||||||
|
upper = length - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if array[upper] == min {
|
||||||
|
return upper
|
||||||
|
}
|
||||||
|
|
||||||
|
if array[upper] < min {
|
||||||
|
// means
|
||||||
|
// array
|
||||||
|
// has no
|
||||||
|
// item
|
||||||
|
// >= min
|
||||||
|
// pos = array.length;
|
||||||
|
return length
|
||||||
|
}
|
||||||
|
|
||||||
|
// we know that the next-smallest span was too small
|
||||||
|
lower += (spansize >> 1)
|
||||||
|
|
||||||
|
mid := 0
|
||||||
|
for lower+1 != upper {
|
||||||
|
mid = (lower + upper) >> 1
|
||||||
|
if array[mid] == min {
|
||||||
|
return mid
|
||||||
|
} else if array[mid] < min {
|
||||||
|
lower = mid
|
||||||
|
} else {
|
||||||
|
upper = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return upper
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func onesidedgallopingintersect2by2(
|
||||||
|
smallset []uint16,
|
||||||
|
largeset []uint16,
|
||||||
|
buffer []uint16) int {
|
||||||
|
|
||||||
|
if 0 == len(smallset) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
buffer = buffer[:cap(buffer)]
|
||||||
|
k1 := 0
|
||||||
|
k2 := 0
|
||||||
|
pos := 0
|
||||||
|
s1 := largeset[k1]
|
||||||
|
s2 := smallset[k2]
|
||||||
|
mainwhile:
|
||||||
|
|
||||||
|
for {
|
||||||
|
if s1 < s2 {
|
||||||
|
k1 = advanceUntil(largeset, k1, len(largeset), s2)
|
||||||
|
if k1 == len(largeset) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s1 = largeset[k1]
|
||||||
|
}
|
||||||
|
if s2 < s1 {
|
||||||
|
k2++
|
||||||
|
if k2 == len(smallset) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s2 = smallset[k2]
|
||||||
|
} else {
|
||||||
|
|
||||||
|
buffer[pos] = s2
|
||||||
|
pos++
|
||||||
|
k2++
|
||||||
|
if k2 == len(smallset) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s2 = smallset[k2]
|
||||||
|
k1 = advanceUntil(largeset, k1, len(largeset), s2)
|
||||||
|
if k1 == len(largeset) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s1 = largeset[k1]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func onesidedgallopingintersect2by2Cardinality(
|
||||||
|
smallset []uint16,
|
||||||
|
largeset []uint16) int {
|
||||||
|
|
||||||
|
if 0 == len(smallset) {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
k1 := 0
|
||||||
|
k2 := 0
|
||||||
|
pos := 0
|
||||||
|
s1 := largeset[k1]
|
||||||
|
s2 := smallset[k2]
|
||||||
|
mainwhile:
|
||||||
|
|
||||||
|
for {
|
||||||
|
if s1 < s2 {
|
||||||
|
k1 = advanceUntil(largeset, k1, len(largeset), s2)
|
||||||
|
if k1 == len(largeset) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s1 = largeset[k1]
|
||||||
|
}
|
||||||
|
if s2 < s1 {
|
||||||
|
k2++
|
||||||
|
if k2 == len(smallset) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s2 = smallset[k2]
|
||||||
|
} else {
|
||||||
|
|
||||||
|
pos++
|
||||||
|
k2++
|
||||||
|
if k2 == len(smallset) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
s2 = smallset[k2]
|
||||||
|
k1 = advanceUntil(largeset, k1, len(largeset), s2)
|
||||||
|
if k1 == len(largeset) {
|
||||||
|
break mainwhile
|
||||||
|
}
|
||||||
|
s1 = largeset[k1]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return pos
|
||||||
|
}
|
||||||
|
|
||||||
|
func binarySearch(array []uint16, ikey uint16) int {
|
||||||
|
low := 0
|
||||||
|
high := len(array) - 1
|
||||||
|
for low+16 <= high {
|
||||||
|
middleIndex := int(uint32(low+high) >> 1)
|
||||||
|
middleValue := array[middleIndex]
|
||||||
|
if middleValue < ikey {
|
||||||
|
low = middleIndex + 1
|
||||||
|
} else if middleValue > ikey {
|
||||||
|
high = middleIndex - 1
|
||||||
|
} else {
|
||||||
|
return middleIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for ; low <= high; low++ {
|
||||||
|
val := array[low]
|
||||||
|
if val >= ikey {
|
||||||
|
if val == ikey {
|
||||||
|
return low
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -(low + 1)
|
||||||
|
}
|
||||||
52
vendor/github.com/RoaringBitmap/roaring/shortiterator.go
сгенерированный
поставляемый
Обычный файл
52
vendor/github.com/RoaringBitmap/roaring/shortiterator.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,52 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
type shortIterable interface {
|
||||||
|
hasNext() bool
|
||||||
|
next() uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type shortPeekable interface {
|
||||||
|
shortIterable
|
||||||
|
peekNext() uint16
|
||||||
|
advanceIfNeeded(minval uint16)
|
||||||
|
}
|
||||||
|
|
||||||
|
type shortIterator struct {
|
||||||
|
slice []uint16
|
||||||
|
loc int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *shortIterator) hasNext() bool {
|
||||||
|
return si.loc < len(si.slice)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *shortIterator) next() uint16 {
|
||||||
|
a := si.slice[si.loc]
|
||||||
|
si.loc++
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *shortIterator) peekNext() uint16 {
|
||||||
|
return si.slice[si.loc]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *shortIterator) advanceIfNeeded(minval uint16) {
|
||||||
|
if si.hasNext() && si.peekNext() < minval {
|
||||||
|
si.loc = advanceUntil(si.slice, si.loc, len(si.slice), minval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type reverseIterator struct {
|
||||||
|
slice []uint16
|
||||||
|
loc int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *reverseIterator) hasNext() bool {
|
||||||
|
return si.loc >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (si *reverseIterator) next() uint16 {
|
||||||
|
a := si.slice[si.loc]
|
||||||
|
si.loc--
|
||||||
|
return a
|
||||||
|
}
|
||||||
383
vendor/github.com/RoaringBitmap/roaring/smat.go
сгенерированный
поставляемый
Обычный файл
383
vendor/github.com/RoaringBitmap/roaring/smat.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,383 @@
|
|||||||
|
// +build gofuzz
|
||||||
|
|
||||||
|
/*
|
||||||
|
# Instructions for smat testing for roaring
|
||||||
|
|
||||||
|
[smat](https://github.com/mschoch/smat) is a framework that provides
|
||||||
|
state machine assisted fuzz testing.
|
||||||
|
|
||||||
|
To run the smat tests for roaring...
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
$ go get github.com/dvyukov/go-fuzz/go-fuzz
|
||||||
|
$ go get github.com/dvyukov/go-fuzz/go-fuzz-build
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
1. Generate initial smat corpus:
|
||||||
|
```
|
||||||
|
go test -tags=gofuzz -run=TestGenerateSmatCorpus
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Build go-fuzz test program with instrumentation:
|
||||||
|
```
|
||||||
|
go-fuzz-build -func FuzzSmat github.com/RoaringBitmap/roaring
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run go-fuzz:
|
||||||
|
```
|
||||||
|
go-fuzz -bin=./roaring-fuzz.zip -workdir=workdir/ -timeout=200
|
||||||
|
```
|
||||||
|
|
||||||
|
You should see output like...
|
||||||
|
```
|
||||||
|
2016/09/16 13:58:35 slaves: 8, corpus: 1 (3s ago), crashers: 0, restarts: 1/0, execs: 0 (0/sec), cover: 0, uptime: 3s
|
||||||
|
2016/09/16 13:58:38 slaves: 8, corpus: 1 (6s ago), crashers: 0, restarts: 1/0, execs: 0 (0/sec), cover: 0, uptime: 6s
|
||||||
|
2016/09/16 13:58:41 slaves: 8, corpus: 1 (9s ago), crashers: 0, restarts: 1/44, execs: 44 (5/sec), cover: 0, uptime: 9s
|
||||||
|
2016/09/16 13:58:44 slaves: 8, corpus: 1 (12s ago), crashers: 0, restarts: 1/45, execs: 45 (4/sec), cover: 0, uptime: 12s
|
||||||
|
2016/09/16 13:58:47 slaves: 8, corpus: 1 (15s ago), crashers: 0, restarts: 1/46, execs: 46 (3/sec), cover: 0, uptime: 15s
|
||||||
|
2016/09/16 13:58:50 slaves: 8, corpus: 1 (18s ago), crashers: 0, restarts: 1/47, execs: 47 (3/sec), cover: 0, uptime: 18s
|
||||||
|
2016/09/16 13:58:53 slaves: 8, corpus: 1 (21s ago), crashers: 0, restarts: 1/63, execs: 63 (3/sec), cover: 0, uptime: 21s
|
||||||
|
2016/09/16 13:58:56 slaves: 8, corpus: 1 (24s ago), crashers: 0, restarts: 1/65, execs: 65 (3/sec), cover: 0, uptime: 24s
|
||||||
|
2016/09/16 13:58:59 slaves: 8, corpus: 1 (27s ago), crashers: 0, restarts: 1/66, execs: 66 (2/sec), cover: 0, uptime: 27s
|
||||||
|
2016/09/16 13:59:02 slaves: 8, corpus: 1 (30s ago), crashers: 0, restarts: 1/67, execs: 67 (2/sec), cover: 0, uptime: 30s
|
||||||
|
2016/09/16 13:59:05 slaves: 8, corpus: 1 (33s ago), crashers: 0, restarts: 1/83, execs: 83 (3/sec), cover: 0, uptime: 33s
|
||||||
|
2016/09/16 13:59:08 slaves: 8, corpus: 1 (36s ago), crashers: 0, restarts: 1/84, execs: 84 (2/sec), cover: 0, uptime: 36s
|
||||||
|
2016/09/16 13:59:11 slaves: 8, corpus: 2 (0s ago), crashers: 0, restarts: 1/85, execs: 85 (2/sec), cover: 0, uptime: 39s
|
||||||
|
2016/09/16 13:59:14 slaves: 8, corpus: 17 (2s ago), crashers: 0, restarts: 1/86, execs: 86 (2/sec), cover: 480, uptime: 42s
|
||||||
|
2016/09/16 13:59:17 slaves: 8, corpus: 17 (5s ago), crashers: 0, restarts: 1/66, execs: 132 (3/sec), cover: 487, uptime: 45s
|
||||||
|
2016/09/16 13:59:20 slaves: 8, corpus: 17 (8s ago), crashers: 0, restarts: 1/440, execs: 2645 (55/sec), cover: 487, uptime: 48s
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Let it run, and if the # of crashers is > 0, check out the reports in
|
||||||
|
the workdir where you should be able to find the panic goroutine stack
|
||||||
|
traces.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/mschoch/smat"
|
||||||
|
"github.com/willf/bitset"
|
||||||
|
)
|
||||||
|
|
||||||
|
// fuzz test using state machine driven by byte stream.
|
||||||
|
func FuzzSmat(data []byte) int {
|
||||||
|
return smat.Fuzz(&smatContext{}, smat.ActionID('S'), smat.ActionID('T'),
|
||||||
|
smatActionMap, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
var smatDebug = false
|
||||||
|
|
||||||
|
func smatLog(prefix, format string, args ...interface{}) {
|
||||||
|
if smatDebug {
|
||||||
|
fmt.Print(prefix)
|
||||||
|
fmt.Printf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type smatContext struct {
|
||||||
|
pairs []*smatPair
|
||||||
|
|
||||||
|
// Two registers, x & y.
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
|
||||||
|
actions int
|
||||||
|
}
|
||||||
|
|
||||||
|
type smatPair struct {
|
||||||
|
bm *Bitmap
|
||||||
|
bs *bitset.BitSet
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
var smatActionMap = smat.ActionMap{
|
||||||
|
smat.ActionID('X'): smatAction("x++", smatWrap(func(c *smatContext) { c.x++ })),
|
||||||
|
smat.ActionID('x'): smatAction("x--", smatWrap(func(c *smatContext) { c.x-- })),
|
||||||
|
smat.ActionID('Y'): smatAction("y++", smatWrap(func(c *smatContext) { c.y++ })),
|
||||||
|
smat.ActionID('y'): smatAction("y--", smatWrap(func(c *smatContext) { c.y-- })),
|
||||||
|
smat.ActionID('*'): smatAction("x*y", smatWrap(func(c *smatContext) { c.x = c.x * c.y })),
|
||||||
|
smat.ActionID('<'): smatAction("x<<", smatWrap(func(c *smatContext) { c.x = c.x << 1 })),
|
||||||
|
|
||||||
|
smat.ActionID('^'): smatAction("swap", smatWrap(func(c *smatContext) { c.x, c.y = c.y, c.x })),
|
||||||
|
|
||||||
|
smat.ActionID('['): smatAction(" pushPair", smatWrap(smatPushPair)),
|
||||||
|
smat.ActionID(']'): smatAction(" popPair", smatWrap(smatPopPair)),
|
||||||
|
|
||||||
|
smat.ActionID('B'): smatAction(" setBit", smatWrap(smatSetBit)),
|
||||||
|
smat.ActionID('b'): smatAction(" removeBit", smatWrap(smatRemoveBit)),
|
||||||
|
|
||||||
|
smat.ActionID('o'): smatAction(" or", smatWrap(smatOr)),
|
||||||
|
smat.ActionID('a'): smatAction(" and", smatWrap(smatAnd)),
|
||||||
|
|
||||||
|
smat.ActionID('#'): smatAction(" cardinality", smatWrap(smatCardinality)),
|
||||||
|
|
||||||
|
smat.ActionID('O'): smatAction(" orCardinality", smatWrap(smatOrCardinality)),
|
||||||
|
smat.ActionID('A'): smatAction(" andCardinality", smatWrap(smatAndCardinality)),
|
||||||
|
|
||||||
|
smat.ActionID('c'): smatAction(" clear", smatWrap(smatClear)),
|
||||||
|
smat.ActionID('r'): smatAction(" runOptimize", smatWrap(smatRunOptimize)),
|
||||||
|
|
||||||
|
smat.ActionID('e'): smatAction(" isEmpty", smatWrap(smatIsEmpty)),
|
||||||
|
|
||||||
|
smat.ActionID('i'): smatAction(" intersects", smatWrap(smatIntersects)),
|
||||||
|
|
||||||
|
smat.ActionID('f'): smatAction(" flip", smatWrap(smatFlip)),
|
||||||
|
|
||||||
|
smat.ActionID('-'): smatAction(" difference", smatWrap(smatDifference)),
|
||||||
|
}
|
||||||
|
|
||||||
|
var smatRunningPercentActions []smat.PercentAction
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var ids []int
|
||||||
|
for actionId := range smatActionMap {
|
||||||
|
ids = append(ids, int(actionId))
|
||||||
|
}
|
||||||
|
sort.Ints(ids)
|
||||||
|
|
||||||
|
pct := 100 / len(smatActionMap)
|
||||||
|
for _, actionId := range ids {
|
||||||
|
smatRunningPercentActions = append(smatRunningPercentActions,
|
||||||
|
smat.PercentAction{pct, smat.ActionID(actionId)})
|
||||||
|
}
|
||||||
|
|
||||||
|
smatActionMap[smat.ActionID('S')] = smatAction("SETUP", smatSetupFunc)
|
||||||
|
smatActionMap[smat.ActionID('T')] = smatAction("TEARDOWN", smatTeardownFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only have one smat state: running.
|
||||||
|
func smatRunning(next byte) smat.ActionID {
|
||||||
|
return smat.PercentExecute(next, smatRunningPercentActions...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatAction(name string, f func(ctx smat.Context) (smat.State, error)) func(smat.Context) (smat.State, error) {
|
||||||
|
return func(ctx smat.Context) (smat.State, error) {
|
||||||
|
c := ctx.(*smatContext)
|
||||||
|
c.actions++
|
||||||
|
|
||||||
|
smatLog(" ", "%s\n", name)
|
||||||
|
|
||||||
|
return f(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates an smat action func based on a simple callback.
|
||||||
|
func smatWrap(cb func(c *smatContext)) func(smat.Context) (next smat.State, err error) {
|
||||||
|
return func(ctx smat.Context) (next smat.State, err error) {
|
||||||
|
c := ctx.(*smatContext)
|
||||||
|
cb(c)
|
||||||
|
return smatRunning, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invokes a callback function with the input v bounded to len(c.pairs).
|
||||||
|
func (c *smatContext) withPair(v int, cb func(*smatPair)) {
|
||||||
|
if len(c.pairs) > 0 {
|
||||||
|
if v < 0 {
|
||||||
|
v = -v
|
||||||
|
}
|
||||||
|
v = v % len(c.pairs)
|
||||||
|
cb(c.pairs[v])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
func smatSetupFunc(ctx smat.Context) (next smat.State, err error) {
|
||||||
|
return smatRunning, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatTeardownFunc(ctx smat.Context) (next smat.State, err error) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
|
func smatPushPair(c *smatContext) {
|
||||||
|
c.pairs = append(c.pairs, &smatPair{
|
||||||
|
bm: NewBitmap(),
|
||||||
|
bs: bitset.New(100),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatPopPair(c *smatContext) {
|
||||||
|
if len(c.pairs) > 0 {
|
||||||
|
c.pairs = c.pairs[0 : len(c.pairs)-1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatSetBit(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(p *smatPair) {
|
||||||
|
y := uint32(c.y)
|
||||||
|
p.bm.AddInt(int(y))
|
||||||
|
p.bs.Set(uint(y))
|
||||||
|
p.checkEquals()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatRemoveBit(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(p *smatPair) {
|
||||||
|
y := uint32(c.y)
|
||||||
|
p.bm.Remove(y)
|
||||||
|
p.bs.Clear(uint(y))
|
||||||
|
p.checkEquals()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatAnd(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
c.withPair(c.y, func(py *smatPair) {
|
||||||
|
px.bm.And(py.bm)
|
||||||
|
px.bs = px.bs.Intersection(py.bs)
|
||||||
|
px.checkEquals()
|
||||||
|
py.checkEquals()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatOr(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
c.withPair(c.y, func(py *smatPair) {
|
||||||
|
px.bm.Or(py.bm)
|
||||||
|
px.bs = px.bs.Union(py.bs)
|
||||||
|
px.checkEquals()
|
||||||
|
py.checkEquals()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatAndCardinality(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
c.withPair(c.y, func(py *smatPair) {
|
||||||
|
c0 := px.bm.AndCardinality(py.bm)
|
||||||
|
c1 := px.bs.IntersectionCardinality(py.bs)
|
||||||
|
if c0 != uint64(c1) {
|
||||||
|
panic("expected same add cardinality")
|
||||||
|
}
|
||||||
|
px.checkEquals()
|
||||||
|
py.checkEquals()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatOrCardinality(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
c.withPair(c.y, func(py *smatPair) {
|
||||||
|
c0 := px.bm.OrCardinality(py.bm)
|
||||||
|
c1 := px.bs.UnionCardinality(py.bs)
|
||||||
|
if c0 != uint64(c1) {
|
||||||
|
panic("expected same or cardinality")
|
||||||
|
}
|
||||||
|
px.checkEquals()
|
||||||
|
py.checkEquals()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatRunOptimize(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
px.bm.RunOptimize()
|
||||||
|
px.checkEquals()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatClear(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
px.bm.Clear()
|
||||||
|
px.bs = px.bs.ClearAll()
|
||||||
|
px.checkEquals()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatCardinality(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
c0 := px.bm.GetCardinality()
|
||||||
|
c1 := px.bs.Count()
|
||||||
|
if c0 != uint64(c1) {
|
||||||
|
panic("expected same cardinality")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatIsEmpty(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
c0 := px.bm.IsEmpty()
|
||||||
|
c1 := px.bs.None()
|
||||||
|
if c0 != c1 {
|
||||||
|
panic("expected same is empty")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatIntersects(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
c.withPair(c.y, func(py *smatPair) {
|
||||||
|
v0 := px.bm.Intersects(py.bm)
|
||||||
|
v1 := px.bs.IntersectionCardinality(py.bs) > 0
|
||||||
|
if v0 != v1 {
|
||||||
|
panic("intersects not equal")
|
||||||
|
}
|
||||||
|
|
||||||
|
px.checkEquals()
|
||||||
|
py.checkEquals()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatFlip(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(p *smatPair) {
|
||||||
|
y := uint32(c.y)
|
||||||
|
p.bm.Flip(uint64(y), uint64(y)+1)
|
||||||
|
p.bs = p.bs.Flip(uint(y))
|
||||||
|
p.checkEquals()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func smatDifference(c *smatContext) {
|
||||||
|
c.withPair(c.x, func(px *smatPair) {
|
||||||
|
c.withPair(c.y, func(py *smatPair) {
|
||||||
|
px.bm.AndNot(py.bm)
|
||||||
|
px.bs = px.bs.Difference(py.bs)
|
||||||
|
px.checkEquals()
|
||||||
|
py.checkEquals()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *smatPair) checkEquals() {
|
||||||
|
if !p.equalsBitSet(p.bs, p.bm) {
|
||||||
|
panic("bitset mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *smatPair) equalsBitSet(a *bitset.BitSet, b *Bitmap) bool {
|
||||||
|
for i, e := a.NextSet(0); e; i, e = a.NextSet(i + 1) {
|
||||||
|
if !b.ContainsInt(int(i)) {
|
||||||
|
fmt.Printf("in a bitset, not b bitmap, i: %d\n", i)
|
||||||
|
fmt.Printf(" a bitset: %s\n b bitmap: %s\n",
|
||||||
|
a.String(), b.String())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i := b.Iterator()
|
||||||
|
for i.HasNext() {
|
||||||
|
v := i.Next()
|
||||||
|
if !a.Test(uint(v)) {
|
||||||
|
fmt.Printf("in b bitmap, not a bitset, v: %d\n", v)
|
||||||
|
fmt.Printf(" a bitset: %s\n b bitmap: %s\n",
|
||||||
|
a.String(), b.String())
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
304
vendor/github.com/RoaringBitmap/roaring/util.go
сгенерированный
поставляемый
Обычный файл
304
vendor/github.com/RoaringBitmap/roaring/util.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,304 @@
|
|||||||
|
package roaring
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
arrayDefaultMaxSize = 4096 // containers with 4096 or fewer integers should be array containers.
|
||||||
|
arrayLazyLowerBound = 1024
|
||||||
|
maxCapacity = 1 << 16
|
||||||
|
serialCookieNoRunContainer = 12346 // only arrays and bitmaps
|
||||||
|
invalidCardinality = -1
|
||||||
|
serialCookie = 12347 // runs, arrays, and bitmaps
|
||||||
|
noOffsetThreshold = 4
|
||||||
|
|
||||||
|
// MaxUint32 is the largest uint32 value.
|
||||||
|
MaxUint32 = 4294967295
|
||||||
|
|
||||||
|
// MaxRange is One more than the maximum allowed bitmap bit index. For use as an upper
|
||||||
|
// bound for ranges.
|
||||||
|
MaxRange uint64 = MaxUint32 + 1
|
||||||
|
|
||||||
|
// MaxUint16 is the largest 16 bit unsigned int.
|
||||||
|
// This is the largest value an interval16 can store.
|
||||||
|
MaxUint16 = 65535
|
||||||
|
|
||||||
|
// Compute wordSizeInBytes, the size of a word in bytes.
|
||||||
|
_m = ^uint64(0)
|
||||||
|
_logS = _m>>8&1 + _m>>16&1 + _m>>32&1
|
||||||
|
wordSizeInBytes = 1 << _logS
|
||||||
|
|
||||||
|
// other constants used in ctz_generic.go
|
||||||
|
wordSizeInBits = wordSizeInBytes << 3 // word size in bits
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxWord = 1<<wordSizeInBits - 1
|
||||||
|
|
||||||
|
// doesn't apply to runContainers
|
||||||
|
func getSizeInBytesFromCardinality(card int) int {
|
||||||
|
if card > arrayDefaultMaxSize {
|
||||||
|
// bitmapContainer
|
||||||
|
return maxCapacity / 8
|
||||||
|
}
|
||||||
|
// arrayContainer
|
||||||
|
return 2 * card
|
||||||
|
}
|
||||||
|
|
||||||
|
func fill(arr []uint64, val uint64) {
|
||||||
|
for i := range arr {
|
||||||
|
arr[i] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func fillRange(arr []uint64, start, end int, val uint64) {
|
||||||
|
for i := start; i < end; i++ {
|
||||||
|
arr[i] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillArrayAND(container []uint16, bitmap1, bitmap2 []uint64) {
|
||||||
|
if len(bitmap1) != len(bitmap2) {
|
||||||
|
panic("array lengths don't match")
|
||||||
|
}
|
||||||
|
// TODO: rewrite in assembly
|
||||||
|
pos := 0
|
||||||
|
for k := range bitmap1 {
|
||||||
|
bitset := bitmap1[k] & bitmap2[k]
|
||||||
|
for bitset != 0 {
|
||||||
|
t := bitset & -bitset
|
||||||
|
container[pos] = uint16((k*64 + int(popcount(t-1))))
|
||||||
|
pos = pos + 1
|
||||||
|
bitset ^= t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillArrayANDNOT(container []uint16, bitmap1, bitmap2 []uint64) {
|
||||||
|
if len(bitmap1) != len(bitmap2) {
|
||||||
|
panic("array lengths don't match")
|
||||||
|
}
|
||||||
|
// TODO: rewrite in assembly
|
||||||
|
pos := 0
|
||||||
|
for k := range bitmap1 {
|
||||||
|
bitset := bitmap1[k] &^ bitmap2[k]
|
||||||
|
for bitset != 0 {
|
||||||
|
t := bitset & -bitset
|
||||||
|
container[pos] = uint16((k*64 + int(popcount(t-1))))
|
||||||
|
pos = pos + 1
|
||||||
|
bitset ^= t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fillArrayXOR(container []uint16, bitmap1, bitmap2 []uint64) {
|
||||||
|
if len(bitmap1) != len(bitmap2) {
|
||||||
|
panic("array lengths don't match")
|
||||||
|
}
|
||||||
|
// TODO: rewrite in assembly
|
||||||
|
pos := 0
|
||||||
|
for k := 0; k < len(bitmap1); k++ {
|
||||||
|
bitset := bitmap1[k] ^ bitmap2[k]
|
||||||
|
for bitset != 0 {
|
||||||
|
t := bitset & -bitset
|
||||||
|
container[pos] = uint16((k*64 + int(popcount(t-1))))
|
||||||
|
pos = pos + 1
|
||||||
|
bitset ^= t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func highbits(x uint32) uint16 {
|
||||||
|
return uint16(x >> 16)
|
||||||
|
}
|
||||||
|
func lowbits(x uint32) uint16 {
|
||||||
|
return uint16(x & maxLowBit)
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxLowBit = 0xFFFF
|
||||||
|
|
||||||
|
func flipBitmapRange(bitmap []uint64, start int, end int) {
|
||||||
|
if start >= end {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
firstword := start / 64
|
||||||
|
endword := (end - 1) / 64
|
||||||
|
bitmap[firstword] ^= ^(^uint64(0) << uint(start%64))
|
||||||
|
for i := firstword; i < endword; i++ {
|
||||||
|
bitmap[i] = ^bitmap[i]
|
||||||
|
}
|
||||||
|
bitmap[endword] ^= ^uint64(0) >> (uint(-end) % 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetBitmapRange(bitmap []uint64, start int, end int) {
|
||||||
|
if start >= end {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
firstword := start / 64
|
||||||
|
endword := (end - 1) / 64
|
||||||
|
if firstword == endword {
|
||||||
|
bitmap[firstword] &= ^((^uint64(0) << uint(start%64)) & (^uint64(0) >> (uint(-end) % 64)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bitmap[firstword] &= ^(^uint64(0) << uint(start%64))
|
||||||
|
for i := firstword + 1; i < endword; i++ {
|
||||||
|
bitmap[i] = 0
|
||||||
|
}
|
||||||
|
bitmap[endword] &= ^(^uint64(0) >> (uint(-end) % 64))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func setBitmapRange(bitmap []uint64, start int, end int) {
|
||||||
|
if start >= end {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
firstword := start / 64
|
||||||
|
endword := (end - 1) / 64
|
||||||
|
if firstword == endword {
|
||||||
|
bitmap[firstword] |= (^uint64(0) << uint(start%64)) & (^uint64(0) >> (uint(-end) % 64))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bitmap[firstword] |= ^uint64(0) << uint(start%64)
|
||||||
|
for i := firstword + 1; i < endword; i++ {
|
||||||
|
bitmap[i] = ^uint64(0)
|
||||||
|
}
|
||||||
|
bitmap[endword] |= ^uint64(0) >> (uint(-end) % 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
func flipBitmapRangeAndCardinalityChange(bitmap []uint64, start int, end int) int {
|
||||||
|
before := wordCardinalityForBitmapRange(bitmap, start, end)
|
||||||
|
flipBitmapRange(bitmap, start, end)
|
||||||
|
after := wordCardinalityForBitmapRange(bitmap, start, end)
|
||||||
|
return int(after - before)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetBitmapRangeAndCardinalityChange(bitmap []uint64, start int, end int) int {
|
||||||
|
before := wordCardinalityForBitmapRange(bitmap, start, end)
|
||||||
|
resetBitmapRange(bitmap, start, end)
|
||||||
|
after := wordCardinalityForBitmapRange(bitmap, start, end)
|
||||||
|
return int(after - before)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setBitmapRangeAndCardinalityChange(bitmap []uint64, start int, end int) int {
|
||||||
|
before := wordCardinalityForBitmapRange(bitmap, start, end)
|
||||||
|
setBitmapRange(bitmap, start, end)
|
||||||
|
after := wordCardinalityForBitmapRange(bitmap, start, end)
|
||||||
|
return int(after - before)
|
||||||
|
}
|
||||||
|
|
||||||
|
func wordCardinalityForBitmapRange(bitmap []uint64, start int, end int) uint64 {
|
||||||
|
answer := uint64(0)
|
||||||
|
if start >= end {
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
firstword := start / 64
|
||||||
|
endword := (end - 1) / 64
|
||||||
|
for i := firstword; i <= endword; i++ {
|
||||||
|
answer += popcount(bitmap[i])
|
||||||
|
}
|
||||||
|
return answer
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectBitPosition(w uint64, j int) int {
|
||||||
|
seen := 0
|
||||||
|
|
||||||
|
// Divide 64bit
|
||||||
|
part := w & 0xFFFFFFFF
|
||||||
|
n := popcount(part)
|
||||||
|
if n <= uint64(j) {
|
||||||
|
part = w >> 32
|
||||||
|
seen += 32
|
||||||
|
j -= int(n)
|
||||||
|
}
|
||||||
|
w = part
|
||||||
|
|
||||||
|
// Divide 32bit
|
||||||
|
part = w & 0xFFFF
|
||||||
|
n = popcount(part)
|
||||||
|
if n <= uint64(j) {
|
||||||
|
part = w >> 16
|
||||||
|
seen += 16
|
||||||
|
j -= int(n)
|
||||||
|
}
|
||||||
|
w = part
|
||||||
|
|
||||||
|
// Divide 16bit
|
||||||
|
part = w & 0xFF
|
||||||
|
n = popcount(part)
|
||||||
|
if n <= uint64(j) {
|
||||||
|
part = w >> 8
|
||||||
|
seen += 8
|
||||||
|
j -= int(n)
|
||||||
|
}
|
||||||
|
w = part
|
||||||
|
|
||||||
|
// Lookup in final byte
|
||||||
|
var counter uint
|
||||||
|
for counter = 0; counter < 8; counter++ {
|
||||||
|
j -= int((w >> counter) & 1)
|
||||||
|
if j < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seen + int(counter)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func panicOn(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ph struct {
|
||||||
|
orig int
|
||||||
|
rand int
|
||||||
|
}
|
||||||
|
|
||||||
|
type pha []ph
|
||||||
|
|
||||||
|
func (p pha) Len() int { return len(p) }
|
||||||
|
func (p pha) Less(i, j int) bool { return p[i].rand < p[j].rand }
|
||||||
|
func (p pha) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||||
|
|
||||||
|
func getRandomPermutation(n int) []int {
|
||||||
|
r := make([]ph, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
r[i].orig = i
|
||||||
|
r[i].rand = rand.Intn(1 << 29)
|
||||||
|
}
|
||||||
|
sort.Sort(pha(r))
|
||||||
|
m := make([]int, n)
|
||||||
|
for i := range m {
|
||||||
|
m[i] = r[i].orig
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func minOfInt(a, b int) int {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxOfInt(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxOfUint16(a, b uint16) uint16 {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func minOfUint16(a, b uint16) uint16 {
|
||||||
|
if a < b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
19
vendor/github.com/blevesearch/bleve/.gitignore
сгенерированный
поставляемый
Обычный файл
19
vendor/github.com/blevesearch/bleve/.gitignore
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,19 @@
|
|||||||
|
#*
|
||||||
|
*.sublime-*
|
||||||
|
*~
|
||||||
|
.#*
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
**/.idea/
|
||||||
|
**/*.iml
|
||||||
|
.DS_Store
|
||||||
|
query_string.y.go.tmp
|
||||||
|
/analysis/token_filters/cld2/cld2-read-only
|
||||||
|
/analysis/token_filters/cld2/libcld2_full.a
|
||||||
|
/cmd/bleve/bleve
|
||||||
|
vendor/**
|
||||||
|
!vendor/manifest
|
||||||
|
/y.output
|
||||||
|
/search/query/y.output
|
||||||
|
*.test
|
||||||
|
tags
|
||||||
25
vendor/github.com/blevesearch/bleve/.travis.yml
сгенерированный
поставляемый
Обычный файл
25
vendor/github.com/blevesearch/bleve/.travis.yml
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,25 @@
|
|||||||
|
sudo: false
|
||||||
|
|
||||||
|
language: go
|
||||||
|
|
||||||
|
go:
|
||||||
|
- "1.12.x"
|
||||||
|
- "1.13.x"
|
||||||
|
- "1.14.x"
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go get golang.org/x/tools/cmd/cover
|
||||||
|
- go get github.com/mattn/goveralls
|
||||||
|
- go get github.com/kisielk/errcheck
|
||||||
|
- go get -u github.com/FiloSottile/gvt
|
||||||
|
- gvt restore
|
||||||
|
- go test -race -v $(go list ./... | grep -v vendor/)
|
||||||
|
- go vet $(go list ./... | grep -v vendor/)
|
||||||
|
- go test ./test -v -indexType scorch
|
||||||
|
- errcheck -ignorepkg fmt $(go list ./... | grep -v vendor/);
|
||||||
|
- docs/project-code-coverage.sh
|
||||||
|
- docs/build_children.sh
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
- marty.schoch@gmail.com
|
||||||
16
vendor/github.com/blevesearch/bleve/CONTRIBUTING.md
сгенерированный
поставляемый
Обычный файл
16
vendor/github.com/blevesearch/bleve/CONTRIBUTING.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,16 @@
|
|||||||
|
# Contributing to Bleve
|
||||||
|
|
||||||
|
We look forward to your contributions, but ask that you first review these guidelines.
|
||||||
|
|
||||||
|
### Sign the CLA
|
||||||
|
|
||||||
|
As Bleve is a Couchbase project we require contributors accept the [Couchbase Contributor License Agreement](http://review.couchbase.org/static/individual_agreement.html). To sign this agreement log into the Couchbase [code review tool](http://review.couchbase.org/). The Bleve project does not use this code review tool but it is still used to track acceptance of the contributor license agreements.
|
||||||
|
|
||||||
|
### Submitting a Pull Request
|
||||||
|
|
||||||
|
All types of contributions are welcome, but please keep the following in mind:
|
||||||
|
|
||||||
|
- If you're planning a large change, you should really discuss it in a github issue or on the google group first. This helps avoid duplicate effort and spending time on something that may not be merged.
|
||||||
|
- Existing tests should continue to pass, new tests for the contribution are nice to have.
|
||||||
|
- All code should have gone through `go fmt`
|
||||||
|
- All code should pass `go vet`
|
||||||
202
vendor/github.com/blevesearch/bleve/LICENSE
сгенерированный
поставляемый
Обычный файл
202
vendor/github.com/blevesearch/bleve/LICENSE
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
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.
|
||||||
67
vendor/github.com/blevesearch/bleve/README.md
сгенерированный
поставляемый
Обычный файл
67
vendor/github.com/blevesearch/bleve/README.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,67 @@
|
|||||||
|
#  bleve
|
||||||
|
|
||||||
|
[](https://travis-ci.org/blevesearch/bleve) [](https://coveralls.io/github/blevesearch/bleve?branch=master) [](https://godoc.org/github.com/blevesearch/bleve)
|
||||||
|
[](https://gitter.im/blevesearch/bleve?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
[](https://codebeat.co/projects/github-com-blevesearch-bleve)
|
||||||
|
[](https://goreportcard.com/report/blevesearch/bleve)
|
||||||
|
[](https://sourcegraph.com/github.com/blevesearch/bleve?badge) [](https://opensource.org/licenses/Apache-2.0)
|
||||||
|
|
||||||
|
modern text indexing in go - [blevesearch.com](http://www.blevesearch.com/)
|
||||||
|
|
||||||
|
Try out bleve live by [searching the bleve website](http://www.blevesearch.com/search/?q=bleve).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
* Index any go data structure (including JSON)
|
||||||
|
* Intelligent defaults backed up by powerful configuration
|
||||||
|
* Supported field types:
|
||||||
|
* Text, Numeric, Date
|
||||||
|
* Supported query types:
|
||||||
|
* Term, Phrase, Match, Match Phrase, Prefix
|
||||||
|
* Conjunction, Disjunction, Boolean
|
||||||
|
* Numeric Range, Date Range
|
||||||
|
* Simple query [syntax](http://www.blevesearch.com/docs/Query-String-Query/) for human entry
|
||||||
|
* tf-idf Scoring
|
||||||
|
* Search result match highlighting
|
||||||
|
* Supports Aggregating Facets:
|
||||||
|
* Terms Facet
|
||||||
|
* Numeric Range Facet
|
||||||
|
* Date Range Facet
|
||||||
|
|
||||||
|
## Discussion
|
||||||
|
|
||||||
|
Discuss usage and development of bleve in the [google group](https://groups.google.com/forum/#!forum/bleve).
|
||||||
|
|
||||||
|
## Indexing
|
||||||
|
|
||||||
|
```go
|
||||||
|
message := struct{
|
||||||
|
Id string
|
||||||
|
From string
|
||||||
|
Body string
|
||||||
|
}{
|
||||||
|
Id: "example",
|
||||||
|
From: "marty.schoch@gmail.com",
|
||||||
|
Body: "bleve indexing is easy",
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping := bleve.NewIndexMapping()
|
||||||
|
index, err := bleve.New("example.bleve", mapping)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
index.Index(message.Id, message)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Querying
|
||||||
|
|
||||||
|
```go
|
||||||
|
index, _ := bleve.Open("example.bleve")
|
||||||
|
query := bleve.NewQueryStringQuery("bleve")
|
||||||
|
searchRequest := bleve.NewSearchRequest(query)
|
||||||
|
searchResult, _ := index.Search(searchRequest)
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Apache License Version 2.0
|
||||||
38
vendor/github.com/blevesearch/bleve/analysis/analyzer/keyword/keyword.go
сгенерированный
поставляемый
Обычный файл
38
vendor/github.com/blevesearch/bleve/analysis/analyzer/keyword/keyword.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 keyword
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/analysis/tokenizer/single"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Name = "keyword"
|
||||||
|
|
||||||
|
func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) {
|
||||||
|
keywordTokenizer, err := cache.TokenizerNamed(single.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rv := analysis.Analyzer{
|
||||||
|
Tokenizer: keywordTokenizer,
|
||||||
|
}
|
||||||
|
return &rv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterAnalyzer(Name, AnalyzerConstructor)
|
||||||
|
}
|
||||||
52
vendor/github.com/blevesearch/bleve/analysis/analyzer/standard/standard.go
сгенерированный
поставляемый
Обычный файл
52
vendor/github.com/blevesearch/bleve/analysis/analyzer/standard/standard.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 standard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/analysis/lang/en"
|
||||||
|
"github.com/blevesearch/bleve/analysis/token/lowercase"
|
||||||
|
"github.com/blevesearch/bleve/analysis/tokenizer/unicode"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Name = "standard"
|
||||||
|
|
||||||
|
func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) {
|
||||||
|
tokenizer, err := cache.TokenizerNamed(unicode.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
toLowerFilter, err := cache.TokenFilterNamed(lowercase.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stopEnFilter, err := cache.TokenFilterNamed(en.StopName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rv := analysis.Analyzer{
|
||||||
|
Tokenizer: tokenizer,
|
||||||
|
TokenFilters: []analysis.TokenFilter{
|
||||||
|
toLowerFilter,
|
||||||
|
stopEnFilter,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return &rv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterAnalyzer(Name, AnalyzerConstructor)
|
||||||
|
}
|
||||||
64
vendor/github.com/blevesearch/bleve/analysis/datetime/flexible/flexible.go
сгенерированный
поставляемый
Обычный файл
64
vendor/github.com/blevesearch/bleve/analysis/datetime/flexible/flexible.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 flexible
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Name = "flexiblego"
|
||||||
|
|
||||||
|
type DateTimeParser struct {
|
||||||
|
layouts []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(layouts []string) *DateTimeParser {
|
||||||
|
return &DateTimeParser{
|
||||||
|
layouts: layouts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DateTimeParser) ParseDateTime(input string) (time.Time, error) {
|
||||||
|
for _, layout := range p.layouts {
|
||||||
|
rv, err := time.Parse(layout, input)
|
||||||
|
if err == nil {
|
||||||
|
return rv, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return time.Time{}, analysis.ErrInvalidDateTime
|
||||||
|
}
|
||||||
|
|
||||||
|
func DateTimeParserConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.DateTimeParser, error) {
|
||||||
|
layouts, ok := config["layouts"].([]interface{})
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("must specify layouts")
|
||||||
|
}
|
||||||
|
var layoutStrs []string
|
||||||
|
for _, layout := range layouts {
|
||||||
|
layoutStr, ok := layout.(string)
|
||||||
|
if ok {
|
||||||
|
layoutStrs = append(layoutStrs, layoutStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return New(layoutStrs), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterDateTimeParser(Name, DateTimeParserConstructor)
|
||||||
|
}
|
||||||
45
vendor/github.com/blevesearch/bleve/analysis/datetime/optional/optional.go
сгенерированный
поставляемый
Обычный файл
45
vendor/github.com/blevesearch/bleve/analysis/datetime/optional/optional.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 optional
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/analysis/datetime/flexible"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Name = "dateTimeOptional"
|
||||||
|
|
||||||
|
const rfc3339NoTimezone = "2006-01-02T15:04:05"
|
||||||
|
const rfc3339NoTimezoneNoT = "2006-01-02 15:04:05"
|
||||||
|
const rfc3339NoTime = "2006-01-02"
|
||||||
|
|
||||||
|
var layouts = []string{
|
||||||
|
time.RFC3339Nano,
|
||||||
|
time.RFC3339,
|
||||||
|
rfc3339NoTimezone,
|
||||||
|
rfc3339NoTimezoneNoT,
|
||||||
|
rfc3339NoTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
func DateTimeParserConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.DateTimeParser, error) {
|
||||||
|
return flexible.New(layouts), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterDateTimeParser(Name, DateTimeParserConstructor)
|
||||||
|
}
|
||||||
152
vendor/github.com/blevesearch/bleve/analysis/freq.go
сгенерированный
поставляемый
Обычный файл
152
vendor/github.com/blevesearch/bleve/analysis/freq.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,152 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 analysis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/size"
|
||||||
|
)
|
||||||
|
|
||||||
|
var reflectStaticSizeTokenLocation int
|
||||||
|
var reflectStaticSizeTokenFreq int
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var tl TokenLocation
|
||||||
|
reflectStaticSizeTokenLocation = int(reflect.TypeOf(tl).Size())
|
||||||
|
var tf TokenFreq
|
||||||
|
reflectStaticSizeTokenFreq = int(reflect.TypeOf(tf).Size())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenLocation represents one occurrence of a term at a particular location in
|
||||||
|
// a field. Start, End and Position have the same meaning as in analysis.Token.
|
||||||
|
// Field and ArrayPositions identify the field value in the source document.
|
||||||
|
// See document.Field for details.
|
||||||
|
type TokenLocation struct {
|
||||||
|
Field string
|
||||||
|
ArrayPositions []uint64
|
||||||
|
Start int
|
||||||
|
End int
|
||||||
|
Position int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tl *TokenLocation) Size() int {
|
||||||
|
rv := reflectStaticSizeTokenLocation
|
||||||
|
rv += len(tl.ArrayPositions) * size.SizeOfUint64
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenFreq represents all the occurrences of a term in all fields of a
|
||||||
|
// document.
|
||||||
|
type TokenFreq struct {
|
||||||
|
Term []byte
|
||||||
|
Locations []*TokenLocation
|
||||||
|
frequency int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tf *TokenFreq) Size() int {
|
||||||
|
rv := reflectStaticSizeTokenFreq
|
||||||
|
rv += len(tf.Term)
|
||||||
|
for _, loc := range tf.Locations {
|
||||||
|
rv += loc.Size()
|
||||||
|
}
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tf *TokenFreq) Frequency() int {
|
||||||
|
return tf.frequency
|
||||||
|
}
|
||||||
|
|
||||||
|
// TokenFrequencies maps document terms to their combined frequencies from all
|
||||||
|
// fields.
|
||||||
|
type TokenFrequencies map[string]*TokenFreq
|
||||||
|
|
||||||
|
func (tfs TokenFrequencies) Size() int {
|
||||||
|
rv := size.SizeOfMap
|
||||||
|
rv += len(tfs) * (size.SizeOfString + size.SizeOfPtr)
|
||||||
|
for k, v := range tfs {
|
||||||
|
rv += len(k)
|
||||||
|
rv += v.Size()
|
||||||
|
}
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tfs TokenFrequencies) MergeAll(remoteField string, other TokenFrequencies) {
|
||||||
|
// walk the new token frequencies
|
||||||
|
for tfk, tf := range other {
|
||||||
|
// set the remoteField value in incoming token freqs
|
||||||
|
for _, l := range tf.Locations {
|
||||||
|
l.Field = remoteField
|
||||||
|
}
|
||||||
|
existingTf, exists := tfs[tfk]
|
||||||
|
if exists {
|
||||||
|
existingTf.Locations = append(existingTf.Locations, tf.Locations...)
|
||||||
|
existingTf.frequency = existingTf.frequency + tf.frequency
|
||||||
|
} else {
|
||||||
|
tfs[tfk] = &TokenFreq{
|
||||||
|
Term: tf.Term,
|
||||||
|
frequency: tf.frequency,
|
||||||
|
Locations: make([]*TokenLocation, len(tf.Locations)),
|
||||||
|
}
|
||||||
|
copy(tfs[tfk].Locations, tf.Locations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TokenFrequency(tokens TokenStream, arrayPositions []uint64, includeTermVectors bool) TokenFrequencies {
|
||||||
|
rv := make(map[string]*TokenFreq, len(tokens))
|
||||||
|
|
||||||
|
if includeTermVectors {
|
||||||
|
tls := make([]TokenLocation, len(tokens))
|
||||||
|
tlNext := 0
|
||||||
|
|
||||||
|
for _, token := range tokens {
|
||||||
|
tls[tlNext] = TokenLocation{
|
||||||
|
ArrayPositions: arrayPositions,
|
||||||
|
Start: token.Start,
|
||||||
|
End: token.End,
|
||||||
|
Position: token.Position,
|
||||||
|
}
|
||||||
|
|
||||||
|
curr, ok := rv[string(token.Term)]
|
||||||
|
if ok {
|
||||||
|
curr.Locations = append(curr.Locations, &tls[tlNext])
|
||||||
|
curr.frequency++
|
||||||
|
} else {
|
||||||
|
rv[string(token.Term)] = &TokenFreq{
|
||||||
|
Term: token.Term,
|
||||||
|
Locations: []*TokenLocation{&tls[tlNext]},
|
||||||
|
frequency: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tlNext++
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, token := range tokens {
|
||||||
|
curr, exists := rv[string(token.Term)]
|
||||||
|
if exists {
|
||||||
|
curr.frequency++
|
||||||
|
} else {
|
||||||
|
rv[string(token.Term)] = &TokenFreq{
|
||||||
|
Term: token.Term,
|
||||||
|
frequency: 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv
|
||||||
|
}
|
||||||
70
vendor/github.com/blevesearch/bleve/analysis/lang/en/analyzer_en.go
сгенерированный
поставляемый
Обычный файл
70
vendor/github.com/blevesearch/bleve/analysis/lang/en/analyzer_en.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,70 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 en implements an analyzer with reasonable defaults for processing
|
||||||
|
// English text.
|
||||||
|
//
|
||||||
|
// It strips possessive suffixes ('s), transforms tokens to lower case,
|
||||||
|
// removes stopwords from a built-in list, and applies porter stemming.
|
||||||
|
//
|
||||||
|
// The built-in stopwords list is defined in EnglishStopWords.
|
||||||
|
package en
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/analysis/token/lowercase"
|
||||||
|
"github.com/blevesearch/bleve/analysis/token/porter"
|
||||||
|
"github.com/blevesearch/bleve/analysis/tokenizer/unicode"
|
||||||
|
)
|
||||||
|
|
||||||
|
const AnalyzerName = "en"
|
||||||
|
|
||||||
|
func AnalyzerConstructor(config map[string]interface{}, cache *registry.Cache) (*analysis.Analyzer, error) {
|
||||||
|
tokenizer, err := cache.TokenizerNamed(unicode.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
possEnFilter, err := cache.TokenFilterNamed(PossessiveName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
toLowerFilter, err := cache.TokenFilterNamed(lowercase.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stopEnFilter, err := cache.TokenFilterNamed(StopName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stemmerEnFilter, err := cache.TokenFilterNamed(porter.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rv := analysis.Analyzer{
|
||||||
|
Tokenizer: tokenizer,
|
||||||
|
TokenFilters: []analysis.TokenFilter{
|
||||||
|
possEnFilter,
|
||||||
|
toLowerFilter,
|
||||||
|
stopEnFilter,
|
||||||
|
stemmerEnFilter,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return &rv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterAnalyzer(AnalyzerName, AnalyzerConstructor)
|
||||||
|
}
|
||||||
67
vendor/github.com/blevesearch/bleve/analysis/lang/en/possessive_filter_en.go
сгенерированный
поставляемый
Обычный файл
67
vendor/github.com/blevesearch/bleve/analysis/lang/en/possessive_filter_en.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,67 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 en
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PossessiveName is the name PossessiveFilter is registered as
|
||||||
|
// in the bleve registry.
|
||||||
|
const PossessiveName = "possessive_en"
|
||||||
|
|
||||||
|
const rightSingleQuotationMark = '’'
|
||||||
|
const apostrophe = '\''
|
||||||
|
const fullWidthApostrophe = '''
|
||||||
|
|
||||||
|
const apostropheChars = rightSingleQuotationMark + apostrophe + fullWidthApostrophe
|
||||||
|
|
||||||
|
// PossessiveFilter implements a TokenFilter which
|
||||||
|
// strips the English possessive suffix ('s) from tokens.
|
||||||
|
// It handle a variety of apostrophe types, is case-insensitive
|
||||||
|
// and doesn't distinguish between possessive and contraction.
|
||||||
|
// (ie "She's So Rad" becomes "She So Rad")
|
||||||
|
type PossessiveFilter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPossessiveFilter() *PossessiveFilter {
|
||||||
|
return &PossessiveFilter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PossessiveFilter) Filter(input analysis.TokenStream) analysis.TokenStream {
|
||||||
|
for _, token := range input {
|
||||||
|
lastRune, lastRuneSize := utf8.DecodeLastRune(token.Term)
|
||||||
|
if lastRune == 's' || lastRune == 'S' {
|
||||||
|
nextLastRune, nextLastRuneSize := utf8.DecodeLastRune(token.Term[:len(token.Term)-lastRuneSize])
|
||||||
|
if nextLastRune == rightSingleQuotationMark ||
|
||||||
|
nextLastRune == apostrophe ||
|
||||||
|
nextLastRune == fullWidthApostrophe {
|
||||||
|
token.Term = token.Term[:len(token.Term)-lastRuneSize-nextLastRuneSize]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
|
func PossessiveFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) {
|
||||||
|
return NewPossessiveFilter(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterTokenFilter(PossessiveName, PossessiveFilterConstructor)
|
||||||
|
}
|
||||||
49
vendor/github.com/blevesearch/bleve/analysis/lang/en/stemmer_en_snowball.go
сгенерированный
поставляемый
Обычный файл
49
vendor/github.com/blevesearch/bleve/analysis/lang/en/stemmer_en_snowball.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) 2020 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 en
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
|
||||||
|
"github.com/blevesearch/snowballstem"
|
||||||
|
"github.com/blevesearch/snowballstem/english"
|
||||||
|
)
|
||||||
|
|
||||||
|
const SnowballStemmerName = "stemmer_en_snowball"
|
||||||
|
|
||||||
|
type EnglishStemmerFilter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEnglishStemmerFilter() *EnglishStemmerFilter {
|
||||||
|
return &EnglishStemmerFilter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *EnglishStemmerFilter) Filter(input analysis.TokenStream) analysis.TokenStream {
|
||||||
|
for _, token := range input {
|
||||||
|
env := snowballstem.NewEnv(string(token.Term))
|
||||||
|
english.Stem(env)
|
||||||
|
token.Term = []byte(env.Current())
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
|
func EnglishStemmerFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) {
|
||||||
|
return NewEnglishStemmerFilter(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterTokenFilter(SnowballStemmerName, EnglishStemmerFilterConstructor)
|
||||||
|
}
|
||||||
33
vendor/github.com/blevesearch/bleve/analysis/lang/en/stop_filter_en.go
сгенерированный
поставляемый
Обычный файл
33
vendor/github.com/blevesearch/bleve/analysis/lang/en/stop_filter_en.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 en
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/analysis/token/stop"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func StopTokenFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) {
|
||||||
|
tokenMap, err := cache.TokenMapNamed(StopName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return stop.NewStopTokensFilter(tokenMap), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterTokenFilter(StopName, StopTokenFilterConstructor)
|
||||||
|
}
|
||||||
344
vendor/github.com/blevesearch/bleve/analysis/lang/en/stop_words_en.go
сгенерированный
поставляемый
Обычный файл
344
vendor/github.com/blevesearch/bleve/analysis/lang/en/stop_words_en.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,344 @@
|
|||||||
|
package en
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const StopName = "stop_en"
|
||||||
|
|
||||||
|
// EnglishStopWords is the built-in list of stopwords used by the "stop_en" TokenFilter.
|
||||||
|
//
|
||||||
|
// this content was obtained from:
|
||||||
|
// lucene-4.7.2/analysis/common/src/resources/org/apache/lucene/analysis/snowball/
|
||||||
|
// ` was changed to ' to allow for literal string
|
||||||
|
var EnglishStopWords = []byte(` | From svn.tartarus.org/snowball/trunk/website/algorithms/english/stop.txt
|
||||||
|
| This file is distributed under the BSD License.
|
||||||
|
| See http://snowball.tartarus.org/license.php
|
||||||
|
| Also see http://www.opensource.org/licenses/bsd-license.html
|
||||||
|
| - Encoding was converted to UTF-8.
|
||||||
|
| - This notice was added.
|
||||||
|
|
|
||||||
|
| NOTE: To use this file with StopFilterFactory, you must specify format="snowball"
|
||||||
|
|
||||||
|
| An English stop word list. Comments begin with vertical bar. Each stop
|
||||||
|
| word is at the start of a line.
|
||||||
|
|
||||||
|
| Many of the forms below are quite rare (e.g. "yourselves") but included for
|
||||||
|
| completeness.
|
||||||
|
|
||||||
|
| PRONOUNS FORMS
|
||||||
|
| 1st person sing
|
||||||
|
|
||||||
|
i | subject, always in upper case of course
|
||||||
|
|
||||||
|
me | object
|
||||||
|
my | possessive adjective
|
||||||
|
| the possessive pronoun 'mine' is best suppressed, because of the
|
||||||
|
| sense of coal-mine etc.
|
||||||
|
myself | reflexive
|
||||||
|
| 1st person plural
|
||||||
|
we | subject
|
||||||
|
|
||||||
|
| us | object
|
||||||
|
| care is required here because US = United States. It is usually
|
||||||
|
| safe to remove it if it is in lower case.
|
||||||
|
our | possessive adjective
|
||||||
|
ours | possessive pronoun
|
||||||
|
ourselves | reflexive
|
||||||
|
| second person (archaic 'thou' forms not included)
|
||||||
|
you | subject and object
|
||||||
|
your | possessive adjective
|
||||||
|
yours | possessive pronoun
|
||||||
|
yourself | reflexive (singular)
|
||||||
|
yourselves | reflexive (plural)
|
||||||
|
| third person singular
|
||||||
|
he | subject
|
||||||
|
him | object
|
||||||
|
his | possessive adjective and pronoun
|
||||||
|
himself | reflexive
|
||||||
|
|
||||||
|
she | subject
|
||||||
|
her | object and possessive adjective
|
||||||
|
hers | possessive pronoun
|
||||||
|
herself | reflexive
|
||||||
|
|
||||||
|
it | subject and object
|
||||||
|
its | possessive adjective
|
||||||
|
itself | reflexive
|
||||||
|
| third person plural
|
||||||
|
they | subject
|
||||||
|
them | object
|
||||||
|
their | possessive adjective
|
||||||
|
theirs | possessive pronoun
|
||||||
|
themselves | reflexive
|
||||||
|
| other forms (demonstratives, interrogatives)
|
||||||
|
what
|
||||||
|
which
|
||||||
|
who
|
||||||
|
whom
|
||||||
|
this
|
||||||
|
that
|
||||||
|
these
|
||||||
|
those
|
||||||
|
|
||||||
|
| VERB FORMS (using F.R. Palmer's nomenclature)
|
||||||
|
| BE
|
||||||
|
am | 1st person, present
|
||||||
|
is | -s form (3rd person, present)
|
||||||
|
are | present
|
||||||
|
was | 1st person, past
|
||||||
|
were | past
|
||||||
|
be | infinitive
|
||||||
|
been | past participle
|
||||||
|
being | -ing form
|
||||||
|
| HAVE
|
||||||
|
have | simple
|
||||||
|
has | -s form
|
||||||
|
had | past
|
||||||
|
having | -ing form
|
||||||
|
| DO
|
||||||
|
do | simple
|
||||||
|
does | -s form
|
||||||
|
did | past
|
||||||
|
doing | -ing form
|
||||||
|
|
||||||
|
| The forms below are, I believe, best omitted, because of the significant
|
||||||
|
| homonym forms:
|
||||||
|
|
||||||
|
| He made a WILL
|
||||||
|
| old tin CAN
|
||||||
|
| merry month of MAY
|
||||||
|
| a smell of MUST
|
||||||
|
| fight the good fight with all thy MIGHT
|
||||||
|
|
||||||
|
| would, could, should, ought might however be included
|
||||||
|
|
||||||
|
| | AUXILIARIES
|
||||||
|
| | WILL
|
||||||
|
|will
|
||||||
|
|
||||||
|
would
|
||||||
|
|
||||||
|
| | SHALL
|
||||||
|
|shall
|
||||||
|
|
||||||
|
should
|
||||||
|
|
||||||
|
| | CAN
|
||||||
|
|can
|
||||||
|
|
||||||
|
could
|
||||||
|
|
||||||
|
| | MAY
|
||||||
|
|may
|
||||||
|
|might
|
||||||
|
| | MUST
|
||||||
|
|must
|
||||||
|
| | OUGHT
|
||||||
|
|
||||||
|
ought
|
||||||
|
|
||||||
|
| COMPOUND FORMS, increasingly encountered nowadays in 'formal' writing
|
||||||
|
| pronoun + verb
|
||||||
|
|
||||||
|
i'm
|
||||||
|
you're
|
||||||
|
he's
|
||||||
|
she's
|
||||||
|
it's
|
||||||
|
we're
|
||||||
|
they're
|
||||||
|
i've
|
||||||
|
you've
|
||||||
|
we've
|
||||||
|
they've
|
||||||
|
i'd
|
||||||
|
you'd
|
||||||
|
he'd
|
||||||
|
she'd
|
||||||
|
we'd
|
||||||
|
they'd
|
||||||
|
i'll
|
||||||
|
you'll
|
||||||
|
he'll
|
||||||
|
she'll
|
||||||
|
we'll
|
||||||
|
they'll
|
||||||
|
|
||||||
|
| verb + negation
|
||||||
|
|
||||||
|
isn't
|
||||||
|
aren't
|
||||||
|
wasn't
|
||||||
|
weren't
|
||||||
|
hasn't
|
||||||
|
haven't
|
||||||
|
hadn't
|
||||||
|
doesn't
|
||||||
|
don't
|
||||||
|
didn't
|
||||||
|
|
||||||
|
| auxiliary + negation
|
||||||
|
|
||||||
|
won't
|
||||||
|
wouldn't
|
||||||
|
shan't
|
||||||
|
shouldn't
|
||||||
|
can't
|
||||||
|
cannot
|
||||||
|
couldn't
|
||||||
|
mustn't
|
||||||
|
|
||||||
|
| miscellaneous forms
|
||||||
|
|
||||||
|
let's
|
||||||
|
that's
|
||||||
|
who's
|
||||||
|
what's
|
||||||
|
here's
|
||||||
|
there's
|
||||||
|
when's
|
||||||
|
where's
|
||||||
|
why's
|
||||||
|
how's
|
||||||
|
|
||||||
|
| rarer forms
|
||||||
|
|
||||||
|
| daren't needn't
|
||||||
|
|
||||||
|
| doubtful forms
|
||||||
|
|
||||||
|
| oughtn't mightn't
|
||||||
|
|
||||||
|
| ARTICLES
|
||||||
|
a
|
||||||
|
an
|
||||||
|
the
|
||||||
|
|
||||||
|
| THE REST (Overlap among prepositions, conjunctions, adverbs etc is so
|
||||||
|
| high, that classification is pointless.)
|
||||||
|
and
|
||||||
|
but
|
||||||
|
if
|
||||||
|
or
|
||||||
|
because
|
||||||
|
as
|
||||||
|
until
|
||||||
|
while
|
||||||
|
|
||||||
|
of
|
||||||
|
at
|
||||||
|
by
|
||||||
|
for
|
||||||
|
with
|
||||||
|
about
|
||||||
|
against
|
||||||
|
between
|
||||||
|
into
|
||||||
|
through
|
||||||
|
during
|
||||||
|
before
|
||||||
|
after
|
||||||
|
above
|
||||||
|
below
|
||||||
|
to
|
||||||
|
from
|
||||||
|
up
|
||||||
|
down
|
||||||
|
in
|
||||||
|
out
|
||||||
|
on
|
||||||
|
off
|
||||||
|
over
|
||||||
|
under
|
||||||
|
|
||||||
|
again
|
||||||
|
further
|
||||||
|
then
|
||||||
|
once
|
||||||
|
|
||||||
|
here
|
||||||
|
there
|
||||||
|
when
|
||||||
|
where
|
||||||
|
why
|
||||||
|
how
|
||||||
|
|
||||||
|
all
|
||||||
|
any
|
||||||
|
both
|
||||||
|
each
|
||||||
|
few
|
||||||
|
more
|
||||||
|
most
|
||||||
|
other
|
||||||
|
some
|
||||||
|
such
|
||||||
|
|
||||||
|
no
|
||||||
|
nor
|
||||||
|
not
|
||||||
|
only
|
||||||
|
own
|
||||||
|
same
|
||||||
|
so
|
||||||
|
than
|
||||||
|
too
|
||||||
|
very
|
||||||
|
|
||||||
|
| Just for the record, the following words are among the commonest in English
|
||||||
|
|
||||||
|
| one
|
||||||
|
| every
|
||||||
|
| least
|
||||||
|
| less
|
||||||
|
| many
|
||||||
|
| now
|
||||||
|
| ever
|
||||||
|
| never
|
||||||
|
| say
|
||||||
|
| says
|
||||||
|
| said
|
||||||
|
| also
|
||||||
|
| get
|
||||||
|
| go
|
||||||
|
| goes
|
||||||
|
| just
|
||||||
|
| made
|
||||||
|
| make
|
||||||
|
| put
|
||||||
|
| see
|
||||||
|
| seen
|
||||||
|
| whether
|
||||||
|
| like
|
||||||
|
| well
|
||||||
|
| back
|
||||||
|
| even
|
||||||
|
| still
|
||||||
|
| way
|
||||||
|
| take
|
||||||
|
| since
|
||||||
|
| another
|
||||||
|
| however
|
||||||
|
| two
|
||||||
|
| three
|
||||||
|
| four
|
||||||
|
| five
|
||||||
|
| first
|
||||||
|
| second
|
||||||
|
| new
|
||||||
|
| old
|
||||||
|
| high
|
||||||
|
| long
|
||||||
|
`)
|
||||||
|
|
||||||
|
func TokenMapConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenMap, error) {
|
||||||
|
rv := analysis.NewTokenMap()
|
||||||
|
err := rv.LoadBytes(EnglishStopWords)
|
||||||
|
return rv, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterTokenMap(StopName, TokenMapConstructor)
|
||||||
|
}
|
||||||
7
vendor/github.com/blevesearch/bleve/analysis/test_words.txt
сгенерированный
поставляемый
Обычный файл
7
vendor/github.com/blevesearch/bleve/analysis/test_words.txt
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,7 @@
|
|||||||
|
# full line comment
|
||||||
|
marty
|
||||||
|
steve # trailing comment
|
||||||
|
| different format of comment
|
||||||
|
dustin
|
||||||
|
siri | different style trailing comment
|
||||||
|
multiple words with different whitespace
|
||||||
105
vendor/github.com/blevesearch/bleve/analysis/token/lowercase/lowercase.go
сгенерированный
поставляемый
Обычный файл
105
vendor/github.com/blevesearch/bleve/analysis/token/lowercase/lowercase.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,105 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 lowercase implements a TokenFilter which converts
|
||||||
|
// tokens to lower case according to unicode rules.
|
||||||
|
package lowercase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Name is the name used to register LowerCaseFilter in the bleve registry
|
||||||
|
const Name = "to_lower"
|
||||||
|
|
||||||
|
type LowerCaseFilter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLowerCaseFilter() *LowerCaseFilter {
|
||||||
|
return &LowerCaseFilter{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *LowerCaseFilter) Filter(input analysis.TokenStream) analysis.TokenStream {
|
||||||
|
for _, token := range input {
|
||||||
|
token.Term = toLowerDeferredCopy(token.Term)
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
|
func LowerCaseFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) {
|
||||||
|
return NewLowerCaseFilter(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterTokenFilter(Name, LowerCaseFilterConstructor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// toLowerDeferredCopy will function exactly like
|
||||||
|
// bytes.ToLower() only it will reuse (overwrite)
|
||||||
|
// the original byte array when possible
|
||||||
|
// NOTE: because its possible that the lower-case
|
||||||
|
// form of a rune has a different utf-8 encoded
|
||||||
|
// length, in these cases a new byte array is allocated
|
||||||
|
func toLowerDeferredCopy(s []byte) []byte {
|
||||||
|
j := 0
|
||||||
|
for i := 0; i < len(s); {
|
||||||
|
wid := 1
|
||||||
|
r := rune(s[i])
|
||||||
|
if r >= utf8.RuneSelf {
|
||||||
|
r, wid = utf8.DecodeRune(s[i:])
|
||||||
|
}
|
||||||
|
|
||||||
|
l := unicode.ToLower(r)
|
||||||
|
|
||||||
|
// If the rune is already lowercased, just move to the
|
||||||
|
// next rune.
|
||||||
|
if l == r {
|
||||||
|
i += wid
|
||||||
|
j += wid
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles the Unicode edge-case where the last
|
||||||
|
// rune in a word on the greek Σ needs to be converted
|
||||||
|
// differently.
|
||||||
|
if l == 'σ' && i+2 == len(s) {
|
||||||
|
l = 'ς'
|
||||||
|
}
|
||||||
|
|
||||||
|
lwid := utf8.RuneLen(l)
|
||||||
|
if lwid > wid {
|
||||||
|
// utf-8 encoded replacement is wider
|
||||||
|
// for now, punt and defer
|
||||||
|
// to bytes.ToLower() for the remainder
|
||||||
|
// only known to happen with chars
|
||||||
|
// Rune Ⱥ(570) width 2 - Lower ⱥ(11365) width 3
|
||||||
|
// Rune Ⱦ(574) width 2 - Lower ⱦ(11366) width 3
|
||||||
|
rest := bytes.ToLower(s[i:])
|
||||||
|
rv := make([]byte, j+len(rest))
|
||||||
|
copy(rv[:j], s[:j])
|
||||||
|
copy(rv[j:], rest)
|
||||||
|
return rv
|
||||||
|
} else {
|
||||||
|
utf8.EncodeRune(s[j:], l)
|
||||||
|
}
|
||||||
|
i += wid
|
||||||
|
j += lwid
|
||||||
|
}
|
||||||
|
return s[:j]
|
||||||
|
}
|
||||||
53
vendor/github.com/blevesearch/bleve/analysis/token/porter/porter.go
сгенерированный
поставляемый
Обычный файл
53
vendor/github.com/blevesearch/bleve/analysis/token/porter/porter.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,53 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 porter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
|
||||||
|
"github.com/blevesearch/go-porterstemmer"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Name = "stemmer_porter"
|
||||||
|
|
||||||
|
type PorterStemmer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPorterStemmer() *PorterStemmer {
|
||||||
|
return &PorterStemmer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *PorterStemmer) Filter(input analysis.TokenStream) analysis.TokenStream {
|
||||||
|
for _, token := range input {
|
||||||
|
// if it is not a protected keyword, stem it
|
||||||
|
if !token.KeyWord {
|
||||||
|
termRunes := bytes.Runes(token.Term)
|
||||||
|
stemmedRunes := porterstemmer.StemWithoutLowerCasing(termRunes)
|
||||||
|
token.Term = analysis.BuildTermFromRunes(stemmedRunes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return input
|
||||||
|
}
|
||||||
|
|
||||||
|
func PorterStemmerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) {
|
||||||
|
return NewPorterStemmer(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterTokenFilter(Name, PorterStemmerConstructor)
|
||||||
|
}
|
||||||
70
vendor/github.com/blevesearch/bleve/analysis/token/stop/stop.go
сгенерированный
поставляемый
Обычный файл
70
vendor/github.com/blevesearch/bleve/analysis/token/stop/stop.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,70 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 stop implements a TokenFilter removing tokens found in
|
||||||
|
// a TokenMap.
|
||||||
|
//
|
||||||
|
// It constructor takes the following arguments:
|
||||||
|
//
|
||||||
|
// "stop_token_map" (string): the name of the token map identifying tokens to
|
||||||
|
// remove.
|
||||||
|
package stop
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Name = "stop_tokens"
|
||||||
|
|
||||||
|
type StopTokensFilter struct {
|
||||||
|
stopTokens analysis.TokenMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStopTokensFilter(stopTokens analysis.TokenMap) *StopTokensFilter {
|
||||||
|
return &StopTokensFilter{
|
||||||
|
stopTokens: stopTokens,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *StopTokensFilter) Filter(input analysis.TokenStream) analysis.TokenStream {
|
||||||
|
j := 0
|
||||||
|
for _, token := range input {
|
||||||
|
_, isStopToken := f.stopTokens[string(token.Term)]
|
||||||
|
if !isStopToken {
|
||||||
|
input[j] = token
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return input[:j]
|
||||||
|
}
|
||||||
|
|
||||||
|
func StopTokensFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) {
|
||||||
|
stopTokenMapName, ok := config["stop_token_map"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("must specify stop_token_map")
|
||||||
|
}
|
||||||
|
stopTokenMap, err := cache.TokenMapNamed(stopTokenMapName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error building stop words filter: %v", err)
|
||||||
|
}
|
||||||
|
return NewStopTokensFilter(stopTokenMap), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterTokenFilter(Name, StopTokensFilterConstructor)
|
||||||
|
}
|
||||||
49
vendor/github.com/blevesearch/bleve/analysis/tokenizer/single/single.go
сгенерированный
поставляемый
Обычный файл
49
vendor/github.com/blevesearch/bleve/analysis/tokenizer/single/single.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 single
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Name = "single"
|
||||||
|
|
||||||
|
type SingleTokenTokenizer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSingleTokenTokenizer() *SingleTokenTokenizer {
|
||||||
|
return &SingleTokenTokenizer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *SingleTokenTokenizer) Tokenize(input []byte) analysis.TokenStream {
|
||||||
|
return analysis.TokenStream{
|
||||||
|
&analysis.Token{
|
||||||
|
Term: input,
|
||||||
|
Position: 1,
|
||||||
|
Start: 0,
|
||||||
|
End: len(input),
|
||||||
|
Type: analysis.AlphaNumeric,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SingleTokenTokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) {
|
||||||
|
return NewSingleTokenTokenizer(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterTokenizer(Name, SingleTokenTokenizerConstructor)
|
||||||
|
}
|
||||||
131
vendor/github.com/blevesearch/bleve/analysis/tokenizer/unicode/unicode.go
сгенерированный
поставляемый
Обычный файл
131
vendor/github.com/blevesearch/bleve/analysis/tokenizer/unicode/unicode.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,131 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 unicode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/blevesearch/segment"
|
||||||
|
|
||||||
|
"github.com/blevesearch/bleve/analysis"
|
||||||
|
"github.com/blevesearch/bleve/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
const Name = "unicode"
|
||||||
|
|
||||||
|
type UnicodeTokenizer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewUnicodeTokenizer() *UnicodeTokenizer {
|
||||||
|
return &UnicodeTokenizer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rt *UnicodeTokenizer) Tokenize(input []byte) analysis.TokenStream {
|
||||||
|
rvx := make([]analysis.TokenStream, 0, 10) // When rv gets full, append to rvx.
|
||||||
|
rv := make(analysis.TokenStream, 0, 1)
|
||||||
|
|
||||||
|
ta := []analysis.Token(nil)
|
||||||
|
taNext := 0
|
||||||
|
|
||||||
|
segmenter := segment.NewWordSegmenterDirect(input)
|
||||||
|
start := 0
|
||||||
|
pos := 1
|
||||||
|
|
||||||
|
guessRemaining := func(end int) int {
|
||||||
|
avgSegmentLen := end / (len(rv) + 1)
|
||||||
|
if avgSegmentLen < 1 {
|
||||||
|
avgSegmentLen = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
remainingLen := len(input) - end
|
||||||
|
|
||||||
|
return remainingLen / avgSegmentLen
|
||||||
|
}
|
||||||
|
|
||||||
|
for segmenter.Segment() {
|
||||||
|
segmentBytes := segmenter.Bytes()
|
||||||
|
end := start + len(segmentBytes)
|
||||||
|
if segmenter.Type() != segment.None {
|
||||||
|
if taNext >= len(ta) {
|
||||||
|
remainingSegments := guessRemaining(end)
|
||||||
|
if remainingSegments > 1000 {
|
||||||
|
remainingSegments = 1000
|
||||||
|
}
|
||||||
|
if remainingSegments < 1 {
|
||||||
|
remainingSegments = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ta = make([]analysis.Token, remainingSegments)
|
||||||
|
taNext = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
token := &ta[taNext]
|
||||||
|
taNext++
|
||||||
|
|
||||||
|
token.Term = segmentBytes
|
||||||
|
token.Start = start
|
||||||
|
token.End = end
|
||||||
|
token.Position = pos
|
||||||
|
token.Type = convertType(segmenter.Type())
|
||||||
|
|
||||||
|
if len(rv) >= cap(rv) { // When rv is full, save it into rvx.
|
||||||
|
rvx = append(rvx, rv)
|
||||||
|
|
||||||
|
rvCap := cap(rv) * 2
|
||||||
|
if rvCap > 256 {
|
||||||
|
rvCap = 256
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = make(analysis.TokenStream, 0, rvCap) // Next rv cap is bigger.
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = append(rv, token)
|
||||||
|
pos++
|
||||||
|
}
|
||||||
|
start = end
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rvx) > 0 {
|
||||||
|
n := len(rv)
|
||||||
|
for _, r := range rvx {
|
||||||
|
n += len(r)
|
||||||
|
}
|
||||||
|
rall := make(analysis.TokenStream, 0, n)
|
||||||
|
for _, r := range rvx {
|
||||||
|
rall = append(rall, r...)
|
||||||
|
}
|
||||||
|
return append(rall, rv...)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnicodeTokenizerConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.Tokenizer, error) {
|
||||||
|
return NewUnicodeTokenizer(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
registry.RegisterTokenizer(Name, UnicodeTokenizerConstructor)
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertType(segmentWordType int) analysis.TokenType {
|
||||||
|
switch segmentWordType {
|
||||||
|
case segment.Ideo:
|
||||||
|
return analysis.Ideographic
|
||||||
|
case segment.Kana:
|
||||||
|
return analysis.Ideographic
|
||||||
|
case segment.Number:
|
||||||
|
return analysis.Numeric
|
||||||
|
}
|
||||||
|
return analysis.AlphaNumeric
|
||||||
|
}
|
||||||
76
vendor/github.com/blevesearch/bleve/analysis/tokenmap.go
сгенерированный
поставляемый
Обычный файл
76
vendor/github.com/blevesearch/bleve/analysis/tokenmap.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,76 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 analysis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TokenMap map[string]bool
|
||||||
|
|
||||||
|
func NewTokenMap() TokenMap {
|
||||||
|
return make(TokenMap, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadFile reads in a list of tokens from a text file,
|
||||||
|
// one per line.
|
||||||
|
// Comments are supported using `#` or `|`
|
||||||
|
func (t TokenMap) LoadFile(filename string) error {
|
||||||
|
data, err := ioutil.ReadFile(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return t.LoadBytes(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadBytes reads in a list of tokens from memory,
|
||||||
|
// one per line.
|
||||||
|
// Comments are supported using `#` or `|`
|
||||||
|
func (t TokenMap) LoadBytes(data []byte) error {
|
||||||
|
bytesReader := bytes.NewReader(data)
|
||||||
|
bufioReader := bufio.NewReader(bytesReader)
|
||||||
|
line, err := bufioReader.ReadString('\n')
|
||||||
|
for err == nil {
|
||||||
|
t.LoadLine(line)
|
||||||
|
line, err = bufioReader.ReadString('\n')
|
||||||
|
}
|
||||||
|
// if the err was EOF we still need to process the last value
|
||||||
|
if err == io.EOF {
|
||||||
|
t.LoadLine(line)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TokenMap) LoadLine(line string) {
|
||||||
|
// find the start of a comment, if any
|
||||||
|
startComment := strings.IndexAny(line, "#|")
|
||||||
|
if startComment >= 0 {
|
||||||
|
line = line[:startComment]
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens := strings.Fields(line)
|
||||||
|
for _, token := range tokens {
|
||||||
|
t.AddToken(token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TokenMap) AddToken(token string) {
|
||||||
|
t[token] = true
|
||||||
|
}
|
||||||
103
vendor/github.com/blevesearch/bleve/analysis/type.go
сгенерированный
поставляемый
Обычный файл
103
vendor/github.com/blevesearch/bleve/analysis/type.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,103 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 analysis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CharFilter interface {
|
||||||
|
Filter([]byte) []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type TokenType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
AlphaNumeric TokenType = iota
|
||||||
|
Ideographic
|
||||||
|
Numeric
|
||||||
|
DateTime
|
||||||
|
Shingle
|
||||||
|
Single
|
||||||
|
Double
|
||||||
|
Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
// Token represents one occurrence of a term at a particular location in a
|
||||||
|
// field.
|
||||||
|
type Token struct {
|
||||||
|
// Start specifies the byte offset of the beginning of the term in the
|
||||||
|
// field.
|
||||||
|
Start int `json:"start"`
|
||||||
|
|
||||||
|
// End specifies the byte offset of the end of the term in the field.
|
||||||
|
End int `json:"end"`
|
||||||
|
Term []byte `json:"term"`
|
||||||
|
|
||||||
|
// Position specifies the 1-based index of the token in the sequence of
|
||||||
|
// occurrences of its term in the field.
|
||||||
|
Position int `json:"position"`
|
||||||
|
Type TokenType `json:"type"`
|
||||||
|
KeyWord bool `json:"keyword"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Token) String() string {
|
||||||
|
return fmt.Sprintf("Start: %d End: %d Position: %d Token: %s Type: %d", t.Start, t.End, t.Position, string(t.Term), t.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
type TokenStream []*Token
|
||||||
|
|
||||||
|
// A Tokenizer splits an input string into tokens, the usual behaviour being to
|
||||||
|
// map words to tokens.
|
||||||
|
type Tokenizer interface {
|
||||||
|
Tokenize([]byte) TokenStream
|
||||||
|
}
|
||||||
|
|
||||||
|
// A TokenFilter adds, transforms or removes tokens from a token stream.
|
||||||
|
type TokenFilter interface {
|
||||||
|
Filter(TokenStream) TokenStream
|
||||||
|
}
|
||||||
|
|
||||||
|
type Analyzer struct {
|
||||||
|
CharFilters []CharFilter
|
||||||
|
Tokenizer Tokenizer
|
||||||
|
TokenFilters []TokenFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Analyzer) Analyze(input []byte) TokenStream {
|
||||||
|
if a.CharFilters != nil {
|
||||||
|
for _, cf := range a.CharFilters {
|
||||||
|
input = cf.Filter(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokens := a.Tokenizer.Tokenize(input)
|
||||||
|
if a.TokenFilters != nil {
|
||||||
|
for _, tf := range a.TokenFilters {
|
||||||
|
tokens = tf.Filter(tokens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
var ErrInvalidDateTime = fmt.Errorf("unable to parse datetime with any of the layouts")
|
||||||
|
|
||||||
|
type DateTimeParser interface {
|
||||||
|
ParseDateTime(string) (time.Time, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ByteArrayConverter interface {
|
||||||
|
Convert([]byte) (interface{}, error)
|
||||||
|
}
|
||||||
92
vendor/github.com/blevesearch/bleve/analysis/util.go
сгенерированный
поставляемый
Обычный файл
92
vendor/github.com/blevesearch/bleve/analysis/util.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,92 @@
|
|||||||
|
// Copyright (c) 2014 Couchbase, Inc.
|
||||||
|
//
|
||||||
|
// 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 analysis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DeleteRune(in []rune, pos int) []rune {
|
||||||
|
if pos >= len(in) {
|
||||||
|
return in
|
||||||
|
}
|
||||||
|
copy(in[pos:], in[pos+1:])
|
||||||
|
return in[:len(in)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func InsertRune(in []rune, pos int, r rune) []rune {
|
||||||
|
// create a new slice 1 rune larger
|
||||||
|
rv := make([]rune, len(in)+1)
|
||||||
|
// copy the characters before the insert pos
|
||||||
|
copy(rv[0:pos], in[0:pos])
|
||||||
|
// set the inserted rune
|
||||||
|
rv[pos] = r
|
||||||
|
// copy the characters after the insert pos
|
||||||
|
copy(rv[pos+1:], in[pos:])
|
||||||
|
return rv
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildTermFromRunesOptimistic will build a term from the provided runes
|
||||||
|
// AND optimistically attempt to encode into the provided buffer
|
||||||
|
// if at any point it appears the buffer is too small, a new buffer is
|
||||||
|
// allocated and that is used instead
|
||||||
|
// this should be used in cases where frequently the new term is the same
|
||||||
|
// length or shorter than the original term (in number of bytes)
|
||||||
|
func BuildTermFromRunesOptimistic(buf []byte, runes []rune) []byte {
|
||||||
|
rv := buf
|
||||||
|
used := 0
|
||||||
|
for _, r := range runes {
|
||||||
|
nextLen := utf8.RuneLen(r)
|
||||||
|
if used+nextLen > len(rv) {
|
||||||
|
// alloc new buf
|
||||||
|
buf = make([]byte, len(runes)*utf8.UTFMax)
|
||||||
|
// copy work we've already done
|
||||||
|
copy(buf, rv[:used])
|
||||||
|
rv = buf
|
||||||
|
}
|
||||||
|
written := utf8.EncodeRune(rv[used:], r)
|
||||||
|
used += written
|
||||||
|
}
|
||||||
|
return rv[:used]
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildTermFromRunes(runes []rune) []byte {
|
||||||
|
return BuildTermFromRunesOptimistic(make([]byte, len(runes)*utf8.UTFMax), runes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TruncateRunes(input []byte, num int) []byte {
|
||||||
|
runes := bytes.Runes(input)
|
||||||
|
runes = runes[:len(runes)-num]
|
||||||
|
out := BuildTermFromRunes(runes)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunesEndsWith(input []rune, suffix string) bool {
|
||||||
|
inputLen := len(input)
|
||||||
|
suffixRunes := []rune(suffix)
|
||||||
|
suffixLen := len(suffixRunes)
|
||||||
|
if suffixLen > inputLen {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := suffixLen - 1; i >= 0; i-- {
|
||||||
|
if input[inputLen-(suffixLen-i)] != suffixRunes[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user