mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-10-08 03:47:51 +00:00
174 lines
5 KiB
Go
174 lines
5 KiB
Go
package index
|
|
|
|
// #cgo CFLAGS:-mpopcnt
|
|
|
|
import (
|
|
"log"
|
|
"pilosa/config"
|
|
"pilosa/util"
|
|
|
|
"time"
|
|
|
|
"github.com/gocql/gocql"
|
|
)
|
|
|
|
type CassandraStorage struct {
|
|
db *gocql.Session
|
|
batch *gocql.Batch
|
|
stmt string
|
|
batch_time time.Time
|
|
batch_counter int
|
|
cass_time_window_secs float64
|
|
cass_flush_size int
|
|
}
|
|
|
|
var cluster *gocql.ClusterConfig
|
|
|
|
func init() {
|
|
hosts := config.GetStringArrayDefault("cassandra_hosts", []string{"localhost"})
|
|
keyspace := config.GetStringDefault("cassandra_keyspace", "pilosa")
|
|
cluster = gocql.NewCluster(hosts...)
|
|
cluster.Keyspace = keyspace
|
|
cluster.Consistency = gocql.One
|
|
cluster.Timeout = 5 * time.Second
|
|
cluster.RetryPolicy = gocql.RetryPolicy{NumRetries: 10}
|
|
}
|
|
|
|
func BuildSchema() {
|
|
/*
|
|
"CREATE KEYSPACE IF NOT EXISTS pilosa WITH strategy_class = SimpleStrategy AND strategy_options:replication_factor = 1"
|
|
create keyspace if not exists pilosa with replication = {'class': 'SimpleStrategy', 'replication_factor' : 1} and durable_writes = true;
|
|
CREATE TABLE IF NOT EXISTS bitmap (bitmap_id bigint, db varchar, frame varchar, slice int, filter int, chunkkey bigint, blockindex int, block bigint, PRIMARY KEY ((bitmap_id, db, frame, slice), chunkkey, blockindex) )
|
|
"
|
|
*/
|
|
|
|
}
|
|
func NewCassStorage() Storage {
|
|
obj := new(CassandraStorage)
|
|
// cluster.CQLVersion = "3.0.0"
|
|
session, err := cluster.CreateSession()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
obj.db = session
|
|
obj.stmt = `INSERT INTO bitmap ( bitmap_id, db, frame, slice , filter, ChunkKey, BlockIndex, block) VALUES (?,?,?,?,?,?,?,?) USING timestamp ?;`
|
|
obj.batch = nil
|
|
obj.batch_time = time.Now()
|
|
obj.batch_counter = 0
|
|
obj.cass_time_window_secs = float64(config.GetIntDefault("cassandra_time_window_secs", 5))
|
|
obj.cass_flush_size = config.GetIntDefault("cassandra_max_size_batch", 15)
|
|
return obj
|
|
}
|
|
|
|
func (c *CassandraStorage) Close() {
|
|
}
|
|
func (c *CassandraStorage) Fetch(bitmap_id uint64, db string, frame string, slice int) (IBitmap, uint64) {
|
|
var dumb = COUNTERMASK
|
|
last_key := int64(dumb)
|
|
marker := int64(dumb)
|
|
var id = util.Uint64ToInt64(bitmap_id)
|
|
start := time.Now()
|
|
var (
|
|
chunk *Chunk
|
|
chunk_key, block int64
|
|
block_index uint32
|
|
s8 uint8
|
|
filter int
|
|
)
|
|
|
|
bitmap := CreateRBBitmap()
|
|
iter := c.db.Query("SELECT filter,Chunkkey,BlockIndex,block FROM bitmap WHERE bitmap_id=? AND db=? AND frame=? AND slice=? ", id, db, frame, slice).Iter()
|
|
count := int64(0)
|
|
|
|
for iter.Scan(&filter, &chunk_key, &block_index, &block) {
|
|
s8 = uint8(block_index)
|
|
if chunk_key != marker {
|
|
if chunk_key != last_key {
|
|
chunk = &Chunk{uint64(chunk_key), BlockArray{make([]uint64, 32, 32)}}
|
|
bitmap.AddChunk(chunk)
|
|
}
|
|
chunk.Value.Block[s8] = uint64(block)
|
|
|
|
} else {
|
|
count = block
|
|
}
|
|
last_key = chunk_key
|
|
|
|
}
|
|
delta := time.Since(start)
|
|
util.SendTimer("cassandra_storage_Fetch", delta.Nanoseconds())
|
|
bitmap.SetCount(uint64(count))
|
|
return bitmap, uint64(filter)
|
|
}
|
|
func (self *CassandraStorage) BeginBatch() {
|
|
if self.batch == nil {
|
|
self.batch = gocql.NewBatch(gocql.LoggedBatch)
|
|
}
|
|
self.batch_counter++
|
|
}
|
|
func (self *CassandraStorage) runBatch(batch *gocql.Batch) {
|
|
if batch != nil {
|
|
self.db.ExecuteBatch(batch)
|
|
}
|
|
}
|
|
func (self *CassandraStorage) FlushBatch() {
|
|
start := time.Now()
|
|
self.runBatch(self.batch) //maybe this is crazy but i'll give it a whirl
|
|
self.batch = nil
|
|
self.batch_time = time.Now()
|
|
self.batch_counter = 0
|
|
delta := time.Since(start)
|
|
util.SendTimer("cassandra_storage_FlushBatch", delta.Nanoseconds())
|
|
}
|
|
func (self *CassandraStorage) EndBatch() {
|
|
start := time.Now()
|
|
if self.batch != nil {
|
|
self.FlushBatch()
|
|
/*
|
|
last := time.Since(self.batch_time)
|
|
if last.Seconds() > self.cass_time_window_secs {
|
|
self.FlushBatch()
|
|
} else if self.batch_counter > self.cass_flush_size {
|
|
self.FlushBatch()
|
|
}
|
|
*/
|
|
} else {
|
|
log.Println("NIL BATCH")
|
|
}
|
|
delta := time.Since(start)
|
|
util.SendTimer("cassandra_storage_EndBatch", delta.Nanoseconds())
|
|
|
|
}
|
|
|
|
func (self *CassandraStorage) Store(id uint64, db string, frame string, slice int, filter uint64, bitmap *Bitmap) error {
|
|
self.BeginBatch()
|
|
for i := bitmap.Min(); !i.Limit(); i = i.Next() {
|
|
var chunk = i.Item()
|
|
for idx, block := range chunk.Value.Block {
|
|
block_index := int32(idx)
|
|
if block != 0 {
|
|
self.StoreBlock(id, db, frame, slice, filter, chunk.Key, block_index, block)
|
|
}
|
|
}
|
|
}
|
|
cnt := BitCount(bitmap)
|
|
self.StoreBlock(id, db, frame, slice, filter, COUNTERMASK, 0, cnt)
|
|
self.EndBatch()
|
|
return nil
|
|
}
|
|
|
|
func (self *CassandraStorage) StoreBlock(bid uint64, db string, frame string, slice int, filter uint64, bchunk uint64, block_index int32, bblock uint64) error {
|
|
id := util.Uint64ToInt64(bid) //these fucntions ignore overflow
|
|
block := util.Uint64ToInt64(bblock)
|
|
chunk := util.Uint64ToInt64(bchunk)
|
|
|
|
if self.batch == nil {
|
|
self.BeginBatch()
|
|
}
|
|
start := time.Now()
|
|
self.batch.Query(self.stmt, id, db, frame, slice, int(filter), chunk, block_index, block, start.UnixNano())
|
|
delta := time.Since(start)
|
|
util.SendTimer("cassandra_storage_StoreBlock", delta.Nanoseconds())
|
|
return nil
|
|
}
|