func (db *DB) _raw_ssttlat_put(ns byte, key []byte, ttlat uint64) bool { if ttlat == 0 { return true } key = skv.RawNsKeyConcat(ns, key) batch := new(leveldb.Batch) // if prev := db.RawGet(skv.RawTtlEntry(key)); prev.Status == skv.ReplyOK { if prev_ttlat := dbutil.BytesToUint64(prev.Bytes()); prev_ttlat != ttlat { batch.Delete(skv.RawTtlQueue(key, prev_ttlat)) } } // batch.Put(skv.RawTtlQueue(key, ttlat), []byte{}) // batch.Put(skv.RawTtlEntry(key), dbutil.Uint64ToBytes(ttlat)) if err := db.ldb.Write(batch, nil); err != nil { return false } return true }
func (db *DB) _raw_ssttl_get(ns byte, key []byte) *skv.Reply { key = skv.RawNsKeyConcat(ns, key) rpl, ttl := skv.NewReply(""), int64(0) if ttlat := dbutil.BytesToUint64(db.RawGet(skv.RawTtlEntry(key)).Bytes()); ttlat > 0 { ttl = (dbutil.MetaTimeParse(ttlat).UnixNano() - time.Now().UTC().UnixNano()) / 1e6 } if ttl < 0 { ttl = 0 } rpl.Data = append(rpl.Data, []byte(strconv.FormatInt(ttl, 10))) return rpl }
func (db *DB) ttl_worker() { go func() { for { ls := db._raw_ssttlat_range(0, dbutil.MetaTimeNow(), _ttl_worker_limit).Hash() for _, v := range ls { batch := new(leveldb.Batch) if dbutil.BytesToUint64(db.RawGet(skv.RawTtlEntry(v.Key[9:])).Bytes()) == v.Uint64() { batch.Delete(skv.RawTtlEntry(v.Key[9:])) switch v.Key[9] { case skv.NsObjectEntry: db.ObjectDel(string(v.Key[10:])) case skv.NsKvEntry: batch.Delete(v.Key[9:]) } } batch.Delete(v.Key) db.ldb.Write(batch, nil) } if uint64(len(ls)) < _ttl_worker_limit { time.Sleep(_ttl_worker_sleep) } } }() }
func (db *DB) ObjectDocPut(fold, key string, obj interface{}, opts *skv.ObjectWriteOptions) *skv.Reply { _obj_doc_global_locker.Lock() _obj_doc_global_locker.Unlock() var ( opath = skv.NewObjectPathKey(fold, key) rpl = skv.NewReply("") ) if len(opath.Fold) > skv.ObjectDocKeyLenMax || len(opath.Field) > skv.ObjectDocPriLenMax || obj == nil { rpl.Status = skv.ReplyBadArgument return rpl } var ( bkey = opath.EntryIndex() objt = reflect.TypeOf(obj) objv = reflect.ValueOf(obj) prev = map[string]interface{}{} previdx = map[uint8]skv.ObjectDocSchemaIndexEntryBytes{} set = map[string]interface{}{} ) if opts == nil { opts = _obj_options_def } prevobj := db.RawGet(bkey).Object() if prevobj.Status == skv.ReplyOK { if err := prevobj.Data.JsonDecode(&prev); err == nil { previdx = skv.ObjectDocIndexDataExport(_obj_doc_indexes, opath.Fold, prev) } } if objt.Kind() == reflect.Struct { for i := 0; i < objt.NumField(); i++ { set[skv.ObjectDocIndexStringFilter(objt.Field(i).Name)] = objv.Field(i).Interface() } } else if objt.Kind() == reflect.Map { mks := objv.MapKeys() for _, mkv := range mks { if mkv.Kind() == reflect.String { set[skv.ObjectDocIndexStringFilter(mkv.String())] = objv.MapIndex(mkv).Interface() } } } else { rpl.Status = skv.ReplyBadArgument return rpl } setidx, idxnew, idxdup := skv.ObjectDocIndexDataExport(_obj_doc_indexes, opath.Fold, set), [][]byte{}, [][]byte{} // fmt.Println("\tsetidx", setidx) // fmt.Println("\tprevidx", previdx) for siKey, siEntry := range setidx { var incr_set, incr_prev uint64 if siEntry.AutoIncr { incr_set = dbutil.BytesToUint64(siEntry.Data) } // if piEntry, ok := previdx[siKey]; ok { if siEntry.AutoIncr && incr_set == 0 { if incr_prev = dbutil.BytesToUint64(piEntry.Data); incr_prev > 0 { siEntry.Data, incr_set = piEntry.Data, incr_prev set[siEntry.FieldName] = incr_set continue } } else if bytes.Compare(piEntry.Data, siEntry.Data) == 0 { continue } idxdup = append(idxdup, append(append(skv.ObjectDocIndexFieldPrefix(opath.Fold, siKey), piEntry.Data...), opath.Field...)) } // if siEntry.AutoIncr { if incr_set == 0 { incr_set = db.RawIncrby(skv.ObjectDocIndexIncrKey(opath.Fold, siEntry.Seq), 1).Uint64() ibs := make([]byte, 8) binary.BigEndian.PutUint64(ibs, incr_set) siEntry.Data = ibs[(8 - len(siEntry.Data)):] set[siEntry.FieldName] = incr_set } else if incr_set > 0 && incr_set > incr_prev { if db.RawGet(skv.ObjectDocIndexIncrKey(opath.Fold, siEntry.Seq)).Uint64() < incr_set { db.RawPut(skv.ObjectDocIndexIncrKey(opath.Fold, siEntry.Seq), []byte(strconv.FormatUint(incr_set, 10)), 0) } } } if siEntry.Unique || siEntry.AutoIncr { objIdxKeyPrefix := append(skv.ObjectDocIndexFieldPrefix(opath.Fold, siKey), siEntry.Data...) if rs := db.RawScan(objIdxKeyPrefix, []byte{}, 1).Hash(); len(rs) > 0 { rpl.Status = skv.ReplyBadArgument return rpl } } idxnew = append(idxnew, append(append(skv.ObjectDocIndexFieldPrefix(opath.Fold, siKey), siEntry.Data...), opath.Field...)) } // // batch := new(leveldb.Batch) for _, idxkey := range idxdup { batch.Delete(idxkey) } for _, idxkey := range idxnew { batch.Put(idxkey, []byte{}) } bvalue, _ := dbutil.JsonEncode(set) sum := crc32.ChecksumIEEE(bvalue) if prevobj.Meta.Sum == sum { return skv.NewReply(skv.ReplyOK) } db._obj_meta_sync(skv.ObjectTypeDocument, &prevobj.Meta, opath, int64(len(bvalue)), sum, _obj_options_def) batch.Put(bkey, append(prevobj.Meta.Export(), bvalue...)) if err := db.ldb.Write(batch, nil); err != nil { rpl.Status = err.Error() } return rpl }